diff options
Diffstat (limited to 'arch/powerpc/mm/fault.c')
-rw-r--r-- | arch/powerpc/mm/fault.c | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 51ab9e7e6c39..08d659a9fcdb 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -30,9 +30,9 @@ | |||
30 | #include <linux/kprobes.h> | 30 | #include <linux/kprobes.h> |
31 | #include <linux/kdebug.h> | 31 | #include <linux/kdebug.h> |
32 | #include <linux/perf_event.h> | 32 | #include <linux/perf_event.h> |
33 | #include <linux/magic.h> | ||
34 | #include <linux/ratelimit.h> | 33 | #include <linux/ratelimit.h> |
35 | #include <linux/context_tracking.h> | 34 | #include <linux/context_tracking.h> |
35 | #include <linux/hugetlb.h> | ||
36 | 36 | ||
37 | #include <asm/firmware.h> | 37 | #include <asm/firmware.h> |
38 | #include <asm/page.h> | 38 | #include <asm/page.h> |
@@ -114,22 +114,37 @@ static int store_updates_sp(struct pt_regs *regs) | |||
114 | #define MM_FAULT_CONTINUE -1 | 114 | #define MM_FAULT_CONTINUE -1 |
115 | #define MM_FAULT_ERR(sig) (sig) | 115 | #define MM_FAULT_ERR(sig) (sig) |
116 | 116 | ||
117 | static int do_sigbus(struct pt_regs *regs, unsigned long address) | 117 | static int do_sigbus(struct pt_regs *regs, unsigned long address, |
118 | unsigned int fault) | ||
118 | { | 119 | { |
119 | siginfo_t info; | 120 | siginfo_t info; |
121 | unsigned int lsb = 0; | ||
120 | 122 | ||
121 | up_read(¤t->mm->mmap_sem); | 123 | up_read(¤t->mm->mmap_sem); |
122 | 124 | ||
123 | if (user_mode(regs)) { | 125 | if (!user_mode(regs)) |
124 | current->thread.trap_nr = BUS_ADRERR; | 126 | return MM_FAULT_ERR(SIGBUS); |
125 | info.si_signo = SIGBUS; | 127 | |
126 | info.si_errno = 0; | 128 | current->thread.trap_nr = BUS_ADRERR; |
127 | info.si_code = BUS_ADRERR; | 129 | info.si_signo = SIGBUS; |
128 | info.si_addr = (void __user *)address; | 130 | info.si_errno = 0; |
129 | force_sig_info(SIGBUS, &info, current); | 131 | info.si_code = BUS_ADRERR; |
130 | return MM_FAULT_RETURN; | 132 | info.si_addr = (void __user *)address; |
133 | #ifdef CONFIG_MEMORY_FAILURE | ||
134 | if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { | ||
135 | pr_err("MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", | ||
136 | current->comm, current->pid, address); | ||
137 | info.si_code = BUS_MCEERR_AR; | ||
131 | } | 138 | } |
132 | return MM_FAULT_ERR(SIGBUS); | 139 | |
140 | if (fault & VM_FAULT_HWPOISON_LARGE) | ||
141 | lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); | ||
142 | if (fault & VM_FAULT_HWPOISON) | ||
143 | lsb = PAGE_SHIFT; | ||
144 | #endif | ||
145 | info.si_addr_lsb = lsb; | ||
146 | force_sig_info(SIGBUS, &info, current); | ||
147 | return MM_FAULT_RETURN; | ||
133 | } | 148 | } |
134 | 149 | ||
135 | static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) | 150 | static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) |
@@ -170,11 +185,8 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) | |||
170 | return MM_FAULT_RETURN; | 185 | return MM_FAULT_RETURN; |
171 | } | 186 | } |
172 | 187 | ||
173 | /* Bus error. x86 handles HWPOISON here, we'll add this if/when | 188 | if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) |
174 | * we support the feature in HW | 189 | return do_sigbus(regs, addr, fault); |
175 | */ | ||
176 | if (fault & VM_FAULT_SIGBUS) | ||
177 | return do_sigbus(regs, addr); | ||
178 | 190 | ||
179 | /* We don't understand the fault code, this is fatal */ | 191 | /* We don't understand the fault code, this is fatal */ |
180 | BUG(); | 192 | BUG(); |
@@ -508,7 +520,6 @@ bail: | |||
508 | void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) | 520 | void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) |
509 | { | 521 | { |
510 | const struct exception_table_entry *entry; | 522 | const struct exception_table_entry *entry; |
511 | unsigned long *stackend; | ||
512 | 523 | ||
513 | /* Are we prepared to handle this fault? */ | 524 | /* Are we prepared to handle this fault? */ |
514 | if ((entry = search_exception_tables(regs->nip)) != NULL) { | 525 | if ((entry = search_exception_tables(regs->nip)) != NULL) { |
@@ -537,8 +548,7 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) | |||
537 | printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n", | 548 | printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n", |
538 | regs->nip); | 549 | regs->nip); |
539 | 550 | ||
540 | stackend = end_of_stack(current); | 551 | if (task_stack_end_corrupted(current)) |
541 | if (current != &init_task && *stackend != STACK_END_MAGIC) | ||
542 | printk(KERN_ALERT "Thread overran stack, or stack corrupted\n"); | 552 | printk(KERN_ALERT "Thread overran stack, or stack corrupted\n"); |
543 | 553 | ||
544 | die("Kernel access of bad area", regs, sig); | 554 | die("Kernel access of bad area", regs, sig); |