10 #include <linux/string.h>
11 #include <linux/types.h>
12 #include <linux/sched.h>
13 #include <linux/ptrace.h>
14 #include <linux/mman.h>
15 #include <linux/signal.h>
17 #include <linux/module.h>
19 #include <linux/perf_event.h>
26 #include <asm/pgtable.h>
27 #include <asm/openprom.h>
28 #include <asm/oplib.h>
29 #include <asm/uaccess.h>
32 #include <asm/sections.h>
33 #include <asm/mmu_context.h>
42 if (kprobes_built_in() && !
user_mode(regs)) {
55 if ((
unsigned long) address <
PAGE_SIZE) {
57 "pointer dereference\n");
60 "at virtual address %016lx\n", (
unsigned long)address);
67 (tsk->
mm ? (
unsigned long) tsk->
mm->pgd :
80 unhandled_fault(regs->tpc,
current, regs);
90 static unsigned int get_user_insn(
unsigned long tpc)
110 __asm__ __volatile__(
"rdpr %%pstate, %0" :
"=r" (pstate));
111 __asm__ __volatile__(
"wrpr %0, %1, %%pstate"
122 __asm__ __volatile__(
"lduwa [%1] %2, %0"
128 __asm__ __volatile__(
"wrpr %0, 0x0, %%pstate" : :
"r" (pstate));
140 if (!printk_ratelimit())
143 printk(
"%s%s[%d]: segfault at %lx ip %p (rpc %p) sp %p error %x",
145 tsk->
comm, task_pid_nr(tsk), address,
154 static void do_fault_siginfo(
int code,
int sig,
struct pt_regs *regs,
155 unsigned int insn,
int fault_code)
163 if (fault_code & FAULT_CODE_ITLB)
167 info.si_addr = (
void __user *) addr;
171 show_signal_msg(regs, sig, code, addr,
current);
179 static unsigned int get_fault_insn(
struct pt_regs *regs,
unsigned int insn)
182 if (!regs->tpc || (regs->tpc & 0x3))
185 insn = *(
unsigned int *) regs->tpc;
187 insn = get_user_insn(regs->tpc);
194 int fault_code,
unsigned int insn,
195 unsigned long address)
197 unsigned char asi =
ASI_P;
208 (insn & 0xc0800000) == 0xc0800000) {
210 asi = (regs->tstate >> 24);
213 if ((asi & 0xf2) == 0x82) {
214 if (insn & 0x1000000) {
233 regs->tpc = entry->
fixup;
234 regs->tnpc = regs->tpc + 4;
241 do_fault_siginfo(si_code,
SIGSEGV, regs, insn, fault_code);
246 unhandled_fault (address,
current, regs);
255 "64-bit TPC [%lx]\n",
268 "reports 64-bit fault address [%lx]\n",
277 unsigned int insn = 0;
278 int si_code, fault_code,
fault;
280 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
282 fault_code = get_thread_fault_code();
284 if (notify_page_fault(regs))
290 if ((fault_code & FAULT_CODE_ITLB) &&
291 (fault_code & FAULT_CODE_DTLB))
294 if (test_thread_flag(TIF_32BIT)) {
296 if (
unlikely((regs->tpc >> 32) != 0)) {
297 bogus_32bit_fault_tpc(regs);
301 if (
unlikely((address >> 32) != 0)) {
302 bogus_32bit_fault_address(regs, address);
308 unsigned long tpc = regs->tpc;
315 bad_kernel_pc(regs, address);
332 insn = get_fault_insn(regs, insn);
333 goto handle_kernel_fault;
353 (FAULT_CODE_DTLB |
FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) &&
355 insn = get_fault_insn(regs, 0);
362 if ((insn & 0xc0200000) == 0xc0200000 &&
363 (insn & 0x01780000) != 0x01680000) {
375 if (!(vma->
vm_flags & VM_GROWSDOWN))
379 insn = get_fault_insn(regs, insn);
380 if ((insn & 0xc0800000) == 0xc0800000) {
384 asi = (regs->tstate >> 24);
387 if ((asi & 0xf2) == 0x82)
403 if ((fault_code & FAULT_CODE_ITLB) && !(vma->
vm_flags & VM_EXEC)) {
404 BUG_ON(address != regs->tpc);
409 if (fault_code & FAULT_CODE_WRITE) {
419 set_thread_fault_code(fault_code |
420 FAULT_CODE_BLKCOMMIT);
423 if (!(vma->
vm_flags & (VM_READ | VM_EXEC)))
430 if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(
current))
433 if (
unlikely(fault & VM_FAULT_ERROR)) {
434 if (fault & VM_FAULT_OOM)
436 else if (fault & VM_FAULT_SIGBUS)
441 if (flags & FAULT_FLAG_ALLOW_RETRY) {
442 if (fault & VM_FAULT_MAJOR) {
451 if (fault & VM_FAULT_RETRY) {
452 flags &= ~FAULT_FLAG_ALLOW_RETRY;
453 flags |= FAULT_FLAG_TRIED;
465 mm_rss = get_mm_rss(mm);
466 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
472 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
485 insn = get_fault_insn(regs, insn);
489 do_kernel_fault(regs, si_code, fault_code, insn, address);
497 insn = get_fault_insn(regs, insn);
503 goto handle_kernel_fault;
506 insn = get_fault_insn(regs, 0);
507 goto handle_kernel_fault;
510 insn = get_fault_insn(regs, insn);
521 goto handle_kernel_fault;