浏览代码

:new: 中断上半部

fslongjin 3 年之前
父节点
当前提交
d4c07ac4ad
共有 5 个文件被更改,包括 404 次插入8 次删除
  1. 1 0
      kernel/driver/acpi/acpi.c
  2. 59 2
      kernel/driver/interrupt/apic/apic.c
  3. 164 2
      kernel/driver/interrupt/apic/apic.h
  4. 51 0
      kernel/exception/irq.c
  5. 129 4
      kernel/exception/irq.h

+ 1 - 0
kernel/driver/acpi/acpi.c

@@ -112,4 +112,5 @@ void acpi_init()
     kdebug("acpi_RSDT_entry_phys_base=%#018lx", acpi_RSDT_entry_phys_base);
     // 映射RSDT ENTRY的物理地址
     mm_map_phys_addr(ACPI_DESCRIPTION_HEDERS_BASE, acpi_RSDT_entry_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+    kinfo("ACPI module initialized!")
 }

+ 59 - 2
kernel/driver/interrupt/apic/apic.c

@@ -74,7 +74,7 @@ void apic_io_apic_init()
     // 初始化RTE表项,将所有RTE表项屏蔽
     for (int i = 0x10; i < 0x40; i += 2)
     {
-        // 以0x20起始中断向量号,初始化RTE
+        // 以0x20起始中断向量号,初始化RTE
         apic_ioapic_write_rte(i, 0x10020 + ((i - 0x10) >> 1));
     }
 
@@ -285,13 +285,24 @@ void apic_init()
  * @brief 中断服务程序
  *
  * @param rsp 中断栈指针
- * @param number 中断号
+ * @param number 中断向量
  */
 void do_IRQ(struct pt_regs *rsp, ul number)
 {
+
     unsigned char x = io_in8(0x60);
     printk_color(BLUE, WHITE, "(IRQ:%#04x)\tkey code:%#04x\n", number, x);
 
+    irq_desc_t *irq = &interrupt_desc[number - 32];
+
+    // 执行中断上半部处理程序
+    if (irq->handler != NULL)
+        irq->handler(number, irq->parameter, rsp);
+
+    // 向中断控制器发送应答消息
+    if (irq->controller != NULL && irq->controller->ack != NULL)
+        irq->controller->ack(number);
+
     // 向EOI寄存器写入0x00表示结束中断
     io_mfence();
     uint *eoi = (uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI);
@@ -347,4 +358,50 @@ void apic_ioapic_write_rte(unsigned char index, ul value)
     io_mfence();
     *apic_ioapic_map.virtual_data_addr = value & 0xffffffff;
     io_mfence();
+}
+
+// =========== 中断控制操作接口 ============
+void apic_ioapic_enable(ul irq_num)
+{
+    ul index = 0x10 + ((irq_num - 32) << 1);
+    ul value = apic_ioapic_read_rte(index);
+    value &= (~0x10000UL);
+    apic_ioapic_write_rte(index, value);
+}
+
+void apic_ioapic_disable(ul irq_num)
+{
+    ul index = 0x10 + ((irq_num - 32) << 1);
+    ul value = apic_ioapic_read_rte(index);
+    value |= (0x10000UL);
+    apic_ioapic_write_rte(index, value);
+}
+
+ul apic_ioapic_install(ul irq_num, void *arg)
+{
+    struct apic_IO_APIC_RTE_entry *entry = (struct apic_IO_APIC_RTE_entry *)arg;
+    // RTE表项值写入对应的RTE寄存器
+    apic_ioapic_write_rte(0x10 + ((irq_num - 32) << 1), *(ul *)entry);
+    return 0;
+}
+
+void apic_ioapic_uninstall(ul irq_num)
+{
+    // 将对应的RTE表项设置为屏蔽状态
+    apic_ioapic_write_rte(0x10 + ((irq_num - 32) << 1), 0x10000UL);
+}
+
+void apic_ioapic_level_ack(ul irq_num) // 电平触发
+{
+    // 向EOI寄存器写入0x00表示结束中断
+    uint *eoi = (uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI);
+    *eoi = 0x00;
+    *apic_ioapic_map.virtual_EOI_addr = irq_num;
+}
+
+void apic_ioapic_edge_ack(ul irq_num) // 边沿触发
+{
+    // 向EOI寄存器写入0x00表示结束中断
+    uint *eoi = (uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI);
+    *eoi = 0x00;
 }

+ 164 - 2
kernel/driver/interrupt/apic/apic.h

@@ -70,9 +70,163 @@
 // 分频配置寄存器(定时器专用)
 #define LOCAL_APIC_OFFSET_Local_APIC_CLKDIV 0x3e0
 
+/*
 
+1:	LVT	CMCI
+2:	LVT	Timer
+3:	LVT	Thermal Monitor
+4:	LVT	Performace Counter
+5:	LVT	LINT0
+6:	LVT	LINT1
+7:	LVT	Error
 
+*/
+/**
+ * LVT表项
+ * */
+struct apic_LVT
+{
+    uint vector : 8,         // 0-7位全部置为1
+        delivery_mode : 3,   // 第[10:8]位置为100, 表示NMI
+        reserved_1 : 1,      // 第11位保留
+        delivery_status : 1, // 第12位,投递状态 -> 发送挂起
+        polarity : 1,        // 第13位,电平触发极性 存在于LINT0,LINT1
+        remote_IRR : 1,      // 第14位,远程IRR标志位(只读) 存在于LINT0,LINT1
+        trigger_mode : 1,    // 第15位,触发模式(0位边沿触发,1为电平触发) 存在于LINT0,LINT1
+        mask : 1,            // 第16位,屏蔽标志位,(0为未屏蔽, 1为已屏蔽)
+        timer_mode : 2,      // 第[18:17]位,定时模式。(00:一次性定时,   01:周期性定时,  10:指定TSC值计数), 存在于定时器寄存器
+        reserved_2 : 13;     // [31:19]位保留
+
+} __attribute((packed)); // 取消结构体的align
+
+/*
+    ICR
+*/
+
+struct INT_CMD_REG
+{
+    unsigned int vector : 8, // 0~7
+        deliver_mode : 3,    // 8~10
+        dest_mode : 1,       // 11
+        deliver_status : 1,  // 12
+        res_1 : 1,           // 13
+        level : 1,           // 14
+        trigger : 1,         // 15
+        res_2 : 2,           // 16~17
+        dest_shorthand : 2,  // 18~19
+        res_3 : 12;          // 20~31
+
+    union
+    {
+        struct
+        {
+            unsigned int res_4 : 24, // 32~55
+                dest_field : 8;      // 56~63
+        } apic_destination;
+
+        unsigned int x2apic_destination; // 32~63
+    } destination;
+
+} __attribute__((packed));
+
+/**
+ * @brief I/O APIC 的中断定向寄存器的结构体
+ *
+ */
+struct apic_IO_APIC_RTE_entry
+{
+    unsigned int vector : 8, // 0~7
+        deliver_mode : 3,    // [10:8] 投递模式默认为NMI
+        dest_mode : 1,       // 11 目标模式(0位物理模式,1为逻辑模式)
+        deliver_status : 1,  // 12 投递状态
+        polarity : 1,        // 13 电平触发极性
+        remote_IRR : 1,      // 14 远程IRR标志位(只读)
+        trigger_mode : 1,    // 15 触发模式(0位边沿触发,1为电平触发)
+        mask : 1,            // 16 屏蔽标志位,(0为未屏蔽, 1为已屏蔽)
+        reserved : 19;       // [31:17]位保留
+
+    union
+    {
+        // 物理模式
+        struct
+        {
+            unsigned int reserved1 : 24, // [55:32] 保留
+                phy_dest : 4,            // [59:56] APIC ID
+                reserved2 : 4;           // [63:60] 保留
+        } physical;
+
+        // 逻辑模式
+        struct
+        {
+            unsigned int reserved1 : 24, // [55:32] 保留
+                logical_dest : 8;        // [63:56] 自定义APIC ID
+        } logical;
+    } destination;
+} __attribute__((packed));
 
+// ========== APIC的寄存器的参数定义 ==============
+// 投递模式
+#define LOCAL_APIC_FIXED 0
+#define IO_APIC_FIXED 0
+#define ICR_APIC_FIXED 0
+
+#define IO_APIC_Lowest_Priority 1
+#define ICR_Lowest_Priority 1
+
+#define LOCAL_APIC_SMI 2
+#define APIC_SMI 2
+#define ICR_SMI 2
+
+#define LOCAL_APIC_NMI 4
+#define APIC_NMI 4
+#define ICR_NMI 4
+
+#define LOCAL_APIC_INIT 5
+#define APIC_INIT 5
+#define ICR_INIT 5
+
+#define ICR_Start_up 6
+
+#define IO_APIC_ExtINT 7
+
+// 时钟模式
+#define APIC_LVT_Timer_One_Shot 0
+#define APIC_LVT_Timer_Periodic 1
+#define APIC_LVT_Timer_TSC_Deadline 2
+
+// 屏蔽
+#define UNMASKED 0
+#define MASKED 1
+
+// 触发模式
+#define EDGE_TRIGGER 0  // 边沿触发
+#define Level_TRIGGER 1 // 电平触发
+
+// 投递模式
+#define IDLE 0         // 挂起
+#define SEND_PENDING 1 // 发送等待
+
+// destination shorthand
+#define ICR_No_Shorthand 0
+#define ICR_Self 1
+#define ICR_ALL_INCLUDE_Self 2
+#define ICR_ALL_EXCLUDE_Self 3
+
+// 目标模式
+#define DEST_PHYSICAL 0 // 物理模式
+#define DEST_LOGIC 1    // 逻辑模式
+
+// level
+#define ICR_LEVEL_DE_ASSERT 0
+#define ICR_LEVEL_ASSERT 1
+
+// 远程IRR
+#define IRR_RESET 0
+#define IRR_ACCEPT 1
+
+// 电平触发极性
+#define POLARITY_HIGH 0
+#define POLARITY_LOW 1
 
 struct apic_IO_APIC_map
 {
@@ -90,7 +244,7 @@ struct apic_IO_APIC_map
  * @brief 中断服务程序
  *
  * @param rsp 中断栈指针
- * @param number 中断号
+ * @param number 中断向量
  */
 void do_IRQ(struct pt_regs *rsp, ul number);
 
@@ -114,4 +268,12 @@ void apic_ioapic_write_rte(unsigned char index, ul value);
  * @brief 初始化apic控制器
  *
  */
-void apic_init();
+void apic_init();
+
+// =========== 中断控制操作接口 ============
+void apic_ioapic_enable(ul irq_num);
+void apic_ioapic_disable(ul irq_num);
+ul apic_ioapic_install(ul irq_num, void *arg);
+void apic_ioapic_uninstall(ul irq_num);
+void apic_ioapic_level_ack(ul irq_num); // 电平触发
+void apic_ioapic_edge_ack(ul irq_num);  // 边沿触发

+ 51 - 0
kernel/exception/irq.c

@@ -111,6 +111,55 @@ void (*interrupt_table[24])(void) =
         IRQ0x37interrupt,
 };
 
+/**
+ * @brief 中断注册函数
+ *
+ * @param irq_num 中断向量号
+ * @param arg 传递给中断安装接口的参数
+ * @param handler 中断处理函数
+ * @param paramater 中断处理函数的参数
+ * @param controller 中断控制器结构
+ * @param irq_name 中断名
+ * @return int
+ */
+int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater, hardware_int_controller *controller, char *irq_name)
+{
+    // 由于为I/O APIC分配的中断向量号是从32开始的,因此要减去32才是对应的interrupt_desc的元素
+    irq_desc_t *p = &interrupt_desc[irq_num - 32];
+
+    p->controller = controller;
+    p->irq_name = irq_name;
+    p->parameter = paramater;
+    p->flags = 0;
+    p->handler = handler;
+
+    p->controller->install(irq_num, arg);
+    p->controller->enable(irq_num);
+
+    return 0;
+}
+
+/**
+ * @brief 中断注销函数
+ *
+ * @param irq_num 中断向量号
+ * @return int
+ */
+int irq_unregister(ul irq_num)
+{
+    irq_desc_t *p = &interrupt_desc[irq_num - 32];
+    p->controller->disable(irq_num);
+    p->controller->uninstall(irq_num);
+
+    p->controller = NULL;
+    p->irq_name = NULL;
+    p->parameter = NULL;
+    p->flags = 0;
+    p->handler = NULL;
+    
+    return 0;
+}
+
 /**
  * @brief 初始化中断模块
  */
@@ -119,6 +168,8 @@ void irq_init()
 #if _INTR_8259A_
     init_8259A();
 #else
+    memset(interrupt_desc, 0, sizeof(irq_desc_t) * IRQ_NUM);
+
     apic_init();
 #endif
 }

+ 129 - 4
kernel/exception/irq.h

@@ -4,9 +4,9 @@
  * @brief 中断处理程序
  * @version 0.1
  * @date 2022-01-28
- * 
+ *
  * @copyright Copyright (c) 2022
- * 
+ *
  */
 
 #pragma once
@@ -15,9 +15,134 @@
 
 #include "../process/ptrace.h"
 
+extern void (*interrupt_table[24])(void);
+extern void do_IRQ(struct pt_regs *regs, ul number);
+
+/* ========= 中断向量分配表 ==========
+
+0~255 IDT
+
+0   ~   31	trap fault abort for system
+	0	devide error
+	1	debug
+	2	NMI
+	3	breakpoint
+	4	overflow
+	5	bound range
+	6	undefined opcode
+	7	device	not available
+	8	double fault
+	9	coprocessor segment overrun
+	10	invalid TSS
+	11	segment not present
+	12	stack segment fault
+	13	general protection
+	14	page fault
+	15	
+	16	x87 FPU error
+	17	alignment check
+	18	machine check
+	19	SIMD exception
+	20	virtualization exception
+21  ~   31	Do not use
+
+32  ~   55	I/O APIC
+	32	8259A
+	33	keyboard
+	34	HPET timer 0,8254 counter 0
+	35	serial port A
+	36	serial port B
+	37	parallel port
+	38	floppy
+	39	parallel port
+	40	RTC,HPET timer 1
+	41	Generic
+	42	Generic
+	43	HPET timer 2
+	44	HPET timer 3
+	45	FERR#
+	46	SATA primary
+	47	SATA secondary
+	48	PIRQA
+	49	PIRQB
+	50	PIRQC
+	51	PIRQD
+	52	PIRQE
+	53	PIRQF
+	54	PIRQG
+	55	PIRQH
+	
+	
+0x80		system call
+
+150 ~   200	Local APIC
+	150	CMCI
+	151	Timer
+	152	Thermal Monitor
+	153	Performance Counter
+	154	LINT0
+	155	LINT1
+	156	Error
+
+200 ~   255	MP IPI
+
+*/
+
+typedef struct hardware_int_type
+{
+    // 使能中断操作接口
+    void (*enable)(ul irq_num);
+    // 禁止中断操作接口
+    void (*disable)(ul irq_num);
+
+    // 安装中断操作接口
+    ul (*install)(ul irq_num, void *arg);
+    // 卸载中断操作接口
+    void (*uninstall)(ul irq_num);
+    // 应答中断操作接口
+    void (*ack)(ul irq_num);
+} hardware_int_controller;
+
+// 中断描述结构体
+typedef struct
+{
+    hardware_int_controller *controller;
+    // 中断名
+    char *irq_name;
+    // 中断处理函数的参数
+    ul parameter;
+    // 中断处理函数
+    void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs);
+
+    // 自定义的标志位
+    ul flags;
+} irq_desc_t;
+
+#define IRQ_NUM 24
+irq_desc_t interrupt_desc[IRQ_NUM] = {0};
+
 /**
- * @brief 初始化中断模块
+ * @brief 中断注册函数
+ * 
+ * @param irq_num 中断向量号
+ * @param arg 传递给中断安装接口的参数
+ * @param handler 中断处理函数
+ * @param paramater 中断处理函数的参数
+ * @param controller 中断控制器结构
+ * @param irq_name 中断名
+ * @return int 
  */
-void irq_init();
+int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater, hardware_int_controller *controller, char *irq_name);
 
+/**
+ * @brief 中断注销函数
+ * 
+ * @param irq_num 中断向量号
+ * @return int 
+ */
+int irq_unregister(ul irq_num);
 
+/**
+ * @brief 初始化中断模块
+ */
+void irq_init();