11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/arch/frv/mm/fault.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Written by David Howells (dhowells@redhat.com)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Derived from arch/m68knommu/mm/fault.c
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Copyright (C) 2000  Lineo, Inc.  (www.lineo.com)
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Based on:
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/arch/m68k/mm/fault.c
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1995  Hamish Macdonald
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mman.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hardirq.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/gdb-stub.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine handles page faults.  It determines the problem, and
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then passes it off to one of the appropriate routines.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear0)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vm_area_struct *vma;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mm_struct *mm;
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long _pme, lrai, lrad, fixup;
37759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner	unsigned long flags = 0;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginfo_t info;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgd_t *pge;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pud_t *pue;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pte_t *pte;
4283c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin	int fault;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *atxc[16] = {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[0x0] = "mmu-miss", [0x8] = "multi-dat", [0x9] = "multi-sat",
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		[0xa] = "tlb-miss", [0xc] = "privilege", [0xd] = "write-prot",
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("do_page_fault(%d,%lx [%s],%lx)\n",
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       datammu, esr0, atxc[esr0 >> 20 & 0xf], ear0);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mm = current->mm;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We fault-in kernel-space virtual memory on-demand. The
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * 'reference' page table is init_mm.pgd.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * NOTE! We MUST NOT take any locks for this case. We may
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * be in an interrupt or a critical region, and should
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * only copy the information from the master page table,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * nothing more.
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This verifies that the fault happens in kernel space
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and that the fault was a page not present (invalid) error
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!user_mode(__frame) && (esr0 & ESR0_ATXC) == ESR0_ATXC_AMRTLB_MISS) {
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ear0 >= VMALLOC_START && ear0 < VMALLOC_END)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto kernel_pte_fault;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ear0 >= PKMAP_BASE && ear0 < PKMAP_END)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto kernel_pte_fault;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code = SEGV_MAPERR;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we're in an interrupt or have no user
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * context, we must not take the fault..
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
816edaf68a87d17570790fd55f0c451a29ec1d6703Peter Zijlstra	if (in_atomic() || !mm)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_context;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
84759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner	if (user_mode(__frame))
85759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner		flags |= FAULT_FLAG_USER;
86759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down_read(&mm->mmap_sem);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vma = find_vma(mm, ear0);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!vma)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad_area;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vma->vm_start <= ear0)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto good_area;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(vma->vm_flags & VM_GROWSDOWN))
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad_area;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (user_mode(__frame)) {
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * accessing the stack below %esp is always a bug.
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The "+ 32" is there due to some instructions (like
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * pusha) doing post-decrement on the stack and that
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * doesn't show up until later..
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ear0 & PAGE_MASK) + 2 * PAGE_SIZE < __frame->sp) {
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("[%d] ### Access below stack @%lx (sp=%lx)\n",
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       current->pid, ear0, __frame->sp);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			show_registers(__frame);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("[%d] ### Code: [%08lx] %02x %02x %02x %02x %02x %02x %02x %02x\n",
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       current->pid,
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       __frame->pc,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[0],
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[1],
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[2],
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[3],
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[4],
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[5],
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[6],
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ((u8*)__frame->pc)[7]
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       );
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto bad_area;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (expand_stack(vma, ear0))
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad_area;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ok, we have a good vm_area for this memory access, so
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we can handle it..
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds good_area:
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code = SEGV_ACCERR;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (esr0 & ESR0_ATXC) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle write to write protected page */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ESR0_ATXC_WP_EXCEP:
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef TEST_VERIFY_AREA
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(user_mode(__frame)))
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("WP fault at %08lx\n", __frame->pc);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(vma->vm_flags & VM_WRITE))
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto bad_area;
145759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner		flags |= FAULT_FLAG_WRITE;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 /* handle read from protected page */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ESR0_ATXC_PRIV_EXCEP:
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad_area;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 /* handle read, write or exec on absent page
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  * - can't support write without permitting read
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  * - don't support execute without permitting read and vice-versa
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ESR0_ATXC_AMRTLB_MISS:
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto bad_area;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If for any reason at all we couldn't handle the fault,
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * make sure we exit gracefully rather than endlessly redo
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the fault.
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
167759496ba6407c6994d6a5ce3a5e74937d7816208Johannes Weiner	fault = handle_mm_fault(mm, vma, ear0, flags);
16883c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin	if (unlikely(fault & VM_FAULT_ERROR)) {
16983c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin		if (fault & VM_FAULT_OOM)
17083c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin			goto out_of_memory;
17183c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin		else if (fault & VM_FAULT_SIGBUS)
17283c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin			goto do_sigbus;
17383c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin		BUG();
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17583c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin	if (fault & VM_FAULT_MAJOR)
17683c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin		current->maj_flt++;
17783c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin	else
17883c54070ee1a2d05c89793884bea1a03f2851ed4Nick Piggin		current->min_flt++;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_read(&mm->mmap_sem);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Something tried to access memory that isn't in our memory map..
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fix it, but check if it's kernel or user first..
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bad_area:
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_read(&mm->mmap_sem);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* User mode accesses just cause a SIGSEGV */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (user_mode(__frame)) {
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_signo = SIGSEGV;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_errno = 0;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* info.si_code has been set above */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_addr = (void *) ear0;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		force_sig_info(SIGSEGV, &info, current);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_context:
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* are we prepared to handle this kernel fault? */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((fixup = search_exception_table(__frame->pc)) != 0) {
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__frame->pc = fixup;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops. The kernel tried to access some bad page. We'll have to
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * terminate things with extreme prejudice.
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bust_spinlocks(1);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ear0 < PAGE_SIZE)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ALERT "Unable to handle kernel paging request");
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(" at virtual addr %08lx\n", ear0);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("  PC  : %08lx\n", __frame->pc);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("  EXC : esr0=%08lx ear0=%08lx\n", esr0, ear0);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asm("lrai %1,%0,#1,#0,#0" : "=&r"(lrai) : "r"(ear0));
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asm("lrad %1,%0,#1,#0,#0" : "=&r"(lrad) : "r"(ear0));
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ALERT "  LRAI: %08lx\n", lrai);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ALERT "  LRAD: %08lx\n", lrad);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__break_hijack_kernel_event();
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pge = pgd_offset(current->mm, ear0);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pue = pud_offset(pge, ear0);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_pme = pue->pue[0].ste[0];
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ALERT "  PGE : %8p { PME %08lx }\n", pge, _pme);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (_pme & xAMPRx_V) {
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long dampr, damlr, val;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		asm volatile("movsg dampr2,%0 ! movgs %2,dampr2 ! movsg damlr2,%1"
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     : "=&r"(dampr), "=r"(damlr)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     : "r" (_pme | xAMPRx_L|xAMPRx_SS_16Kb|xAMPRx_S|xAMPRx_C|xAMPRx_V)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     );
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pte = (pte_t *) damlr + __pte_index(ear0);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = pte_val(*pte);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		asm volatile("movgs %0,dampr2" :: "r" (dampr));
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ALERT "  PTE : %8p { %08lx }\n", pte, val);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("Oops\n");
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_exit(SIGKILL);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We ran out of memory, or some other thing happened to us that made
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * us unable to handle the page fault gracefully.
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_of_memory:
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_read(&mm->mmap_sem);
261f9c497c4aea28be826b8450a5339952f2ffc705eNick Piggin	if (!user_mode(__frame))
262f9c497c4aea28be826b8450a5339952f2ffc705eNick Piggin		goto no_context;
263f9c497c4aea28be826b8450a5339952f2ffc705eNick Piggin	pagefault_out_of_memory();
264f9c497c4aea28be826b8450a5339952f2ffc705eNick Piggin	return;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_sigbus:
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up_read(&mm->mmap_sem);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Send a sigbus, regardless of whether we were in kernel
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * or user mode.
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_signo = SIGBUS;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_errno = 0;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code = BUS_ADRERR;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_addr = (void *) ear0;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig_info(SIGBUS, &info, current);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Kernel mode? Handle exceptions or die */
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!user_mode(__frame))
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_context;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The fault was caused by a kernel PTE (such as installed by vmalloc or kmap)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kernel_pte_fault:
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Synchronize this task's top level page-table
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * with the 'reference' page table.
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Do _not_ use "tsk" here. We might be inside
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * an interrupt in the middle of a task switch..
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int index = pgd_index(ear0);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgd_t *pgd, *pgd_k;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pud_t *pud, *pud_k;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pmd_t *pmd, *pmd_k;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pte_t *pte_k;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgd = (pgd_t *) __get_TTBR();
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgd = (pgd_t *)__va(pgd) + index;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgd_k = ((pgd_t *)(init_mm.pgd)) + index;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!pgd_present(*pgd_k))
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto no_context;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//set_pgd(pgd, *pgd_k); /////// gcc ICE's on this line
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pud_k = pud_offset(pgd_k, ear0);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!pud_present(*pud_k))
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto no_context;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pmd_k = pmd_offset(pud_k, ear0);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!pmd_present(*pmd_k))
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto no_context;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pud = pud_offset(pgd, ear0);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pmd = pmd_offset(pud, ear0);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_pmd(pmd, *pmd_k);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pte_k = pte_offset_kernel(pmd_k, ear0);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!pte_present(*pte_k))
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto no_context;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end do_page_fault() */
328