clang-format
This commit is contained in:
@@ -40,81 +40,68 @@
|
||||
#include <mainbus.h>
|
||||
#include <syscall.h>
|
||||
|
||||
|
||||
/* in exception-*.S */
|
||||
extern __DEAD void asm_usermode(struct trapframe *tf);
|
||||
|
||||
/* called only from assembler, so not declared in a header */
|
||||
void mips_trap(struct trapframe *tf);
|
||||
|
||||
|
||||
/* Names for trap codes */
|
||||
#define NTRAPCODES 13
|
||||
static const char *const trapcodenames[NTRAPCODES] = {
|
||||
"Interrupt",
|
||||
"TLB modify trap",
|
||||
"TLB miss on load",
|
||||
"TLB miss on store",
|
||||
"Address error on load",
|
||||
"Address error on store",
|
||||
"Bus error on code",
|
||||
"Bus error on data",
|
||||
"System call",
|
||||
"Break instruction",
|
||||
"Illegal instruction",
|
||||
"Coprocessor unusable",
|
||||
"Arithmetic overflow",
|
||||
"Interrupt", "TLB modify trap", "TLB miss on load",
|
||||
"TLB miss on store", "Address error on load", "Address error on store",
|
||||
"Bus error on code", "Bus error on data", "System call",
|
||||
"Break instruction", "Illegal instruction", "Coprocessor unusable",
|
||||
"Arithmetic overflow",
|
||||
};
|
||||
|
||||
/*
|
||||
* Function called when user-level code hits a fatal fault.
|
||||
*/
|
||||
static
|
||||
void
|
||||
kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
|
||||
{
|
||||
int sig = 0;
|
||||
static void kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr) {
|
||||
int sig = 0;
|
||||
|
||||
KASSERT(code < NTRAPCODES);
|
||||
switch (code) {
|
||||
case EX_IRQ:
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
case EX_SYS:
|
||||
/* should not be seen */
|
||||
KASSERT(0);
|
||||
sig = SIGABRT;
|
||||
break;
|
||||
case EX_MOD:
|
||||
case EX_TLBL:
|
||||
case EX_TLBS:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_ADEL:
|
||||
case EX_ADES:
|
||||
sig = SIGBUS;
|
||||
break;
|
||||
case EX_BP:
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
case EX_RI:
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case EX_CPU:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_OVF:
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
}
|
||||
KASSERT(code < NTRAPCODES);
|
||||
switch (code) {
|
||||
case EX_IRQ:
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
case EX_SYS:
|
||||
/* should not be seen */
|
||||
KASSERT(0);
|
||||
sig = SIGABRT;
|
||||
break;
|
||||
case EX_MOD:
|
||||
case EX_TLBL:
|
||||
case EX_TLBS:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_ADEL:
|
||||
case EX_ADES:
|
||||
sig = SIGBUS;
|
||||
break;
|
||||
case EX_BP:
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
case EX_RI:
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case EX_CPU:
|
||||
sig = SIGSEGV;
|
||||
break;
|
||||
case EX_OVF:
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* You will probably want to change this.
|
||||
*/
|
||||
/*
|
||||
* You will probably want to change this.
|
||||
*/
|
||||
|
||||
kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",
|
||||
code, sig, trapcodenames[code], epc, vaddr);
|
||||
panic("I don't know how to handle this\n");
|
||||
kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n", code,
|
||||
sig, trapcodenames[code], epc, vaddr);
|
||||
panic("I don't know how to handle this\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -122,229 +109,223 @@ kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
|
||||
* This is called by the assembly-language exception handler once
|
||||
* the trapframe has been set up.
|
||||
*/
|
||||
void
|
||||
mips_trap(struct trapframe *tf)
|
||||
{
|
||||
uint32_t code;
|
||||
/*bool isutlb; -- not used */
|
||||
bool iskern;
|
||||
int spl;
|
||||
void mips_trap(struct trapframe *tf) {
|
||||
uint32_t code;
|
||||
/*bool isutlb; -- not used */
|
||||
bool iskern;
|
||||
int spl;
|
||||
|
||||
/* The trap frame is supposed to be 35 registers long. */
|
||||
KASSERT(sizeof(struct trapframe)==(35*4));
|
||||
/* The trap frame is supposed to be 35 registers long. */
|
||||
KASSERT(sizeof(struct trapframe) == (35 * 4));
|
||||
|
||||
/*
|
||||
* Extract the exception code info from the register fields.
|
||||
*/
|
||||
code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
|
||||
/*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/
|
||||
iskern = (tf->tf_status & CST_KUp) == 0;
|
||||
/*
|
||||
* Extract the exception code info from the register fields.
|
||||
*/
|
||||
code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
|
||||
/*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/
|
||||
iskern = (tf->tf_status & CST_KUp) == 0;
|
||||
|
||||
KASSERT(code < NTRAPCODES);
|
||||
KASSERT(code < NTRAPCODES);
|
||||
|
||||
/* Make sure we haven't run off our stack */
|
||||
if (curthread != NULL && curthread->t_stack != NULL) {
|
||||
KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
|
||||
KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack
|
||||
+ STACK_SIZE));
|
||||
}
|
||||
/* Make sure we haven't run off our stack */
|
||||
if (curthread != NULL && curthread->t_stack != NULL) {
|
||||
KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
|
||||
KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack + STACK_SIZE));
|
||||
}
|
||||
|
||||
/* Interrupt? Call the interrupt handler and return. */
|
||||
if (code == EX_IRQ) {
|
||||
int old_in;
|
||||
bool doadjust;
|
||||
/* Interrupt? Call the interrupt handler and return. */
|
||||
if (code == EX_IRQ) {
|
||||
int old_in;
|
||||
bool doadjust;
|
||||
|
||||
old_in = curthread->t_in_interrupt;
|
||||
curthread->t_in_interrupt = 1;
|
||||
old_in = curthread->t_in_interrupt;
|
||||
curthread->t_in_interrupt = 1;
|
||||
|
||||
/*
|
||||
* The processor has turned interrupts off; if the
|
||||
* currently recorded interrupt state is interrupts on
|
||||
* (spl of 0), adjust the recorded state to match, and
|
||||
* restore after processing the interrupt.
|
||||
*
|
||||
* How can we get an interrupt if the recorded state
|
||||
* is interrupts off? Well, as things currently stand
|
||||
* when the CPU finishes idling it flips interrupts on
|
||||
* and off to allow things to happen, but leaves
|
||||
* curspl high while doing so.
|
||||
*
|
||||
* While we're here, assert that the interrupt
|
||||
* handling code hasn't leaked a spinlock or an
|
||||
* splhigh().
|
||||
*/
|
||||
/*
|
||||
* The processor has turned interrupts off; if the
|
||||
* currently recorded interrupt state is interrupts on
|
||||
* (spl of 0), adjust the recorded state to match, and
|
||||
* restore after processing the interrupt.
|
||||
*
|
||||
* How can we get an interrupt if the recorded state
|
||||
* is interrupts off? Well, as things currently stand
|
||||
* when the CPU finishes idling it flips interrupts on
|
||||
* and off to allow things to happen, but leaves
|
||||
* curspl high while doing so.
|
||||
*
|
||||
* While we're here, assert that the interrupt
|
||||
* handling code hasn't leaked a spinlock or an
|
||||
* splhigh().
|
||||
*/
|
||||
|
||||
if (curthread->t_curspl == 0) {
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
curthread->t_curspl = IPL_HIGH;
|
||||
curthread->t_iplhigh_count++;
|
||||
doadjust = true;
|
||||
}
|
||||
else {
|
||||
doadjust = false;
|
||||
}
|
||||
if (curthread->t_curspl == 0) {
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
curthread->t_curspl = IPL_HIGH;
|
||||
curthread->t_iplhigh_count++;
|
||||
doadjust = true;
|
||||
} else {
|
||||
doadjust = false;
|
||||
}
|
||||
|
||||
mainbus_interrupt(tf);
|
||||
mainbus_interrupt(tf);
|
||||
|
||||
if (doadjust) {
|
||||
KASSERT(curthread->t_curspl == IPL_HIGH);
|
||||
KASSERT(curthread->t_iplhigh_count == 1);
|
||||
curthread->t_iplhigh_count--;
|
||||
curthread->t_curspl = 0;
|
||||
}
|
||||
if (doadjust) {
|
||||
KASSERT(curthread->t_curspl == IPL_HIGH);
|
||||
KASSERT(curthread->t_iplhigh_count == 1);
|
||||
curthread->t_iplhigh_count--;
|
||||
curthread->t_curspl = 0;
|
||||
}
|
||||
|
||||
curthread->t_in_interrupt = old_in;
|
||||
goto done2;
|
||||
}
|
||||
curthread->t_in_interrupt = old_in;
|
||||
goto done2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The processor turned interrupts off when it took the trap.
|
||||
*
|
||||
* While we're in the kernel, and not actually handling an
|
||||
* interrupt, restore the interrupt state to where it was in
|
||||
* the previous context, which may be low (interrupts on).
|
||||
*
|
||||
* Do this by forcing splhigh(), which may do a redundant
|
||||
* cpu_irqoff() but forces the stored MI interrupt state into
|
||||
* sync, then restoring the previous state.
|
||||
*/
|
||||
spl = splhigh();
|
||||
splx(spl);
|
||||
/*
|
||||
* The processor turned interrupts off when it took the trap.
|
||||
*
|
||||
* While we're in the kernel, and not actually handling an
|
||||
* interrupt, restore the interrupt state to where it was in
|
||||
* the previous context, which may be low (interrupts on).
|
||||
*
|
||||
* Do this by forcing splhigh(), which may do a redundant
|
||||
* cpu_irqoff() but forces the stored MI interrupt state into
|
||||
* sync, then restoring the previous state.
|
||||
*/
|
||||
spl = splhigh();
|
||||
splx(spl);
|
||||
|
||||
/* Syscall? Call the syscall handler and return. */
|
||||
if (code == EX_SYS) {
|
||||
/* Interrupts should have been on while in user mode. */
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
/* Syscall? Call the syscall handler and return. */
|
||||
if (code == EX_SYS) {
|
||||
/* Interrupts should have been on while in user mode. */
|
||||
KASSERT(curthread->t_curspl == 0);
|
||||
KASSERT(curthread->t_iplhigh_count == 0);
|
||||
|
||||
DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n",
|
||||
tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);
|
||||
DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n", tf->tf_v0, tf->tf_a0,
|
||||
tf->tf_a1, tf->tf_a2, tf->tf_a3);
|
||||
|
||||
syscall(tf);
|
||||
goto done;
|
||||
}
|
||||
syscall(tf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, it wasn't any of the really easy cases.
|
||||
* Call vm_fault on the TLB exceptions.
|
||||
* Panic on the bus error exceptions.
|
||||
*/
|
||||
switch (code) {
|
||||
case EX_MOD:
|
||||
if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBL:
|
||||
if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBS:
|
||||
if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
/*
|
||||
* This means you loaded invalid TLB entries, or
|
||||
* touched invalid parts of the direct-mapped
|
||||
* segments. These are serious kernel errors, so
|
||||
* panic.
|
||||
*
|
||||
* The MIPS won't even tell you what invalid address
|
||||
* caused the bus error.
|
||||
*/
|
||||
panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Ok, it wasn't any of the really easy cases.
|
||||
* Call vm_fault on the TLB exceptions.
|
||||
* Panic on the bus error exceptions.
|
||||
*/
|
||||
switch (code) {
|
||||
case EX_MOD:
|
||||
if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr) == 0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBL:
|
||||
if (vm_fault(VM_FAULT_READ, tf->tf_vaddr) == 0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_TLBS:
|
||||
if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr) == 0) {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case EX_IBE:
|
||||
case EX_DBE:
|
||||
/*
|
||||
* This means you loaded invalid TLB entries, or
|
||||
* touched invalid parts of the direct-mapped
|
||||
* segments. These are serious kernel errors, so
|
||||
* panic.
|
||||
*
|
||||
* The MIPS won't even tell you what invalid address
|
||||
* caused the bus error.
|
||||
*/
|
||||
panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get to this point, it's a fatal fault - either it's
|
||||
* one of the other exceptions, like illegal instruction, or
|
||||
* it was a page fault we couldn't handle.
|
||||
*/
|
||||
/*
|
||||
* If we get to this point, it's a fatal fault - either it's
|
||||
* one of the other exceptions, like illegal instruction, or
|
||||
* it was a page fault we couldn't handle.
|
||||
*/
|
||||
|
||||
if (!iskern) {
|
||||
/*
|
||||
* Fatal fault in user mode.
|
||||
* Kill the current user process.
|
||||
*/
|
||||
kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
|
||||
goto done;
|
||||
}
|
||||
if (!iskern) {
|
||||
/*
|
||||
* Fatal fault in user mode.
|
||||
* Kill the current user process.
|
||||
*/
|
||||
kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fatal fault in kernel mode.
|
||||
*
|
||||
* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
|
||||
* set by copyin/copyout and related functions to signify that
|
||||
* the addresses they're accessing are userlevel-supplied and
|
||||
* not trustable. What we actually want to do is resume
|
||||
* execution at the function pointed to by badfaultfunc. That's
|
||||
* going to be "copyfail" (see copyinout.c), which longjmps
|
||||
* back to copyin/copyout or wherever and returns EFAULT.
|
||||
*
|
||||
* Note that we do not just *call* this function, because that
|
||||
* won't necessarily do anything. We want the control flow
|
||||
* that is currently executing in copyin (or whichever), and
|
||||
* is stopped while we process the exception, to *teleport* to
|
||||
* copyfail.
|
||||
*
|
||||
* This is accomplished by changing tf->tf_epc and returning
|
||||
* from the exception handler.
|
||||
*/
|
||||
/*
|
||||
* Fatal fault in kernel mode.
|
||||
*
|
||||
* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
|
||||
* set by copyin/copyout and related functions to signify that
|
||||
* the addresses they're accessing are userlevel-supplied and
|
||||
* not trustable. What we actually want to do is resume
|
||||
* execution at the function pointed to by badfaultfunc. That's
|
||||
* going to be "copyfail" (see copyinout.c), which longjmps
|
||||
* back to copyin/copyout or wherever and returns EFAULT.
|
||||
*
|
||||
* Note that we do not just *call* this function, because that
|
||||
* won't necessarily do anything. We want the control flow
|
||||
* that is currently executing in copyin (or whichever), and
|
||||
* is stopped while we process the exception, to *teleport* to
|
||||
* copyfail.
|
||||
*
|
||||
* This is accomplished by changing tf->tf_epc and returning
|
||||
* from the exception handler.
|
||||
*/
|
||||
|
||||
if (curthread != NULL &&
|
||||
curthread->t_machdep.tm_badfaultfunc != NULL) {
|
||||
tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;
|
||||
goto done;
|
||||
}
|
||||
if (curthread != NULL && curthread->t_machdep.tm_badfaultfunc != NULL) {
|
||||
tf->tf_epc = (vaddr_t)curthread->t_machdep.tm_badfaultfunc;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Really fatal kernel-mode fault.
|
||||
*/
|
||||
/*
|
||||
* Really fatal kernel-mode fault.
|
||||
*/
|
||||
|
||||
kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
|
||||
trapcodenames[code]);
|
||||
kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n",
|
||||
tf->tf_epc, tf->tf_vaddr);
|
||||
kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
|
||||
trapcodenames[code]);
|
||||
kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n", tf->tf_epc, tf->tf_vaddr);
|
||||
|
||||
panic("I can't handle this... I think I'll just die now...\n");
|
||||
panic("I can't handle this... I think I'll just die now...\n");
|
||||
|
||||
done:
|
||||
/*
|
||||
* Turn interrupts off on the processor, without affecting the
|
||||
* stored interrupt state.
|
||||
*/
|
||||
cpu_irqoff();
|
||||
done2:
|
||||
done:
|
||||
/*
|
||||
* Turn interrupts off on the processor, without affecting the
|
||||
* stored interrupt state.
|
||||
*/
|
||||
cpu_irqoff();
|
||||
done2:
|
||||
|
||||
/*
|
||||
* The boot thread can get here (e.g. on interrupt return) but
|
||||
* since it doesn't go to userlevel, it can't be returning to
|
||||
* userlevel, so there's no need to set cputhreads[] and
|
||||
* cpustacks[]. Just return.
|
||||
*/
|
||||
if (curthread->t_stack == NULL) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* The boot thread can get here (e.g. on interrupt return) but
|
||||
* since it doesn't go to userlevel, it can't be returning to
|
||||
* userlevel, so there's no need to set cputhreads[] and
|
||||
* cpustacks[]. Just return.
|
||||
*/
|
||||
if (curthread->t_stack == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) curthread->t_stack is corrupted, or
|
||||
* (2) the trap frame is somehow on the wrong kernel stack.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) curthread->t_stack is corrupted, or
|
||||
* (2) the trap frame is somehow on the wrong kernel stack.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number] - 1, (vaddr_t)tf));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -364,43 +345,41 @@ mips_trap(struct trapframe *tf)
|
||||
* - enter_new_process, for use by exec and equivalent.
|
||||
* - enter_forked_process, in syscall.c, for use by fork.
|
||||
*/
|
||||
void
|
||||
mips_usermode(struct trapframe *tf)
|
||||
{
|
||||
void mips_usermode(struct trapframe *tf) {
|
||||
|
||||
/*
|
||||
* Interrupts should be off within the kernel while entering
|
||||
* user mode. However, while in user mode, interrupts should
|
||||
* be on. To interact properly with the spl-handling logic
|
||||
* above, we explicitly call spl0() and then call cpu_irqoff().
|
||||
*/
|
||||
spl0();
|
||||
cpu_irqoff();
|
||||
/*
|
||||
* Interrupts should be off within the kernel while entering
|
||||
* user mode. However, while in user mode, interrupts should
|
||||
* be on. To interact properly with the spl-handling logic
|
||||
* above, we explicitly call spl0() and then call cpu_irqoff().
|
||||
*/
|
||||
spl0();
|
||||
cpu_irqoff();
|
||||
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
|
||||
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
|
||||
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) cpustacks[] is corrupted, or
|
||||
* (2) the trap frame is not on our own kernel stack, or
|
||||
* (3) the boot thread tries to enter user mode.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*
|
||||
* It's necessary for the trap frame used here to be on the
|
||||
* current thread's own stack. It cannot correctly be on
|
||||
* either another thread's stack or in the kernel heap.
|
||||
* (Exercise: why?)
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
|
||||
/*
|
||||
* This assertion will fail if either
|
||||
* (1) cpustacks[] is corrupted, or
|
||||
* (2) the trap frame is not on our own kernel stack, or
|
||||
* (3) the boot thread tries to enter user mode.
|
||||
*
|
||||
* If cpustacks[] is corrupted, the next trap back to the
|
||||
* kernel will (most likely) hang the system, so it's better
|
||||
* to find out now.
|
||||
*
|
||||
* It's necessary for the trap frame used here to be on the
|
||||
* current thread's own stack. It cannot correctly be on
|
||||
* either another thread's stack or in the kernel heap.
|
||||
* (Exercise: why?)
|
||||
*/
|
||||
KASSERT(SAME_STACK(cpustacks[curcpu->c_number] - 1, (vaddr_t)tf));
|
||||
|
||||
/*
|
||||
* This actually does it. See exception-*.S.
|
||||
*/
|
||||
asm_usermode(tf);
|
||||
/*
|
||||
* This actually does it. See exception-*.S.
|
||||
*/
|
||||
asm_usermode(tf);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -419,20 +398,18 @@ mips_usermode(struct trapframe *tf)
|
||||
*
|
||||
* Works by creating an ersatz trapframe.
|
||||
*/
|
||||
void
|
||||
enter_new_process(int argc, userptr_t argv, userptr_t env,
|
||||
vaddr_t stack, vaddr_t entry)
|
||||
{
|
||||
struct trapframe tf;
|
||||
void enter_new_process(int argc, userptr_t argv, userptr_t env, vaddr_t stack,
|
||||
vaddr_t entry) {
|
||||
struct trapframe tf;
|
||||
|
||||
bzero(&tf, sizeof(tf));
|
||||
bzero(&tf, sizeof(tf));
|
||||
|
||||
tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
|
||||
tf.tf_epc = entry;
|
||||
tf.tf_a0 = argc;
|
||||
tf.tf_a1 = (vaddr_t)argv;
|
||||
tf.tf_a2 = (vaddr_t)env;
|
||||
tf.tf_sp = stack;
|
||||
tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
|
||||
tf.tf_epc = entry;
|
||||
tf.tf_a0 = argc;
|
||||
tf.tf_a1 = (vaddr_t)argv;
|
||||
tf.tf_a2 = (vaddr_t)env;
|
||||
tf.tf_sp = stack;
|
||||
|
||||
mips_usermode(&tf);
|
||||
mips_usermode(&tf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user