diff options
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r-- | arch/x86/mm/fault.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 2dbf6bf4c7e..0d17c8c50ac 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/traps.h> /* dotraplinkage, ... */ | 17 | #include <asm/traps.h> /* dotraplinkage, ... */ |
18 | #include <asm/pgalloc.h> /* pgd_*(), ... */ | 18 | #include <asm/pgalloc.h> /* pgd_*(), ... */ |
19 | #include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ | 19 | #include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ |
20 | #include <asm/vsyscall.h> | ||
20 | 21 | ||
21 | /* | 22 | /* |
22 | * Page fault error code bits: | 23 | * Page fault error code bits: |
@@ -105,7 +106,7 @@ check_prefetch_opcode(struct pt_regs *regs, unsigned char *instr, | |||
105 | * but for now it's good enough to assume that long | 106 | * but for now it's good enough to assume that long |
106 | * mode only uses well known segments or kernel. | 107 | * mode only uses well known segments or kernel. |
107 | */ | 108 | */ |
108 | return (!user_mode(regs)) || (regs->cs == __USER_CS); | 109 | return (!user_mode(regs) || user_64bit_mode(regs)); |
109 | #endif | 110 | #endif |
110 | case 0x60: | 111 | case 0x60: |
111 | /* 0x64 thru 0x67 are valid prefixes in all modes. */ | 112 | /* 0x64 thru 0x67 are valid prefixes in all modes. */ |
@@ -720,6 +721,18 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | |||
720 | if (is_errata100(regs, address)) | 721 | if (is_errata100(regs, address)) |
721 | return; | 722 | return; |
722 | 723 | ||
724 | #ifdef CONFIG_X86_64 | ||
725 | /* | ||
726 | * Instruction fetch faults in the vsyscall page might need | ||
727 | * emulation. | ||
728 | */ | ||
729 | if (unlikely((error_code & PF_INSTR) && | ||
730 | ((address & ~0xfff) == VSYSCALL_START))) { | ||
731 | if (emulate_vsyscall(regs, address)) | ||
732 | return; | ||
733 | } | ||
734 | #endif | ||
735 | |||
723 | if (unlikely(show_unhandled_signals)) | 736 | if (unlikely(show_unhandled_signals)) |
724 | show_signal_msg(regs, error_code, address, tsk); | 737 | show_signal_msg(regs, error_code, address, tsk); |
725 | 738 | ||
@@ -1059,7 +1072,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
1059 | if (unlikely(error_code & PF_RSVD)) | 1072 | if (unlikely(error_code & PF_RSVD)) |
1060 | pgtable_bad(regs, error_code, address); | 1073 | pgtable_bad(regs, error_code, address); |
1061 | 1074 | ||
1062 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); | 1075 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); |
1063 | 1076 | ||
1064 | /* | 1077 | /* |
1065 | * If we're in an interrupt, have no user context or are running | 1078 | * If we're in an interrupt, have no user context or are running |
@@ -1161,11 +1174,11 @@ good_area: | |||
1161 | if (flags & FAULT_FLAG_ALLOW_RETRY) { | 1174 | if (flags & FAULT_FLAG_ALLOW_RETRY) { |
1162 | if (fault & VM_FAULT_MAJOR) { | 1175 | if (fault & VM_FAULT_MAJOR) { |
1163 | tsk->maj_flt++; | 1176 | tsk->maj_flt++; |
1164 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, | 1177 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, |
1165 | regs, address); | 1178 | regs, address); |
1166 | } else { | 1179 | } else { |
1167 | tsk->min_flt++; | 1180 | tsk->min_flt++; |
1168 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, | 1181 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, |
1169 | regs, address); | 1182 | regs, address); |
1170 | } | 1183 | } |
1171 | if (fault & VM_FAULT_RETRY) { | 1184 | if (fault & VM_FAULT_RETRY) { |