18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) 68c2ecf20Sopenharmony_ci * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/head.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/string.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/sched.h> 148c2ecf20Sopenharmony_ci#include <linux/sched/debug.h> 158c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 168c2ecf20Sopenharmony_ci#include <linux/mman.h> 178c2ecf20Sopenharmony_ci#include <linux/signal.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci#include <linux/extable.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 228c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 238c2ecf20Sopenharmony_ci#include <linux/kprobes.h> 248c2ecf20Sopenharmony_ci#include <linux/kdebug.h> 258c2ecf20Sopenharmony_ci#include <linux/percpu.h> 268c2ecf20Sopenharmony_ci#include <linux/context_tracking.h> 278c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <asm/page.h> 308c2ecf20Sopenharmony_ci#include <asm/openprom.h> 318c2ecf20Sopenharmony_ci#include <asm/oplib.h> 328c2ecf20Sopenharmony_ci#include <asm/asi.h> 338c2ecf20Sopenharmony_ci#include <asm/lsu.h> 348c2ecf20Sopenharmony_ci#include <asm/sections.h> 358c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 368c2ecf20Sopenharmony_ci#include <asm/setup.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint show_unhandled_signals = 1; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void __kprobes unhandled_fault(unsigned long address, 418c2ecf20Sopenharmony_ci struct task_struct *tsk, 428c2ecf20Sopenharmony_ci struct pt_regs *regs) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci if ((unsigned long) address < PAGE_SIZE) { 458c2ecf20Sopenharmony_ci printk(KERN_ALERT "Unable to handle kernel NULL " 468c2ecf20Sopenharmony_ci "pointer dereference\n"); 478c2ecf20Sopenharmony_ci } else { 488c2ecf20Sopenharmony_ci printk(KERN_ALERT "Unable to handle kernel paging request " 498c2ecf20Sopenharmony_ci "at virtual address %016lx\n", (unsigned long)address); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n", 528c2ecf20Sopenharmony_ci (tsk->mm ? 538c2ecf20Sopenharmony_ci CTX_HWBITS(tsk->mm->context) : 548c2ecf20Sopenharmony_ci CTX_HWBITS(tsk->active_mm->context))); 558c2ecf20Sopenharmony_ci printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", 568c2ecf20Sopenharmony_ci (tsk->mm ? (unsigned long) tsk->mm->pgd : 578c2ecf20Sopenharmony_ci (unsigned long) tsk->active_mm->pgd)); 588c2ecf20Sopenharmony_ci die_if_kernel("Oops", regs); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void __kprobes bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", 648c2ecf20Sopenharmony_ci regs->tpc); 658c2ecf20Sopenharmony_ci printk(KERN_CRIT "OOPS: RPC [%016lx]\n", regs->u_regs[15]); 668c2ecf20Sopenharmony_ci printk("OOPS: RPC <%pS>\n", (void *) regs->u_regs[15]); 678c2ecf20Sopenharmony_ci printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); 688c2ecf20Sopenharmony_ci dump_stack(); 698c2ecf20Sopenharmony_ci unhandled_fault(regs->tpc, current, regs); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * We now make sure that mmap_lock is held in all paths that call 748c2ecf20Sopenharmony_ci * this. Additionally, to prevent kswapd from ripping ptes from 758c2ecf20Sopenharmony_ci * under us, raise interrupts around the time that we look at the 768c2ecf20Sopenharmony_ci * pte, kswapd will have to wait to get his smp ipi response from 778c2ecf20Sopenharmony_ci * us. vmtruncate likewise. This saves us having to get pte lock. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_cistatic unsigned int get_user_insn(unsigned long tpc) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci pgd_t *pgdp = pgd_offset(current->mm, tpc); 828c2ecf20Sopenharmony_ci p4d_t *p4dp; 838c2ecf20Sopenharmony_ci pud_t *pudp; 848c2ecf20Sopenharmony_ci pmd_t *pmdp; 858c2ecf20Sopenharmony_ci pte_t *ptep, pte; 868c2ecf20Sopenharmony_ci unsigned long pa; 878c2ecf20Sopenharmony_ci u32 insn = 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (pgd_none(*pgdp) || unlikely(pgd_bad(*pgdp))) 908c2ecf20Sopenharmony_ci goto out; 918c2ecf20Sopenharmony_ci p4dp = p4d_offset(pgdp, tpc); 928c2ecf20Sopenharmony_ci if (p4d_none(*p4dp) || unlikely(p4d_bad(*p4dp))) 938c2ecf20Sopenharmony_ci goto out; 948c2ecf20Sopenharmony_ci pudp = pud_offset(p4dp, tpc); 958c2ecf20Sopenharmony_ci if (pud_none(*pudp) || unlikely(pud_bad(*pudp))) 968c2ecf20Sopenharmony_ci goto out; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* This disables preemption for us as well. */ 998c2ecf20Sopenharmony_ci local_irq_disable(); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci pmdp = pmd_offset(pudp, tpc); 1028c2ecf20Sopenharmony_ci if (pmd_none(*pmdp) || unlikely(pmd_bad(*pmdp))) 1038c2ecf20Sopenharmony_ci goto out_irq_enable; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 1068c2ecf20Sopenharmony_ci if (is_hugetlb_pmd(*pmdp)) { 1078c2ecf20Sopenharmony_ci pa = pmd_pfn(*pmdp) << PAGE_SHIFT; 1088c2ecf20Sopenharmony_ci pa += tpc & ~HPAGE_MASK; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Use phys bypass so we don't pollute dtlb/dcache. */ 1118c2ecf20Sopenharmony_ci __asm__ __volatile__("lduwa [%1] %2, %0" 1128c2ecf20Sopenharmony_ci : "=r" (insn) 1138c2ecf20Sopenharmony_ci : "r" (pa), "i" (ASI_PHYS_USE_EC)); 1148c2ecf20Sopenharmony_ci } else 1158c2ecf20Sopenharmony_ci#endif 1168c2ecf20Sopenharmony_ci { 1178c2ecf20Sopenharmony_ci ptep = pte_offset_map(pmdp, tpc); 1188c2ecf20Sopenharmony_ci pte = *ptep; 1198c2ecf20Sopenharmony_ci if (pte_present(pte)) { 1208c2ecf20Sopenharmony_ci pa = (pte_pfn(pte) << PAGE_SHIFT); 1218c2ecf20Sopenharmony_ci pa += (tpc & ~PAGE_MASK); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* Use phys bypass so we don't pollute dtlb/dcache. */ 1248c2ecf20Sopenharmony_ci __asm__ __volatile__("lduwa [%1] %2, %0" 1258c2ecf20Sopenharmony_ci : "=r" (insn) 1268c2ecf20Sopenharmony_ci : "r" (pa), "i" (ASI_PHYS_USE_EC)); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci pte_unmap(ptep); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ciout_irq_enable: 1318c2ecf20Sopenharmony_ci local_irq_enable(); 1328c2ecf20Sopenharmony_ciout: 1338c2ecf20Sopenharmony_ci return insn; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic inline void 1378c2ecf20Sopenharmony_cishow_signal_msg(struct pt_regs *regs, int sig, int code, 1388c2ecf20Sopenharmony_ci unsigned long address, struct task_struct *tsk) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci if (!unhandled_signal(tsk, sig)) 1418c2ecf20Sopenharmony_ci return; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (!printk_ratelimit()) 1448c2ecf20Sopenharmony_ci return; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci printk("%s%s[%d]: segfault at %lx ip %px (rpc %px) sp %px error %x", 1478c2ecf20Sopenharmony_ci task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, 1488c2ecf20Sopenharmony_ci tsk->comm, task_pid_nr(tsk), address, 1498c2ecf20Sopenharmony_ci (void *)regs->tpc, (void *)regs->u_regs[UREG_I7], 1508c2ecf20Sopenharmony_ci (void *)regs->u_regs[UREG_FP], code); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci print_vma_addr(KERN_CONT " in ", regs->tpc); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void do_fault_siginfo(int code, int sig, struct pt_regs *regs, 1588c2ecf20Sopenharmony_ci unsigned long fault_addr, unsigned int insn, 1598c2ecf20Sopenharmony_ci int fault_code) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci unsigned long addr; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (fault_code & FAULT_CODE_ITLB) { 1648c2ecf20Sopenharmony_ci addr = regs->tpc; 1658c2ecf20Sopenharmony_ci } else { 1668c2ecf20Sopenharmony_ci /* If we were able to probe the faulting instruction, use it 1678c2ecf20Sopenharmony_ci * to compute a precise fault address. Otherwise use the fault 1688c2ecf20Sopenharmony_ci * time provided address which may only have page granularity. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci if (insn) 1718c2ecf20Sopenharmony_ci addr = compute_effective_address(regs, insn, 0); 1728c2ecf20Sopenharmony_ci else 1738c2ecf20Sopenharmony_ci addr = fault_addr; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (unlikely(show_unhandled_signals)) 1778c2ecf20Sopenharmony_ci show_signal_msg(regs, sig, code, addr, current); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci force_sig_fault(sig, code, (void __user *) addr, 0); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci if (!insn) { 1858c2ecf20Sopenharmony_ci if (!regs->tpc || (regs->tpc & 0x3)) 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) { 1888c2ecf20Sopenharmony_ci insn = *(unsigned int *) regs->tpc; 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci insn = get_user_insn(regs->tpc); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci return insn; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void __kprobes do_kernel_fault(struct pt_regs *regs, int si_code, 1978c2ecf20Sopenharmony_ci int fault_code, unsigned int insn, 1988c2ecf20Sopenharmony_ci unsigned long address) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci unsigned char asi = ASI_P; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if ((!insn) && (regs->tstate & TSTATE_PRIV)) 2038c2ecf20Sopenharmony_ci goto cannot_handle; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* If user insn could be read (thus insn is zero), that 2068c2ecf20Sopenharmony_ci * is fine. We will just gun down the process with a signal 2078c2ecf20Sopenharmony_ci * in that case. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!(fault_code & (FAULT_CODE_WRITE|FAULT_CODE_ITLB)) && 2118c2ecf20Sopenharmony_ci (insn & 0xc0800000) == 0xc0800000) { 2128c2ecf20Sopenharmony_ci if (insn & 0x2000) 2138c2ecf20Sopenharmony_ci asi = (regs->tstate >> 24); 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci asi = (insn >> 5); 2168c2ecf20Sopenharmony_ci if ((asi & 0xf2) == 0x82) { 2178c2ecf20Sopenharmony_ci if (insn & 0x1000000) { 2188c2ecf20Sopenharmony_ci handle_ldf_stq(insn, regs); 2198c2ecf20Sopenharmony_ci } else { 2208c2ecf20Sopenharmony_ci /* This was a non-faulting load. Just clear the 2218c2ecf20Sopenharmony_ci * destination register(s) and continue with the next 2228c2ecf20Sopenharmony_ci * instruction. -jj 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci handle_ld_nf(insn, regs); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci return; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Is this in ex_table? */ 2318c2ecf20Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) { 2328c2ecf20Sopenharmony_ci const struct exception_table_entry *entry; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci entry = search_exception_tables(regs->tpc); 2358c2ecf20Sopenharmony_ci if (entry) { 2368c2ecf20Sopenharmony_ci regs->tpc = entry->fixup; 2378c2ecf20Sopenharmony_ci regs->tnpc = regs->tpc + 4; 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } else { 2418c2ecf20Sopenharmony_ci /* The si_code was set to make clear whether 2428c2ecf20Sopenharmony_ci * this was a SEGV_MAPERR or SEGV_ACCERR fault. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci do_fault_siginfo(si_code, SIGSEGV, regs, address, insn, fault_code); 2458c2ecf20Sopenharmony_ci return; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cicannot_handle: 2498c2ecf20Sopenharmony_ci unhandled_fault (address, current, regs); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic void noinline __kprobes bogus_32bit_fault_tpc(struct pt_regs *regs) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci static int times; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (times++ < 10) 2578c2ecf20Sopenharmony_ci printk(KERN_ERR "FAULT[%s:%d]: 32-bit process reports " 2588c2ecf20Sopenharmony_ci "64-bit TPC [%lx]\n", 2598c2ecf20Sopenharmony_ci current->comm, current->pid, 2608c2ecf20Sopenharmony_ci regs->tpc); 2618c2ecf20Sopenharmony_ci show_regs(regs); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciasmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci enum ctx_state prev_state = exception_enter(); 2678c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 2688c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 2698c2ecf20Sopenharmony_ci unsigned int insn = 0; 2708c2ecf20Sopenharmony_ci int si_code, fault_code; 2718c2ecf20Sopenharmony_ci vm_fault_t fault; 2728c2ecf20Sopenharmony_ci unsigned long address, mm_rss; 2738c2ecf20Sopenharmony_ci unsigned int flags = FAULT_FLAG_DEFAULT; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci fault_code = get_thread_fault_code(); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (kprobe_page_fault(regs, 0)) 2788c2ecf20Sopenharmony_ci goto exit_exception; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci si_code = SEGV_MAPERR; 2818c2ecf20Sopenharmony_ci address = current_thread_info()->fault_address; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if ((fault_code & FAULT_CODE_ITLB) && 2848c2ecf20Sopenharmony_ci (fault_code & FAULT_CODE_DTLB)) 2858c2ecf20Sopenharmony_ci BUG(); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (test_thread_flag(TIF_32BIT)) { 2888c2ecf20Sopenharmony_ci if (!(regs->tstate & TSTATE_PRIV)) { 2898c2ecf20Sopenharmony_ci if (unlikely((regs->tpc >> 32) != 0)) { 2908c2ecf20Sopenharmony_ci bogus_32bit_fault_tpc(regs); 2918c2ecf20Sopenharmony_ci goto intr_or_no_mm; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci if (unlikely((address >> 32) != 0)) 2958c2ecf20Sopenharmony_ci goto intr_or_no_mm; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) { 2998c2ecf20Sopenharmony_ci unsigned long tpc = regs->tpc; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Sanity check the PC. */ 3028c2ecf20Sopenharmony_ci if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) || 3038c2ecf20Sopenharmony_ci (tpc >= MODULES_VADDR && tpc < MODULES_END)) { 3048c2ecf20Sopenharmony_ci /* Valid, no problems... */ 3058c2ecf20Sopenharmony_ci } else { 3068c2ecf20Sopenharmony_ci bad_kernel_pc(regs, address); 3078c2ecf20Sopenharmony_ci goto exit_exception; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci } else 3108c2ecf20Sopenharmony_ci flags |= FAULT_FLAG_USER; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * If we're in an interrupt or have no user 3148c2ecf20Sopenharmony_ci * context, we must not take the fault.. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci if (faulthandler_disabled() || !mm) 3178c2ecf20Sopenharmony_ci goto intr_or_no_mm; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!mmap_read_trylock(mm)) { 3228c2ecf20Sopenharmony_ci if ((regs->tstate & TSTATE_PRIV) && 3238c2ecf20Sopenharmony_ci !search_exception_tables(regs->tpc)) { 3248c2ecf20Sopenharmony_ci insn = get_fault_insn(regs, insn); 3258c2ecf20Sopenharmony_ci goto handle_kernel_fault; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ciretry: 3298c2ecf20Sopenharmony_ci mmap_read_lock(mm); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (fault_code & FAULT_CODE_BAD_RA) 3338c2ecf20Sopenharmony_ci goto do_sigbus; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci vma = find_vma(mm, address); 3368c2ecf20Sopenharmony_ci if (!vma) 3378c2ecf20Sopenharmony_ci goto bad_area; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* Pure DTLB misses do not tell us whether the fault causing 3408c2ecf20Sopenharmony_ci * load/store/atomic was a write or not, it only says that there 3418c2ecf20Sopenharmony_ci * was no match. So in such a case we (carefully) read the 3428c2ecf20Sopenharmony_ci * instruction to try and figure this out. It's an optimization 3438c2ecf20Sopenharmony_ci * so it's ok if we can't do this. 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * Special hack, window spill/fill knows the exact fault type. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci if (((fault_code & 3488c2ecf20Sopenharmony_ci (FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) && 3498c2ecf20Sopenharmony_ci (vma->vm_flags & VM_WRITE) != 0) { 3508c2ecf20Sopenharmony_ci insn = get_fault_insn(regs, 0); 3518c2ecf20Sopenharmony_ci if (!insn) 3528c2ecf20Sopenharmony_ci goto continue_fault; 3538c2ecf20Sopenharmony_ci /* All loads, stores and atomics have bits 30 and 31 both set 3548c2ecf20Sopenharmony_ci * in the instruction. Bit 21 is set in all stores, but we 3558c2ecf20Sopenharmony_ci * have to avoid prefetches which also have bit 21 set. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci if ((insn & 0xc0200000) == 0xc0200000 && 3588c2ecf20Sopenharmony_ci (insn & 0x01780000) != 0x01680000) { 3598c2ecf20Sopenharmony_ci /* Don't bother updating thread struct value, 3608c2ecf20Sopenharmony_ci * because update_mmu_cache only cares which tlb 3618c2ecf20Sopenharmony_ci * the access came from. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci fault_code |= FAULT_CODE_WRITE; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_cicontinue_fault: 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (vma->vm_start <= address) 3698c2ecf20Sopenharmony_ci goto good_area; 3708c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_GROWSDOWN)) 3718c2ecf20Sopenharmony_ci goto bad_area; 3728c2ecf20Sopenharmony_ci if (!(fault_code & FAULT_CODE_WRITE)) { 3738c2ecf20Sopenharmony_ci /* Non-faulting loads shouldn't expand stack. */ 3748c2ecf20Sopenharmony_ci insn = get_fault_insn(regs, insn); 3758c2ecf20Sopenharmony_ci if ((insn & 0xc0800000) == 0xc0800000) { 3768c2ecf20Sopenharmony_ci unsigned char asi; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (insn & 0x2000) 3798c2ecf20Sopenharmony_ci asi = (regs->tstate >> 24); 3808c2ecf20Sopenharmony_ci else 3818c2ecf20Sopenharmony_ci asi = (insn >> 5); 3828c2ecf20Sopenharmony_ci if ((asi & 0xf2) == 0x82) 3838c2ecf20Sopenharmony_ci goto bad_area; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci if (expand_stack(vma, address)) 3878c2ecf20Sopenharmony_ci goto bad_area; 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * Ok, we have a good vm_area for this memory access, so 3908c2ecf20Sopenharmony_ci * we can handle it.. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cigood_area: 3938c2ecf20Sopenharmony_ci si_code = SEGV_ACCERR; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* If we took a ITLB miss on a non-executable page, catch 3968c2ecf20Sopenharmony_ci * that here. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) { 3998c2ecf20Sopenharmony_ci WARN(address != regs->tpc, 4008c2ecf20Sopenharmony_ci "address (%lx) != regs->tpc (%lx)\n", address, regs->tpc); 4018c2ecf20Sopenharmony_ci WARN_ON(regs->tstate & TSTATE_PRIV); 4028c2ecf20Sopenharmony_ci goto bad_area; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (fault_code & FAULT_CODE_WRITE) { 4068c2ecf20Sopenharmony_ci if (!(vma->vm_flags & VM_WRITE)) 4078c2ecf20Sopenharmony_ci goto bad_area; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Spitfire has an icache which does not snoop 4108c2ecf20Sopenharmony_ci * processor stores. Later processors do... 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci if (tlb_type == spitfire && 4138c2ecf20Sopenharmony_ci (vma->vm_flags & VM_EXEC) != 0 && 4148c2ecf20Sopenharmony_ci vma->vm_file != NULL) 4158c2ecf20Sopenharmony_ci set_thread_fault_code(fault_code | 4168c2ecf20Sopenharmony_ci FAULT_CODE_BLKCOMMIT); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci flags |= FAULT_FLAG_WRITE; 4198c2ecf20Sopenharmony_ci } else { 4208c2ecf20Sopenharmony_ci /* Allow reads even for write-only mappings */ 4218c2ecf20Sopenharmony_ci if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 4228c2ecf20Sopenharmony_ci goto bad_area; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci fault = handle_mm_fault(vma, address, flags, regs); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (fault_signal_pending(fault, regs)) 4288c2ecf20Sopenharmony_ci goto exit_exception; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (unlikely(fault & VM_FAULT_ERROR)) { 4318c2ecf20Sopenharmony_ci if (fault & VM_FAULT_OOM) 4328c2ecf20Sopenharmony_ci goto out_of_memory; 4338c2ecf20Sopenharmony_ci else if (fault & VM_FAULT_SIGSEGV) 4348c2ecf20Sopenharmony_ci goto bad_area; 4358c2ecf20Sopenharmony_ci else if (fault & VM_FAULT_SIGBUS) 4368c2ecf20Sopenharmony_ci goto do_sigbus; 4378c2ecf20Sopenharmony_ci BUG(); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (flags & FAULT_FLAG_ALLOW_RETRY) { 4418c2ecf20Sopenharmony_ci if (fault & VM_FAULT_RETRY) { 4428c2ecf20Sopenharmony_ci flags |= FAULT_FLAG_TRIED; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* No need to mmap_read_unlock(mm) as we would 4458c2ecf20Sopenharmony_ci * have already released it in __lock_page_or_retry 4468c2ecf20Sopenharmony_ci * in mm/filemap.c. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci goto retry; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci mm_rss = get_mm_rss(mm); 4558c2ecf20Sopenharmony_ci#if defined(CONFIG_TRANSPARENT_HUGEPAGE) 4568c2ecf20Sopenharmony_ci mm_rss -= (mm->context.thp_pte_count * (HPAGE_SIZE / PAGE_SIZE)); 4578c2ecf20Sopenharmony_ci#endif 4588c2ecf20Sopenharmony_ci if (unlikely(mm_rss > 4598c2ecf20Sopenharmony_ci mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit)) 4608c2ecf20Sopenharmony_ci tsb_grow(mm, MM_TSB_BASE, mm_rss); 4618c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 4628c2ecf20Sopenharmony_ci mm_rss = mm->context.hugetlb_pte_count + mm->context.thp_pte_count; 4638c2ecf20Sopenharmony_ci mm_rss *= REAL_HPAGE_PER_HPAGE; 4648c2ecf20Sopenharmony_ci if (unlikely(mm_rss > 4658c2ecf20Sopenharmony_ci mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) { 4668c2ecf20Sopenharmony_ci if (mm->context.tsb_block[MM_TSB_HUGE].tsb) 4678c2ecf20Sopenharmony_ci tsb_grow(mm, MM_TSB_HUGE, mm_rss); 4688c2ecf20Sopenharmony_ci else 4698c2ecf20Sopenharmony_ci hugetlb_setup(regs); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci#endif 4738c2ecf20Sopenharmony_ciexit_exception: 4748c2ecf20Sopenharmony_ci exception_exit(prev_state); 4758c2ecf20Sopenharmony_ci return; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* 4788c2ecf20Sopenharmony_ci * Something tried to access memory that isn't in our memory map.. 4798c2ecf20Sopenharmony_ci * Fix it, but check if it's kernel or user first.. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_cibad_area: 4828c2ecf20Sopenharmony_ci insn = get_fault_insn(regs, insn); 4838c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cihandle_kernel_fault: 4868c2ecf20Sopenharmony_ci do_kernel_fault(regs, si_code, fault_code, insn, address); 4878c2ecf20Sopenharmony_ci goto exit_exception; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci/* 4908c2ecf20Sopenharmony_ci * We ran out of memory, or some other thing happened to us that made 4918c2ecf20Sopenharmony_ci * us unable to handle the page fault gracefully. 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ciout_of_memory: 4948c2ecf20Sopenharmony_ci insn = get_fault_insn(regs, insn); 4958c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 4968c2ecf20Sopenharmony_ci if (!(regs->tstate & TSTATE_PRIV)) { 4978c2ecf20Sopenharmony_ci pagefault_out_of_memory(); 4988c2ecf20Sopenharmony_ci goto exit_exception; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci goto handle_kernel_fault; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ciintr_or_no_mm: 5038c2ecf20Sopenharmony_ci insn = get_fault_insn(regs, 0); 5048c2ecf20Sopenharmony_ci goto handle_kernel_fault; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cido_sigbus: 5078c2ecf20Sopenharmony_ci insn = get_fault_insn(regs, insn); 5088c2ecf20Sopenharmony_ci mmap_read_unlock(mm); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* 5118c2ecf20Sopenharmony_ci * Send a sigbus, regardless of whether we were in kernel 5128c2ecf20Sopenharmony_ci * or user mode. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, address, insn, fault_code); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* Kernel mode? Handle exceptions or die */ 5178c2ecf20Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) 5188c2ecf20Sopenharmony_ci goto handle_kernel_fault; 5198c2ecf20Sopenharmony_ci} 520