00001 #include "threads/interrupt.h"
00002
00003 #include <debug.h>
00004 #include <inttypes.h>
00005 #include <stdint.h>
00006 #include <stdio.h>
00007 #include "threads/flags.h"
00008 #include "threads/intr-stubs.h"
00009 #include "threads/io.h"
00010 #include "threads/thread.h"
00011 #include "threads/vaddr.h"
00012 #include "devices/timer.h"
00013
00014
00015
00016
00017 #define PIC0_CTRL 0x20
00018 #define PIC0_DATA 0x21
00019 #define PIC1_CTRL 0xa0
00020 #define PIC1_DATA 0xa1
00021 #define IRQ_CASCADE0 2
00022 #define IRQ_CASCADE1 9
00023
00024
00025
00026
00027 #define PIC0_CTRL 0x20
00028 #define PIC0_DATA 0x21
00029 #define PIC1_CTRL 0xa0
00030 #define PIC1_DATA 0xa1
00031
00032
00033 #define INTR_CNT 256
00034
00035
00036
00037
00038
00039 static uint64_t idt[INTR_CNT];
00040
00041
00042 static intr_handler_func *intr_handlers[INTR_CNT];
00043
00044
00045 static const char *intr_names[INTR_CNT];
00046
00047
00048 static uint8_t pic_mask[2];
00049
00050
00051
00052
00053
00054
00055
00056
00057 static bool in_external_intr;
00058 static bool yield_on_return;
00059
00060
00061 static void pic_init (void);
00062 static void pic_end_of_interrupt (int irq);
00063
00064
00065 static uint64_t make_intr_gate (void (*) (void), int dpl);
00066 static uint64_t make_trap_gate (void (*) (void), int dpl);
00067 static inline uint64_t make_idtr_operand (uint16_t limit, void *base);
00068
00069
00070 void intr_handler (struct intr_frame *args);
00071
00072
00073 enum intr_level
00074 intr_get_level (void)
00075 {
00076 uint32_t flags;
00077
00078
00079
00080
00081
00082 asm volatile ("pushfl; popl %0" : "=g" (flags));
00083
00084 return flags & FLAG_IF ? INTR_ON : INTR_OFF;
00085 }
00086
00087
00088
00089 enum intr_level
00090 intr_set_level (enum intr_level level)
00091 {
00092 return level == INTR_ON ? intr_enable () : intr_disable ();
00093 }
00094
00095
00096 enum intr_level
00097 intr_enable (void)
00098 {
00099 enum intr_level old_level = intr_get_level ();
00100 ASSERT (!intr_context ());
00101
00102
00103
00104
00105
00106 asm volatile ("sti");
00107
00108 return old_level;
00109 }
00110
00111
00112 enum intr_level
00113 intr_disable (void)
00114 {
00115 enum intr_level old_level = intr_get_level ();
00116
00117
00118
00119
00120 asm volatile ("cli" : : : "memory");
00121
00122 return old_level;
00123 }
00124
00125
00126 void
00127 intr_init (void)
00128 {
00129 uint64_t idtr_operand;
00130 int i;
00131
00132
00133 pic_init ();
00134
00135
00136 for (i = 0; i < INTR_CNT; i++)
00137 idt[i] = make_intr_gate (intr_stubs[i], 0);
00138
00139
00140
00141
00142 idtr_operand = make_idtr_operand (sizeof idt - 1, idt);
00143 asm volatile ("lidt %0" : : "m" (idtr_operand));
00144
00145
00146 for (i = 0; i < INTR_CNT; i++)
00147 intr_names[i] = "unknown";
00148 intr_names[0] = "#DE Divide Error";
00149 intr_names[1] = "#DB Debug Exception";
00150 intr_names[2] = "NMI Interrupt";
00151 intr_names[3] = "#BP Breakpoint Exception";
00152 intr_names[4] = "#OF Overflow Exception";
00153 intr_names[5] = "#BR BOUND Range Exceeded Exception";
00154 intr_names[6] = "#UD Invalid Opcode Exception";
00155 intr_names[7] = "#NM Device Not Available Exception";
00156 intr_names[8] = "#DF Double Fault Exception";
00157 intr_names[9] = "Coprocessor Segment Overrun";
00158 intr_names[10] = "#TS Invalid TSS Exception";
00159 intr_names[11] = "#NP Segment Not Present";
00160 intr_names[12] = "#SS Stack Fault Exception";
00161 intr_names[13] = "#GP General Protection Exception";
00162 intr_names[14] = "#PF Page-Fault Exception";
00163 intr_names[16] = "#MF x87 FPU Floating-Point Error";
00164 intr_names[17] = "#AC Alignment Check Exception";
00165 intr_names[18] = "#MC Machine-Check Exception";
00166 intr_names[19] = "#XF SIMD Floating-Point Exception";
00167 }
00168
00169
00170
00171
00172
00173 static void
00174 register_handler (uint8_t vec_no, int dpl, enum intr_level level,
00175 intr_handler_func *handler, const char *name)
00176 {
00177 ASSERT (intr_handlers[vec_no] == NULL);
00178 if (level == INTR_ON)
00179 idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
00180 else
00181 idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
00182 intr_handlers[vec_no] = handler;
00183 intr_names[vec_no] = name;
00184 }
00185
00186
00187
00188
00189 void
00190 intr_register_ext (uint8_t vec_no, intr_handler_func *handler,
00191 const char *name)
00192 {
00193 ASSERT (vec_no >= 0x20 && vec_no <= 0x2f);
00194 register_handler (vec_no, 0, INTR_OFF, handler, name);
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 void
00211 intr_register_int (uint8_t vec_no, int dpl, enum intr_level level,
00212 intr_handler_func *handler, const char *name)
00213 {
00214 ASSERT (vec_no < 0x20 || vec_no > 0x2f);
00215 register_handler (vec_no, dpl, level, handler, name);
00216 }
00217
00218
00219
00220 bool
00221 intr_context (void)
00222 {
00223 return in_external_intr;
00224 }
00225
00226
00227
00228
00229
00230 void
00231 intr_yield_on_return (void)
00232 {
00233 ASSERT (intr_context ());
00234 yield_on_return = true;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 static void
00247 pic_init (void)
00248 {
00249
00250 outb (PIC0_DATA, 0xff);
00251 outb (PIC1_DATA, 0xff);
00252
00253
00254 outb (PIC0_CTRL, 0x11);
00255 outb (PIC0_DATA, 0x20);
00256 outb (PIC0_DATA, 0x04);
00257 outb (PIC0_DATA, 0x01);
00258
00259
00260 outb (PIC1_CTRL, 0x11);
00261 outb (PIC1_DATA, 0x28);
00262 outb (PIC1_DATA, 0x02);
00263 outb (PIC1_DATA, 0x01);
00264
00265
00266 outb (PIC0_DATA, 0x00);
00267 outb (PIC1_DATA, 0x00);
00268 pic_mask[0] = 0;
00269 pic_mask[1] = 0;
00270 }
00271
00272
00273
00274
00275 static void
00276 pic_end_of_interrupt (int irq)
00277 {
00278 ASSERT (irq >= 0x20 && irq < 0x30);
00279
00280
00281 outb (0x20, 0x20);
00282
00283
00284 if (irq >= 0x28)
00285 outb (0xa0, 0x20);
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 static uint64_t
00305 make_gate (void (*function) (void), int dpl, int type)
00306 {
00307 uint32_t e0, e1;
00308
00309 ASSERT (function != NULL);
00310 ASSERT (dpl >= 0 && dpl <= 3);
00311 ASSERT (type >= 0 && type <= 15);
00312
00313 e0 = (((uint32_t) function & 0xffff)
00314 | (SEL_KCSEG << 16));
00315
00316 e1 = (((uint32_t) function & 0xffff0000)
00317 | (1 << 15)
00318 | ((uint32_t) dpl << 13)
00319 | (0 << 12)
00320 | ((uint32_t) type << 8));
00321
00322 return e0 | ((uint64_t) e1 << 32);
00323 }
00324
00325
00326
00327 static uint64_t
00328 make_intr_gate (void (*function) (void), int dpl)
00329 {
00330 return make_gate (function, dpl, 14);
00331 }
00332
00333
00334
00335 static uint64_t
00336 make_trap_gate (void (*function) (void), int dpl)
00337 {
00338 return make_gate (function, dpl, 15);
00339 }
00340
00341
00342
00343 static inline uint64_t
00344 make_idtr_operand (uint16_t limit, void *base)
00345 {
00346 return limit | ((uint64_t) (uint32_t) base << 16);
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 void
00356 intr_handler (struct intr_frame *frame)
00357 {
00358 bool external;
00359 intr_handler_func *handler;
00360
00361
00362
00363
00364
00365 external = frame->vec_no >= 0x20 && frame->vec_no < 0x30;
00366 if (external)
00367 {
00368 ASSERT (intr_get_level () == INTR_OFF);
00369 ASSERT (!intr_context ());
00370
00371 in_external_intr = true;
00372 yield_on_return = false;
00373 }
00374
00375
00376 handler = intr_handlers[frame->vec_no];
00377 if (handler != NULL)
00378 handler (frame);
00379 else if (frame->vec_no == 0x27 || frame->vec_no == 0x2f)
00380 {
00381
00382
00383
00384 }
00385 else
00386 {
00387
00388
00389 intr_dump_frame (frame);
00390 PANIC ("Unexpected interrupt");
00391 }
00392
00393
00394 if (external)
00395 {
00396 ASSERT (intr_get_level () == INTR_OFF);
00397 ASSERT (intr_context ());
00398
00399 in_external_intr = false;
00400 pic_end_of_interrupt (frame->vec_no);
00401
00402 if (yield_on_return)
00403 thread_yield ();
00404 }
00405 }
00406
00407
00408 void
00409 intr_dump_frame (const struct intr_frame *f)
00410 {
00411 uint32_t cr2;
00412
00413
00414
00415
00416
00417
00418 asm ("movl %%cr2, %0" : "=r" (cr2));
00419
00420 printf ("Interrupt %#04x (%s) at eip=%p\n",
00421 f->vec_no, intr_names[f->vec_no], f->eip);
00422 printf (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
00423 printf (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
00424 f->eax, f->ebx, f->ecx, f->edx);
00425 printf (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
00426 f->esi, f->edi, (uint32_t) f->esp, f->ebp);
00427 printf (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
00428 f->cs, f->ds, f->es, f->ss);
00429 }
00430
00431
00432 const char *
00433 intr_name (uint8_t vec)
00434 {
00435 return intr_names[vec];
00436 }
00437
00439 void intr_irq_mask(int irq)
00440 {
00441 if(irq < 8){
00442 pic_mask[0] |= 1 << irq;
00443 outb (PIC0_DATA, pic_mask[0]);
00444 }else{
00445 pic_mask[1] |= 1 << (irq - 8);
00446 outb (PIC1_DATA, pic_mask[1]);
00447 }
00448 }
00449
00451 void intr_irq_unmask(int irq)
00452 {
00453 if(irq >= 8){
00454
00455 if(pic_mask[1] & (1 << (IRQ_CASCADE1 - 8)))
00456 pic_mask[1] &= ~(1 << (IRQ_CASCADE1 - 8));
00457
00458 pic_mask[1] &= ~(1 << (irq - 8));
00459 outb(PIC1_DATA, pic_mask[1]);
00460
00461
00462 if(pic_mask[0] & (1 << IRQ_CASCADE0))
00463 irq = IRQ_CASCADE0;
00464 }
00465
00466 if(irq < 8){
00467 pic_mask[0] &= ~(1 << irq);
00468 outb (PIC0_DATA, pic_mask[0]);
00469 }
00470
00471 }
00472
00473
00474 bool intr_is_registered(uint8_t vec_no)
00475 {
00476 return (intr_handlers[vec_no] != NULL);
00477 }