Break GDT, TSS out of init.c, mmu.h.
[pintos-anon] / src / threads / interrupt.c
1 #include "interrupt.h"
2 #include <inttypes.h>
3 #include <stdint.h>
4 #include "intr-stubs.h"
5 #include "debug.h"
6 #include "gdt.h"
7 #include "io.h"
8 #include "lib.h"
9 #include "mmu.h"
10 #include "thread.h"
11 #include "timer.h"
12
13 /* Number of x86 interrupts. */
14 #define INTR_CNT 256
15
16 /* The Interrupt Descriptor Table (IDT).  The format is fixed by
17    the CPU.  See [IA32-v3] sections 5.10, 5.11, 5.12.1.2. */
18 static uint64_t idt[INTR_CNT];
19
20 /* Interrupt handler functions for each interrupt. */
21 static intr_handler_func *intr_handlers[INTR_CNT];
22
23 /* Names for each interrupt, for debugging purposes. */
24 static const char *intr_names[INTR_CNT];
25
26 /* External interrupts are those generated by devices outside the
27    CPU, such as the timer.  External interrupts run with
28    interrupts turned off, so they never nest, nor are they ever
29    pre-empted.  Handlers for external interrupts also may not
30    sleep, although they may invoke intr_yield_on_return() to
31    request that a new process be scheduled just before the
32    interrupt returns. */
33 static bool in_external_intr;   /* Are we processing an external interrupt? */
34 static bool yield_on_return;    /* Should we yield on interrupt return? */
35
36 /* Programmable Interrupt Controller helpers. */
37 static void pic_init (void);
38 static void pic_end_of_interrupt (int irq);
39
40 /* Interrupt Descriptor Table helpers. */
41 static uint64_t make_intr_gate (void (*) (void), int dpl);
42 static uint64_t make_trap_gate (void (*) (void), int dpl);
43
44 /* Interrupt handlers. */
45 void intr_handler (struct intr_frame *args);
46 static intr_handler_func panic NO_RETURN;
47 static intr_handler_func kill NO_RETURN;
48 \f
49 /* Returns the current interrupt status. */
50 enum intr_level
51 intr_get_level (void) 
52 {
53   uint32_t flags;
54   
55   asm ("pushfl; popl %0" : "=g" (flags));
56
57   return flags & FLAG_IF ? INTR_ON : INTR_OFF;
58 }
59
60 /* Enables or disables interrupts as specified by LEVEL and
61    returns the previous interrupt status. */
62 enum intr_level
63 intr_set_level (enum intr_level level) 
64 {
65   return level == INTR_ON ? intr_enable () : intr_disable ();
66 }
67
68 /* Enables interrupts and returns the previous interrupt status. */
69 enum intr_level
70 intr_enable (void) 
71 {
72   enum intr_level old_level = intr_get_level ();
73   asm volatile ("sti");
74   return old_level;
75 }
76
77 /* Disables interrupts and returns the previous interrupt status. */
78 enum intr_level
79 intr_disable (void) 
80 {
81   enum intr_level old_level = intr_get_level ();
82   asm volatile ("cli");
83   return old_level;
84 }
85 \f
86 /* Initializes the interrupt system. */
87 void
88 intr_init (void)
89 {
90   uint64_t idtr_operand;
91   int i;
92
93   pic_init ();
94
95   /* Initialize intr_names. */
96   for (i = 0; i < INTR_CNT; i++)
97     intr_names[i] = "unknown";
98
99   /* Most exceptions require ring 0.
100      Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
101   intr_register (0, 0, INTR_ON, kill, "#DE Divide Error");
102   intr_register (1, 0, INTR_ON, kill, "#DB Debug Exception");
103   intr_register (2, 0, INTR_ON, panic, "NMI Interrupt");
104   intr_register (3, 3, INTR_ON, kill, "#BP Breakpoint Exception");
105   intr_register (4, 3, INTR_ON, kill, "#OF Overflow Exception");
106   intr_register (5, 3, INTR_ON, kill, "#BR BOUND Range Exceeded Exception");
107   intr_register (6, 0, INTR_ON, kill, "#UD Invalid Opcode Exception");
108   intr_register (7, 0, INTR_ON, kill, "#NM Device Not Available Exception");
109   intr_register (8, 0, INTR_ON, panic, "#DF Double Fault Exception");
110   intr_register (9, 0, INTR_ON, panic, "Coprocessor Segment Overrun");
111   intr_register (10, 0, INTR_ON, panic, "#TS Invalid TSS Exception");
112   intr_register (11, 0, INTR_ON, kill, "#NP Segment Not Present");
113   intr_register (12, 0, INTR_ON, kill, "#SS Stack Fault Exception");
114   intr_register (13, 0, INTR_ON, kill, "#GP General Protection Exception");
115   intr_register (16, 0, INTR_ON, kill, "#MF x87 FPU Floating-Point Error");
116   intr_register (17, 0, INTR_ON, panic, "#AC Alignment Check Exception");
117   intr_register (18, 0, INTR_ON, panic, "#MC Machine-Check Exception");
118   intr_register (19, 0, INTR_ON, kill, "#XF SIMD Floating-Point Exception");
119
120   /* Most exceptions can be handled with interrupts turned on.
121      We need to disable interrupts for page faults because the
122      fault address is stored in CR2 and needs to be preserved. */
123   intr_register (14, 0, INTR_OFF, kill, "#PF Page-Fault Exception");
124
125   idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
126   asm volatile ("lidt %0" :: "m" (idtr_operand));
127 }
128
129 /* Registers interrupt VEC_NO to invoke HANDLER, which is named
130    NAME for debugging purposes.  The interrupt handler will be
131    invoked with interrupt status set to LEVEL.
132
133    The handler will have descriptor privilege level DPL, meaning
134    that it can be invoked intentionally when the processor is in
135    the DPL or lower-numbered ring.  In practice, DPL==3 allows
136    user mode to invoke the interrupts and DPL==0 prevents such
137    invocation.  Faults and exceptions that occur in user mode
138    still cause interrupts with DPL==0 to be invoked.  See
139    [IA32-v3] sections 4.5 and 4.8.1.1 for further discussion. */
140 void
141 intr_register (uint8_t vec_no, int dpl, enum intr_level level,
142                intr_handler_func *handler,
143                const char *name) 
144 {
145   /* Make sure this handler isn't already registered to someone
146      else. */
147   ASSERT (intr_handlers[vec_no] == NULL);
148
149   /* Interrupts generated by external hardware (0x20 <= VEC_NO <=
150      0x2f) should specify INTR_OFF for LEVEL.  Otherwise a timer
151      interrupt could cause a task switch during interrupt
152      handling.  Most other interrupts can and should be handled
153      with interrupts enabled. */
154   ASSERT (vec_no < 0x20 || vec_no > 0x2f || level == INTR_OFF);
155
156   if (level == INTR_ON)
157     idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
158   else
159     idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
160   intr_handlers[vec_no] = handler;
161   intr_names[vec_no] = name;
162 }
163
164 /* Returns true during processing of an external interrupt
165    and false at all other times. */
166 bool
167 intr_context (void) 
168 {
169   return in_external_intr;
170 }
171
172 /* During processing of an external interrupt, directs the
173    interrupt handler to yield to a new process just before
174    returning from the interrupt.  May not be called at any other
175    time. */
176 void
177 intr_yield_on_return (void) 
178 {
179   ASSERT (intr_context ());
180   yield_on_return = true;
181 }
182 \f
183 /* 8259A Programmable Interrupt Controller. */
184
185 /* Every PC has two 8259A Programmable Interrupt Controller (PIC)
186    chips.  One is a "master" accessible at ports 0x20 and 0x21.
187    The other is a "slave" cascaded onto the master's IRQ 2 line
188    and accessible at ports 0xa0 and 0xa1.  Accesses to port 0x20
189    set the A0 line to 0 and accesses to 0x21 set the A1 line to
190    1.  The situation is similar for the slave PIC.
191
192    By default, interrupts 0...15 delivered by the PICs will go to
193    interrupt vectors 0...15.  Unfortunately, those vectors are
194    also used for CPU traps and exceptions.  We reprogram the PICs
195    so that interrupts 0...15 are delivered to interrupt vectors
196    32...47 (0x20...0x2f) instead. */
197
198 /* Initializes the PICs.  Refer to [8259A] for details. */
199 static void
200 pic_init (void)
201 {
202   /* Mask all interrupts on both PICs. */
203   outb (0x21, 0xff);
204   outb (0xa1, 0xff);
205
206   /* Initialize master. */
207   outb (0x20, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
208   outb (0x21, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
209   outb (0x21, 0x04); /* ICW3: slave PIC on line IR2. */
210   outb (0x21, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
211
212   /* Initialize slave. */
213   outb (0xa0, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
214   outb (0xa1, 0x28); /* ICW2: line IR0...7 -> irq 0x28...0x2f. */
215   outb (0xa1, 0x02); /* ICW3: slave ID is 2. */
216   outb (0xa1, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
217
218   /* Unmask all interrupts. */
219   outb (0x21, 0x00);
220   outb (0xa1, 0x00);
221 }
222
223 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
224    If we don't acknowledge the IRQ, it will never be delivered to
225    us again, so this is important.  */
226 static void
227 pic_end_of_interrupt (int irq) 
228 {
229   ASSERT (irq >= 0x20 && irq < 0x30);
230
231   /* Acknowledge master PIC. */
232   outb (0x20, 0x20);
233
234   /* Acknowledge slave PIC if this is a slave interrupt. */
235   if (irq >= 0x28)
236     outb (0xa0, 0x20);
237 }
238 \f
239 /* Creates an gate that invokes FUNCTION.
240
241    The gate has descriptor privilege level DPL, meaning that it
242    can be invoked intentionally when the processor is in the DPL
243    or lower-numbered ring.  In practice, DPL==3 allows user mode
244    to call into the gate and DPL==0 prevents such calls.  Faults
245    and exceptions that occur in user mode still cause gates with
246    DPL==0 to be invoked.  See [IA32-v3] sections 4.5 and 4.8.1.1
247    for further discussion.
248
249    TYPE must be either 14 (for an interrupt gate) or 15 (for a
250    trap gate).  The difference is that entering an interrupt gate
251    disables interrupts, but entering a trap gate does not.  See
252    [IA32-v3] section 5.12.1.2 for discussion. */
253 static uint64_t
254 make_gate (void (*function) (void), int dpl, int type)
255 {
256   uint32_t e0, e1;
257
258   ASSERT (function != NULL);
259   ASSERT (dpl >= 0 && dpl <= 3);
260   ASSERT (type >= 0 && type <= 15);
261
262   e0 = (((uint32_t) function & 0xffff)     /* Offset 15:0. */
263         | (SEL_KCSEG << 16));              /* Target code segment. */
264
265   e1 = (((uint32_t) function & 0xffff0000) /* Offset 31:16. */
266         | (1 << 15)                        /* Present. */
267         | ((uint32_t) dpl << 13)           /* Descriptor privilege level. */
268         | (0 << 12)                        /* System. */
269         | ((uint32_t) type << 8));         /* Gate type. */
270
271   return e0 | ((uint64_t) e1 << 32);
272 }
273
274 /* Creates an interrupt gate that invokes FUNCTION with the given
275    DPL. */
276 static uint64_t
277 make_intr_gate (void (*function) (void), int dpl)
278 {
279   return make_gate (function, dpl, 14);
280 }
281
282 /* Creates a trap gate that invokes FUNCTION with the given
283    DPL. */
284 static uint64_t
285 make_trap_gate (void (*function) (void), int dpl)
286 {
287   return make_gate (function, dpl, 15);
288 }
289 \f
290 /* Interrupt handlers. */
291
292 static void dump_intr_frame (struct intr_frame *);
293
294 /* Handler for all interrupts, faults, and exceptions.  This
295    function is called by the assembly language interrupt stubs in
296    intr-stubs.S (see intr-stubs.pl).  ARGS describes the
297    interrupt and the interrupted thread's registers. */
298 void
299 intr_handler (struct intr_frame *args) 
300 {
301   bool external;
302   intr_handler_func *handler;
303
304   external = args->vec_no >= 0x20 && args->vec_no < 0x30;
305   if (external) 
306     {
307       ASSERT (intr_get_level () == INTR_OFF);
308       ASSERT (!intr_context ());
309
310       in_external_intr = true;
311       yield_on_return = false;
312     }
313
314   /* Invoke the interrupt's handler.
315      If there is no handler, invoke the unexpected interrupt
316      handler. */
317   handler = intr_handlers[args->vec_no];
318   if (handler == NULL)
319     handler = panic;
320   handler (args);
321
322   /* Complete the processing of an external interrupt. */
323   if (external) 
324     {
325       ASSERT (intr_get_level () == INTR_OFF);
326       ASSERT (intr_context ());
327
328       in_external_intr = false;
329       pic_end_of_interrupt (args->vec_no); 
330
331       if (yield_on_return) 
332         thread_yield (); 
333     }
334 }
335
336 /* Handler for an interrupt that should not have been invoked. */
337 static void
338 panic (struct intr_frame *regs) 
339 {
340   dump_intr_frame (regs);
341   PANIC ("Panic!");
342 }
343
344 /* Handler for an exception (probably) caused by a user process. */
345 static void
346 kill (struct intr_frame *f) 
347 {
348   /* This interrupt is one (probably) caused by a user process.
349      For example, the process might have tried to access unmapped
350      virtual memory (a page fault).  For now, we simply kill the
351      user process.  Later, we'll want to handle page faults in
352      the kernel.  Real Unix-like operating systems pass most
353      exceptions back to the process via signals, but we don't
354      implement them. */
355      
356   /* The interrupt frame's code segment value tells us where the
357      exception originated. */
358   switch (f->cs)
359     {
360     case SEL_UCSEG:
361       /* User's code segment, so it's a user exception, as we
362          expected. */
363       printk ("%s: dying due to interrupt %#04x (%s).\n",
364               thread_name (thread_current ()),
365               f->vec_no, intr_names[f->vec_no]);
366       dump_intr_frame (f);
367       thread_exit (); 
368
369     case SEL_KCSEG:
370       /* Kernel's code segment, which indicates a kernel bug.
371          Kernel code shouldn't throw exceptions.  (Page faults
372          may cause kernel exceptions--but they shouldn't arrive
373          here.) */
374       printk ("Kernel bug - unexpected interrupt in kernel\n");
375       panic (f);
376
377     default:
378       /* Some other code segment?  Shouldn't happen. */
379       printk ("Interrupt %#04x (%s) in unknown segment %04x\n",
380              f->vec_no, intr_names[f->vec_no], f->cs);
381       thread_exit ();
382     }
383 }
384
385 /* Dumps interrupt frame F to the console, for debugging. */
386 static void
387 dump_intr_frame (struct intr_frame *f) 
388 {
389   uint32_t cr2, ss;
390   asm ("movl %%cr2, %0" : "=r" (cr2));
391   asm ("movl %%ss, %0" : "=r" (ss));
392
393   printk ("Interrupt %#04x (%s) at eip=%p\n",
394           f->vec_no, intr_names[f->vec_no], f->eip);
395   printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
396   printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
397           f->eax, f->ebx, f->ecx, f->edx);
398   printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
399           f->esi, f->edi, (uint32_t) f->esp, f->ebp);
400   printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
401           f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
402 }
403