interrupt.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #include "interrupt.h"
  2. #include "stdint.h"
  3. #include "global.h"
  4. #include "../lib/kernel/print.h"
  5. #include "../lib/kernel/io.h"
  6. char *intr_name[IDT_DESC_CNT]; // 用于保存异常的名字
  7. intr_handler idt_table[IDT_DESC_CNT]; // 中断处理函数数组
  8. /*创建中断门描述符*/
  9. static void make_idt_desc(gate_desc *p_gdesc, uint8_t attr, intr_handler function)
  10. {
  11. p_gdesc->offset_low = (uint32_t)function & 0x0000FFFF;
  12. p_gdesc->selector = SELECTOR_K_CODE;
  13. p_gdesc->dcount = 0;
  14. p_gdesc->attribute = attr;
  15. p_gdesc->offset_high = ((uint32_t)function & 0xFFFF0000) >> 16;
  16. }
  17. /* 初始化中断描述符表*/
  18. static void itd_desc_init(void)
  19. {
  20. int i;
  21. for (i = 0; i < IDT_DESC_CNT; i++)
  22. {
  23. make_idt_desc(&idt[i], IDT_DESC_ATTR_DPL0, intr_entry_table[i]);
  24. }
  25. put_str(" idt_desc_init done\n");
  26. }
  27. /* 初始化可编程中断控制器 8259A */
  28. static void pic_init(void)
  29. {
  30. /* 初始化主片*/
  31. outb(PIC_M_CTRL, 0x11); // ICW1: 边沿触发,级联8259, 需要 ICW4
  32. outb(PIC_M_DATA, 0x20); // ICW2: 起始中断向量号 0x20, 也就是 IRQ[0~7] 为 0x20~0x27
  33. outb(PIC_M_DATA, 0x04); // ICW3: IR2 接从片
  34. outb(PIC_M_DATA, 0x01); // ICW4: 8086 模式, 正常 EOI
  35. /* 初始化从片 */
  36. outb(PIC_S_CTRL, 0x11); // ICW1: 边沿触发,级联8259, 需要 ICW4
  37. outb(PIC_S_DATA, 0x28); // ICW2: 起始中断向量号 0x28, 也就是 IRQ[8~15] 以 0x28~0x2F
  38. outb(PIC_S_DATA, 0x02); // ICW3: 设置从片连接到主片的 IR2 引脚
  39. outb(PIC_S_DATA, 0x01); // ICW4: 8086 模式, 正常 EOI
  40. /* 打开主片上 IR0, 也就是目前只接受时钟产生的中断*/
  41. outb(PIC_M_DATA, 0xfe);
  42. outb(PIC_S_DATA, 0xff);
  43. put_str(" pic_init done\n");
  44. }
  45. static void general_intr_handler(uint8_t vec_nr)
  46. {
  47. if (vec_nr == 0x27 || vec_nr == 0x2f)
  48. {
  49. // IRQ7 和 IRQ15 会产生伪中断,无需处理
  50. // 0x2f 是从片8259A上的最后一个 IRQ 引脚,保留项
  51. return;
  52. }
  53. put_str("int vector: 0x");
  54. put_int(vec_nr);
  55. put_char('\n');
  56. }
  57. static void exception_init(void)
  58. {
  59. int i;
  60. for (i = 0; i < IDT_DESC_CNT; i++)
  61. {
  62. /*idt_table 数组中的函数是进入中断后根据中断向量号调用的,见 kernel/kernel.S 的 call [itd_table + %1*4]*/
  63. idt_table[i] = general_intr_handler; // 默认为 general_intr_handler
  64. intr_name[i] = "unknown";
  65. }
  66. intr_name[0] = "#DE Divide Error";
  67. intr_name[1] = "#DB Debug Exception";
  68. intr_name[2] = "NMI Interrupt";
  69. intr_name[3] = "#BP Breakpoint Exception";
  70. intr_name[4] = "#OF Overflow Exception";
  71. intr_name[5] = "#BR BOUND Range Exceeded Exception";
  72. intr_name[6] = "#UD Invalid Opcode Exception";
  73. intr_name[7] = "#NM Device Not Available Exception";
  74. intr_name[8] = "#DF Double Fault Exception";
  75. intr_name[9] = "Coprocessor Segment Overrun";
  76. intr_name[10] = "#TS Invalid TSS Exception";
  77. intr_name[11] = "#NP Segment Not Present";
  78. intr_name[12] = "#SS Stack Fault Exception";
  79. intr_name[13] = "#GP General Protection Exception";
  80. intr_name[14] = "#PF Page-Fault Exception";
  81. // intr_name[15] 第 15 项是 intel 保留项,未使用
  82. intr_name[16] = "#MF x87 FPU Floating-Point Error";
  83. intr_name[17] = "#AC Alignment Check Exception";
  84. intr_name[18] = "#MC Machine-Check Exception";
  85. intr_name[19] = "#XF SIMD Floating-Point Exception";
  86. put_str(" exception_init done\n");
  87. }
  88. /* 中断初始化主函数 */
  89. void itd_init(void)
  90. {
  91. put_str("init_idt start\n");
  92. itd_desc_init(); // 初始化中断描述符表
  93. exception_init(); // 完成一般中断处理函数注册及异常名称注册
  94. pic_init(); // 初始化可编程中断控制器8259A
  95. /* 加载 idt */
  96. uint64_t idt_operand = ((sizeof(idt) - 1) | ((uint64_t)((uint32_t)idt << 16)));
  97. asm volatile("lidt %0" ::"m"(idt_operand));
  98. put_str("itd_init done\n");
  99. }