162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) 662306a36Sopenharmony_ci * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/head.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/string.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/sched/debug.h> 1562306a36Sopenharmony_ci#include <linux/ptrace.h> 1662306a36Sopenharmony_ci#include <linux/mman.h> 1762306a36Sopenharmony_ci#include <linux/signal.h> 1862306a36Sopenharmony_ci#include <linux/mm.h> 1962306a36Sopenharmony_ci#include <linux/extable.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/perf_event.h> 2262306a36Sopenharmony_ci#include <linux/interrupt.h> 2362306a36Sopenharmony_ci#include <linux/kprobes.h> 2462306a36Sopenharmony_ci#include <linux/kdebug.h> 2562306a36Sopenharmony_ci#include <linux/percpu.h> 2662306a36Sopenharmony_ci#include <linux/context_tracking.h> 2762306a36Sopenharmony_ci#include <linux/uaccess.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <asm/page.h> 3062306a36Sopenharmony_ci#include <asm/openprom.h> 3162306a36Sopenharmony_ci#include <asm/oplib.h> 3262306a36Sopenharmony_ci#include <asm/asi.h> 3362306a36Sopenharmony_ci#include <asm/lsu.h> 3462306a36Sopenharmony_ci#include <asm/sections.h> 3562306a36Sopenharmony_ci#include <asm/mmu_context.h> 3662306a36Sopenharmony_ci#include <asm/setup.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciint show_unhandled_signals = 1; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void __kprobes unhandled_fault(unsigned long address, 4162306a36Sopenharmony_ci struct task_struct *tsk, 4262306a36Sopenharmony_ci struct pt_regs *regs) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci if ((unsigned long) address < PAGE_SIZE) { 4562306a36Sopenharmony_ci printk(KERN_ALERT "Unable to handle kernel NULL " 4662306a36Sopenharmony_ci "pointer dereference\n"); 4762306a36Sopenharmony_ci } else { 4862306a36Sopenharmony_ci printk(KERN_ALERT "Unable to handle kernel paging request " 4962306a36Sopenharmony_ci "at virtual address %016lx\n", (unsigned long)address); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n", 5262306a36Sopenharmony_ci (tsk->mm ? 5362306a36Sopenharmony_ci CTX_HWBITS(tsk->mm->context) : 5462306a36Sopenharmony_ci CTX_HWBITS(tsk->active_mm->context))); 5562306a36Sopenharmony_ci printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", 5662306a36Sopenharmony_ci (tsk->mm ? (unsigned long) tsk->mm->pgd : 5762306a36Sopenharmony_ci (unsigned long) tsk->active_mm->pgd)); 5862306a36Sopenharmony_ci die_if_kernel("Oops", regs); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void __kprobes bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", 6462306a36Sopenharmony_ci regs->tpc); 6562306a36Sopenharmony_ci printk(KERN_CRIT "OOPS: RPC [%016lx]\n", regs->u_regs[15]); 6662306a36Sopenharmony_ci printk("OOPS: RPC <%pS>\n", (void *) regs->u_regs[15]); 6762306a36Sopenharmony_ci printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); 6862306a36Sopenharmony_ci dump_stack(); 6962306a36Sopenharmony_ci unhandled_fault(regs->tpc, current, regs); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * We now make sure that mmap_lock is held in all paths that call 7462306a36Sopenharmony_ci * this. Additionally, to prevent kswapd from ripping ptes from 7562306a36Sopenharmony_ci * under us, raise interrupts around the time that we look at the 7662306a36Sopenharmony_ci * pte, kswapd will have to wait to get his smp ipi response from 7762306a36Sopenharmony_ci * us. vmtruncate likewise. This saves us having to get pte lock. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_cistatic unsigned int get_user_insn(unsigned long tpc) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci pgd_t *pgdp = pgd_offset(current->mm, tpc); 8262306a36Sopenharmony_ci p4d_t *p4dp; 8362306a36Sopenharmony_ci pud_t *pudp; 8462306a36Sopenharmony_ci pmd_t *pmdp; 8562306a36Sopenharmony_ci pte_t *ptep, pte; 8662306a36Sopenharmony_ci unsigned long pa; 8762306a36Sopenharmony_ci u32 insn = 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (pgd_none(*pgdp) || unlikely(pgd_bad(*pgdp))) 9062306a36Sopenharmony_ci goto out; 9162306a36Sopenharmony_ci p4dp = p4d_offset(pgdp, tpc); 9262306a36Sopenharmony_ci if (p4d_none(*p4dp) || unlikely(p4d_bad(*p4dp))) 9362306a36Sopenharmony_ci goto out; 9462306a36Sopenharmony_ci pudp = pud_offset(p4dp, tpc); 9562306a36Sopenharmony_ci if (pud_none(*pudp) || unlikely(pud_bad(*pudp))) 9662306a36Sopenharmony_ci goto out; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* This disables preemption for us as well. */ 9962306a36Sopenharmony_ci local_irq_disable(); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci pmdp = pmd_offset(pudp, tpc); 10262306a36Sopenharmony_ciagain: 10362306a36Sopenharmony_ci if (pmd_none(*pmdp) || unlikely(pmd_bad(*pmdp))) 10462306a36Sopenharmony_ci goto out_irq_enable; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 10762306a36Sopenharmony_ci if (is_hugetlb_pmd(*pmdp)) { 10862306a36Sopenharmony_ci pa = pmd_pfn(*pmdp) << PAGE_SHIFT; 10962306a36Sopenharmony_ci pa += tpc & ~HPAGE_MASK; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* Use phys bypass so we don't pollute dtlb/dcache. */ 11262306a36Sopenharmony_ci __asm__ __volatile__("lduwa [%1] %2, %0" 11362306a36Sopenharmony_ci : "=r" (insn) 11462306a36Sopenharmony_ci : "r" (pa), "i" (ASI_PHYS_USE_EC)); 11562306a36Sopenharmony_ci } else 11662306a36Sopenharmony_ci#endif 11762306a36Sopenharmony_ci { 11862306a36Sopenharmony_ci ptep = pte_offset_map(pmdp, tpc); 11962306a36Sopenharmony_ci if (!ptep) 12062306a36Sopenharmony_ci goto again; 12162306a36Sopenharmony_ci pte = *ptep; 12262306a36Sopenharmony_ci if (pte_present(pte)) { 12362306a36Sopenharmony_ci pa = (pte_pfn(pte) << PAGE_SHIFT); 12462306a36Sopenharmony_ci pa += (tpc & ~PAGE_MASK); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* Use phys bypass so we don't pollute dtlb/dcache. */ 12762306a36Sopenharmony_ci __asm__ __volatile__("lduwa [%1] %2, %0" 12862306a36Sopenharmony_ci : "=r" (insn) 12962306a36Sopenharmony_ci : "r" (pa), "i" (ASI_PHYS_USE_EC)); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci pte_unmap(ptep); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ciout_irq_enable: 13462306a36Sopenharmony_ci local_irq_enable(); 13562306a36Sopenharmony_ciout: 13662306a36Sopenharmony_ci return insn; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic inline void 14062306a36Sopenharmony_cishow_signal_msg(struct pt_regs *regs, int sig, int code, 14162306a36Sopenharmony_ci unsigned long address, struct task_struct *tsk) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci if (!unhandled_signal(tsk, sig)) 14462306a36Sopenharmony_ci return; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!printk_ratelimit()) 14762306a36Sopenharmony_ci return; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci printk("%s%s[%d]: segfault at %lx ip %px (rpc %px) sp %px error %x", 15062306a36Sopenharmony_ci task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, 15162306a36Sopenharmony_ci tsk->comm, task_pid_nr(tsk), address, 15262306a36Sopenharmony_ci (void *)regs->tpc, (void *)regs->u_regs[UREG_I7], 15362306a36Sopenharmony_ci (void *)regs->u_regs[UREG_FP], code); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci print_vma_addr(KERN_CONT " in ", regs->tpc); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci printk(KERN_CONT "\n"); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void do_fault_siginfo(int code, int sig, struct pt_regs *regs, 16162306a36Sopenharmony_ci unsigned long fault_addr, unsigned int insn, 16262306a36Sopenharmony_ci int fault_code) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci unsigned long addr; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (fault_code & FAULT_CODE_ITLB) { 16762306a36Sopenharmony_ci addr = regs->tpc; 16862306a36Sopenharmony_ci } else { 16962306a36Sopenharmony_ci /* If we were able to probe the faulting instruction, use it 17062306a36Sopenharmony_ci * to compute a precise fault address. Otherwise use the fault 17162306a36Sopenharmony_ci * time provided address which may only have page granularity. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci if (insn) 17462306a36Sopenharmony_ci addr = compute_effective_address(regs, insn, 0); 17562306a36Sopenharmony_ci else 17662306a36Sopenharmony_ci addr = fault_addr; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (unlikely(show_unhandled_signals)) 18062306a36Sopenharmony_ci show_signal_msg(regs, sig, code, addr, current); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci force_sig_fault(sig, code, (void __user *) addr); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci if (!insn) { 18862306a36Sopenharmony_ci if (!regs->tpc || (regs->tpc & 0x3)) 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) { 19162306a36Sopenharmony_ci insn = *(unsigned int *) regs->tpc; 19262306a36Sopenharmony_ci } else { 19362306a36Sopenharmony_ci insn = get_user_insn(regs->tpc); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci return insn; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void __kprobes do_kernel_fault(struct pt_regs *regs, int si_code, 20062306a36Sopenharmony_ci int fault_code, unsigned int insn, 20162306a36Sopenharmony_ci unsigned long address) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci unsigned char asi = ASI_P; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if ((!insn) && (regs->tstate & TSTATE_PRIV)) 20662306a36Sopenharmony_ci goto cannot_handle; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* If user insn could be read (thus insn is zero), that 20962306a36Sopenharmony_ci * is fine. We will just gun down the process with a signal 21062306a36Sopenharmony_ci * in that case. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (!(fault_code & (FAULT_CODE_WRITE|FAULT_CODE_ITLB)) && 21462306a36Sopenharmony_ci (insn & 0xc0800000) == 0xc0800000) { 21562306a36Sopenharmony_ci if (insn & 0x2000) 21662306a36Sopenharmony_ci asi = (regs->tstate >> 24); 21762306a36Sopenharmony_ci else 21862306a36Sopenharmony_ci asi = (insn >> 5); 21962306a36Sopenharmony_ci if ((asi & 0xf2) == 0x82) { 22062306a36Sopenharmony_ci if (insn & 0x1000000) { 22162306a36Sopenharmony_ci handle_ldf_stq(insn, regs); 22262306a36Sopenharmony_ci } else { 22362306a36Sopenharmony_ci /* This was a non-faulting load. Just clear the 22462306a36Sopenharmony_ci * destination register(s) and continue with the next 22562306a36Sopenharmony_ci * instruction. -jj 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci handle_ld_nf(insn, regs); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci return; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Is this in ex_table? */ 23462306a36Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) { 23562306a36Sopenharmony_ci const struct exception_table_entry *entry; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci entry = search_exception_tables(regs->tpc); 23862306a36Sopenharmony_ci if (entry) { 23962306a36Sopenharmony_ci regs->tpc = entry->fixup; 24062306a36Sopenharmony_ci regs->tnpc = regs->tpc + 4; 24162306a36Sopenharmony_ci return; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } else { 24462306a36Sopenharmony_ci /* The si_code was set to make clear whether 24562306a36Sopenharmony_ci * this was a SEGV_MAPERR or SEGV_ACCERR fault. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci do_fault_siginfo(si_code, SIGSEGV, regs, address, insn, fault_code); 24862306a36Sopenharmony_ci return; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cicannot_handle: 25262306a36Sopenharmony_ci unhandled_fault (address, current, regs); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic void noinline __kprobes bogus_32bit_fault_tpc(struct pt_regs *regs) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci static int times; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (times++ < 10) 26062306a36Sopenharmony_ci printk(KERN_ERR "FAULT[%s:%d]: 32-bit process reports " 26162306a36Sopenharmony_ci "64-bit TPC [%lx]\n", 26262306a36Sopenharmony_ci current->comm, current->pid, 26362306a36Sopenharmony_ci regs->tpc); 26462306a36Sopenharmony_ci show_regs(regs); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciasmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci enum ctx_state prev_state = exception_enter(); 27062306a36Sopenharmony_ci struct mm_struct *mm = current->mm; 27162306a36Sopenharmony_ci struct vm_area_struct *vma; 27262306a36Sopenharmony_ci unsigned int insn = 0; 27362306a36Sopenharmony_ci int si_code, fault_code; 27462306a36Sopenharmony_ci vm_fault_t fault; 27562306a36Sopenharmony_ci unsigned long address, mm_rss; 27662306a36Sopenharmony_ci unsigned int flags = FAULT_FLAG_DEFAULT; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci fault_code = get_thread_fault_code(); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (kprobe_page_fault(regs, 0)) 28162306a36Sopenharmony_ci goto exit_exception; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci si_code = SEGV_MAPERR; 28462306a36Sopenharmony_ci address = current_thread_info()->fault_address; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if ((fault_code & FAULT_CODE_ITLB) && 28762306a36Sopenharmony_ci (fault_code & FAULT_CODE_DTLB)) 28862306a36Sopenharmony_ci BUG(); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (test_thread_flag(TIF_32BIT)) { 29162306a36Sopenharmony_ci if (!(regs->tstate & TSTATE_PRIV)) { 29262306a36Sopenharmony_ci if (unlikely((regs->tpc >> 32) != 0)) { 29362306a36Sopenharmony_ci bogus_32bit_fault_tpc(regs); 29462306a36Sopenharmony_ci goto intr_or_no_mm; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci if (unlikely((address >> 32) != 0)) 29862306a36Sopenharmony_ci goto intr_or_no_mm; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) { 30262306a36Sopenharmony_ci unsigned long tpc = regs->tpc; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Sanity check the PC. */ 30562306a36Sopenharmony_ci if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) || 30662306a36Sopenharmony_ci (tpc >= MODULES_VADDR && tpc < MODULES_END)) { 30762306a36Sopenharmony_ci /* Valid, no problems... */ 30862306a36Sopenharmony_ci } else { 30962306a36Sopenharmony_ci bad_kernel_pc(regs, address); 31062306a36Sopenharmony_ci goto exit_exception; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci } else 31362306a36Sopenharmony_ci flags |= FAULT_FLAG_USER; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * If we're in an interrupt or have no user 31762306a36Sopenharmony_ci * context, we must not take the fault.. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci if (faulthandler_disabled() || !mm) 32062306a36Sopenharmony_ci goto intr_or_no_mm; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (!mmap_read_trylock(mm)) { 32562306a36Sopenharmony_ci if ((regs->tstate & TSTATE_PRIV) && 32662306a36Sopenharmony_ci !search_exception_tables(regs->tpc)) { 32762306a36Sopenharmony_ci insn = get_fault_insn(regs, insn); 32862306a36Sopenharmony_ci goto handle_kernel_fault; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ciretry: 33262306a36Sopenharmony_ci mmap_read_lock(mm); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (fault_code & FAULT_CODE_BAD_RA) 33662306a36Sopenharmony_ci goto do_sigbus; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci vma = find_vma(mm, address); 33962306a36Sopenharmony_ci if (!vma) 34062306a36Sopenharmony_ci goto bad_area; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* Pure DTLB misses do not tell us whether the fault causing 34362306a36Sopenharmony_ci * load/store/atomic was a write or not, it only says that there 34462306a36Sopenharmony_ci * was no match. So in such a case we (carefully) read the 34562306a36Sopenharmony_ci * instruction to try and figure this out. It's an optimization 34662306a36Sopenharmony_ci * so it's ok if we can't do this. 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * Special hack, window spill/fill knows the exact fault type. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci if (((fault_code & 35162306a36Sopenharmony_ci (FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) && 35262306a36Sopenharmony_ci (vma->vm_flags & VM_WRITE) != 0) { 35362306a36Sopenharmony_ci insn = get_fault_insn(regs, 0); 35462306a36Sopenharmony_ci if (!insn) 35562306a36Sopenharmony_ci goto continue_fault; 35662306a36Sopenharmony_ci /* All loads, stores and atomics have bits 30 and 31 both set 35762306a36Sopenharmony_ci * in the instruction. Bit 21 is set in all stores, but we 35862306a36Sopenharmony_ci * have to avoid prefetches which also have bit 21 set. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci if ((insn & 0xc0200000) == 0xc0200000 && 36162306a36Sopenharmony_ci (insn & 0x01780000) != 0x01680000) { 36262306a36Sopenharmony_ci /* Don't bother updating thread struct value, 36362306a36Sopenharmony_ci * because update_mmu_cache only cares which tlb 36462306a36Sopenharmony_ci * the access came from. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci fault_code |= FAULT_CODE_WRITE; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_cicontinue_fault: 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (vma->vm_start <= address) 37262306a36Sopenharmony_ci goto good_area; 37362306a36Sopenharmony_ci if (!(vma->vm_flags & VM_GROWSDOWN)) 37462306a36Sopenharmony_ci goto bad_area; 37562306a36Sopenharmony_ci if (!(fault_code & FAULT_CODE_WRITE)) { 37662306a36Sopenharmony_ci /* Non-faulting loads shouldn't expand stack. */ 37762306a36Sopenharmony_ci insn = get_fault_insn(regs, insn); 37862306a36Sopenharmony_ci if ((insn & 0xc0800000) == 0xc0800000) { 37962306a36Sopenharmony_ci unsigned char asi; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (insn & 0x2000) 38262306a36Sopenharmony_ci asi = (regs->tstate >> 24); 38362306a36Sopenharmony_ci else 38462306a36Sopenharmony_ci asi = (insn >> 5); 38562306a36Sopenharmony_ci if ((asi & 0xf2) == 0x82) 38662306a36Sopenharmony_ci goto bad_area; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci vma = expand_stack(mm, address); 39062306a36Sopenharmony_ci if (!vma) 39162306a36Sopenharmony_ci goto bad_area_nosemaphore; 39262306a36Sopenharmony_ci /* 39362306a36Sopenharmony_ci * Ok, we have a good vm_area for this memory access, so 39462306a36Sopenharmony_ci * we can handle it.. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_cigood_area: 39762306a36Sopenharmony_ci si_code = SEGV_ACCERR; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* If we took a ITLB miss on a non-executable page, catch 40062306a36Sopenharmony_ci * that here. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) { 40362306a36Sopenharmony_ci WARN(address != regs->tpc, 40462306a36Sopenharmony_ci "address (%lx) != regs->tpc (%lx)\n", address, regs->tpc); 40562306a36Sopenharmony_ci WARN_ON(regs->tstate & TSTATE_PRIV); 40662306a36Sopenharmony_ci goto bad_area; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (fault_code & FAULT_CODE_WRITE) { 41062306a36Sopenharmony_ci if (!(vma->vm_flags & VM_WRITE)) 41162306a36Sopenharmony_ci goto bad_area; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Spitfire has an icache which does not snoop 41462306a36Sopenharmony_ci * processor stores. Later processors do... 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci if (tlb_type == spitfire && 41762306a36Sopenharmony_ci (vma->vm_flags & VM_EXEC) != 0 && 41862306a36Sopenharmony_ci vma->vm_file != NULL) 41962306a36Sopenharmony_ci set_thread_fault_code(fault_code | 42062306a36Sopenharmony_ci FAULT_CODE_BLKCOMMIT); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci flags |= FAULT_FLAG_WRITE; 42362306a36Sopenharmony_ci } else { 42462306a36Sopenharmony_ci /* Allow reads even for write-only mappings */ 42562306a36Sopenharmony_ci if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 42662306a36Sopenharmony_ci goto bad_area; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci fault = handle_mm_fault(vma, address, flags, regs); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (fault_signal_pending(fault, regs)) { 43262306a36Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) { 43362306a36Sopenharmony_ci insn = get_fault_insn(regs, insn); 43462306a36Sopenharmony_ci goto handle_kernel_fault; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci goto exit_exception; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* The fault is fully completed (including releasing mmap lock) */ 44062306a36Sopenharmony_ci if (fault & VM_FAULT_COMPLETED) 44162306a36Sopenharmony_ci goto lock_released; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (unlikely(fault & VM_FAULT_ERROR)) { 44462306a36Sopenharmony_ci if (fault & VM_FAULT_OOM) 44562306a36Sopenharmony_ci goto out_of_memory; 44662306a36Sopenharmony_ci else if (fault & VM_FAULT_SIGSEGV) 44762306a36Sopenharmony_ci goto bad_area; 44862306a36Sopenharmony_ci else if (fault & VM_FAULT_SIGBUS) 44962306a36Sopenharmony_ci goto do_sigbus; 45062306a36Sopenharmony_ci BUG(); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (fault & VM_FAULT_RETRY) { 45462306a36Sopenharmony_ci flags |= FAULT_FLAG_TRIED; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* No need to mmap_read_unlock(mm) as we would 45762306a36Sopenharmony_ci * have already released it in __lock_page_or_retry 45862306a36Sopenharmony_ci * in mm/filemap.c. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci goto retry; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci mmap_read_unlock(mm); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cilock_released: 46662306a36Sopenharmony_ci mm_rss = get_mm_rss(mm); 46762306a36Sopenharmony_ci#if defined(CONFIG_TRANSPARENT_HUGEPAGE) 46862306a36Sopenharmony_ci mm_rss -= (mm->context.thp_pte_count * (HPAGE_SIZE / PAGE_SIZE)); 46962306a36Sopenharmony_ci#endif 47062306a36Sopenharmony_ci if (unlikely(mm_rss > 47162306a36Sopenharmony_ci mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit)) 47262306a36Sopenharmony_ci tsb_grow(mm, MM_TSB_BASE, mm_rss); 47362306a36Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 47462306a36Sopenharmony_ci mm_rss = mm->context.hugetlb_pte_count + mm->context.thp_pte_count; 47562306a36Sopenharmony_ci mm_rss *= REAL_HPAGE_PER_HPAGE; 47662306a36Sopenharmony_ci if (unlikely(mm_rss > 47762306a36Sopenharmony_ci mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) { 47862306a36Sopenharmony_ci if (mm->context.tsb_block[MM_TSB_HUGE].tsb) 47962306a36Sopenharmony_ci tsb_grow(mm, MM_TSB_HUGE, mm_rss); 48062306a36Sopenharmony_ci else 48162306a36Sopenharmony_ci hugetlb_setup(regs); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci#endif 48562306a36Sopenharmony_ciexit_exception: 48662306a36Sopenharmony_ci exception_exit(prev_state); 48762306a36Sopenharmony_ci return; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* 49062306a36Sopenharmony_ci * Something tried to access memory that isn't in our memory map.. 49162306a36Sopenharmony_ci * Fix it, but check if it's kernel or user first.. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_cibad_area: 49462306a36Sopenharmony_ci mmap_read_unlock(mm); 49562306a36Sopenharmony_cibad_area_nosemaphore: 49662306a36Sopenharmony_ci insn = get_fault_insn(regs, insn); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cihandle_kernel_fault: 49962306a36Sopenharmony_ci do_kernel_fault(regs, si_code, fault_code, insn, address); 50062306a36Sopenharmony_ci goto exit_exception; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci/* 50362306a36Sopenharmony_ci * We ran out of memory, or some other thing happened to us that made 50462306a36Sopenharmony_ci * us unable to handle the page fault gracefully. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ciout_of_memory: 50762306a36Sopenharmony_ci insn = get_fault_insn(regs, insn); 50862306a36Sopenharmony_ci mmap_read_unlock(mm); 50962306a36Sopenharmony_ci if (!(regs->tstate & TSTATE_PRIV)) { 51062306a36Sopenharmony_ci pagefault_out_of_memory(); 51162306a36Sopenharmony_ci goto exit_exception; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci goto handle_kernel_fault; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ciintr_or_no_mm: 51662306a36Sopenharmony_ci insn = get_fault_insn(regs, 0); 51762306a36Sopenharmony_ci goto handle_kernel_fault; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cido_sigbus: 52062306a36Sopenharmony_ci insn = get_fault_insn(regs, insn); 52162306a36Sopenharmony_ci mmap_read_unlock(mm); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* 52462306a36Sopenharmony_ci * Send a sigbus, regardless of whether we were in kernel 52562306a36Sopenharmony_ci * or user mode. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, address, insn, fault_code); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* Kernel mode? Handle exceptions or die */ 53062306a36Sopenharmony_ci if (regs->tstate & TSTATE_PRIV) 53162306a36Sopenharmony_ci goto handle_kernel_fault; 53262306a36Sopenharmony_ci} 533