1/* MN10300 MMU Fault handler 2 * 3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. 4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 5 * Modified by David Howells (dhowells@redhat.com) 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public Licence 9 * as published by the Free Software Foundation; either version 10 * 2 of the Licence, or (at your option) any later version. 11 */ 12 13#include <linux/signal.h> 14#include <linux/sched.h> 15#include <linux/kernel.h> 16#include <linux/errno.h> 17#include <linux/string.h> 18#include <linux/types.h> 19#include <linux/ptrace.h> 20#include <linux/mman.h> 21#include <linux/mm.h> 22#include <linux/smp.h> 23#include <linux/interrupt.h> 24#include <linux/init.h> 25#include <linux/vt_kern.h> /* For unblank_screen() */ 26 27#include <asm/system.h> 28#include <asm/uaccess.h> 29#include <asm/pgalloc.h> 30#include <asm/hardirq.h> 31#include <asm/gdb-stub.h> 32#include <asm/cpu-regs.h> 33 34/* 35 * Unlock any spinlocks which will prevent us from getting the 36 * message out 37 */ 38void bust_spinlocks(int yes) 39{ 40 if (yes) { 41 oops_in_progress = 1; 42#ifdef CONFIG_SMP 43 /* Many serial drivers do __global_cli() */ 44 global_irq_lock = 0; 45#endif 46 } else { 47 int loglevel_save = console_loglevel; 48#ifdef CONFIG_VT 49 unblank_screen(); 50#endif 51 oops_in_progress = 0; 52 /* 53 * OK, the message is on the console. Now we call printk() 54 * without oops_in_progress set so that printk will give klogd 55 * a poke. Hold onto your hats... 56 */ 57 console_loglevel = 15; /* NMI oopser may have shut the console 58 * up */ 59 printk(" "); 60 console_loglevel = loglevel_save; 61 } 62} 63 64void do_BUG(const char *file, int line) 65{ 66 bust_spinlocks(1); 67 printk(KERN_EMERG "------------[ cut here ]------------\n"); 68 printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); 69} 70 71 72asmlinkage void monitor_signal(struct pt_regs *); 73 74/* 75 * This routine handles page faults. It determines the address, 76 * and the problem, and then passes it off to one of the appropriate 77 * routines. 78 * 79 * fault_code: 80 * - LSW: either MMUFCR_IFC or MMUFCR_DFC as appropriate 81 * - MSW: 0 if data access, 1 if instruction access 82 * - bit 0: TLB miss flag 83 * - bit 1: initial write 84 * - bit 2: page invalid 85 * - bit 3: protection violation 86 * - bit 4: accessor (0=user 1=kernel) 87 * - bit 5: 0=read 1=write 88 * - bit 6-8: page protection spec 89 * - bit 9: illegal address 90 * - bit 16: 0=data 1=ins 91 * 92 */ 93asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code, 94 unsigned long address) 95{ 96 struct vm_area_struct *vma; 97 struct task_struct *tsk; 98 struct mm_struct *mm; 99 unsigned long page; 100 siginfo_t info; 101 int write, fault; 102 103#ifdef CONFIG_GDBSTUB 104 /* handle GDB stub causing a fault */ 105 if (gdbstub_busy) { 106 gdbstub_exception(regs, TBR & TBR_INT_CODE); 107 return; 108 } 109#endif 110 111 112 tsk = current; 113 114 /* 115 * We fault-in kernel-space virtual memory on-demand. The 116 * 'reference' page table is init_mm.pgd. 117 * 118 * NOTE! We MUST NOT take any locks for this case. We may 119 * be in an interrupt or a critical region, and should 120 * only copy the information from the master page table, 121 * nothing more. 122 * 123 * This verifies that the fault happens in kernel space 124 * and that the fault was a page not present (invalid) error 125 */ 126 if (address >= VMALLOC_START && address < VMALLOC_END && 127 (fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_SR && 128 (fault_code & MMUFCR_xFC_PGINVAL) == MMUFCR_xFC_PGINVAL 129 ) 130 goto vmalloc_fault; 131 132 mm = tsk->mm; 133 info.si_code = SEGV_MAPERR; 134 135 /* 136 * If we're in an interrupt or have no user 137 * context, we must not take the fault.. 138 */ 139 if (in_atomic() || !mm) 140 goto no_context; 141 142 down_read(&mm->mmap_sem); 143 144 vma = find_vma(mm, address); 145 if (!vma) 146 goto bad_area; 147 if (vma->vm_start <= address) 148 goto good_area; 149 if (!(vma->vm_flags & VM_GROWSDOWN)) 150 goto bad_area; 151 152 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) { 153 /* accessing the stack below the stack pointer is always a 154 * bug */ 155 if ((address & PAGE_MASK) + 2 * PAGE_SIZE < regs->sp) { 156 goto bad_area; 157 } 158 } 159 160 if (expand_stack(vma, address)) 161 goto bad_area; 162 163/* 164 * Ok, we have a good vm_area for this memory access, so 165 * we can handle it.. 166 */ 167good_area: 168 info.si_code = SEGV_ACCERR; 169 write = 0; 170 switch (fault_code & (MMUFCR_xFC_PGINVAL|MMUFCR_xFC_TYPE)) { 171 default: /* 3: write, present */ 172 case MMUFCR_xFC_TYPE_WRITE: 173#ifdef TEST_VERIFY_AREA 174 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_SR) 175 printk(KERN_DEBUG "WP fault at %08lx\n", regs->pc); 176#endif 177 /* write to absent page */ 178 case MMUFCR_xFC_PGINVAL | MMUFCR_xFC_TYPE_WRITE: 179 if (!(vma->vm_flags & VM_WRITE)) 180 goto bad_area; 181 write++; 182 break; 183 184 /* read from protected page */ 185 case MMUFCR_xFC_TYPE_READ: 186 goto bad_area; 187 188 /* read from absent page present */ 189 case MMUFCR_xFC_PGINVAL | MMUFCR_xFC_TYPE_READ: 190 if (!(vma->vm_flags & (VM_READ | VM_EXEC))) 191 goto bad_area; 192 break; 193 } 194 195 /* 196 * If for any reason at all we couldn't handle the fault, 197 * make sure we exit gracefully rather than endlessly redo 198 * the fault. 199 */ 200 fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); 201 if (unlikely(fault & VM_FAULT_ERROR)) { 202 if (fault & VM_FAULT_OOM) 203 goto out_of_memory; 204 else if (fault & VM_FAULT_SIGBUS) 205 goto do_sigbus; 206 BUG(); 207 } 208 if (fault & VM_FAULT_MAJOR) 209 current->maj_flt++; 210 else 211 current->min_flt++; 212 213 up_read(&mm->mmap_sem); 214 return; 215 216/* 217 * Something tried to access memory that isn't in our memory map.. 218 * Fix it, but check if it's kernel or user first.. 219 */ 220bad_area: 221 up_read(&mm->mmap_sem); 222 monitor_signal(regs); 223 224 /* User mode accesses just cause a SIGSEGV */ 225 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) { 226 info.si_signo = SIGSEGV; 227 info.si_errno = 0; 228 /* info.si_code has been set above */ 229 info.si_addr = (void *)address; 230 force_sig_info(SIGSEGV, &info, tsk); 231 return; 232 } 233 234no_context: 235 monitor_signal(regs); 236 /* Are we prepared to handle this kernel fault? */ 237 if (fixup_exception(regs)) 238 return; 239 240/* 241 * Oops. The kernel tried to access some bad page. We'll have to 242 * terminate things with extreme prejudice. 243 */ 244 245 bust_spinlocks(1); 246 247 if (address < PAGE_SIZE) 248 printk(KERN_ALERT 249 "Unable to handle kernel NULL pointer dereference"); 250 else 251 printk(KERN_ALERT 252 "Unable to handle kernel paging request"); 253 printk(" at virtual address %08lx\n", address); 254 printk(" printing pc:\n"); 255 printk(KERN_ALERT "%08lx\n", regs->pc); 256 257#ifdef CONFIG_GDBSTUB 258 gdbstub_intercept( 259 regs, fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR); 260#endif 261 262 page = PTBR; 263 page = ((unsigned long *) __va(page))[address >> 22]; 264 printk(KERN_ALERT "*pde = %08lx\n", page); 265 if (page & 1) { 266 page &= PAGE_MASK; 267 address &= 0x003ff000; 268 page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; 269 printk(KERN_ALERT "*pte = %08lx\n", page); 270 } 271 272 die("Oops", regs, fault_code); 273 do_exit(SIGKILL); 274 275/* 276 * We ran out of memory, or some other thing happened to us that made 277 * us unable to handle the page fault gracefully. 278 */ 279out_of_memory: 280 up_read(&mm->mmap_sem); 281 if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR) 282 goto no_context; 283 pagefault_out_of_memory(); 284 return; 285 286do_sigbus: 287 up_read(&mm->mmap_sem); 288 monitor_signal(regs); 289 290 /* 291 * Send a sigbus, regardless of whether we were in kernel 292 * or user mode. 293 */ 294 info.si_signo = SIGBUS; 295 info.si_errno = 0; 296 info.si_code = BUS_ADRERR; 297 info.si_addr = (void *)address; 298 force_sig_info(SIGBUS, &info, tsk); 299 300 /* Kernel mode? Handle exceptions or die */ 301 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_SR) 302 goto no_context; 303 return; 304 305vmalloc_fault: 306 { 307 /* 308 * Synchronize this task's top level page-table 309 * with the 'reference' page table. 310 * 311 * Do _not_ use "tsk" here. We might be inside 312 * an interrupt in the middle of a task switch.. 313 */ 314 int index = pgd_index(address); 315 pgd_t *pgd, *pgd_k; 316 pud_t *pud, *pud_k; 317 pmd_t *pmd, *pmd_k; 318 pte_t *pte_k; 319 320 pgd_k = init_mm.pgd + index; 321 322 if (!pgd_present(*pgd_k)) 323 goto no_context; 324 325 pud_k = pud_offset(pgd_k, address); 326 if (!pud_present(*pud_k)) 327 goto no_context; 328 329 pmd_k = pmd_offset(pud_k, address); 330 if (!pmd_present(*pmd_k)) 331 goto no_context; 332 333 pgd = (pgd_t *) PTBR + index; 334 pud = pud_offset(pgd, address); 335 pmd = pmd_offset(pud, address); 336 set_pmd(pmd, *pmd_k); 337 338 pte_k = pte_offset_kernel(pmd_k, address); 339 if (!pte_present(*pte_k)) 340 goto no_context; 341 return; 342 } 343} 344