Initial checkin of toy OS project.
[os.git] / kernel / hal / interrupts.c
1 //+----------------------------------------------------------------------------
2 //
3 // File:     interrupts.c
4 //
5 // Module:   
6 //
7 // Synopsis: 
8 //
9 // Created:  sgasch  6 Jul 2003
10 //
11 //+----------------------------------------------------------------------------
12
13 #include "kernel.h"
14 #include "hal.h"
15 #include "rtl.h"
16 #include "interrupts.h"
17
18 IDT_ENTRY g_IDT[NUM_IDT_ENTRIES];
19 INTERRUPT_HANDLER g_InterruptHandlerTable[NUM_IDT_ENTRIES];
20 ULONG g_uInterruptsEnabled = 0;
21
22 void
23 HalEnableInterrupts(void)
24 {
25     g_uInterruptsEnabled++;
26     ASSERT(g_uInterruptsEnabled == 1);
27
28     __asm__ __volatile__ (
29         "sti"
30         );
31 }
32
33 void
34 HalDisableInterrupts(void)
35 {
36     g_uInterruptsEnabled--;
37     ASSERT(g_uInterruptsEnabled == 0);
38
39     __asm__ __volatile__ (
40         "cli"
41         );
42 }
43
44
45 //+----------------------------------------------------------------------------
46 //
47 // Function:  DoNothing
48 //
49 // Synopsis:  The default interrupt handler, do nothing
50 //
51 // Arguments: INTERRUPT_STATE *p
52 //            
53 // Returns:   void
54 //
55 //+----------------------------------------------------------------------------
56 void HalDoNothing(INTERRUPT_STATE *p)
57 {
58     ;
59 }
60
61
62 //+----------------------------------------------------------------------------
63 //
64 // Function:  InterruptSendIrqEoi
65 //
66 // Synopsis:  Send Interrupt ReQuest End Of Interrupt to the PIC.
67 //
68 // Arguments: INTERRUPT_STATE *is
69 //            
70 // Returns:   void
71 //
72 //+----------------------------------------------------------------------------
73 void 
74 HalInterruptSendIrqEoi(INTERRUPT_STATE *is)
75 {
76     ULONG uIrq;
77     BYTE bCommand;
78     BYTE *p = (BYTE *)0x000B8000;
79
80     *p = '3';
81     *(p + 1) = ' ';
82     
83     if ((is->uIntNum >= FIRST_EXTERNAL_INT) &&
84         (is->uIntNum <= LAST_EXTERNAL_INT))
85     {
86         uIrq = (is->uIntNum - FIRST_EXTERNAL_INT);
87         ASSERT(uIrq >= 0);
88         ASSERT(uIrq <= 15);
89         bCommand = 0x60 | (uIrq & 0x7);
90         
91         if (uIrq < 8)
92         {
93             // EOI to master PIC
94             out(0x20, bCommand);
95             HalIoDelay();
96         }
97         else 
98         {
99             // EOI to slave PIC and cascade line EOI to master PIC
100             out(0xA0, bCommand);
101             out(0x20, 0x62);
102             HalIoDelay();
103         }
104     }
105
106     *p = '4';
107     *(p + 1) = ' ';
108 }
109
110 //+----------------------------------------------------------------------------
111 //
112 // Function:  InterruptInitializeGate
113 //
114 // Synopsis:  Initializes an interrupt gate with given handler address
115 //            and descriptor privilege level.
116 //
117 // Arguments: IDT_ENTRY *pEntry,
118 //            void *pPreamble,
119 //            ULONG uDpl
120 //            
121 // Returns:   void
122 //
123 //+----------------------------------------------------------------------------
124 void 
125 HalInterruptInitializeGate(IDT_ENTRY *pEntry, 
126                            void *pPreamble,
127                            ULONG uDpl)
128 {
129     ULONG u = (ULONG)pPreamble;
130
131     pEntry->i.offsetLow = u & 0xffff;
132     pEntry->i.segmentSelector = (1<<3);
133     pEntry->i.reserved = 0;
134     pEntry->i.signature = 0x70; // == 01110000b
135     pEntry->i.dpl = uDpl;
136     pEntry->i.present = 1;
137     pEntry->i.offsetHigh = u >> 16;
138 }
139
140
141 //+----------------------------------------------------------------------------
142 //
143 // Function:  InterruptInstallHandler
144 //
145 // Synopsis:  Installs an interrupt handler routine for a given IRQ number
146 //
147 // Arguments: ULONG uInterruptNumber,
148 //            INTERRUPT_HANDLER pHandler
149 //            
150 // Returns:   void
151 //
152 //+----------------------------------------------------------------------------
153 void 
154 HalInterruptInstallHandler(ULONG uInterruptNumber,
155                            INTERRUPT_HANDLER pHandler)
156 {
157     ASSERT(uInterruptNumber < ARRAY_LENGTH(g_InterruptHandlerTable));
158     
159     g_InterruptHandlerTable[uInterruptNumber] = pHandler;
160 }
161
162
163 //+----------------------------------------------------------------------------
164 //
165 // Function:  InterruptInitialize
166 //
167 // Synopsis:  Initialize the interrupt system
168 //
169 // Arguments: void
170 //            
171 // Returns:   void
172 //
173 //+----------------------------------------------------------------------------
174 void 
175 HalInitializeInterrupts(void)
176 {
177     ULONG uPreambleEntrySize = (ULONG)&HalInterruptHandlerPreambleAfter;
178     ULONG u;
179     ULONG uDpl;
180     USHORT uLimitAndBase[3];
181     BYTE *p;
182
183     //
184     // Determine the size of an interrupt preamble table entry.
185     //
186     uPreambleEntrySize -= (ULONG)&HalInterruptHandlerPreambleBefore;
187
188     //
189     // Set the base interrupt number for each PIC.  See comments in
190     // intsupport.asm.
191     //
192     HalInterruptInitializePICs();
193
194     //
195     // Build interrupt descriptor table
196     //
197     for (u = 0, p = &HalInterruptHandlerPreamble;
198          u < ARRAY_LENGTH(g_IDT);
199          u++, p += uPreambleEntrySize)
200     {
201         uDpl = (u == 0x2E) ? USER_PRIVILEGE : KERNEL_PRIVILEGE;
202
203         HalInterruptInitializeGate(&(g_IDT[u]), p, uDpl);
204         HalInterruptInstallHandler(u, HalDoNothing);
205     }
206
207     //
208     // Install the IDT
209     //
210     u = (ULONG)&(g_IDT);
211     uLimitAndBase[0] = 8 * NUM_IDT_ENTRIES;
212     uLimitAndBase[1] = (USHORT)(u & 0xffff);
213     uLimitAndBase[2] = (USHORT)(u >> 16);
214     
215     HalInterruptLoadIDTR((void *)uLimitAndBase);
216
217     //
218     // Install interrupt handlers
219     //
220     HalInterruptInstallHandler(IRQ0, HalTimerInt);
221     HalInterruptInstallHandler(IRQ1, HalKeyboardInt);
222
223     out(0x21, 0xFC);                          // turn on keyboard and timer
224
225     //
226     // Enable interrupts
227     //
228     HalEnableInterrupts();
229 }
230