1 // TODO VM_EXEC flag work-around, cache aliasing 2 /* 3 * arch/xtensa/mm/fault.c 4 * 5 * This file is subject to the terms and conditions of the GNU General Public 6 * License. See the file "COPYING" in the main directory of this archive 7 * for more details. 8 * 9 * Copyright (C) 2001 - 2005 Tensilica Inc. 10 * 11 * Chris Zankel <chris@zankel.net> 12 * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> 13 */ 14 15 #include <linux/mm.h> 16 #include <linux/module.h> 17 #include <asm/mmu_context.h> 18 #include <asm/cacheflush.h> 19 #include <asm/hardirq.h> 20 #include <asm/uaccess.h> 21 #include <asm/system.h> 22 #include <asm/pgalloc.h> 23 24 unsigned long asid_cache = ASID_USER_FIRST; 25 void bad_page_fault(struct pt_regs*, unsigned long, int); 26 27 /* 28 * This routine handles page faults. It determines the address, 29 * and the problem, and then passes it off to one of the appropriate 30 * routines. 31 * 32 * Note: does not handle Miss and MultiHit. 33 */ 34 35 void do_page_fault(struct pt_regs *regs) 36 { 37 struct vm_area_struct * vma; 38 struct mm_struct *mm = current->mm; 39 unsigned int exccause = regs->exccause; 40 unsigned int address = regs->excvaddr; 41 siginfo_t info; 42 43 int is_write, is_exec; 44 45 info.si_code = SEGV_MAPERR; 46 47 /* We fault-in kernel-space virtual memory on-demand. The 48 * 'reference' page table is init_mm.pgd. 49 */ 50 if (address >= TASK_SIZE && !user_mode(regs)) 51 goto vmalloc_fault; 52 53 /* If we're in an interrupt or have no user 54 * context, we must not take the fault.. 55 */ 56 if (in_atomic() || !mm) { 57 bad_page_fault(regs, address, SIGSEGV); 58 return; 59 } 60 61 is_write = (exccause == EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0; 62 is_exec = (exccause == EXCCAUSE_ITLB_PRIVILEGE || 63 exccause == EXCCAUSE_ITLB_MISS || 64 exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0; 65 66 #if 0 67 printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid, 68 address, exccause, regs->pc, is_write? "w":"", is_exec? "x":""); 69 #endif 70 71 down_read(&mm->mmap_sem); 72 vma = find_vma(mm, address); 73 74 if (!vma) 75 goto bad_area; 76 if (vma->vm_start <= address) 77 goto good_area; 78 if (!(vma->vm_flags & VM_GROWSDOWN)) 79 goto bad_area; 80 if (expand_stack(vma, address)) 81 goto bad_area; 82 83 /* Ok, we have a good vm_area for this memory access, so 84 * we can handle it.. 85 */ 86 87 good_area: 88 info.si_code = SEGV_ACCERR; 89 90 if (is_write) { 91 if (!(vma->vm_flags & VM_WRITE)) 92 goto bad_area; 93 } else if (is_exec) { 94 if (!(vma->vm_flags & VM_EXEC)) 95 goto bad_area; 96 } else /* Allow read even from write-only pages. */ 97 if (!(vma->vm_flags & (VM_READ | VM_WRITE))) 98 goto bad_area; 99 100 /* If for any reason at all we couldn't handle the fault, 101 * make sure we exit gracefully rather than endlessly redo 102 * the fault. 103 */ 104 survive: 105 switch (handle_mm_fault(mm, vma, address, is_write)) { 106 case VM_FAULT_MINOR: 107 current->min_flt++; 108 break; 109 case VM_FAULT_MAJOR: 110 current->maj_flt++; 111 break; 112 case VM_FAULT_SIGBUS: 113 goto do_sigbus; 114 case VM_FAULT_OOM: 115 goto out_of_memory; 116 default: 117 BUG(); 118 } 119 120 up_read(&mm->mmap_sem); 121 return; 122 123 /* Something tried to access memory that isn't in our memory map.. 124 * Fix it, but check if it's kernel or user first.. 125 */ 126 bad_area: 127 up_read(&mm->mmap_sem); 128 if (user_mode(regs)) { 129 current->thread.bad_vaddr = address; 130 current->thread.error_code = is_write; 131 info.si_signo = SIGSEGV; 132 info.si_errno = 0; 133 /* info.si_code has been set above */ 134 info.si_addr = (void *) address; 135 force_sig_info(SIGSEGV, &info, current); 136 return; 137 } 138 bad_page_fault(regs, address, SIGSEGV); 139 return; 140 141 142 /* We ran out of memory, or some other thing happened to us that made 143 * us unable to handle the page fault gracefully. 144 */ 145 out_of_memory: 146 up_read(&mm->mmap_sem); 147 if (is_init(current)) { 148 yield(); 149 down_read(&mm->mmap_sem); 150 goto survive; 151 } 152 printk("VM: killing process %s\n", current->comm); 153 if (user_mode(regs)) 154 do_exit(SIGKILL); 155 bad_page_fault(regs, address, SIGKILL); 156 return; 157 158 do_sigbus: 159 up_read(&mm->mmap_sem); 160 161 /* Send a sigbus, regardless of whether we were in kernel 162 * or user mode. 163 */ 164 current->thread.bad_vaddr = address; 165 info.si_code = SIGBUS; 166 info.si_errno = 0; 167 info.si_code = BUS_ADRERR; 168 info.si_addr = (void *) address; 169 force_sig_info(SIGBUS, &info, current); 170 171 /* Kernel mode? Handle exceptions or die */ 172 if (!user_mode(regs)) 173 bad_page_fault(regs, address, SIGBUS); 174 175 vmalloc_fault: 176 { 177 /* Synchronize this task's top level page-table 178 * with the 'reference' page table. 179 */ 180 struct mm_struct *act_mm = current->active_mm; 181 int index = pgd_index(address); 182 pgd_t *pgd, *pgd_k; 183 pmd_t *pmd, *pmd_k; 184 pte_t *pte_k; 185 186 if (act_mm == NULL) 187 goto bad_page_fault; 188 189 pgd = act_mm->pgd + index; 190 pgd_k = init_mm.pgd + index; 191 192 if (!pgd_present(*pgd_k)) 193 goto bad_page_fault; 194 195 pgd_val(*pgd) = pgd_val(*pgd_k); 196 197 pmd = pmd_offset(pgd, address); 198 pmd_k = pmd_offset(pgd_k, address); 199 if (!pmd_present(*pmd) || !pmd_present(*pmd_k)) 200 goto bad_page_fault; 201 202 pmd_val(*pmd) = pmd_val(*pmd_k); 203 pte_k = pte_offset_kernel(pmd_k, address); 204 205 if (!pte_present(*pte_k)) 206 goto bad_page_fault; 207 return; 208 } 209 bad_page_fault: 210 bad_page_fault(regs, address, SIGKILL); 211 return; 212 } 213 214 215 void 216 bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) 217 { 218 extern void die(const char*, struct pt_regs*, long); 219 const struct exception_table_entry *entry; 220 221 /* Are we prepared to handle this kernel fault? */ 222 if ((entry = search_exception_tables(regs->pc)) != NULL) { 223 #if 1 224 printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n", 225 current->comm, regs->pc, entry->fixup); 226 #endif 227 current->thread.bad_uaddr = address; 228 regs->pc = entry->fixup; 229 return; 230 } 231 232 /* Oops. The kernel tried to access some bad page. We'll have to 233 * terminate things with extreme prejudice. 234 */ 235 printk(KERN_ALERT "Unable to handle kernel paging request at virtual " 236 "address %08lx\n pc = %08lx, ra = %08lx\n", 237 address, regs->pc, regs->areg[0]); 238 die("Oops", regs, sig); 239 do_exit(sig); 240 } 241 242