1 /* This file contains a simple exception handler. Exceptions in user 2 * processes are converted to signals. Exceptions in a kernel task cause 3 * a panic. 4 */ 5 6 #include "kernel/kernel.h" 7 #include "arch_proto.h" 8 #include <signal.h> 9 #include <string.h> 10 #include <assert.h> 11 #include "kernel/proc.h" 12 #include "kernel/proto.h" 13 #include <machine/vm.h> 14 15 struct ex_s { 16 char *msg; 17 int signum; 18 }; 19 20 static struct ex_s ex_data[] = { 21 { "Reset", 0}, 22 { "Undefined instruction", SIGILL}, 23 { "Supervisor call", 0}, 24 { "Prefetch Abort", SIGILL}, 25 { "Data Abort", SIGSEGV}, 26 { "Hypervisor call", 0}, 27 { "Interrupt", 0}, 28 { "Fast Interrupt", 0}, 29 }; 30 31 static void inkernel_disaster(struct proc *saved_proc, 32 reg_t *saved_lr, struct ex_s *ep, int is_nested); 33 34 extern int catch_pagefaults; 35 36 static void proc_stacktrace_execute(struct proc *whichproc, reg_t v_bp, reg_t pc); 37 38 static void pagefault( struct proc *pr, 39 reg_t *saved_lr, 40 int is_nested, 41 u32_t pagefault_addr, 42 u32_t pagefault_status) 43 { 44 int in_physcopy = 0, in_memset = 0; 45 46 message m_pagefault; 47 int err; 48 49 in_physcopy = (*saved_lr > (vir_bytes) phys_copy) && 50 (*saved_lr < (vir_bytes) phys_copy_fault); 51 52 in_memset = (*saved_lr > (vir_bytes) phys_memset) && 53 (*saved_lr < (vir_bytes) memset_fault); 54 55 if((is_nested || iskernelp(pr)) && 56 catch_pagefaults && (in_physcopy || in_memset)) { 57 if (is_nested) { 58 if(in_physcopy) { 59 assert(!in_memset); 60 *saved_lr = (reg_t) phys_copy_fault_in_kernel; 61 } else { 62 *saved_lr = (reg_t) memset_fault_in_kernel; 63 } 64 } 65 else { 66 pr->p_reg.pc = (reg_t) phys_copy_fault; 67 pr->p_reg.retreg = pagefault_addr; 68 } 69 70 return; 71 } 72 73 if(is_nested) { 74 printf("pagefault in kernel at pc 0x%lx address 0x%lx\n", 75 *saved_lr, pagefault_addr); 76 inkernel_disaster(pr, saved_lr, NULL, is_nested); 77 } 78 79 /* VM can't handle page faults. */ 80 if(pr->p_endpoint == VM_PROC_NR) { 81 /* Page fault we can't / don't want to 82 * handle. 83 */ 84 printf("pagefault for VM on CPU %d, " 85 "pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n", 86 cpuid, pr->p_reg.pc, pagefault_addr, pagefault_status, 87 is_nested); 88 proc_stacktrace(pr); 89 printf("pc of pagefault: 0x%lx\n", pr->p_reg.pc); 90 panic("pagefault in VM"); 91 92 return; 93 } 94 95 /* Don't schedule this process until pagefault is handled. */ 96 RTS_SET(pr, RTS_PAGEFAULT); 97 98 /* tell Vm about the pagefault */ 99 m_pagefault.m_source = pr->p_endpoint; 100 m_pagefault.m_type = VM_PAGEFAULT; 101 m_pagefault.VPF_ADDR = pagefault_addr; 102 m_pagefault.VPF_FLAGS = pagefault_status; 103 104 if ((err = mini_send(pr, VM_PROC_NR, 105 &m_pagefault, FROM_KERNEL))) { 106 panic("WARNING: pagefault: mini_send returned %d\n", err); 107 } 108 109 return; 110 } 111 112 static void inkernel_disaster(struct proc *saved_proc, 113 reg_t *saved_lr, struct ex_s *ep, 114 int is_nested) 115 { 116 #if USE_SYSDEBUG 117 if(ep) 118 printf("\n%s\n", ep->msg); 119 120 printf("cpu %d is_nested = %d ", cpuid, is_nested); 121 122 if (saved_proc) { 123 printf("scheduled was: process %d (%s), ", saved_proc->p_endpoint, saved_proc->p_name); 124 printf("pc = 0x%x\n", (unsigned) saved_proc->p_reg.pc); 125 proc_stacktrace(saved_proc); 126 127 panic("Unhandled kernel exception"); 128 } 129 130 /* in an early stage of boot process we don't have processes yet */ 131 panic("exception in kernel while booting, no saved_proc yet"); 132 133 #endif /* USE_SYSDEBUG */ 134 } 135 136 void exception_handler(int is_nested, reg_t *saved_lr, int vector) 137 { 138 /* An exception or unexpected interrupt has occurred. */ 139 struct ex_s *ep; 140 struct proc *saved_proc; 141 142 saved_proc = get_cpulocal_var(proc_ptr); 143 144 ep = &ex_data[vector]; 145 146 assert((vir_bytes) saved_lr >= kinfo.vir_kern_start); 147 148 /* 149 * handle special cases for nested problems as they might be tricky or filter 150 * them out quickly if the traps are not nested 151 */ 152 if (is_nested) { 153 /* 154 * if a problem occurred while copying a message from userspace because 155 * of a wrong pointer supplied by userland, handle it the only way we 156 * can handle it ... 157 */ 158 if (((void*)*saved_lr >= (void*)copy_msg_to_user && 159 (void*)*saved_lr <= (void*)__copy_msg_to_user_end) || 160 ((void*)*saved_lr >= (void*)copy_msg_from_user && 161 (void*)*saved_lr <= (void*)__copy_msg_from_user_end)) { 162 switch(vector) { 163 /* these error are expected */ 164 case DATA_ABORT_VECTOR: 165 *saved_lr = (reg_t) __user_copy_msg_pointer_failure; 166 return; 167 default: 168 panic("Copy involving a user pointer failed unexpectedly!"); 169 } 170 } 171 } 172 173 if (vector == DATA_ABORT_VECTOR) { 174 pagefault(saved_proc, saved_lr, is_nested, read_dfar(), read_dfsr()); 175 return; 176 } 177 178 if (!is_nested && vector == PREFETCH_ABORT_VECTOR) { 179 reg_t ifar = read_ifar(), ifsr = read_ifsr(); 180 181 /* The saved_lr is the instruction we're going to execute after 182 * the fault is handled; IFAR is the address that pagefaulted 183 * while fetching the instruction. As far as we know the two 184 * should be the same, if not this assumption will lead to very 185 * hard to debug problems (instruction executing being off by one) 186 * and this assumption needs re-examining, hence the assert. 187 */ 188 assert(*saved_lr == ifar); 189 pagefault(saved_proc, saved_lr, is_nested, ifar, ifsr); 190 return; 191 } 192 193 /* If an exception occurs while running a process, the is_nested variable 194 * will be zero. Exceptions in interrupt handlers or system traps will make 195 * is_nested non-zero. 196 */ 197 if (is_nested == 0 && ! iskernelp(saved_proc)) { 198 cause_sig(proc_nr(saved_proc), ep->signum); 199 return; 200 } 201 202 /* Exception in system code. This is not supposed to happen. */ 203 inkernel_disaster(saved_proc, saved_lr, ep, is_nested); 204 205 panic("return from inkernel_disaster"); 206 } 207 208 #if USE_SYSDEBUG 209 /*===========================================================================* 210 * proc_stacktrace_execute * 211 *===========================================================================*/ 212 static void proc_stacktrace_execute(struct proc *whichproc, reg_t v_bp, reg_t pc) 213 { 214 printf("%-8.8s %6d 0x%lx \n", 215 whichproc->p_name, whichproc->p_endpoint, pc); 216 } 217 #endif 218 219 void proc_stacktrace(struct proc *whichproc) 220 { 221 #if USE_SYSDEBUG 222 proc_stacktrace_execute(whichproc, whichproc->p_reg.fp, whichproc->p_reg.pc); 223 #endif /* USE_SYSDEBUG */ 224 } 225 226 void enable_fpu_exception(void) 227 { 228 } 229 230 void disable_fpu_exception(void) 231 { 232 } 233