diff options
Diffstat (limited to 'arch/x86/mm/fault_32.c')
-rw-r--r-- | arch/x86/mm/fault_32.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/arch/x86/mm/fault_32.c b/arch/x86/mm/fault_32.c index 75ae8c498d67..0bd241729aa3 100644 --- a/arch/x86/mm/fault_32.c +++ b/arch/x86/mm/fault_32.c | |||
@@ -286,6 +286,22 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) | |||
286 | return 0; | 286 | return 0; |
287 | } | 287 | } |
288 | 288 | ||
289 | /* | ||
290 | * Work around K8 erratum #100 K8 in compat mode occasionally jumps to illegal | ||
291 | * addresses >4GB. We catch this in the page fault handler because these | ||
292 | * addresses are not reachable. Just detect this case and return. Any code | ||
293 | * segment in LDT is compatibility mode. | ||
294 | */ | ||
295 | static int is_errata100(struct pt_regs *regs, unsigned long address) | ||
296 | { | ||
297 | #ifdef CONFIG_X86_64 | ||
298 | if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) && | ||
299 | (address >> 32)) | ||
300 | return 1; | ||
301 | #endif | ||
302 | return 0; | ||
303 | } | ||
304 | |||
289 | void do_invalid_op(struct pt_regs *, unsigned long); | 305 | void do_invalid_op(struct pt_regs *, unsigned long); |
290 | 306 | ||
291 | static int is_f00f_bug(struct pt_regs *regs, unsigned long address) | 307 | static int is_f00f_bug(struct pt_regs *regs, unsigned long address) |
@@ -566,6 +582,9 @@ bad_area_nosemaphore: | |||
566 | if (is_prefetch(regs, address, error_code)) | 582 | if (is_prefetch(regs, address, error_code)) |
567 | return; | 583 | return; |
568 | 584 | ||
585 | if (is_errata100(regs, address)) | ||
586 | return; | ||
587 | |||
569 | if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && | 588 | if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && |
570 | printk_ratelimit()) { | 589 | printk_ratelimit()) { |
571 | printk( | 590 | printk( |