/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- kill_curthread
- mips_trap
- mips_usermode
- enter_new_process
1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3 * The President and Fellows of Harvard College.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <types.h>
31 #include <signal.h>
32 #include <lib.h>
33 #include <mips/specialreg.h>
34 #include <mips/trapframe.h>
35 #include <cpu.h>
36 #include <spl.h>
37 #include <thread.h>
38 #include <current.h>
39 #include <vm.h>
40 #include <mainbus.h>
41 #include <syscall.h>
42
43
44 /* in exception.S */
45 extern void asm_usermode(struct trapframe *tf);
46
47 /* called only from assembler, so not declared in a header */
48 void mips_trap(struct trapframe *tf);
49
50
51 /* Names for trap codes */
52 #define NTRAPCODES 13
53 static const char *const trapcodenames[NTRAPCODES] = {
54 "Interrupt",
55 "TLB modify trap",
56 "TLB miss on load",
57 "TLB miss on store",
58 "Address error on load",
59 "Address error on store",
60 "Bus error on code",
61 "Bus error on data",
62 "System call",
63 "Break instruction",
64 "Illegal instruction",
65 "Coprocessor unusable",
66 "Arithmetic overflow",
67 };
68
69 /*
70 * Function called when user-level code hits a fatal fault.
71 */
72 static
73 void
74 kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
75 {
76 int sig = 0;
77
78 KASSERT(code < NTRAPCODES);
79 switch (code) {
80 case EX_IRQ:
81 case EX_IBE:
82 case EX_DBE:
83 case EX_SYS:
84 /* should not be seen */
85 KASSERT(0);
86 sig = SIGABRT;
87 break;
88 case EX_MOD:
89 case EX_TLBL:
90 case EX_TLBS:
91 sig = SIGSEGV;
92 break;
93 case EX_ADEL:
94 case EX_ADES:
95 sig = SIGBUS;
96 break;
97 case EX_BP:
98 sig = SIGTRAP;
99 break;
100 case EX_RI:
101 sig = SIGILL;
102 break;
103 case EX_CPU:
104 sig = SIGSEGV;
105 break;
106 case EX_OVF:
107 sig = SIGFPE;
108 break;
109 }
110
111 /*
112 * You will probably want to change this.
113 */
114
115 kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",
116 code, sig, trapcodenames[code], epc, vaddr);
117 panic("I don't know how to handle this\n");
118 }
119
120 /*
121 * General trap (exception) handling function for mips.
122 * This is called by the assembly-language exception handler once
123 * the trapframe has been set up.
124 */
125 void
126 mips_trap(struct trapframe *tf)
127 {
128 uint32_t code;
129 bool isutlb, iskern;
130 int spl;
131
132 /* The trap frame is supposed to be 37 registers long. */
133 KASSERT(sizeof(struct trapframe)==(37*4));
134
135 /*
136 * Extract the exception code info from the register fields.
137 */
138 code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
139 isutlb = (tf->tf_cause & CCA_UTLB) != 0;
140 iskern = (tf->tf_status & CST_KUp) == 0;
141
142 KASSERT(code < NTRAPCODES);
143
144 /* Make sure we haven't run off our stack */
145 if (curthread != NULL && curthread->t_stack != NULL) {
146 KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
147 KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack
148 + STACK_SIZE));
149 }
150
151 /* Interrupt? Call the interrupt handler and return. */
152 if (code == EX_IRQ) {
153 int old_in;
154 bool doadjust;
155
156 old_in = curthread->t_in_interrupt;
157 curthread->t_in_interrupt = 1;
158
159 /*
160 * The processor has turned interrupts off; if the
161 * currently recorded interrupt state is interrupts on
162 * (spl of 0), adjust the recorded state to match, and
163 * restore after processing the interrupt.
164 *
165 * How can we get an interrupt if the recorded state
166 * is interrupts off? Well, as things currently stand
167 * when the CPU finishes idling it flips interrupts on
168 * and off to allow things to happen, but leaves
169 * curspl high while doing so.
170 *
171 * While we're here, assert that the interrupt
172 * handling code hasn't leaked a spinlock or an
173 * splhigh().
174 */
175
176 if (curthread->t_curspl == 0) {
177 KASSERT(curthread->t_curspl == 0);
178 KASSERT(curthread->t_iplhigh_count == 0);
179 curthread->t_curspl = IPL_HIGH;
180 curthread->t_iplhigh_count++;
181 doadjust = true;
182 }
183 else {
184 doadjust = false;
185 }
186
187 mainbus_interrupt(tf);
188
189 if (doadjust) {
190 KASSERT(curthread->t_curspl == IPL_HIGH);
191 KASSERT(curthread->t_iplhigh_count == 1);
192 curthread->t_iplhigh_count--;
193 curthread->t_curspl = 0;
194 }
195
196 curthread->t_in_interrupt = old_in;
197 goto done2;
198 }
199
200 /*
201 * The processor turned interrupts off when it took the trap.
202 *
203 * While we're in the kernel, and not actually handling an
204 * interrupt, restore the interrupt state to where it was in
205 * the previous context, which may be low (interrupts on).
206 *
207 * Do this by forcing splhigh(), which may do a redundant
208 * cpu_irqoff() but forces the stored MI interrupt state into
209 * sync, then restoring the previous state.
210 */
211 spl = splhigh();
212 splx(spl);
213
214 /* Syscall? Call the syscall handler and return. */
215 if (code == EX_SYS) {
216 /* Interrupts should have been on while in user mode. */
217 KASSERT(curthread->t_curspl == 0);
218 KASSERT(curthread->t_iplhigh_count == 0);
219
220 DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n",
221 tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);
222
223 syscall(tf);
224 goto done;
225 }
226
227 /*
228 * Ok, it wasn't any of the really easy cases.
229 * Call vm_fault on the TLB exceptions.
230 * Panic on the bus error exceptions.
231 */
232 switch (code) {
233 case EX_MOD:
234 if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {
235 goto done;
236 }
237 break;
238 case EX_TLBL:
239 if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {
240 goto done;
241 }
242 break;
243 case EX_TLBS:
244 if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {
245 goto done;
246 }
247 break;
248 case EX_IBE:
249 case EX_DBE:
250 /*
251 * This means you loaded invalid TLB entries, or
252 * touched invalid parts of the direct-mapped
253 * segments. These are serious kernel errors, so
254 * panic.
255 *
256 * The MIPS won't even tell you what invalid address
257 * caused the bus error.
258 */
259 panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
260 break;
261 }
262
263 /*
264 * If we get to this point, it's a fatal fault - either it's
265 * one of the other exceptions, like illegal instruction, or
266 * it was a page fault we couldn't handle.
267 */
268
269 if (!iskern) {
270 /*
271 * Fatal fault in user mode.
272 * Kill the current user process.
273 */
274 kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
275 goto done;
276 }
277
278 /*
279 * Fatal fault in kernel mode.
280 *
281 * If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
282 * set by copyin/copyout and related functions to signify that
283 * the addresses they're accessing are userlevel-supplied and
284 * not trustable. What we actually want to do is resume
285 * execution at the function pointed to by badfaultfunc. That's
286 * going to be "copyfail" (see copyinout.c), which longjmps
287 * back to copyin/copyout or wherever and returns EFAULT.
288 *
289 * Note that we do not just *call* this function, because that
290 * won't necessarily do anything. We want the control flow
291 * that is currently executing in copyin (or whichever), and
292 * is stopped while we process the exception, to *teleport* to
293 * copyfail.
294 *
295 * This is accomplished by changing tf->tf_epc and returning
296 * from the exception handler.
297 */
298
299 if (curthread != NULL &&
300 curthread->t_machdep.tm_badfaultfunc != NULL) {
301 tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;
302 goto done;
303 }
304
305 /*
306 * Really fatal kernel-mode fault.
307 */
308
309 kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
310 trapcodenames[code]);
311 kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n",
312 tf->tf_epc, tf->tf_vaddr);
313
314 panic("I can't handle this... I think I'll just die now...\n");
315
316 done:
317 /*
318 * Turn interrupts off on the processor, without affecting the
319 * stored interrupt state.
320 */
321 cpu_irqoff();
322 done2:
323
324 /*
325 * The boot thread can get here (e.g. on interrupt return) but
326 * since it doesn't go to userlevel, it can't be returning to
327 * userlevel, so there's no need to set cputhreads[] and
328 * cpustacks[]. Just return.
329 */
330 if (curthread->t_stack == NULL) {
331 return;
332 }
333
334 cputhreads[curcpu->c_number] = (vaddr_t)curthread;
335 cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
336
337 /*
338 * This assertion will fail if either
339 * (1) curthread->t_stack is corrupted, or
340 * (2) the trap frame is somehow on the wrong kernel stack.
341 *
342 * If cpustacks[] is corrupted, the next trap back to the
343 * kernel will (most likely) hang the system, so it's better
344 * to find out now.
345 */
346 KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
347 }
348
349 /*
350 * Function for entering user mode.
351 *
352 * This should not be used by threads returning from traps - they
353 * should just return from mips_trap(). It should be used by threads
354 * entering user mode for the first time - whether the child thread in
355 * a fork(), or into a brand-new address space after exec(), or when
356 * starting the first userlevel program.
357 *
358 * It works by jumping into the exception return code.
359 *
360 * mips_usermode is common code for this. It cannot usefully be called
361 * outside the mips port, but should be called from one of the
362 * following places:
363 * - enter_new_process, for use by exec and equivalent.
364 * - enter_forked_process, in syscall.c, for use by fork.
365 */
366 void
367 mips_usermode(struct trapframe *tf)
368 {
369
370 /*
371 * Interrupts should be off within the kernel while entering
372 * user mode. However, while in user mode, interrupts should
373 * be on. To interact properly with the spl-handling logic
374 * above, we explicitly call spl0() and then call cpu_irqoff().
375 */
376 spl0();
377 cpu_irqoff();
378
379 cputhreads[curcpu->c_number] = (vaddr_t)curthread;
380 cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
381
382 /*
383 * This assertion will fail if either
384 * (1) cpustacks[] is corrupted, or
385 * (2) the trap frame is not on our own kernel stack, or
386 * (3) the boot thread tries to enter user mode.
387 *
388 * If cpustacks[] is corrupted, the next trap back to the
389 * kernel will (most likely) hang the system, so it's better
390 * to find out now.
391 *
392 * It's necessary for the trap frame used here to be on the
393 * current thread's own stack. It cannot correctly be on
394 * either another thread's stack or in the kernel heap.
395 * (Exercise: why?)
396 */
397 KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
398
399 /*
400 * This actually does it. See exception.S.
401 */
402 asm_usermode(tf);
403 }
404
405 /*
406 * enter_new_process: go to user mode after loading an executable.
407 *
408 * Performs the necessary initialization so that the user program will
409 * get the arguments supplied in argc/argv (note that argv must be a
410 * user-level address), and begin executing at the specified entry
411 * point. The stack pointer is initialized from the stackptr
412 * argument. Note that passing argc/argv may use additional stack
413 * space on some other platforms (but not on mips).
414 *
415 * Works by creating an ersatz trapframe.
416 */
417 void
418 enter_new_process(int argc, userptr_t argv, vaddr_t stack, vaddr_t entry)
419 {
420 struct trapframe tf;
421
422 bzero(&tf, sizeof(tf));
423
424 tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
425 tf.tf_epc = entry;
426 tf.tf_a0 = argc;
427 tf.tf_a1 = (vaddr_t)argv;
428 tf.tf_sp = stack;
429
430 mips_usermode(&tf);
431 }