/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829#include <types.h>30#include <signal.h>31#include <lib.h>32#include <mips/specialreg.h>33#include <mips/trapframe.h>34#include <cpu.h>35#include <spl.h>36#include <thread.h>37#include <current.h>38#include <vm.h>39#include <mainbus.h>40#include <syscall.h>414243/* in exception.S */44extern void asm_usermode(struct trapframe *tf);4546/* called only from assembler, so not declared in a header */47void mips_trap(struct trapframe *tf);484950/* Names for trap codes */51#define NTRAPCODES 1352static const char *const trapcodenames[NTRAPCODES] = {53"Interrupt",54"TLB modify trap",55"TLB miss on load",56"TLB miss on store",57"Address error on load",58"Address error on store",59"Bus error on code",60"Bus error on data",61"System call",62"Break instruction",63"Illegal instruction",64"Coprocessor unusable",65"Arithmetic overflow",66};6768/*69* Function called when user-level code hits a fatal fault.70*/71static72void73kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)74{75int sig = 0;7677KASSERT(code < NTRAPCODES);78switch (code) {79case EX_IRQ:80case EX_IBE:81case EX_DBE:82case EX_SYS:83/* should not be seen */84KASSERT(0);85sig = SIGABRT;86break;87case EX_MOD:88case EX_TLBL:89case EX_TLBS:90sig = SIGSEGV;91break;92case EX_ADEL:93case EX_ADES:94sig = SIGBUS;95break;96case EX_BP:97sig = SIGTRAP;98break;99case EX_RI:100sig = SIGILL;101break;102case EX_CPU:103sig = SIGSEGV;104break;105case EX_OVF:106sig = SIGFPE;107break;108}109110sys__exit( -1 );111return;112113kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",114code, sig, trapcodenames[code], epc, vaddr);115panic("I don't know how to handle this\n");116}117118/*119* General trap (exception) handling function for mips.120* This is called by the assembly-language exception handler once121* the trapframe has been set up.122*/123void124mips_trap(struct trapframe *tf)125{126uint32_t code;127bool isutlb, iskern;128int spl;129130/* The trap frame is supposed to be 37 registers long. */131KASSERT(sizeof(struct trapframe)==(37*4));132133/*134* Extract the exception code info from the register fields.135*/136code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;137isutlb = (tf->tf_cause & CCA_UTLB) != 0;138iskern = (tf->tf_status & CST_KUp) == 0;139140KASSERT(code < NTRAPCODES);141142/* Make sure we haven't run off our stack */143if (curthread != NULL && curthread->t_stack != NULL) {144KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);145KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack146+ STACK_SIZE));147}148149/* Interrupt? Call the interrupt handler and return. */150if (code == EX_IRQ) {151int old_in;152bool doadjust;153154old_in = curthread->t_in_interrupt;155curthread->t_in_interrupt = 1;156157/*158* The processor has turned interrupts off; if the159* currently recorded interrupt state is interrupts on160* (spl of 0), adjust the recorded state to match, and161* restore after processing the interrupt.162*163* How can we get an interrupt if the recorded state164* is interrupts off? Well, as things currently stand165* when the CPU finishes idling it flips interrupts on166* and off to allow things to happen, but leaves167* curspl high while doing so.168*169* While we're here, assert that the interrupt170* handling code hasn't leaked a spinlock or an171* splhigh().172*/173174if (curthread->t_curspl == 0) {175KASSERT(curthread->t_curspl == 0);176KASSERT(curthread->t_iplhigh_count == 0);177curthread->t_curspl = IPL_HIGH;178curthread->t_iplhigh_count++;179doadjust = true;180}181else {182doadjust = false;183}184185mainbus_interrupt(tf);186187if (doadjust) {188KASSERT(curthread->t_curspl == IPL_HIGH);189KASSERT(curthread->t_iplhigh_count == 1);190curthread->t_iplhigh_count--;191curthread->t_curspl = 0;192}193194curthread->t_in_interrupt = old_in;195goto done2;196}197198/*199* The processor turned interrupts off when it took the trap.200*201* While we're in the kernel, and not actually handling an202* interrupt, restore the interrupt state to where it was in203* the previous context, which may be low (interrupts on).204*205* Do this by forcing splhigh(), which may do a redundant206* cpu_irqoff() but forces the stored MI interrupt state into207* sync, then restoring the previous state.208*/209spl = splhigh();210splx(spl);211212/* Syscall? Call the syscall handler and return. */213if (code == EX_SYS) {214/* Interrupts should have been on while in user mode. */215KASSERT(curthread->t_curspl == 0);216KASSERT(curthread->t_iplhigh_count == 0);217218DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n",219tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);220221syscall(tf);222goto done;223}224225/*226* Ok, it wasn't any of the really easy cases.227* Call vm_fault on the TLB exceptions.228* Panic on the bus error exceptions.229*/230switch (code) {231case EX_MOD:232if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {233goto done;234}235break;236case EX_TLBL:237if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {238goto done;239}240break;241case EX_TLBS:242if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {243goto done;244}245break;246case EX_IBE:247case EX_DBE:248/*249* This means you loaded invalid TLB entries, or250* touched invalid parts of the direct-mapped251* segments. These are serious kernel errors, so252* panic.253*254* The MIPS won't even tell you what invalid address255* caused the bus error.256*/257panic("Bus error exception, PC=0x%x\n", tf->tf_epc);258break;259}260261/*262* If we get to this point, it's a fatal fault - either it's263* one of the other exceptions, like illegal instruction, or264* it was a page fault we couldn't handle.265*/266267if (!iskern) {268/*269* Fatal fault in user mode.270* Kill the current user process.271*/272kill_curthread(tf->tf_epc, code, tf->tf_vaddr);273goto done;274}275276/*277* Fatal fault in kernel mode.278*279* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is280* set by copyin/copyout and related functions to signify that281* the addresses they're accessing are userlevel-supplied and282* not trustable. What we actually want to do is resume283* execution at the function pointed to by badfaultfunc. That's284* going to be "copyfail" (see copyinout.c), which longjmps285* back to copyin/copyout or wherever and returns EFAULT.286*287* Note that we do not just *call* this function, because that288* won't necessarily do anything. We want the control flow289* that is currently executing in copyin (or whichever), and290* is stopped while we process the exception, to *teleport* to291* copyfail.292*293* This is accomplished by changing tf->tf_epc and returning294* from the exception handler.295*/296297if (curthread != NULL &&298curthread->t_machdep.tm_badfaultfunc != NULL) {299tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;300goto done;301}302303/*304* Really fatal kernel-mode fault.305*/306307kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,308trapcodenames[code]);309kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n",310tf->tf_epc, tf->tf_vaddr);311312panic("I can't handle this... I think I'll just die now...\n");313314done:315/*316* Turn interrupts off on the processor, without affecting the317* stored interrupt state.318*/319cpu_irqoff();320done2:321322/*323* The boot thread can get here (e.g. on interrupt return) but324* since it doesn't go to userlevel, it can't be returning to325* userlevel, so there's no need to set cputhreads[] and326* cpustacks[]. Just return.327*/328if (curthread->t_stack == NULL) {329return;330}331332cputhreads[curcpu->c_number] = (vaddr_t)curthread;333cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;334335/*336* This assertion will fail if either337* (1) curthread->t_stack is corrupted, or338* (2) the trap frame is somehow on the wrong kernel stack.339*340* If cpustacks[] is corrupted, the next trap back to the341* kernel will (most likely) hang the system, so it's better342* to find out now.343*/344KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));345}346347/*348* Function for entering user mode.349*350* This should not be used by threads returning from traps - they351* should just return from mips_trap(). It should be used by threads352* entering user mode for the first time - whether the child thread in353* a fork(), or into a brand-new address space after exec(), or when354* starting the first userlevel program.355*356* It works by jumping into the exception return code.357*358* mips_usermode is common code for this. It cannot usefully be called359* outside the mips port, but should be called from one of the360* following places:361* - enter_new_process, for use by exec and equivalent.362* - enter_forked_process, in syscall.c, for use by fork.363*/364void365mips_usermode(struct trapframe *tf)366{367368/*369* Interrupts should be off within the kernel while entering370* user mode. However, while in user mode, interrupts should371* be on. To interact properly with the spl-handling logic372* above, we explicitly call spl0() and then call cpu_irqoff().373*/374spl0();375cpu_irqoff();376377cputhreads[curcpu->c_number] = (vaddr_t)curthread;378cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;379380/*381* This assertion will fail if either382* (1) cpustacks[] is corrupted, or383* (2) the trap frame is not on our own kernel stack, or384* (3) the boot thread tries to enter user mode.385*386* If cpustacks[] is corrupted, the next trap back to the387* kernel will (most likely) hang the system, so it's better388* to find out now.389*390* It's necessary for the trap frame used here to be on the391* current thread's own stack. It cannot correctly be on392* either another thread's stack or in the kernel heap.393* (Exercise: why?)394*/395KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));396397/*398* This actually does it. See exception.S.399*/400asm_usermode(tf);401}402403/*404* enter_new_process: go to user mode after loading an executable.405*406* Performs the necessary initialization so that the user program will407* get the arguments supplied in argc/argv (note that argv must be a408* user-level address), and begin executing at the specified entry409* point. The stack pointer is initialized from the stackptr410* argument. Note that passing argc/argv may use additional stack411* space on some other platforms (but not on mips).412*413* Works by creating an ersatz trapframe.414*/415void416enter_new_process(int argc, userptr_t argv, vaddr_t stack, vaddr_t entry)417{418struct trapframe tf;419420bzero(&tf, sizeof(tf));421422tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;423tf.tf_epc = entry;424tf.tf_a0 = argc;425tf.tf_a1 = (vaddr_t)argv;426tf.tf_sp = stack;427428mips_usermode(&tf);429}430431432