/** @brief This function handles SYSCALL or Breakpoint exceptions, which occurs when a SYSCALL or BREAK assembler instruction is executed. @return Void. */ EXTERN void sysBpHandler() { /* Save SYS/BP Old Area state */ saveCurrentState(SYSBP_Old, &(CurrentProcess->p_s)); /* Select handler accordingly to the exception type */ switch (CAUSE_EXCCODE_GET(SYSBP_Old->CP15_Cause)) { /* [Case 1] The exception is a system call */ case EXC_SYSCALL: /* Distinguish between User Mode and Kernel Mode */ ((SYSBP_Old->cpsr & STATUS_SYS_MODE) == STATUS_USER_MODE)? syscallUserMode() : syscallKernelMode(); break; /* [Case 2] The exception is a breakpoint */ case EXC_BREAKPOINT: /* Distinguish whether SYS5 has been invoked or not */ checkSYS5(SYSBK_EXCEPTION, SYSBP_Old); break; default: PANIC(); /* Anomaly */ } }
/********************************************************************** SYSBP_HANDLER Caricato all'arrivo di una eccezione di tipo SYSCALL/BREAKPOINT. Fornisce principalmente il servizio di message passing. In tutti i casi in cui è sollevata una eccezione diversa da SYSCALL di tipo 1 o 2 in Kernel Mode, questa routine, come le altre due di questo modulo affidano il controllo del thread corrente ad un Trap Manager, se specificato, altrimenti viene terminato tutto il sottoalbero corrispondente. **********************************************************************/ void sysbp_handler(){ int exc_cause; int KUmode; /* 0 se Kernel / 1 se User */ tcb_t *trapped; tcb_t *manager; tcb_t *sender; tcb_t *receiver; U32 payload; U32 *reply; /* Aggiornamento tempo thread */ current_thread->cpu_slice += (GET_TODLOW - current_thread_tod); current_thread->cpu_time += (GET_TODLOW - current_thread_tod); /* Salvo lo stato del processore del thread che ha sollevato l'eccezione, nel campo t_state del suo tcb. Lo stato è salvato nella old area dell'attuale eccezione. Modifico opportunamente il PC per non avere un ciclo nel ritorno dall'eccezione. */ save_state(sysbk_oldarea, &(current_thread->t_state)); current_thread->t_state.pc_epc += WORD_SIZE; /* Recupero il tipo di eccezione avvenuta */ exc_cause = CAUSE_EXCCODE_GET(sysbk_oldarea->cause); /* Controllo se Kernel o User Mode */ KUmode = (sysbk_oldarea->status & STATUS_KUp) >> 3; /* Se l'eccezione è una SYSCALL 1 o 2 ed eseguita in kernel mode */ if (KUmode == 0) { if (exc_cause == EXC_SYSCALL) { /* MsgSend */ if (sysbk_oldarea->reg_a0 == SEND) { sender = current_thread; payload = sysbk_oldarea->reg_a2; /* Protezione SSI e incremento thread in attesa di servizio */ if (sysbk_oldarea->reg_a1 == MAGIC_SSI) { receiver = SSI_tcb; soft_block_count++; } else receiver = ((tcb_t *)(sysbk_oldarea->reg_a1)); /* CASO TRAP MANAGER --> Intercettare messaggio TRAPTERMINATE / TRAPCONTINUE */ if ((thereIs_manager(sender)) && (receiver->waiting_for == sender)) { /*** TRAPTERMINATE ***/ if (payload == TRAPTERMINATE) { trapped = receiver; terminate(trapped); /* Termino thread in wait_queue in attesa della decisione del Trap Manager */ scheduler(); } /*** TRAPCONTINUE ***/ if (payload == TRAPCONTINUE) { trapped = receiver; insertThread(&ready_queue, outThread(&wait_queue, trapped)); /* Altrimenti lo risveglio */ scheduler(); } } /* Caso normale di MsgSend (vedi send) */ sender->t_state.reg_v0 = send (sender, receiver, payload); scheduler(); } /* MsgRecv */ if (sysbk_oldarea->reg_a0 == RECV) { receiver = current_thread; reply = (U32 *)sysbk_oldarea->reg_a2; /* Protezione SSI (non decremento qui soft block count ma al momento di ricevimento servizio) */ if (sysbk_oldarea->reg_a1 == MAGIC_SSI) sender = SSI_tcb; else sender = ((tcb_t *)(sysbk_oldarea->reg_a1)); /* MsgRecv (vedi recv) e restituisco sender direttamente (nel caso NON BLOCCANTE e non con SSIRequest) */ current_thread->t_state.reg_v0 = (U32)recv(current_thread, ((tcb_t *)sysbk_oldarea->reg_a1), ((U32 *)sysbk_oldarea->reg_a2)); scheduler(); } } } /* TUTTI gli altri casi*/ manager = current_thread->sysbp_manager_thread; /* Se il thread NON ha specificato un Trap Management thread per questa eccezione viene terminato */ if (manager == NULL) { terminate(current_thread); current_thread = NULL; scheduler(); } /* Se il thread HA invece specificato il gestore viene freezato */ else { /* Invio messaggio al suo Trap manager con registro cause come payload */ send(current_thread, manager, sysbk_oldarea->cause); /* Setto in TCB chi sto aspettando */ current_thread->waiting_for = manager; /* Freeze del thread in attesa della decisione del manager */ insertThread(&wait_queue, current_thread); current_thread = NULL; scheduler(); } }
void sysBpHandler(){ saveStateIn(sysbp_old, ¤tProcess->p_s); unsigned int cause = CAUSE_EXCCODE_GET(sysbp_old->CP15_Cause); unsigned int a0 = (*sysbp_old).a1; unsigned int a1 = (*sysbp_old).a2; unsigned int a2 = (*sysbp_old).a3; unsigned int a3 = (*sysbp_old).a4; /* Se l'eccezione è di tipo System call */ if(cause==EXC_SYSCALL){ /* Se il processo è in kernel mode gestisce adeguatamente */ if( (currentProcess->p_s.cpsr & STATUS_SYS_MODE) == STATUS_SYS_MODE){ /* Se è fra SYS1 e SYS8 richiama le funzioni adeguate */ switch(a0){ case CREATEPROCESS: createProcess((state_t *) a1); break; case TERMINATEPROCESS: terminateProcess(currentProcess); break; case VERHOGEN: verhogen((int *) a1); break; case PASSEREN: passeren((int *) a1); break; case SPECTRAPVEC: specExStVec((int) a1, (state_t *) a2, (state_t *) a3); break; case GETCPUTIME: getCPUTime(); break; case WAITCLOCK: waitForClock(); break; case WAITIO: waitForIO((int) a1, (int) a2, (int) a3); break; /* Altrimenti la gestione viene passata in alto */ default: useExStVec(SPECSYSBP); break; } /* Richiamo lo scheduler */ scheduler(); /* Se invece è in user mode */ } else if((currentProcess->p_s.cpsr & STATUS_USER_MODE) == STATUS_USER_MODE){ /* Se è una system call */ if(a0 >= CREATEPROCESS && a0 <= WAITIO){ /* Gestisco come fosse una program trap */ saveStateIn(sysbp_old, pgmtrap_old); /* Setto il registro cause a Reserved Instruction */ pgmtrap_old->CP15_Cause = CAUSE_EXCCODE_SET(pgmtrap_old->CP15_Cause, EXC_RESERVEDINSTR); /* Richiamo l'handler per le pgmtrap */ pgmHandler(); } else { useExStVec(SPECSYSBP); } } /* Altrimenti se l'eccezione è di tipo BreakPoint */ } else if(cause == EXC_BREAKPOINT){ useExStVec(SPECSYSBP); } PANIC(); }