diff options
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r-- | arch/x86/mm/fault.c | 110 |
1 files changed, 43 insertions, 67 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 8bcb6f40ccb6..455f3fe67b42 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/ptrace.h> | 12 | #include <linux/ptrace.h> |
13 | #include <linux/mmiotrace.h> | ||
13 | #include <linux/mman.h> | 14 | #include <linux/mman.h> |
14 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
15 | #include <linux/smp.h> | 16 | #include <linux/smp.h> |
@@ -49,17 +50,23 @@ | |||
49 | #define PF_RSVD (1<<3) | 50 | #define PF_RSVD (1<<3) |
50 | #define PF_INSTR (1<<4) | 51 | #define PF_INSTR (1<<4) |
51 | 52 | ||
53 | static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) | ||
54 | { | ||
55 | #ifdef CONFIG_MMIOTRACE_HOOKS | ||
56 | if (unlikely(is_kmmio_active())) | ||
57 | if (kmmio_handler(regs, addr) == 1) | ||
58 | return -1; | ||
59 | #endif | ||
60 | return 0; | ||
61 | } | ||
62 | |||
52 | static inline int notify_page_fault(struct pt_regs *regs) | 63 | static inline int notify_page_fault(struct pt_regs *regs) |
53 | { | 64 | { |
54 | #ifdef CONFIG_KPROBES | 65 | #ifdef CONFIG_KPROBES |
55 | int ret = 0; | 66 | int ret = 0; |
56 | 67 | ||
57 | /* kprobe_running() needs smp_processor_id() */ | 68 | /* kprobe_running() needs smp_processor_id() */ |
58 | #ifdef CONFIG_X86_32 | ||
59 | if (!user_mode_vm(regs)) { | 69 | if (!user_mode_vm(regs)) { |
60 | #else | ||
61 | if (!user_mode(regs)) { | ||
62 | #endif | ||
63 | preempt_disable(); | 70 | preempt_disable(); |
64 | if (kprobe_running() && kprobe_fault_handler(regs, 14)) | 71 | if (kprobe_running() && kprobe_fault_handler(regs, 14)) |
65 | ret = 1; | 72 | ret = 1; |
@@ -396,11 +403,7 @@ static void show_fault_oops(struct pt_regs *regs, unsigned long error_code, | |||
396 | printk(KERN_CONT "NULL pointer dereference"); | 403 | printk(KERN_CONT "NULL pointer dereference"); |
397 | else | 404 | else |
398 | printk(KERN_CONT "paging request"); | 405 | printk(KERN_CONT "paging request"); |
399 | #ifdef CONFIG_X86_32 | 406 | printk(KERN_CONT " at %p\n", (void *) address); |
400 | printk(KERN_CONT " at %08lx\n", address); | ||
401 | #else | ||
402 | printk(KERN_CONT " at %016lx\n", address); | ||
403 | #endif | ||
404 | printk(KERN_ALERT "IP:"); | 407 | printk(KERN_ALERT "IP:"); |
405 | printk_address(regs->ip, 1); | 408 | printk_address(regs->ip, 1); |
406 | dump_pagetable(address); | 409 | dump_pagetable(address); |
@@ -606,6 +609,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
606 | 609 | ||
607 | if (notify_page_fault(regs)) | 610 | if (notify_page_fault(regs)) |
608 | return; | 611 | return; |
612 | if (unlikely(kmmio_fault(regs, address))) | ||
613 | return; | ||
609 | 614 | ||
610 | /* | 615 | /* |
611 | * We fault-in kernel-space virtual memory on-demand. The | 616 | * We fault-in kernel-space virtual memory on-demand. The |
@@ -800,14 +805,10 @@ bad_area_nosemaphore: | |||
800 | if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && | 805 | if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && |
801 | printk_ratelimit()) { | 806 | printk_ratelimit()) { |
802 | printk( | 807 | printk( |
803 | #ifdef CONFIG_X86_32 | 808 | "%s%s[%d]: segfault at %lx ip %p sp %p error %lx", |
804 | "%s%s[%d]: segfault at %lx ip %08lx sp %08lx error %lx", | ||
805 | #else | ||
806 | "%s%s[%d]: segfault at %lx ip %lx sp %lx error %lx", | ||
807 | #endif | ||
808 | task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, | 809 | task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, |
809 | tsk->comm, task_pid_nr(tsk), address, regs->ip, | 810 | tsk->comm, task_pid_nr(tsk), address, |
810 | regs->sp, error_code); | 811 | (void *) regs->ip, (void *) regs->sp, error_code); |
811 | print_vma_addr(" in ", regs->ip); | 812 | print_vma_addr(" in ", regs->ip); |
812 | printk("\n"); | 813 | printk("\n"); |
813 | } | 814 | } |
@@ -915,14 +916,7 @@ LIST_HEAD(pgd_list); | |||
915 | void vmalloc_sync_all(void) | 916 | void vmalloc_sync_all(void) |
916 | { | 917 | { |
917 | #ifdef CONFIG_X86_32 | 918 | #ifdef CONFIG_X86_32 |
918 | /* | 919 | unsigned long start = VMALLOC_START & PGDIR_MASK; |
919 | * Note that races in the updates of insync and start aren't | ||
920 | * problematic: insync can only get set bits added, and updates to | ||
921 | * start are only improving performance (without affecting correctness | ||
922 | * if undone). | ||
923 | */ | ||
924 | static DECLARE_BITMAP(insync, PTRS_PER_PGD); | ||
925 | static unsigned long start = TASK_SIZE; | ||
926 | unsigned long address; | 920 | unsigned long address; |
927 | 921 | ||
928 | if (SHARED_KERNEL_PMD) | 922 | if (SHARED_KERNEL_PMD) |
@@ -930,56 +924,38 @@ void vmalloc_sync_all(void) | |||
930 | 924 | ||
931 | BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK); | 925 | BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK); |
932 | for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) { | 926 | for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) { |
933 | if (!test_bit(pgd_index(address), insync)) { | 927 | unsigned long flags; |
934 | unsigned long flags; | 928 | struct page *page; |
935 | struct page *page; | 929 | |
936 | 930 | spin_lock_irqsave(&pgd_lock, flags); | |
937 | spin_lock_irqsave(&pgd_lock, flags); | 931 | list_for_each_entry(page, &pgd_list, lru) { |
938 | list_for_each_entry(page, &pgd_list, lru) { | 932 | if (!vmalloc_sync_one(page_address(page), |
939 | if (!vmalloc_sync_one(page_address(page), | 933 | address)) |
940 | address)) | 934 | break; |
941 | break; | ||
942 | } | ||
943 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
944 | if (!page) | ||
945 | set_bit(pgd_index(address), insync); | ||
946 | } | 935 | } |
947 | if (address == start && test_bit(pgd_index(address), insync)) | 936 | spin_unlock_irqrestore(&pgd_lock, flags); |
948 | start = address + PGDIR_SIZE; | ||
949 | } | 937 | } |
950 | #else /* CONFIG_X86_64 */ | 938 | #else /* CONFIG_X86_64 */ |
951 | /* | 939 | unsigned long start = VMALLOC_START & PGDIR_MASK; |
952 | * Note that races in the updates of insync and start aren't | ||
953 | * problematic: insync can only get set bits added, and updates to | ||
954 | * start are only improving performance (without affecting correctness | ||
955 | * if undone). | ||
956 | */ | ||
957 | static DECLARE_BITMAP(insync, PTRS_PER_PGD); | ||
958 | static unsigned long start = VMALLOC_START & PGDIR_MASK; | ||
959 | unsigned long address; | 940 | unsigned long address; |
960 | 941 | ||
961 | for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) { | 942 | for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) { |
962 | if (!test_bit(pgd_index(address), insync)) { | 943 | const pgd_t *pgd_ref = pgd_offset_k(address); |
963 | const pgd_t *pgd_ref = pgd_offset_k(address); | 944 | unsigned long flags; |
964 | unsigned long flags; | 945 | struct page *page; |
965 | struct page *page; | 946 | |
966 | 947 | if (pgd_none(*pgd_ref)) | |
967 | if (pgd_none(*pgd_ref)) | 948 | continue; |
968 | continue; | 949 | spin_lock_irqsave(&pgd_lock, flags); |
969 | spin_lock_irqsave(&pgd_lock, flags); | 950 | list_for_each_entry(page, &pgd_list, lru) { |
970 | list_for_each_entry(page, &pgd_list, lru) { | 951 | pgd_t *pgd; |
971 | pgd_t *pgd; | 952 | pgd = (pgd_t *)page_address(page) + pgd_index(address); |
972 | pgd = (pgd_t *)page_address(page) + pgd_index(address); | 953 | if (pgd_none(*pgd)) |
973 | if (pgd_none(*pgd)) | 954 | set_pgd(pgd, *pgd_ref); |
974 | set_pgd(pgd, *pgd_ref); | 955 | else |
975 | else | 956 | BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); |
976 | BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); | ||
977 | } | ||
978 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
979 | set_bit(pgd_index(address), insync); | ||
980 | } | 957 | } |
981 | if (address == start) | 958 | spin_unlock_irqrestore(&pgd_lock, flags); |
982 | start = address + PGDIR_SIZE; | ||
983 | } | 959 | } |
984 | #endif | 960 | #endif |
985 | } | 961 | } |