diff --git a/kernel/driver/acpi/acpi.c b/kernel/driver/acpi/acpi.c index a3e49abf..1cd0119e 100644 --- a/kernel/driver/acpi/acpi.c +++ b/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!") } \ No newline at end of file diff --git a/kernel/driver/interrupt/apic/apic.c b/kernel/driver/interrupt/apic/apic.c index 2dd9d66e..9ff50e12 100644 --- a/kernel/driver/interrupt/apic/apic.c +++ b/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; } \ No newline at end of file diff --git a/kernel/driver/interrupt/apic/apic.h b/kernel/driver/interrupt/apic/apic.h index ccdbf412..01d7bda8 100644 --- a/kernel/driver/interrupt/apic/apic.h +++ b/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(); \ No newline at end of file +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); // 边沿触发 \ No newline at end of file diff --git a/kernel/exception/irq.c b/kernel/exception/irq.c index 7194061e..af5dead9 100644 --- a/kernel/exception/irq.c +++ b/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 } diff --git a/kernel/exception/irq.h b/kernel/exception/irq.h index 2742aee3..7da5c6c2 100644 --- a/kernel/exception/irq.h +++ b/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 中断注册函数 + * + * @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); + +/** + * @brief 中断注销函数 + * + * @param irq_num 中断向量号 + * @return int + */ +int irq_unregister(ul irq_num); + /** * @brief 初始化中断模块 */ void irq_init(); - -