/* TMHal.c, Copyright (c) by Christian Conrad, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/Threads/mips/TMHal.c,v $ Author(s): Christian Conrad Affiliation: ETH Zuerich, TIK Version: $Revision: 1.33 $ Creation Date: Last Date of Change: $Date: 2000/03/31 17:50:40 $ by: $Author: gfa $ $Log: TMHal.c,v $ Revision 1.33 2000/03/31 17:50:40 gfa Merged with /Net from several term projects Revision 1.32 1999/12/13 21:48:35 ruf GNU General Public Licence Update Revision 1.31 1999/10/31 14:42:48 jeker first fixes for SimOS Revision 1.30 1999/10/27 11:05:01 jeker fixes R4k R3k port Revision 1.29 1999/10/24 11:11:06 gfa *** empty log message *** Revision 1.27 1999/10/21 20:22:31 jeker first commit for the R4k support Revision 1.26 1999/06/06 20:55:20 jeker putting everything together for Topsy 2.0 Revision 1.25 1999/04/08 11:40:16 jeker added some new files, modified some others for unix port Revision 1.24 1999/01/08 22:07:21 cjeker more bug fixes Revision 1.23 1999/01/08 21:28:01 cjeker moved branchDelayBit handling to TMHalAsm.S Revision 1.22 1999/01/08 18:56:35 cjeker more code cleaning, moved tmResetClockInterrupt to the clock interrupt handlers Revision 1.21 1997/04/23 09:10:28 gfa formatting, comments adjusted * Revision 1.20 1997/04/14 21:09:23 conrad * *** empty log message *** * * Revision 1.19 1997/04/07 09:23:00 gfa * changed interrupt handler management to include the argument and arg table * * Revision 1.18 97/04/06 18:55:43 gfa * changed enable/disableInterrupt functions * * Revision 1.17 1997/03/31 20:33:54 gfa * added low level register access functions * * Revision 1.16 1997/03/27 13:55:20 conrad * *** empty log message *** * * Revision 1.15 1997/03/21 16:14:23 conrad * changed restoreContext() to check if a new threadPtr is NULL, if yes, restore * of a 'fake' idle context * * Revision 1.14 1997/03/19 21:40:32 conrad * cosmetics * * Revision 1.13 1997/03/18 17:43:21 conrad * splitting of TMHal and TMClock * * Revision 1.12 1997/03/18 16:30:40 conrad * c processing of the hw interrupts in intDispatcher() * fixed clock configuration (BEWARE: code for setClockValue cannot be * compiled with the optimized flag !!!!) * * Revision 1.11 1997/03/12 17:54:22 conrad * Debugging Version * * Revision 1.10 1997/03/11 20:07:35 conrad * First version to be debugged with Simulator * * Revision 1.9 1997/03/06 16:15:58 conrad * panic was moved to Error.[ch] * * Revision 1.8 1997/03/05 19:16:18 gfa * added infinite loop to end of panic * * Revision 1.7 1997/03/04 11:33:53 conrad * Implementation of panic() * * Revision 1.6 1997/02/27 14:38:40 conrad * minor changes * * Revision 1.5 1997/02/21 09:15:45 conrad * Intermediate status (not yet completed) * * Revision 1.4 1997/02/19 17:46:51 conrad * *** empty log message *** * * Revision 1.3 1997/02/18 17:25:56 conrad * *** empty log message *** * * Revision 1.2 1997/02/13 15:45:17 conrad * First compilation/linking of complete environment (all modules) * * Revision 1.1 1997/02/13 07:30:17 conrad * Initial revision * */ #include "TMHal.h" #include "IOHal.h" #include "Support.h" #include "SupportMIPS.h" #include "TMClock.h" /* Exception Context, used by the general exception handler before calling * saveContext(). This is a minimal save that allows to call saveContext as * a proper procedure. * - exceptionContext[0] <- a0 * - exceptionContext[1] <- ra * - exceptionContext[2] <- sp * - exceptionContext[3] <- pc */ Register exceptionContext[4]; /* Exception service branch table (exception handlers). * - 16 exception handlers, * - 16 reserved (not set) * - 1 UTLB handler (offset 32 in array) */ ExceptionHandler exceptionHandlerTable[MAXNBOFEXCEPTIONS+1]; /* Hardware interrupt service branch table (interrupt handlers) and * corresponding arguments that may be passed to the interrupt handler. * - 6 hw interrupts * - 2 sw interrupts */ InterruptHandler interruptHandlerTable[MAXNBOFINTERRUPTS]; void* interruptHandlerArgTable[MAXNBOFINTERRUPTS]; #if 0 /* 8254 Register Addressing structure */ typedef struct TimerRegisters_t{ unsigned char counter0; unsigned char pad1[3]; unsigned char counter1; unsigned char pad2[3]; unsigned char counter2; unsigned char pad3[3]; unsigned char ctrlWord; unsigned char pad4[3]; } TimerRegisters; #endif void tmInstallExceptionCode() { /* Installation of default basic exception handlers */ /* INSTALL generalExceptionHandler AT LOCATION 0x8000_0080 */ if ( getPRID() == PRID_R3k ) { byteCopy( (Address)VEC_EXCEPTION_R3k, generalExceptionHandler, endGeneralExceptionHandler-generalExceptionHandler); } else { byteCopy( (Address)VEC_EXCEPTION_R4k, generalExceptionHandler, endGeneralExceptionHandler-generalExceptionHandler); } /* INSTALL UTLBMissHandler AT LOCATION 0x8000_0000 */ if (endUTLBMissHandler-UTLBMissHandler > 0x00000080) PANIC("utlbmisshandler larger than 0x80 bytes"); byteCopy( (Address)VEC_TLB_UMISS, UTLBMissHandler, endUTLBMissHandler-UTLBMissHandler); /* RESETHandler AT LOCATION 0xbfc0_0000 is in EPROMs */ } InterruptHandler tmSetInterruptHandler( InterruptId intId, InterruptHandler intHdler, void* arg) { InterruptHandler oldIntHdler = interruptHandlerTable[intId]; if (intId == SWINT_0 || intId == SWINT_1) { interruptHandlerTable[intId-6] = intHdler; interruptHandlerArgTable[intId-6] = arg; } else { interruptHandlerTable[intId+2] = intHdler; interruptHandlerArgTable[intId+2] = arg; } return oldIntHdler; } ExceptionHandler tmSetExceptionHandler( ExceptionId excId, ExceptionHandler excHdler) { ExceptionHandler oldExcHdler = exceptionHandlerTable[excId]; exceptionHandlerTable[excId] = excHdler; return oldExcHdler; } void intDispatcher( Register causeReg) { int offset=-1; causeReg &= CAUSE_IP_MASK; causeReg >>= CAUSE_IP_SHIFT; /* The invariant here is causeReg>0, otherwise an hardware error would have occurred */ while (causeReg != 0) { causeReg >>= 1; offset += 1; } /* we call here the handler for interrupt offset with * its (optionally) defined argument */ (interruptHandlerTable[offset])(interruptHandlerArgTable[offset]); } int branchDelayHandler( ThreadId fromId, /* thread that caused exception */ Message* msgPtr, /* message reference */ unsigned long int timeout,/* timeout for receiving */ MsgOpCode code) /* SYSCALL_SEND_OP/SYSCALL_RECV_OP */ { Message killMsg; /* since we write no silly code we can assume that we never get caught * here. if we would allow syscalls in BD slots we would have to interpret * the faulting branch in software (which is not funny). */ /* if (branchDelayBit == CAUSE_BD) */ ERROR("Syscall in branch delay slot"); killMsg.id = TM_KILL; killMsg.from = TMTHREADID; killMsg.msg.tmKill.id = fromId; kSend(TMTHREADID, &killMsg); return TM_OK; } void tmSetReturnValue(ProcContextPtr contextPtr, Register value) { contextPtr->returnValue[0] = value; } void tmSetStackPointer(ProcContextPtr contextPtr, Register value) { contextPtr->stackPointer = value; } void tmSetReturnAddress(ProcContextPtr contextPtr, Register value) { contextPtr->returnAddress = value; } void tmSetProgramCounter(ProcContextPtr contextPtr, Register value) { contextPtr->programCounter = value; } void tmSetStatusRegister(ProcContextPtr contextPtr, Register value) { contextPtr->statusRegister = value; } void tmSetFramePointer(ProcContextPtr contextPtr, Register value) { contextPtr->framePointer = value; } void tmSetArgument0(ProcContextPtr contextPtr, Register value) { contextPtr->argument[0] = value; } void tmSetArgument1(ProcContextPtr contextPtr, Register value) { contextPtr->argument[1] = value; } void tmSetMachineDependentRegisters(ProcContextPtr contextPtr, AddressSpace space) { /* not needed on mips Architecture, or? */ } void enableInterruptInContext( InterruptId intId, ProcContextPtr contextPtr) { unsigned long int bitToSet = 1; if (intId < SWINT_0) { /* either CLOCKINT, CENTRONICS, or DUART */ bitToSet <<= (INTMASK_SHIFT+2+intId); } else { bitToSet <<= (INTMASK_SHIFT+intId-SWINT_0); } contextPtr->statusRegister |= bitToSet; } void disableInterruptInContext( InterruptId intId, ProcContextPtr contextPtr) { unsigned long int bitToClear = 1; if (intId < SWINT_0) { /* either CLOCKINT, CENTRONICS, or DUART */ bitToClear <<= (INTMASK_SHIFT+2+intId); } else { bitToClear <<= (INTMASK_SHIFT+intId-SWINT_0); } contextPtr->statusRegister &= ~bitToClear; } void enableAllInterruptsInContext( ProcContextPtr contextPtr) { contextPtr->statusRegister |= SR_INT_MASK; } void msgAdjust(ThreadPtr pFromOrToThread, Message *msg, Boolean ToKernel) { // not needed on mips } void powerSaver(void) { // not needed, mips version runs always :-) }