Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

interrupt.c

Go to the documentation of this file.
00001 /*!     \file arch/i386/kernel/interrupt.c
00002  *      \brief Interrupt manager.
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update: 2004-01-24
00005  *      \note Copyright (&copy;) 2003 Andrea Righi
00006  *
00007  *      \todo
00008  *              Stack fault exception in kernel mode must be
00009  *              managed by a task-gate in the IDT.
00010  *              We have to define a TSS for the double fault
00011  *              exception. When the double fault task will be
00012  *              called we'll have a stack fault exception in
00013  *              kernel-mode.
00014  *              In user-mode there are no problems, because there
00015  *              is also the privileged stack. In this case a stack
00016  *              fault is managed like a normal page fault.
00017  */
00018 
00019 #include <const.h>
00020 
00021 #include <arch/exception.h>
00022 #include <arch/i386.h>
00023 #include <arch/mem.h>
00024 #include <arch/paging.h>
00025 
00026 #include <kernel/clock.h>
00027 #include <kernel/console.h>
00028 #include <kernel/floppy.h>
00029 #include <kernel/keyboard.h>
00030 #include <kernel/serial.h>
00031 #include <kernel/speaker.h>
00032 #include <kernel/syscall.h>
00033 #include <kernel/task.h>
00034 
00035 #include <net/rtl8139.h>
00036 
00037 #include <arch/interrupt.h>
00038 
00039 //! Interrupt Descriptor Table (IDT).
00040 volatile idt_entry_t idt[IDT_DIM];
00041 
00042 //! Value of Interrupt Descriptor Table Register.
00043 idt_reg_t idt_ptr;
00044 
00045 // --- Extern IRQ entry points ---------------------------------------- //
00046 
00047 extern void     _irq_00, _irq_01, _irq_02, _irq_03, _irq_04, _irq_05, _irq_06, _irq_07;
00048 extern void     _irq_08, _irq_09, _irq_0A, _irq_0B, _irq_0C, _irq_0D, _irq_0E, _irq_0F;
00049 extern void     _irq_80;
00050 extern void     _irq_unhand;
00051 
00052 // --- Extern EXC entry points ---------------------------------------- //
00053 
00054 extern void     _exc_00, _exc_01, _exc_02, _exc_03, _exc_04, _exc_05, _exc_06, _exc_07;
00055 extern void     _exc_08, _exc_09, _exc_0A, _exc_0B, _exc_0C, _exc_0D, _exc_0E, _exc_0F;
00056 extern void     _exc_unhand;
00057 
00058 //! \brief Disable an IRQ line.
00059 //! \param IRQ The IRQ line to disable.
00060 void disable_IRQ(uint8_t IRQ)
00061 {
00062         uint8_t mask;
00063 
00064         if (IRQ > 15) return;
00065 
00066         if (IRQ < 8)
00067         {
00068                 // Master                                               //
00069                 mask = inportb(PORT_INT_MASK_M);
00070                 mask |= 1 << IRQ;
00071                 outportb(PORT_INT_MASK_M, mask);
00072         }
00073         else
00074         {
00075                 // Slave                                                //
00076                 mask = inportb(PORT_INT_MASK_S);
00077                 mask |= 1 << (IRQ-8);
00078                 outportb(PORT_INT_MASK_S, mask);
00079         }
00080 }
00081 
00082 //! \brief Enable an IRQ line.
00083 //! \param IRQ The IRQ line to enable.
00084 void enable_IRQ(uint8_t IRQ)
00085 {
00086         uint8_t mask;
00087 
00088         if (IRQ > 15) return;
00089 
00090         if (IRQ < 8)
00091         {
00092                 // Master                                               //
00093                 mask = inportb(PORT_INT_MASK_M);
00094                 mask &= ~(1 << IRQ);
00095                 outportb(PORT_INT_MASK_M, mask);
00096         }
00097         else
00098         {
00099                 // Slave                                                //
00100                 mask = inportb(PORT_INT_MASK_S);
00101                 mask &= ~(1 << (IRQ-8));
00102                 outportb(PORT_INT_MASK_S, mask);
00103         }
00104 }
00105 
00106 //! \brief Initialize the Programmable Interrupt Controllers (PICs).
00107 //! \note
00108 //!     The AT and PS/2 have 2 interrupt controllers to issue the IRQs,
00109 //!     one master and one slaved at IRQ2.
00110 //!     This routine initialize the 8259 interrupt controllers, using
00111 //!     vector [0x20..0x2F] for [IRQ0..IRQ15] (0x20..0x27 for master
00112 //!     and 0x28..0x2F for slave).
00113 void reprogram_PIC()
00114 {
00115         // Start initialization for master & slave                      //
00116         outportb(PORT_8259_M, 0x11);
00117         outportb(PORT_8259_S, 0x11);
00118 
00119         outportb(PORT_INT_MASK_M, 0x20); // master base vector          //
00120         outportb(PORT_INT_MASK_S, 0x28); // slave base vector           //
00121 
00122         outportb(PORT_INT_MASK_M, 1 << 2); // IRQ2 cascade to slave     //
00123         outportb(PORT_INT_MASK_S, 2); // cascade on IRQ2                //
00124 
00125         // Finish 8259 initialization                                   //
00126         outportb(PORT_INT_MASK_M, 1);
00127         outportb(PORT_INT_MASK_S, 1);
00128 
00129         // Disable all IRQs for master, except the IRQ2 cascade line.   //
00130         outportb(PORT_INT_MASK_M, ~(1 << 2));
00131         // Disable all IRQs for slave.                                  //
00132         outportb(PORT_INT_MASK_S, 0xFF);
00133 }
00134 
00135 //! An IRQ handler pointer.
00136 typedef struct irq_desc
00137 {
00138         void *handler;
00139 } irq_desc_t;
00140 
00141 //! A table for hardware interrupt handlers only.
00142 static irq_desc_t irq_handler[] =
00143 {
00144         { NULL },
00145         { NULL },
00146         { NULL },
00147         { NULL },
00148         { NULL },
00149         { NULL },
00150         { NULL },
00151         { NULL },
00152 
00153         { NULL },
00154         { NULL },
00155         { NULL },
00156         { NULL },
00157         { NULL },
00158         { NULL },
00159         { NULL },
00160         { NULL }
00161 };
00162 
00163 //! Total number of hardware interrupts.
00164 #define TOT_IRQ ( sizeof(irq_handler) / sizeof(irq_desc_t) )
00165 
00166 //! \brief Install an IRQ handler routine.
00167 //! \param irq The interrupt number.
00168 //! \param handler A pointer to the handler routine.
00169 //! \note
00170 //!     This is valid only for hardware interrupts. You cannot
00171 //!     install a software interrupt handler in this way.
00172 void install_irq_handler(uint8_t irq, void *handler)
00173 {
00174         dword IF = GET_IF();
00175 
00176         if ( irq > TOT_IRQ )
00177                 return;
00178 
00179         disable();
00180 
00181         irq_handler[irq].handler = handler;
00182         enable_IRQ(irq);
00183 
00184         SET_IF(IF);
00185         return;
00186 }
00187 
00188 //! \brief Manage an unhandled interrupt.
00189 //! \param irq The interrupt number.
00190 void unhandled_interrupt(uint8_t irq)
00191 {
00192         set_color(LIGHT_RED);
00193         kprintf("\n\rUnhandled IRQ #%03u from task [%s] (%u)!!!", irq, get_pname(), get_pid());
00194         set_color(DEFAULT_COLOR);
00195         beep();
00196 
00197         // Kill the task                                                //
00198         if ( kill(get_pid()) == TRUE )
00199         {
00200                 kprintf("\n\rTask [%s] (%u) killed!\n\r",
00201                         get_pname(), get_pid()
00202                 );
00203         }
00204         else
00205                 kprintf("\n\rUnable to kill the task [%s] (%u)", get_pname(), get_pid());
00206 }
00207 
00208 /*! \ingroup KInterrupt */
00209 //! \brief
00210 //!     This is the default interrupt handler. It is invoked
00211 //!     every time an interrupt occurs.
00212 //! \param c The context of the current task after the interrupt.
00213 //! \note
00214 //!     Only hardware interrupts and #MINIRIGHI_INT are accepted.
00215 //!     In the other cases we assume the interrupt is unhandled!
00216 void default_handler(irq_context_t *c)
00217 {
00218         if ( c->IRQ < sizeof(irq_handler) )
00219         {
00220                 // An hardware interrupt occurs                         //
00221                 // Call the interrupt handler if exists                 //
00222                 if ( irq_handler[c->IRQ].handler != NULL )
00223                 {
00224                         // Pointer to the handler function              //
00225                         int (*p)()=(void *)irq_handler[c->IRQ].handler;
00226                         (*p)();
00227                 }
00228                 else
00229                 {
00230                         // Unhandled interrupt!                         //
00231                         unhandled_interrupt(c->IRQ);
00232                 }
00233         }
00234         else
00235         {
00236                 // Software interrupt occurs                            //
00237                 // (only MINIRIGHI INT is accepted)                     //
00238                 switch ( c->IRQ )
00239                 {
00240                         case MINIRIGHI_INT:
00241                                 syscall_handler(&(c->eax), &(c->ebp));
00242                         break;
00243 
00244                         default:
00245                                 unhandled_interrupt(c->IRQ);
00246                         break;
00247                 }
00248                 return;
00249         }
00250         // Re-enable the IRQ line (master channel)                      //
00251         outportb(PORT_8259_M, EOI);
00252         if ( c->IRQ >= 8 )
00253                 // Re-enable also the IRQ slave channel                 //
00254                 outportb(PORT_8259_S, EOI);
00255 }
00256 
00257 //! \brief Set up an IDT entry.
00258 //! \param i The index of the entry.
00259 //! \param selector The selector for the interrupt handler.
00260 //! \param offset The entry point of the handler.
00261 //! \param attribs The descriptor attributes.
00262 //! \param paramcnt
00263 //!     How many items must be copied from the previous stack to the
00264 //!     new privileged stack.
00265 void setup_IDT_entry(byte i, word selector, dword offset, byte attribs, byte paramcnt)
00266 {
00267         dword IF = GET_IF();
00268 
00269         disable();
00270 
00271         idt[i].offset0_15 =  offset & 0xFFFF;
00272         idt[i].offset16_31 = offset >> 16;
00273         idt[i].selector = selector;
00274         idt[i].attribs = attribs;
00275         idt[i].paramcnt = paramcnt;
00276 
00277         SET_IF(IF);
00278 }
00279 
00280 //! \brief Initialize the IDT (Interrupt Descriptor Table).
00281 void install_IDT()
00282 {
00283         unsigned i;
00284 
00285         // Initialize exception handlers (0x00..0x1F)                   //
00286         for(i=0x00; i<=0x1F; i++)
00287                 setup_IDT_entry(i, KERNEL_CODE, (dword)&_exc_unhand, INT_GATE, 0);
00288 
00289         // Setup the IDT entries for exceptions                         //
00290         setup_IDT_entry(0x00, KERNEL_CODE, (dword)&_exc_00, INT_GATE, 0);
00291         setup_IDT_entry(0x01, KERNEL_CODE, (dword)&_exc_01, INT_GATE, 0);
00292         setup_IDT_entry(0x02, KERNEL_CODE, (dword)&_exc_02, INT_GATE, 0);
00293         setup_IDT_entry(0x03, KERNEL_CODE, (dword)&_exc_03, INT_GATE, 0);
00294         setup_IDT_entry(0x04, KERNEL_CODE, (dword)&_exc_04, INT_GATE, 0);
00295         setup_IDT_entry(0x05, KERNEL_CODE, (dword)&_exc_05, INT_GATE, 0);
00296         setup_IDT_entry(0x06, KERNEL_CODE, (dword)&_exc_06, INT_GATE, 0);
00297         setup_IDT_entry(0x07, KERNEL_CODE, (dword)&_exc_07, INT_GATE, 0);
00298         setup_IDT_entry(0x08, KERNEL_CODE, (dword)&_exc_08, INT_GATE, 0);
00299         setup_IDT_entry(0x09, KERNEL_CODE, (dword)&_exc_09, INT_GATE, 0);
00300         setup_IDT_entry(0x0A, KERNEL_CODE, (dword)&_exc_0A, INT_GATE, 0);
00301         setup_IDT_entry(0x0B, KERNEL_CODE, (dword)&_exc_0B, INT_GATE, 0);
00302         setup_IDT_entry(0x0C, KERNEL_CODE, (dword)&_exc_0C, INT_GATE, 0);
00303         setup_IDT_entry(0x0D, KERNEL_CODE, (dword)&_exc_0D, INT_GATE, 0);
00304         setup_IDT_entry(0x0E, KERNEL_CODE, (dword)&_exc_0E, INT_GATE, 0);
00305         setup_IDT_entry(0x0F, KERNEL_CODE, (dword)&_exc_0F, INT_GATE, 0);
00306 
00307         // Initialize interrupt handlers 0x20..0xFF                     //
00308         for(i=0x20; i<=0xFF; i++)
00309                 setup_IDT_entry(i, KERNEL_CODE, (dword)&_irq_unhand, INT_GATE, 0);
00310 
00311         // Setup the IDT entries for IRQs                               //
00312         setup_IDT_entry(0x20, KERNEL_CODE, (dword)&_irq_00, INT_GATE, 0);
00313         setup_IDT_entry(0x21, KERNEL_CODE, (dword)&_irq_01, INT_GATE, 0);
00314         setup_IDT_entry(0x22, KERNEL_CODE, (dword)&_irq_02, INT_GATE, 0);
00315         setup_IDT_entry(0x23, KERNEL_CODE, (dword)&_irq_03, INT_GATE, 0);
00316         setup_IDT_entry(0x24, KERNEL_CODE, (dword)&_irq_04, INT_GATE, 0);
00317         setup_IDT_entry(0x25, KERNEL_CODE, (dword)&_irq_05, INT_GATE, 0);
00318         setup_IDT_entry(0x26, KERNEL_CODE, (dword)&_irq_06, INT_GATE, 0);
00319         setup_IDT_entry(0x27, KERNEL_CODE, (dword)&_irq_07, INT_GATE, 0);
00320         setup_IDT_entry(0x28, KERNEL_CODE, (dword)&_irq_08, INT_GATE, 0);
00321         setup_IDT_entry(0x29, KERNEL_CODE, (dword)&_irq_09, INT_GATE, 0);
00322         setup_IDT_entry(0x2A, KERNEL_CODE, (dword)&_irq_0A, INT_GATE, 0);
00323         setup_IDT_entry(0x2B, KERNEL_CODE, (dword)&_irq_0B, INT_GATE, 0);
00324         setup_IDT_entry(0x2C, KERNEL_CODE, (dword)&_irq_0C, INT_GATE, 0);
00325         setup_IDT_entry(0x2D, KERNEL_CODE, (dword)&_irq_0D, INT_GATE, 0);
00326         setup_IDT_entry(0x2E, KERNEL_CODE, (dword)&_irq_0E, INT_GATE, 0);
00327         setup_IDT_entry(0x2F, KERNEL_CODE, (dword)&_irq_0F, INT_GATE, 0);
00328 
00329         // Install Minirighi system calls handler                       //
00330         setup_IDT_entry(MINIRIGHI_INT, KERNEL_CODE, (dword)&_irq_80, TRAP_GATE | DPL_3, 0);
00331 
00332         // Set up the IDT pointer                                       //
00333         idt_ptr.limit = (IDT_DIM * sizeof(idt_entry_t) - 1);
00334         * (dword *)idt_ptr.base = ((dword)&idt);
00335 
00336         // Load info into IDTR register                                 //
00337         __asm__("lidtl (%0)" : : "r"((dword)&idt_ptr));
00338 }

Generated on Fri Feb 20 15:32:15 2004 for Minirighi by doxygen1.2.18