|
@@ -31,6 +31,7 @@
|
|
|
#include <linux/highmem.h>
|
|
|
#include <linux/perf_event.h>
|
|
|
#include <linux/preempt.h>
|
|
|
+#include <linux/hugetlb.h>
|
|
|
|
|
|
#include <asm/bug.h>
|
|
|
#include <asm/cpufeature.h>
|
|
@@ -256,10 +257,11 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr,
|
|
|
*/
|
|
|
static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
|
|
|
unsigned int esr, unsigned int sig, int code,
|
|
|
- struct pt_regs *regs)
|
|
|
+ struct pt_regs *regs, int fault)
|
|
|
{
|
|
|
struct siginfo si;
|
|
|
const struct fault_info *inf;
|
|
|
+ unsigned int lsb = 0;
|
|
|
|
|
|
if (unhandled_signal(tsk, sig) && show_unhandled_signals_ratelimited()) {
|
|
|
inf = esr_to_fault_info(esr);
|
|
@@ -277,6 +279,17 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
|
|
|
si.si_errno = 0;
|
|
|
si.si_code = code;
|
|
|
si.si_addr = (void __user *)addr;
|
|
|
+ /*
|
|
|
+ * Either small page or large page may be poisoned.
|
|
|
+ * In other words, VM_FAULT_HWPOISON_LARGE and
|
|
|
+ * VM_FAULT_HWPOISON are mutually exclusive.
|
|
|
+ */
|
|
|
+ if (fault & VM_FAULT_HWPOISON_LARGE)
|
|
|
+ lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
|
|
|
+ else if (fault & VM_FAULT_HWPOISON)
|
|
|
+ lsb = PAGE_SHIFT;
|
|
|
+ si.si_addr_lsb = lsb;
|
|
|
+
|
|
|
force_sig_info(sig, &si, tsk);
|
|
|
}
|
|
|
|
|
@@ -291,7 +304,7 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re
|
|
|
*/
|
|
|
if (user_mode(regs)) {
|
|
|
inf = esr_to_fault_info(esr);
|
|
|
- __do_user_fault(tsk, addr, esr, inf->sig, inf->code, regs);
|
|
|
+ __do_user_fault(tsk, addr, esr, inf->sig, inf->code, regs, 0);
|
|
|
} else
|
|
|
__do_kernel_fault(addr, esr, regs);
|
|
|
}
|
|
@@ -478,6 +491,9 @@ retry:
|
|
|
*/
|
|
|
sig = SIGBUS;
|
|
|
code = BUS_ADRERR;
|
|
|
+ } else if (fault & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)) {
|
|
|
+ sig = SIGBUS;
|
|
|
+ code = BUS_MCEERR_AR;
|
|
|
} else {
|
|
|
/*
|
|
|
* Something tried to access memory that isn't in our memory
|
|
@@ -488,7 +504,7 @@ retry:
|
|
|
SEGV_ACCERR : SEGV_MAPERR;
|
|
|
}
|
|
|
|
|
|
- __do_user_fault(tsk, addr, esr, sig, code, regs);
|
|
|
+ __do_user_fault(tsk, addr, esr, sig, code, regs, fault);
|
|
|
return 0;
|
|
|
|
|
|
no_context:
|