/////////////////////////////////////////////////////////////////////////////////// // File : irq_handler.c // Date : 01/04/2012 // Author : alain greiner and joel porquet // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// // The irq_handler.c and irq_handler.h files are part of the GIET nano-kernel. // They contain the code of the _int_demux function that handle // the ICU (Interupt Controler Unit), and the various ISRs associated // to the CoCLib peripherals. /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////////// // Initialize the whole interrupt vector with the default ISR /////////////////////////////////////////////////////////////////////////////////// __attribute__((section (".kdata"))) _isr_func_t _interrupt_vector[32] = { [0 ... 31] = &_isr_default }; /////////////////////////////////////////////////////////////////////////////////// // _int_demux() // This functions uses an external ICU component (Interrupt Controler Unit) // that concentrates up to 32 input interrupts lines. This component // can support up to NB_PROCS output IRQ. // // This component returns the highest priority active interrupt index (smaller // indexes have the highest priority) by reading the ICU_IT_VECTOR register. // Any value larger than 31 means "no active interrupt", and the default ISR // (that does nothing) is executed. // // The interrupt vector (32 ISR addresses array stored at _interrupt_vector // address) is initialised with the default ISR address. The actual ISR // addresses are supposed to be written in the interrupt vector array // during system initialisation. /////////////////////////////////////////////////////////////////////////////////// void _int_demux(void) { int interrupt_index; _isr_func_t isr; unsigned int pid = _procid(); // retrieves the highest priority active interrupt index if (!_icu_read( pid / NB_PROCS, pid % NB_PROCS, ICU_IT_VECTOR, (unsigned int*)&interrupt_index ) ) { if (interrupt_index == -1) // no interrupt is active return; isr = _interrupt_vector[interrupt_index]; isr(); } else { _puts("\n[GIET ERROR] In _demux function : wrong arguments in _icu_read()\n"); _exit(); } } /////////////////////////////////////////////////////////////////////////////////// // _isr_default() // The default ISR is called when no specific ISR has been installed in the // interrupt vector. It simply displays a message on TTY0. /////////////////////////////////////////////////////////////////////////////////// void _isr_default() { _puts("\n\n!!! Default ISR !!!\n"); } /////////////////////////////////////////////////////////////////////////////////// // _isr_dma() // This ISR handles up to 8 IRQs generated by 8 independant channels of the // multi_dma component. It acknowledges the interrupt and reset the synchronisation // variable _dma_busy[i], after copying the status into the _dma_status[i] variable. /////////////////////////////////////////////////////////////////////////////////// void _isr_dma_indexed( unsigned int dma_id ) { volatile unsigned int* dma_address; // compute DMA channel address dma_address = (unsigned int*)&seg_dma_base + (dma_id * DMA_SPAN); // save DMA channel status _dma_status[dma_id] = dma_address[DMA_LEN]; /* save status */ // reset DMA channel dma_address[DMA_RESET] = 0; /* reset IRQ */ // release DMA channel _dma_busy[dma_id] = 0; /* release DMA */ } void _isr_dma_0() { _isr_dma_indexed(0); } void _isr_dma_1() { _isr_dma_indexed(1); } void _isr_dma_2() { _isr_dma_indexed(2); } void _isr_dma_3() { _isr_dma_indexed(3); } void _isr_dma_4() { _isr_dma_indexed(4); } void _isr_dma_5() { _isr_dma_indexed(5); } void _isr_dma_6() { _isr_dma_indexed(6); } void _isr_dma_7() { _isr_dma_indexed(7); } /////////////////////////////////////////////////////////////////////////////////// // _isr_ioc() // There is only one IOC controler shared by all tasks. It acknowledge the IRQ // using the ioc base address, save the status, and set the _ioc_done variable // to signal completion. /////////////////////////////////////////////////////////////////////////////////// void _isr_ioc() { volatile unsigned int* ioc_address; ioc_address = (unsigned int*)&seg_ioc_base; _ioc_status = ioc_address[BLOCK_DEVICE_STATUS]; /* save status & reset IRQ */ _ioc_done = 1; /* signals completion */ } /////////////////////////////////////////////////////////////////////////////////// // _isr_timer_* (* = 0,1,2,3,4,5,6,7) // This ISR handles up to 8 IRQs generated by 8 independant timers. // It acknowledges the IRQ on TIMER[*] and displays a message on TTY0 /////////////////////////////////////////////////////////////////////////////////// void _isr_timer_indexed(unsigned int timer_id) { volatile unsigned int *timer_address; timer_address = (unsigned int*)&seg_timer_base + (timer_id * TIMER_SPAN); timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */ _puts("\n\n!!! Interrupt timer received from timer "); _putw( timer_id ); _puts(" at cycle "); _putw( _proctime() ); _puts("\n\n"); } void _isr_timer_0() { _isr_timer_indexed(0); } void _isr_timer_1() { _isr_timer_indexed(1); } void _isr_timer_2() { _isr_timer_indexed(2); } void _isr_timer_3() { _isr_timer_indexed(3); } void _isr_timer_4() { _isr_timer_indexed(4); } void _isr_timer_5() { _isr_timer_indexed(5); } void _isr_timer_6() { _isr_timer_indexed(6); } void _isr_timer_7() { _isr_timer_indexed(7); } /////////////////////////////////////////////////////////////////////////////////// // _isr_tty_get_* (* = 0,1,2,3,4,5,6,7,9,10,11,12,13,14,15) // The Giet supports up to 16 TTY terminals. // These 16 ISRs handle the up to 16 IRQs associated to 16 independant // terminals, signaling that a character is available. // There is one communication buffer _tty_get_buf[tty_id] per terminal. // The sychronisation variable _tty_get_full[tty_id], is set by the ISR, // and reset by the OS. // A character is lost if the buffer is full when the ISR is executed. /////////////////////////////////////////////////////////////////////////////////// void _isr_tty_get_indexed(unsigned int tty_id) { volatile unsigned int *tty_address; /* compute terminal base address */ tty_address = (unsigned int*)&seg_tty_base + (tty_id * TTY_SPAN); /* save character and reset IRQ */ _tty_get_buf[tty_id] = (unsigned char)tty_address[TTY_READ]; /* signals character available */ _tty_get_full[tty_id] = 1; } void _isr_tty_get_0() { _isr_tty_get_indexed(0); } void _isr_tty_get_1() { _isr_tty_get_indexed(1); } void _isr_tty_get_2() { _isr_tty_get_indexed(2); } void _isr_tty_get_3() { _isr_tty_get_indexed(3); } void _isr_tty_get_4() { _isr_tty_get_indexed(4); } void _isr_tty_get_5() { _isr_tty_get_indexed(5); } void _isr_tty_get_6() { _isr_tty_get_indexed(6); } void _isr_tty_get_7() { _isr_tty_get_indexed(7); } void _isr_tty_get_8() { _isr_tty_get_indexed(8); } void _isr_tty_get_9() { _isr_tty_get_indexed(9); } void _isr_tty_get_10() { _isr_tty_get_indexed(10); } void _isr_tty_get_11() { _isr_tty_get_indexed(11); } void _isr_tty_get_12() { _isr_tty_get_indexed(12); } void _isr_tty_get_13() { _isr_tty_get_indexed(13); } void _isr_tty_get_14() { _isr_tty_get_indexed(14); } void _isr_tty_get_15() { _isr_tty_get_indexed(15); } ///////////////////////////////////////////////////////////////////////////////////// // _isr_switch // This ISR is in charge of context switch. // It acknowledges the IRQ on TIMER[proc_id] and calls the _ctx_switch() function. ///////////////////////////////////////////////////////////////////////////////////// void _isr_switch() { volatile unsigned int *timer_address; unsigned int proc_id; proc_id = _procid(); timer_address = (unsigned int*)&seg_timer_base + (proc_id * TIMER_SPAN); timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */ _ctx_switch(); }