18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/arch/arm/mm/fault.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1995  Linus Torvalds
68c2ecf20Sopenharmony_ci *  Modifications for ARM processor (c) 1995-2004 Russell King
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/extable.h>
98c2ecf20Sopenharmony_ci#include <linux/signal.h>
108c2ecf20Sopenharmony_ci#include <linux/mm.h>
118c2ecf20Sopenharmony_ci#include <linux/hardirq.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/kprobes.h>
148c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
158c2ecf20Sopenharmony_ci#include <linux/page-flags.h>
168c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
178c2ecf20Sopenharmony_ci#include <linux/sched/debug.h>
188c2ecf20Sopenharmony_ci#include <linux/highmem.h>
198c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <asm/system_misc.h>
228c2ecf20Sopenharmony_ci#include <asm/system_info.h>
238c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "fault.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * This is useful to dump out the page tables associated with
318c2ecf20Sopenharmony_ci * 'addr' in mm 'mm'.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_civoid show_pte(const char *lvl, struct mm_struct *mm, unsigned long addr)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	pgd_t *pgd;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (!mm)
388c2ecf20Sopenharmony_ci		mm = &init_mm;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	pgd = pgd_offset(mm, addr);
418c2ecf20Sopenharmony_ci	printk("%s[%08lx] *pgd=%08llx", lvl, addr, (long long)pgd_val(*pgd));
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	do {
448c2ecf20Sopenharmony_ci		p4d_t *p4d;
458c2ecf20Sopenharmony_ci		pud_t *pud;
468c2ecf20Sopenharmony_ci		pmd_t *pmd;
478c2ecf20Sopenharmony_ci		pte_t *pte;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci		p4d = p4d_offset(pgd, addr);
508c2ecf20Sopenharmony_ci		if (p4d_none(*p4d))
518c2ecf20Sopenharmony_ci			break;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci		if (p4d_bad(*p4d)) {
548c2ecf20Sopenharmony_ci			pr_cont("(bad)");
558c2ecf20Sopenharmony_ci			break;
568c2ecf20Sopenharmony_ci		}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		pud = pud_offset(p4d, addr);
598c2ecf20Sopenharmony_ci		if (PTRS_PER_PUD != 1)
608c2ecf20Sopenharmony_ci			pr_cont(", *pud=%08llx", (long long)pud_val(*pud));
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		if (pud_none(*pud))
638c2ecf20Sopenharmony_ci			break;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		if (pud_bad(*pud)) {
668c2ecf20Sopenharmony_ci			pr_cont("(bad)");
678c2ecf20Sopenharmony_ci			break;
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		pmd = pmd_offset(pud, addr);
718c2ecf20Sopenharmony_ci		if (PTRS_PER_PMD != 1)
728c2ecf20Sopenharmony_ci			pr_cont(", *pmd=%08llx", (long long)pmd_val(*pmd));
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		if (pmd_none(*pmd))
758c2ecf20Sopenharmony_ci			break;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		if (pmd_bad(*pmd)) {
788c2ecf20Sopenharmony_ci			pr_cont("(bad)");
798c2ecf20Sopenharmony_ci			break;
808c2ecf20Sopenharmony_ci		}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		/* We must not map this if we have highmem enabled */
838c2ecf20Sopenharmony_ci		if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
848c2ecf20Sopenharmony_ci			break;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		pte = pte_offset_map(pmd, addr);
878c2ecf20Sopenharmony_ci		pr_cont(", *pte=%08llx", (long long)pte_val(*pte));
888c2ecf20Sopenharmony_ci#ifndef CONFIG_ARM_LPAE
898c2ecf20Sopenharmony_ci		pr_cont(", *ppte=%08llx",
908c2ecf20Sopenharmony_ci		       (long long)pte_val(pte[PTE_HWTABLE_PTRS]));
918c2ecf20Sopenharmony_ci#endif
928c2ecf20Sopenharmony_ci		pte_unmap(pte);
938c2ecf20Sopenharmony_ci	} while(0);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	pr_cont("\n");
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci#else					/* CONFIG_MMU */
988c2ecf20Sopenharmony_civoid show_pte(const char *lvl, struct mm_struct *mm, unsigned long addr)
998c2ecf20Sopenharmony_ci{ }
1008c2ecf20Sopenharmony_ci#endif					/* CONFIG_MMU */
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void die_kernel_fault(const char *msg, struct mm_struct *mm,
1038c2ecf20Sopenharmony_ci			     unsigned long addr, unsigned int fsr,
1048c2ecf20Sopenharmony_ci			     struct pt_regs *regs)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	bust_spinlocks(1);
1078c2ecf20Sopenharmony_ci	pr_alert("8<--- cut here ---\n");
1088c2ecf20Sopenharmony_ci	pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
1098c2ecf20Sopenharmony_ci		 msg, addr);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	show_pte(KERN_ALERT, mm, addr);
1128c2ecf20Sopenharmony_ci	die("Oops", regs, fsr);
1138c2ecf20Sopenharmony_ci	bust_spinlocks(0);
1148c2ecf20Sopenharmony_ci	make_task_dead(SIGKILL);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/*
1188c2ecf20Sopenharmony_ci * Oops.  The kernel tried to access some page that wasn't present.
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_cistatic void
1218c2ecf20Sopenharmony_ci__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
1228c2ecf20Sopenharmony_ci		  struct pt_regs *regs)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	const char *msg;
1258c2ecf20Sopenharmony_ci	/*
1268c2ecf20Sopenharmony_ci	 * Are we prepared to handle this kernel fault?
1278c2ecf20Sopenharmony_ci	 */
1288c2ecf20Sopenharmony_ci	if (fixup_exception(regs))
1298c2ecf20Sopenharmony_ci		return;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * No handler, we'll have to terminate things with extreme prejudice.
1338c2ecf20Sopenharmony_ci	 */
1348c2ecf20Sopenharmony_ci	if (addr < PAGE_SIZE)
1358c2ecf20Sopenharmony_ci		msg = "NULL pointer dereference";
1368c2ecf20Sopenharmony_ci	else
1378c2ecf20Sopenharmony_ci		msg = "paging request";
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	die_kernel_fault(msg, mm, addr, fsr, regs);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/*
1438c2ecf20Sopenharmony_ci * Something tried to access memory that isn't in our memory map..
1448c2ecf20Sopenharmony_ci * User mode accesses just cause a SIGSEGV
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_cistatic void
1478c2ecf20Sopenharmony_ci__do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
1488c2ecf20Sopenharmony_ci		int code, struct pt_regs *regs)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct task_struct *tsk = current;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (addr > TASK_SIZE)
1538c2ecf20Sopenharmony_ci		harden_branch_predictor();
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_USER
1568c2ecf20Sopenharmony_ci	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
1578c2ecf20Sopenharmony_ci	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
1588c2ecf20Sopenharmony_ci		pr_err("8<--- cut here ---\n");
1598c2ecf20Sopenharmony_ci		pr_err("%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
1608c2ecf20Sopenharmony_ci		       tsk->comm, sig, addr, fsr);
1618c2ecf20Sopenharmony_ci		show_pte(KERN_ERR, tsk->mm, addr);
1628c2ecf20Sopenharmony_ci		show_regs(regs);
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci#endif
1658c2ecf20Sopenharmony_ci#ifndef CONFIG_KUSER_HELPERS
1668c2ecf20Sopenharmony_ci	if ((sig == SIGSEGV) && ((addr & PAGE_MASK) == 0xffff0000))
1678c2ecf20Sopenharmony_ci		printk_ratelimited(KERN_DEBUG
1688c2ecf20Sopenharmony_ci				   "%s: CONFIG_KUSER_HELPERS disabled at 0x%08lx\n",
1698c2ecf20Sopenharmony_ci				   tsk->comm, addr);
1708c2ecf20Sopenharmony_ci#endif
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	tsk->thread.address = addr;
1738c2ecf20Sopenharmony_ci	tsk->thread.error_code = fsr;
1748c2ecf20Sopenharmony_ci	tsk->thread.trap_no = 14;
1758c2ecf20Sopenharmony_ci	force_sig_fault(sig, code, (void __user *)addr);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_civoid do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct task_struct *tsk = current;
1818c2ecf20Sopenharmony_ci	struct mm_struct *mm = tsk->active_mm;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/*
1848c2ecf20Sopenharmony_ci	 * If we are in kernel mode at this point, we
1858c2ecf20Sopenharmony_ci	 * have no context to handle this fault with.
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci	if (user_mode(regs))
1888c2ecf20Sopenharmony_ci		__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
1898c2ecf20Sopenharmony_ci	else
1908c2ecf20Sopenharmony_ci		__do_kernel_fault(mm, addr, fsr, regs);
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU
1948c2ecf20Sopenharmony_ci#define VM_FAULT_BADMAP		0x010000
1958c2ecf20Sopenharmony_ci#define VM_FAULT_BADACCESS	0x020000
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline bool is_permission_fault(unsigned int fsr)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	int fs = fsr_fs(fsr);
2008c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
2018c2ecf20Sopenharmony_ci	if ((fs & FS_PERM_NOLL_MASK) == FS_PERM_NOLL)
2028c2ecf20Sopenharmony_ci		return true;
2038c2ecf20Sopenharmony_ci#else
2048c2ecf20Sopenharmony_ci	if (fs == FS_L1_PERM || fs == FS_L2_PERM)
2058c2ecf20Sopenharmony_ci		return true;
2068c2ecf20Sopenharmony_ci#endif
2078c2ecf20Sopenharmony_ci	return false;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic vm_fault_t __kprobes
2118c2ecf20Sopenharmony_ci__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int flags,
2128c2ecf20Sopenharmony_ci		unsigned long vma_flags, struct pt_regs *regs)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct vm_area_struct *vma = find_vma(mm, addr);
2158c2ecf20Sopenharmony_ci	if (unlikely(!vma))
2168c2ecf20Sopenharmony_ci		return VM_FAULT_BADMAP;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (unlikely(vma->vm_start > addr)) {
2198c2ecf20Sopenharmony_ci		if (!(vma->vm_flags & VM_GROWSDOWN))
2208c2ecf20Sopenharmony_ci			return VM_FAULT_BADMAP;
2218c2ecf20Sopenharmony_ci		if (addr < FIRST_USER_ADDRESS)
2228c2ecf20Sopenharmony_ci			return VM_FAULT_BADMAP;
2238c2ecf20Sopenharmony_ci		if (expand_stack(vma, addr))
2248c2ecf20Sopenharmony_ci			return VM_FAULT_BADMAP;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/*
2288c2ecf20Sopenharmony_ci	 * ok, we have a good vm_area for this memory access, check the
2298c2ecf20Sopenharmony_ci	 * permissions on the VMA allow for the fault which occurred.
2308c2ecf20Sopenharmony_ci	 */
2318c2ecf20Sopenharmony_ci	if (!(vma->vm_flags & vma_flags))
2328c2ecf20Sopenharmony_ci		return VM_FAULT_BADACCESS;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return handle_mm_fault(vma, addr & PAGE_MASK, flags, regs);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int __kprobes
2388c2ecf20Sopenharmony_cido_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	struct mm_struct *mm = current->mm;
2418c2ecf20Sopenharmony_ci	int sig, code;
2428c2ecf20Sopenharmony_ci	vm_fault_t fault;
2438c2ecf20Sopenharmony_ci	unsigned int flags = FAULT_FLAG_DEFAULT;
2448c2ecf20Sopenharmony_ci	unsigned long vm_flags = VM_ACCESS_FLAGS;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (kprobe_page_fault(regs, fsr))
2478c2ecf20Sopenharmony_ci		return 0;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	/* Enable interrupts if they were enabled in the parent context. */
2518c2ecf20Sopenharmony_ci	if (interrupts_enabled(regs))
2528c2ecf20Sopenharmony_ci		local_irq_enable();
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/*
2558c2ecf20Sopenharmony_ci	 * If we're in an interrupt or have no user
2568c2ecf20Sopenharmony_ci	 * context, we must not take the fault..
2578c2ecf20Sopenharmony_ci	 */
2588c2ecf20Sopenharmony_ci	if (faulthandler_disabled() || !mm)
2598c2ecf20Sopenharmony_ci		goto no_context;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (user_mode(regs))
2628c2ecf20Sopenharmony_ci		flags |= FAULT_FLAG_USER;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if ((fsr & FSR_WRITE) && !(fsr & FSR_CM)) {
2658c2ecf20Sopenharmony_ci		flags |= FAULT_FLAG_WRITE;
2668c2ecf20Sopenharmony_ci		vm_flags = VM_WRITE;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (fsr & FSR_LNX_PF) {
2708c2ecf20Sopenharmony_ci		vm_flags = VM_EXEC;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		if (is_permission_fault(fsr) && !user_mode(regs))
2738c2ecf20Sopenharmony_ci			die_kernel_fault("execution of memory",
2748c2ecf20Sopenharmony_ci					 mm, addr, fsr, regs);
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/*
2808c2ecf20Sopenharmony_ci	 * As per x86, we may deadlock here.  However, since the kernel only
2818c2ecf20Sopenharmony_ci	 * validly references user space from well defined areas of the code,
2828c2ecf20Sopenharmony_ci	 * we can bug out early if this is from code which shouldn't.
2838c2ecf20Sopenharmony_ci	 */
2848c2ecf20Sopenharmony_ci	if (!mmap_read_trylock(mm)) {
2858c2ecf20Sopenharmony_ci		if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc))
2868c2ecf20Sopenharmony_ci			goto no_context;
2878c2ecf20Sopenharmony_ciretry:
2888c2ecf20Sopenharmony_ci		mmap_read_lock(mm);
2898c2ecf20Sopenharmony_ci	} else {
2908c2ecf20Sopenharmony_ci		/*
2918c2ecf20Sopenharmony_ci		 * The above down_read_trylock() might have succeeded in
2928c2ecf20Sopenharmony_ci		 * which case, we'll have missed the might_sleep() from
2938c2ecf20Sopenharmony_ci		 * down_read()
2948c2ecf20Sopenharmony_ci		 */
2958c2ecf20Sopenharmony_ci		might_sleep();
2968c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_VM
2978c2ecf20Sopenharmony_ci		if (!user_mode(regs) &&
2988c2ecf20Sopenharmony_ci		    !search_exception_tables(regs->ARM_pc))
2998c2ecf20Sopenharmony_ci			goto no_context;
3008c2ecf20Sopenharmony_ci#endif
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	fault = __do_page_fault(mm, addr, flags, vm_flags, regs);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* If we need to retry but a fatal signal is pending, handle the
3068c2ecf20Sopenharmony_ci	 * signal first. We do not need to release the mmap_lock because
3078c2ecf20Sopenharmony_ci	 * it would already be released in __lock_page_or_retry in
3088c2ecf20Sopenharmony_ci	 * mm/filemap.c. */
3098c2ecf20Sopenharmony_ci	if (fault_signal_pending(fault, regs)) {
3108c2ecf20Sopenharmony_ci		if (!user_mode(regs))
3118c2ecf20Sopenharmony_ci			goto no_context;
3128c2ecf20Sopenharmony_ci		return 0;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	if (!(fault & VM_FAULT_ERROR) && flags & FAULT_FLAG_ALLOW_RETRY) {
3168c2ecf20Sopenharmony_ci		if (fault & VM_FAULT_RETRY) {
3178c2ecf20Sopenharmony_ci			flags |= FAULT_FLAG_TRIED;
3188c2ecf20Sopenharmony_ci			goto retry;
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	mmap_read_unlock(mm);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/*
3258c2ecf20Sopenharmony_ci	 * Handle the "normal" case first - VM_FAULT_MAJOR
3268c2ecf20Sopenharmony_ci	 */
3278c2ecf20Sopenharmony_ci	if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
3288c2ecf20Sopenharmony_ci		return 0;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/*
3318c2ecf20Sopenharmony_ci	 * If we are in kernel mode at this point, we
3328c2ecf20Sopenharmony_ci	 * have no context to handle this fault with.
3338c2ecf20Sopenharmony_ci	 */
3348c2ecf20Sopenharmony_ci	if (!user_mode(regs))
3358c2ecf20Sopenharmony_ci		goto no_context;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (fault & VM_FAULT_OOM) {
3388c2ecf20Sopenharmony_ci		/*
3398c2ecf20Sopenharmony_ci		 * We ran out of memory, call the OOM killer, and return to
3408c2ecf20Sopenharmony_ci		 * userspace (which will retry the fault, or kill us if we
3418c2ecf20Sopenharmony_ci		 * got oom-killed)
3428c2ecf20Sopenharmony_ci		 */
3438c2ecf20Sopenharmony_ci		pagefault_out_of_memory();
3448c2ecf20Sopenharmony_ci		return 0;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (fault & VM_FAULT_SIGBUS) {
3488c2ecf20Sopenharmony_ci		/*
3498c2ecf20Sopenharmony_ci		 * We had some memory, but were unable to
3508c2ecf20Sopenharmony_ci		 * successfully fix up this page fault.
3518c2ecf20Sopenharmony_ci		 */
3528c2ecf20Sopenharmony_ci		sig = SIGBUS;
3538c2ecf20Sopenharmony_ci		code = BUS_ADRERR;
3548c2ecf20Sopenharmony_ci	} else {
3558c2ecf20Sopenharmony_ci		/*
3568c2ecf20Sopenharmony_ci		 * Something tried to access memory that
3578c2ecf20Sopenharmony_ci		 * isn't in our memory map..
3588c2ecf20Sopenharmony_ci		 */
3598c2ecf20Sopenharmony_ci		sig = SIGSEGV;
3608c2ecf20Sopenharmony_ci		code = fault == VM_FAULT_BADACCESS ?
3618c2ecf20Sopenharmony_ci			SEGV_ACCERR : SEGV_MAPERR;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	__do_user_fault(addr, fsr, sig, code, regs);
3658c2ecf20Sopenharmony_ci	return 0;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cino_context:
3688c2ecf20Sopenharmony_ci	__do_kernel_fault(mm, addr, fsr, regs);
3698c2ecf20Sopenharmony_ci	return 0;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci#else					/* CONFIG_MMU */
3728c2ecf20Sopenharmony_cistatic int
3738c2ecf20Sopenharmony_cido_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci#endif					/* CONFIG_MMU */
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci/*
3808c2ecf20Sopenharmony_ci * First Level Translation Fault Handler
3818c2ecf20Sopenharmony_ci *
3828c2ecf20Sopenharmony_ci * We enter here because the first level page table doesn't contain
3838c2ecf20Sopenharmony_ci * a valid entry for the address.
3848c2ecf20Sopenharmony_ci *
3858c2ecf20Sopenharmony_ci * If the address is in kernel space (>= TASK_SIZE), then we are
3868c2ecf20Sopenharmony_ci * probably faulting in the vmalloc() area.
3878c2ecf20Sopenharmony_ci *
3888c2ecf20Sopenharmony_ci * If the init_task's first level page tables contains the relevant
3898c2ecf20Sopenharmony_ci * entry, we copy the it to this task.  If not, we send the process
3908c2ecf20Sopenharmony_ci * a signal, fixup the exception, or oops the kernel.
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * NOTE! We MUST NOT take any locks for this case. We may be in an
3938c2ecf20Sopenharmony_ci * interrupt or a critical region, and should only copy the information
3948c2ecf20Sopenharmony_ci * from the master page table, nothing more.
3958c2ecf20Sopenharmony_ci */
3968c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU
3978c2ecf20Sopenharmony_cistatic int __kprobes
3988c2ecf20Sopenharmony_cido_translation_fault(unsigned long addr, unsigned int fsr,
3998c2ecf20Sopenharmony_ci		     struct pt_regs *regs)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	unsigned int index;
4028c2ecf20Sopenharmony_ci	pgd_t *pgd, *pgd_k;
4038c2ecf20Sopenharmony_ci	p4d_t *p4d, *p4d_k;
4048c2ecf20Sopenharmony_ci	pud_t *pud, *pud_k;
4058c2ecf20Sopenharmony_ci	pmd_t *pmd, *pmd_k;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (addr < TASK_SIZE)
4088c2ecf20Sopenharmony_ci		return do_page_fault(addr, fsr, regs);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (user_mode(regs))
4118c2ecf20Sopenharmony_ci		goto bad_area;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	index = pgd_index(addr);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	pgd = cpu_get_pgd() + index;
4168c2ecf20Sopenharmony_ci	pgd_k = init_mm.pgd + index;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	p4d = p4d_offset(pgd, addr);
4198c2ecf20Sopenharmony_ci	p4d_k = p4d_offset(pgd_k, addr);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (p4d_none(*p4d_k))
4228c2ecf20Sopenharmony_ci		goto bad_area;
4238c2ecf20Sopenharmony_ci	if (!p4d_present(*p4d))
4248c2ecf20Sopenharmony_ci		set_p4d(p4d, *p4d_k);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	pud = pud_offset(p4d, addr);
4278c2ecf20Sopenharmony_ci	pud_k = pud_offset(p4d_k, addr);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (pud_none(*pud_k))
4308c2ecf20Sopenharmony_ci		goto bad_area;
4318c2ecf20Sopenharmony_ci	if (!pud_present(*pud))
4328c2ecf20Sopenharmony_ci		set_pud(pud, *pud_k);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	pmd = pmd_offset(pud, addr);
4358c2ecf20Sopenharmony_ci	pmd_k = pmd_offset(pud_k, addr);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
4388c2ecf20Sopenharmony_ci	/*
4398c2ecf20Sopenharmony_ci	 * Only one hardware entry per PMD with LPAE.
4408c2ecf20Sopenharmony_ci	 */
4418c2ecf20Sopenharmony_ci	index = 0;
4428c2ecf20Sopenharmony_ci#else
4438c2ecf20Sopenharmony_ci	/*
4448c2ecf20Sopenharmony_ci	 * On ARM one Linux PGD entry contains two hardware entries (see page
4458c2ecf20Sopenharmony_ci	 * tables layout in pgtable.h). We normally guarantee that we always
4468c2ecf20Sopenharmony_ci	 * fill both L1 entries. But create_mapping() doesn't follow the rule.
4478c2ecf20Sopenharmony_ci	 * It can create inidividual L1 entries, so here we have to call
4488c2ecf20Sopenharmony_ci	 * pmd_none() check for the entry really corresponded to address, not
4498c2ecf20Sopenharmony_ci	 * for the first of pair.
4508c2ecf20Sopenharmony_ci	 */
4518c2ecf20Sopenharmony_ci	index = (addr >> SECTION_SHIFT) & 1;
4528c2ecf20Sopenharmony_ci#endif
4538c2ecf20Sopenharmony_ci	if (pmd_none(pmd_k[index]))
4548c2ecf20Sopenharmony_ci		goto bad_area;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	copy_pmd(pmd, pmd_k);
4578c2ecf20Sopenharmony_ci	return 0;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cibad_area:
4608c2ecf20Sopenharmony_ci	do_bad_area(addr, fsr, regs);
4618c2ecf20Sopenharmony_ci	return 0;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci#else					/* CONFIG_MMU */
4648c2ecf20Sopenharmony_cistatic int
4658c2ecf20Sopenharmony_cido_translation_fault(unsigned long addr, unsigned int fsr,
4668c2ecf20Sopenharmony_ci		     struct pt_regs *regs)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	return 0;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci#endif					/* CONFIG_MMU */
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci/*
4738c2ecf20Sopenharmony_ci * Some section permission faults need to be handled gracefully.
4748c2ecf20Sopenharmony_ci * They can happen due to a __{get,put}_user during an oops.
4758c2ecf20Sopenharmony_ci */
4768c2ecf20Sopenharmony_ci#ifndef CONFIG_ARM_LPAE
4778c2ecf20Sopenharmony_cistatic int
4788c2ecf20Sopenharmony_cido_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	do_bad_area(addr, fsr, regs);
4818c2ecf20Sopenharmony_ci	return 0;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci#endif /* CONFIG_ARM_LPAE */
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci/*
4868c2ecf20Sopenharmony_ci * This abort handler always returns "fault".
4878c2ecf20Sopenharmony_ci */
4888c2ecf20Sopenharmony_cistatic int
4898c2ecf20Sopenharmony_cido_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	return 1;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistruct fsr_info {
4958c2ecf20Sopenharmony_ci	int	(*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
4968c2ecf20Sopenharmony_ci	int	sig;
4978c2ecf20Sopenharmony_ci	int	code;
4988c2ecf20Sopenharmony_ci	const char *name;
4998c2ecf20Sopenharmony_ci};
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci/* FSR definition */
5028c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
5038c2ecf20Sopenharmony_ci#include "fsr-3level.c"
5048c2ecf20Sopenharmony_ci#else
5058c2ecf20Sopenharmony_ci#include "fsr-2level.c"
5068c2ecf20Sopenharmony_ci#endif
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_civoid __init
5098c2ecf20Sopenharmony_cihook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
5108c2ecf20Sopenharmony_ci		int sig, int code, const char *name)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	if (nr < 0 || nr >= ARRAY_SIZE(fsr_info))
5138c2ecf20Sopenharmony_ci		BUG();
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	fsr_info[nr].fn   = fn;
5168c2ecf20Sopenharmony_ci	fsr_info[nr].sig  = sig;
5178c2ecf20Sopenharmony_ci	fsr_info[nr].code = code;
5188c2ecf20Sopenharmony_ci	fsr_info[nr].name = name;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci/*
5228c2ecf20Sopenharmony_ci * Dispatch a data abort to the relevant handler.
5238c2ecf20Sopenharmony_ci */
5248c2ecf20Sopenharmony_ciasmlinkage void
5258c2ecf20Sopenharmony_cido_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
5308c2ecf20Sopenharmony_ci		return;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	pr_alert("8<--- cut here ---\n");
5338c2ecf20Sopenharmony_ci	pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
5348c2ecf20Sopenharmony_ci		inf->name, fsr, addr);
5358c2ecf20Sopenharmony_ci	show_pte(KERN_ALERT, current->mm, addr);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
5388c2ecf20Sopenharmony_ci		       fsr, 0);
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_civoid __init
5428c2ecf20Sopenharmony_cihook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
5438c2ecf20Sopenharmony_ci		 int sig, int code, const char *name)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	if (nr < 0 || nr >= ARRAY_SIZE(ifsr_info))
5468c2ecf20Sopenharmony_ci		BUG();
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	ifsr_info[nr].fn   = fn;
5498c2ecf20Sopenharmony_ci	ifsr_info[nr].sig  = sig;
5508c2ecf20Sopenharmony_ci	ifsr_info[nr].code = code;
5518c2ecf20Sopenharmony_ci	ifsr_info[nr].name = name;
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ciasmlinkage void
5558c2ecf20Sopenharmony_cido_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
5608c2ecf20Sopenharmony_ci		return;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
5638c2ecf20Sopenharmony_ci		inf->name, ifsr, addr);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
5668c2ecf20Sopenharmony_ci		       ifsr, 0);
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci/*
5708c2ecf20Sopenharmony_ci * Abort handler to be used only during first unmasking of asynchronous aborts
5718c2ecf20Sopenharmony_ci * on the boot CPU. This makes sure that the machine will not die if the
5728c2ecf20Sopenharmony_ci * firmware/bootloader left an imprecise abort pending for us to trip over.
5738c2ecf20Sopenharmony_ci */
5748c2ecf20Sopenharmony_cistatic int __init early_abort_handler(unsigned long addr, unsigned int fsr,
5758c2ecf20Sopenharmony_ci				      struct pt_regs *regs)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	pr_warn("Hit pending asynchronous external abort (FSR=0x%08x) during "
5788c2ecf20Sopenharmony_ci		"first unmask, this is most likely caused by a "
5798c2ecf20Sopenharmony_ci		"firmware/bootloader bug.\n", fsr);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	return 0;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_civoid __init early_abt_enable(void)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	fsr_info[FSR_FS_AEA].fn = early_abort_handler;
5878c2ecf20Sopenharmony_ci	local_abt_enable();
5888c2ecf20Sopenharmony_ci	fsr_info[FSR_FS_AEA].fn = do_bad;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci#ifndef CONFIG_ARM_LPAE
5928c2ecf20Sopenharmony_cistatic int __init exceptions_init(void)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	if (cpu_architecture() >= CPU_ARCH_ARMv6) {
5958c2ecf20Sopenharmony_ci		hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR,
5968c2ecf20Sopenharmony_ci				"I-cache maintenance fault");
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if (cpu_architecture() >= CPU_ARCH_ARMv7) {
6008c2ecf20Sopenharmony_ci		/*
6018c2ecf20Sopenharmony_ci		 * TODO: Access flag faults introduced in ARMv6K.
6028c2ecf20Sopenharmony_ci		 * Runtime check for 'K' extension is needed
6038c2ecf20Sopenharmony_ci		 */
6048c2ecf20Sopenharmony_ci		hook_fault_code(3, do_bad, SIGSEGV, SEGV_MAPERR,
6058c2ecf20Sopenharmony_ci				"section access flag fault");
6068c2ecf20Sopenharmony_ci		hook_fault_code(6, do_bad, SIGSEGV, SEGV_MAPERR,
6078c2ecf20Sopenharmony_ci				"section access flag fault");
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ciarch_initcall(exceptions_init);
6148c2ecf20Sopenharmony_ci#endif
615