void intHandler(void) { unsigned int timeStamp = GET_TODLOW; unsigned int prid = getPRID(); state_t *ints_oldarea; pcb_t* current = getCurrentProcess(prid); if(prid == 0) ints_oldarea = (state_t *) INT_OLDAREA; else ints_oldarea = getNewOldAreaPtr(prid, INT_OLDAREA_INDEX); // Aggiorno i tempi di esecuzione del processo updateProcessExecTime(timeStamp, current); // Aggiorno lo stato del processore nel pcb updatePcbCPUState(ints_oldarea, current); /* selezione del gestore per gli interrupt giusto */ if(CAUSE_IP_GET(ints_oldarea->cause, 1)) /* interrupt processor local timer */ { pltIntHandler(current); } else if (CAUSE_IP_GET(ints_oldarea->cause, 2)) { intervalIntHandler(ints_oldarea); /* interval timer interrupt */ } else if (CAUSE_IP_GET(ints_oldarea->cause, 7)) /* int terminali */ { unsigned int dBA = dev_search(devCalc(4)); /* calcolo se l'int è del sub-device trasmettitore, ricevitore o entrambi */ if (((*(memaddr *) dBA + 0x8) >= ILLEGAL_OPCODE) || ((*(memaddr *) dBA + 0x8) <= CHAR_TRASM)) IOIntHandler(dBA + 0x8, dBA + 0xc); if (((*(memaddr *) dBA) >= ILLEGAL_OPCODE) || ((*(memaddr *) dBA) <= CHAR_RECV)) IOIntHandler(dBA, dBA + 0x4); } }
//gestore degli interrupt void int_handler(){ interruptStart = getTODLO(); //tempo in cui comincia la gestione dell'interrupt, da //assegnare poi ad un eventuale processo svegliato dall'interrupt state_t *returnState = (state_t*) INT_OLDAREA; returnState->pc -= 4; if( current_process != NULL){ copy_state( returnState, ¤t_process->p_s ); current_process->userTime += interruptStart - userTimeStart;//se c'è un processo aggiorno il suo userTime current_process->CPUTime += interruptStart - CPUTimeStart; } int cause = getCAUSE(); if(CAUSE_IP_GET(cause, IL_TIMER)){ if( current_timer == PSEUDO_CLOCK ){ while( devSem[CLOCK_SEM] < 0 ){ //Ad ogni pseudo clock tick mi assicuro che il semaforo sia sempre a zero verhogen( &devSem[CLOCK_SEM], 1, 0, getTODLO() - interruptStart); } } else if(current_timer == TIME_SLICE ){ if( current_process != NULL ){ insertProcQ( priority_queue(current_process->priority), current_process); current_process->CPUTime += getTODLO() - interruptStart; //se metto in pausa il processo aggiorno anche il suo CPUTime current_process = NULL; } } } else if(CAUSE_IP_GET(cause, IL_DISK)){ dtnp_interrupt(IL_DISK); } else if(CAUSE_IP_GET(cause, IL_TAPE)){ dtnp_interrupt(IL_TAPE); } else if(CAUSE_IP_GET(cause, IL_ETHERNET)){ dtnp_interrupt(IL_ETHERNET); } else if(CAUSE_IP_GET(cause, IL_PRINTER)){ dtnp_interrupt(IL_PRINTER); } else if(CAUSE_IP_GET(cause, IL_TERMINAL)){ terminal_interrupt(); } scheduler(); }
/********************************************************************** INT_HANDLER Caricato all'arrivo di un interrupt, scandisce sequenzialmente, quindi garantendo priorità, le linee, da quelle con indice minore (più veloci) a quelle con indice maggiore (più lente). Ciò viene fatto in base ai bit IP del registro CAUSE, cercando poi quale/i device fra gli 8 possibili ha generato l'interrupt. A questo punto viene gestito l'interrupt, mandando un messaggio a SSI e ACKando il device register, principalmente, più altre azioni a seconda dello specifico device. **********************************************************************/ void int_handler(){ int int_cause; int *status; int *status_trans; int *status_rec; int *int_bitmap; int *command; int *command_trans; int *command_rec; memaddr device_baseaddr; int dev_number; /* Se c'era un processo sulla CPU salvo il precedente stato del processore nel campo t_state del tcb attivo in quel momento. Lo stato è salvato nella old area dell'attuale eccezione. */ if (current_thread != NULL) { /* Aggiornamento tempo thread */ current_thread->cpu_slice += (GET_TODLOW - current_thread_tod); current_thread->cpu_time += (GET_TODLOW - current_thread_tod); /* Salvataggio stato */ save_state(int_oldarea, &(current_thread->t_state)); } /* Prelevo registro cause */ int_cause = int_oldarea->cause; /* Non presenti interrupt da linee 0 e 1 (software) in AmiKaya11 */ /* Linea 2 Interval Timer Interrupt + Gestione PSEUDO CLOCK ****************************/ if (CAUSE_IP_GET(int_cause, INT_TIMER)) { /* Aggiornamento pseudo clock */ pseudo_tick = pseudo_tick + (GET_TODLOW - start_pseudo_tick); start_pseudo_tick = GET_TODLOW; /* Interrupt per Pseudo-clock Tick */ if (pseudo_tick >= SCHED_PSEUDO_CLOCK) { /* Messaggio all'SSI che dovrà gestire lo sbloccaggio dei thread */ interrupt_msg_array[i].service = PSEUDOCLOCK_MSG; interrupt_msg_array[i].arg = 0; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)BUS_INTERVALTIMER, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); /* Faccio ripartire il clock del device virtuale */ pseudo_tick = 0; start_pseudo_tick = GET_TODLOW; } /* Gestione per Slice processo corrente scaduto */ if ((current_thread != NULL) && (current_thread->cpu_slice >= SCHED_TIME_SLICE)) { insertThread(&ready_queue, current_thread); current_thread = NULL; } /* Default */ else SET_IT(SCHED_PSEUDO_CLOCK - pseudo_tick); } /* Interval Timer ********************************************************************/ /* Linea 3 Disk interrupt **************************************************************/ else if (CAUSE_IP_GET(int_cause, INT_DISK)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_DISK - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_DISK - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Disk ******************************************************************************/ /* Linea 4 Tape interrupt **************************************************************/ else if (CAUSE_IP_GET(int_cause, INT_TAPE)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_TAPE - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_TAPE - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Tape ******************************************************************************/ /* Linea 5 Unused line interrupt *******************************************************/ else if (CAUSE_IP_GET(int_cause, INT_UNUSED)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_UNUSED - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_UNUSED - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Unused ****************************************************************************/ /* Linea 6 Printer interrupt ***********************************************************/ else if (CAUSE_IP_GET(int_cause, INT_PRINTER)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_PRINTER - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_PRINTER - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo valore del campo Status del Device Register */ status = (int *)device_baseaddr; /* Puntatore a campo command del Device Register */ command = (int *)(device_baseaddr + 0x4); /* ACK al device */ *command = DEV_C_ACK; /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)device_baseaddr, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); } /* Printer ***************************************************************************/ /* Linea 7 Terminal interrupt **********************************************************/ else if (CAUSE_IP_GET(int_cause, INT_TERMINAL)) { /* Cerco la bitmap della linea attuale */ int_bitmap = (int *)(PENDING_BITMAP_START + (WORD_SIZE * (INT_TERMINAL - INT_LOWEST))); /* Cerco il device a più alta priorità su questa linea con interrupt pendente */ dev_number = which_device(*int_bitmap); /* Salvo indirizzo del Device Register */ device_baseaddr = (memaddr)(DEV_REGS_START + ((INT_TERMINAL - INT_LOWEST) * 0x80) + (dev_number * 0x10)); /* Salvo lo stato e il puntatore al campo command del Device Register in trasmissione */ status_trans = (int *)(device_baseaddr + 0x8); command_trans = (int *)(device_baseaddr + 0xC); /* Salvo lo stato e il puntatore al campo command del Device Register in ricezione */ status_rec = (int *)device_baseaddr; command_rec = (int *)(device_baseaddr + 0x4); /* Analizzo lo stato per estrarre la causa dell'interrupt e agisco di conseguenza*/ /* Un carattere è stato trasmesso -> Priorità alla trasmissione */ if (((*status_trans) & STATUSMASK) == DEV_TTRS_S_CHARTRSM) { /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status_trans; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)status_trans, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); /* ACK al device */ *command_trans = DEV_C_ACK; } /* Un carattere è stato ricevuto */ else if (((*status_rec) & STATUSMASK) == DEV_TRCV_S_CHARRECV) { /* Invio messaggio a SSI, come sender il device register, come payload il valore di status */ interrupt_msg_array[i].service = INTERRUPT_MSG; interrupt_msg_array[i].arg = *status_rec; interrupt_msg_array[i].reply = NOREPLY; if ( send((tcb_t *)status_rec, SSI_tcb, (U32)&interrupt_msg_array[i]) == MSGNOGOOD ) PANIC(); /* ACK al device */ *command_rec = DEV_C_ACK; } } /* Terminal **************************************************************************/ /* Incremento i in modo circolare */ i = (i+1)%48; scheduler(); }