From: acevest Date: Fri, 2 Jan 2026 12:52:21 +0000 (+0800) Subject: 支持键盘中断通过IO APIC到达CPU X-Git-Url: http://repos.zhaoyanbai.com/?a=commitdiff_plain;h=f0f2b9f05274ed284a218f645f275d603413473d;p=kernel.git 支持键盘中断通过IO APIC到达CPU --- diff --git a/boot/acpi.c b/boot/acpi.c index 2fffd03..43e643f 100644 --- a/boot/acpi.c +++ b/boot/acpi.c @@ -153,7 +153,7 @@ void parse_rsdt(paddr_t addr) { for (int i = 0; i < table_count; i++) { uint32_t table_phys_addr = rsdt->table_ptrs[i]; // TODO unioremap - printk("ACPI table %u addr %08x\n", i, table_phys_addr); + // printk("ACPI table %u addr %08x\n", i, table_phys_addr); acpi_sdt_header_t* table = (acpi_sdt_header_t*)(ioremap(PAGE_ALIGN(table_phys_addr), PAGE_SIZE) + (table_phys_addr - PAGE_ALIGN(table_phys_addr))); if (table == 0) { @@ -176,6 +176,7 @@ void parse_rsdt(paddr_t addr) { void init_acpi() { parse_rsdt((paddr_t)system.rsdt_addr); + // asm("cli;hlt;"); } void parse_acpi(void* tag) { diff --git a/boot/boot.c b/boot/boot.c index d30b077..9176add 100644 --- a/boot/boot.c +++ b/boot/boot.c @@ -342,6 +342,10 @@ void init_system_info() { printk("kernel [%x, %x] bootmem bitmap: %x\n", system.kernel_begin, system.kernel_end, system.bootmem_bitmap_begin); + // 先写一个默认值 + system.ioapic_addr = 0xFEC00000; + system.lapic_addr = 0xFEE00000; + printk("bootloader: %s\n", boot_params.bootloader); printk("boot device: bios dev %x partition %x sub partition %x\n", boot_params.biosdev, boot_params.partition, boot_params.sub_partition); diff --git a/include/apic.h b/include/apic.h index 63346f2..54d9035 100644 --- a/include/apic.h +++ b/include/apic.h @@ -75,3 +75,51 @@ typedef struct lapic { uint32_t (*get_lapic_id)(); } lapic_t; + +// IO APIC + +// IO APIC IOREGSEL 的索引值 +// bit[23:0] Reserved +// bit[27:24] IO APIC ID +// bit[31:28] Reserved +#define IOAPIC_ID 0x00 + +// IO APIC 版本寄存器 +// bit[7:0] IO APIC版本 +// bit[15:8] Reserved +// bit[23:16] 可用RTE数 <- 此值+1代表RTE数 +// bit[31:24] Reserved +#define IOAPIC_VERSION 0x01 +// 0x02-0x0F Reserved +#define IOAPIC_REDTBL_BASE 0x10 +// #define IOAPIC_REDTBL00 (IOAPIC_REDTBL_BASE + 0x00 * 0x02) +// #define IOAPIC_REDTBL01 (IOAPIC_REDTBL_BASE + 0x01 * 0x02) +// ... +// #define IOAPIC_REDTBL23 (IOAPIC_REDTBL_BASE + 0x17 * 0x02) +// 0x40-0xFF Reserved + +#define IOAPIC_RTE(n) (IOAPIC_REDTBL_BASE + (n) * 0x02) + +// 总共24个Redirection Table +// 每个2个字节,低字节索引低32位,高字节索引高32位 +// 也就是索引总位宽为64位 + +// Redirect Table Entry +// bit[7:0] 中断向量号 +// bit[10:8] 中断投递模式 +// bit[11] 目标模式 +// bit[12] 投递状态 +// bit[13] 电平触发极性 +// bit[14] 远程IRR标志位 +// bit[15] 触发模式 +// bit[16] 屏蔽标志位 +// bit[55:17] Reserved +// bit[63:56] 中断投递目标 +#define IOAPIC_RTE_MASK 0x00010000 + +typedef struct ioapic_map { + paddr_t phys_base; + vaddr_t io_reg_sel; // 也是 virt_base + vaddr_t io_win; + vaddr_t eoi; +} ioapic_map_t; diff --git a/include/system.h b/include/system.h index bcbb8e1..d5c5ef1 100644 --- a/include/system.h +++ b/include/system.h @@ -164,6 +164,7 @@ typedef struct system { // paddr_t ioapic_addr; + ioapic_map_t* ioapic_map; #define CMD_LINE_SIZE 128 const char* cmdline; @@ -260,6 +261,9 @@ extern volatile int reenter; #define DEFAULT_BOOT_DELAY_TICKS 300 void boot_delay(int ticks); +void io_mfence(); #endif +#define DISABLE_IDE 1 + #endif //_SYSTEM_H diff --git a/kernel/apic.c b/kernel/apic.c index 24bdc89..206d138 100644 --- a/kernel/apic.c +++ b/kernel/apic.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include static inline uint32_t apic_offset_to_msr(uint32_t offset) { return 0x800 + (offset >> 4); @@ -73,7 +75,7 @@ void lapic_lvt_detect() { uint32_t offset; char* name; } lvt[] = { - {LAPIC_LVT_CMCI, "CMCI"}, // + // {LAPIC_LVT_CMCI, "CMCI"}, // {LAPIC_LVT_TIMER, "TIMER"}, // {LAPIC_LVT_THERMAL, "THERMAL"}, // {LAPIC_LVT_PERF, "PERF"}, // @@ -95,6 +97,7 @@ void lapic_init() { if (r.edx & (1 << 9)) { printk("local apic supported\n"); if (r.ecx & (1 << 21)) { + x2apic = true; printk("x2apic supported\n"); } else { panic("x2apic not supported\n"); @@ -119,11 +122,13 @@ void lapic_init() { if (x2apic) { // 开启2xapic apic_base |= (1 << 10); + printk("after 2xapic enable apic base: %08x\n", apic_base); write_msr(MSR_IA32_APIC_BASE, apic_base); + printk("after 2xapic enable apic base: %08x\n", apic_base); apic_base = read_msr32(MSR_IA32_APIC_BASE); assert((apic_base & (1 << 10)) != 0); - printk("after 2xapic enable apic base: %016lx\n", apic_base); + printk("after 2xapic enable apic base: %08x\n", apic_base); system.lapic = &x2apic_lapic; } else { @@ -191,6 +196,39 @@ void lapic_init() { uint32_t PPR = lapic->read(LAPIC_PPR); } +static ioapic_map_t ioapic_map; + +uint64_t ioapic_rte_read(uint32_t index) { + uint64_t v = 0; + *(volatile uint32_t*)ioapic_map.io_reg_sel = index + 1; + io_mfence(); + v = *(volatile uint32_t*)ioapic_map.io_win; + io_mfence(); + + v <<= 32; + + *(volatile uint32_t*)ioapic_map.io_reg_sel = index + 0; + io_mfence(); + v |= *(volatile uint32_t*)ioapic_map.io_win; + io_mfence(); + + return v; +} + +void ioapic_rte_write(uint32_t index, uint64_t v) { + *(volatile uint32_t*)ioapic_map.io_reg_sel = index + 0; + io_mfence(); + *(volatile uint32_t*)ioapic_map.io_win = v & 0xFFFFFFFF; + io_mfence(); + + v >>= 32; + + *(volatile uint32_t*)ioapic_map.io_reg_sel = index + 1; + io_mfence(); + *(volatile uint32_t*)ioapic_map.io_win = v & 0xFFFFFFFF; + io_mfence(); +} + void ioapic_init() { // 先找到RCBA: Root Complex Base Address寄存器 uint32_t cmd = PCI_CMD(0, 31, 0, 0xF0); @@ -201,6 +239,39 @@ void ioapic_init() { panic("RCBA not enabled\n"); } + // 把IO APIC映射进地址空间 + ioapic_map.phys_base = system.ioapic_addr; + ioapic_map.io_reg_sel = (vaddr_t)ioremap(ioapic_map.phys_base, PAGE_SIZE); + ioapic_map.io_win = ioapic_map.io_reg_sel + 0x10; + ioapic_map.eoi = ioapic_map.io_reg_sel + 0x40; + assert(ioapic_map.phys_base != 0); + assert(ioapic_map.io_reg_sel != 0); + printk("IO-APIC mapped %08x to %08x\n", ioapic_map.phys_base, ioapic_map.io_reg_sel); + printk("IO-APIC io_win %08x eoi %08x\n", ioapic_map.io_win, ioapic_map.eoi); + + system.ioapic_map = &ioapic_map; + + // IO APIC ID + *(volatile uint32_t*)ioapic_map.io_reg_sel = IOAPIC_ID; + io_mfence(); + uint32_t ioapic_id = *(volatile uint32_t*)ioapic_map.io_win; + io_mfence(); + + // IO APIC VERSION + *(volatile uint32_t*)ioapic_map.io_reg_sel = IOAPIC_VERSION; + io_mfence(); + uint32_t ioapic_version = *(volatile uint32_t*)ioapic_map.io_win; + io_mfence(); + + int rte_cnt = ((ioapic_version >> 16) & 0xFF) + 1; + printk("IO-APIC id %08x version %08x RTE cnt %d\n", ioapic_id, ioapic_version, rte_cnt); + + // 屏蔽所有中断 + for (int i = 0; i < rte_cnt; i++) { + uint32_t irq = 0x20 + i; + ioapic_rte_write(IOAPIC_RTE(i), IOAPIC_RTE_MASK | irq); + } + // RCBA // bit[0]: 使能位 // bit[13:1]: 保留 @@ -228,9 +299,63 @@ void ioapic_init() { printk("OIC: %04x\n", *pOIC); *pOIC = *pOIC | (1 << 8); printk("OIC: %04x\n", *pOIC); + // TODO + // iounmap(rcba_virt_base); + + // 打开键盘中断 + ioapic_rte_write(IOAPIC_RTE(1), 0x21); } +void disable_i8259(); void init_apic() { + // mask_i8259(); + disable_i8259(); + // imcr_init(); lapic_init(); ioapic_init(); } + +// ## 中断路由路径配置矩阵 + +// | 路径 | IMCR bit0 | 8259A | LAPIC | IOAPIC | 中断引脚连接 | +// |------|-----------|-------|-------|--------|------------| +// | **路径A** | 0 (PIC) | 启用 | 禁用 | 禁用/忽略 | INTR直接到CPU | +// | **路径B** | 1 (APIC) | 启用 | 启用 | 禁用 | INTR到LINT0 | +// | **路径C** | 1 (APIC) | 启用 | 启用 | 启用 | 8259A到IOAPIC | +// | **路径D** | 1 (APIC) | 禁用/掩码 | 启用 | 启用 | 直连IOAPIC | + +// ### 说明: +// - **IMCR bit0**: 0 = PIC模式, 1 = APIC模式 +// - **路径A**: 传统PIC模式,用于实模式/早期保护模式 +// - **路径B**: 过渡模式,8259A中断通过LAPIC的LINT0引脚 +// - **路径C**: 兼容模式,现代系统启动时常用 +// - **路径D**: 现代标准模式,性能最优 + +// A. 8259直接到CPU +// 实模式/早期保护模式 +// 中断向量表直接指向ISR +// 8259A通过INTR引脚直接触发CPU中断 + +// B. 8259 → LAPIC → CPU +// 本地APIC启用,但IOAPIC未启用 +// 8259A中断通过LAPIC的LINTO引脚 +// 需要配置LAPIC的LVT LINT0/1寄存器 + +// C. 8259 → IOAPIC → LAPIC → CPU +// 现代系统兼容模式 +// 8259A中断连接到IOAPIC的IRQ0-15 +// IOAPIC重定向到LAPIC +// 需要IMCR寄存器配置 + +// D. IOAPIC → LAPIC → CPU +// 纯APIC模式 +// 设备中断直接连接到IOAPIC +// IOAPIC重定向到LAPIC +// 8259A被禁用或掩码 + +// irq_chip_t apic_chip = { +// .name = "APIC", +// .enable = enable_apic_irq, +// .disable = disable_apic_irq, +// .ack = ack_apic_irq, +// }; diff --git a/kernel/i8259.c b/kernel/i8259.c index f9ef9f1..04f2a39 100644 --- a/kernel/i8259.c +++ b/kernel/i8259.c @@ -157,3 +157,56 @@ __attribute__((regparm(1))) void boot_irq_handler(pt_regs_t* regs) { // 解除屏蔽当前中断 enable_i8259_irq(irq); } + +// IMCR +#define IMCR_ADDR_PORT 0x22 +#define IMCR_DATA_PORT 0x23 +// IMCR寄存器位定义 +#define IMCR_REG_SELECT 0x70 // 选择寄存器70h +// +#define IMCR_BIT_APIC 0x01 // bit0: 1=APIC模式, 0=PIC模式 +#define IMCR_BIT_PIC_MASK 0x02 // bit1: 0=启用PIC, 1=禁用PIC +#define IMCR_BIT_IMCR_PRESENT 0x80 // bit7: 1=IMCR存在, 0=IMCR不存在 +uint8_t imcr_read(uint8_t reg) { + outb(IMCR_ADDR_PORT, reg); + return inb(IMCR_DATA_PORT); +} +void imcr_write(uint8_t reg, uint8_t value) { + outb(IMCR_ADDR_PORT, reg); + outb(IMCR_DATA_PORT, value); +} + +void imcr_enable_apic_disable_pic() { + uint8_t value = imcr_read(IMCR_REG_SELECT); + printk("IMCR: %02x\n", value); + if ((value & IMCR_BIT_IMCR_PRESENT) == 0) { + panic("IMCR not present\n"); + } + imcr_write(IMCR_REG_SELECT, value | IMCR_BIT_APIC | IMCR_BIT_PIC_MASK); + value = imcr_read(IMCR_REG_SELECT); + printk("IMCR: %02x\n", value); + + if ((value & IMCR_BIT_APIC) == 0) { + panic("IMCR not set to APIC mode\n"); + } else { + printk("IMCR set to APIC mode\n"); + } +} + +void disable_i8259() { + mask_i8259(); + + imcr_enable_apic_disable_pic(); + + // 禁用8259级联 + outb(0x11, PIC_MASTER_CMD); // ICW1: 初始化 + outb(0x20, PIC_MASTER_IMR); // ICW2: IR0-7 mapped to 0x20-0x27 + outb(0x04, PIC_MASTER_IMR); // ICW3: IR2连接从片 + outb(0x01, PIC_MASTER_IMR); // ICW4: Normal EOI + outb(0x11, PIC_SLAVE_CMD); // ICW1: 初始化 + outb(0x28, PIC_SLAVE_IMR); // ICW2: IR0-7 mapped to 0x28-0x2F + outb(0x02, PIC_SLAVE_IMR); // ICW3: IR2连接从片 + outb(0x01, PIC_SLAVE_IMR); // ICW4: Normal EOI + + mask_i8259(); +} diff --git a/kernel/innerint.c b/kernel/innerint.c index 76b3b68..c3c22d0 100644 --- a/kernel/innerint.c +++ b/kernel/innerint.c @@ -23,8 +23,7 @@ do { \ printk("Unsupport Now...[%s]\n", __FUNCTION__); \ printk("EFLAGS:%08x CS:%02x EIP:%08x ERRCODE:%x", regs.eflags, regs.cs, regs.eip, regs.errcode); \ - while (1) \ - ; \ + asm("cli;hlt;"); \ } while (0); void doDivideError(pt_regs_t regs) { @@ -95,7 +94,7 @@ US RW P - Description asm("movl %%cr2,%%eax" : "=a"(addr)); - // printk("do page fault errcode %x addr %08x [%08x]\n", errcode, addr, current); + printk("do page fault errcode %x addr %08x [%08x] %s\n", errcode, addr, current, current->name); // assert(errcode != 2 && errcode != 6); diff --git a/kernel/irq.c b/kernel/irq.c index 2eea8a5..101f640 100644 --- a/kernel/irq.c +++ b/kernel/irq.c @@ -32,6 +32,9 @@ volatile int reenter_count = 0; volatile uint32_t clk_irq_cnt = 0; +#include +#include +#include __attribute__((regparm(1))) void irq_handler(pt_regs_t* regs) { assert(current->magic == TASK_MAGIC); unsigned int irq = regs->irq; @@ -39,6 +42,34 @@ __attribute__((regparm(1))) void irq_handler(pt_regs_t* regs) { panic("invalid irq %d\n", irq); } + assert(1 == irq); + uint8_t b = inb(0x60); + printk("irq %d b %02x\n", irq, b); + // write_msr32(0x80b, 0); + system.lapic->write(0xB0, 0); + // vaddr_t apic_virt_base_addr = fixid_to_vaddr(FIX_LAPIC_BASE); + // apic_virt_base_addr += 0xB0; + // *((volatile uint32_t*)apic_virt_base_addr) = 0x0; + +#if 1 + // 检查IMCR + outb(0x22, 0x70); + uint8_t imcr = inb(0x23); + printk("IMCR: 0x%02x (bit0=%s, bit1=%s)\n", imcr, (imcr & 0x01) ? "APIC" : "PIC", + (imcr & 0x02) ? "PIC masked" : "PIC active"); + + // 检查8259A状态 + uint8_t pic1_imr = inb(0x21); + uint8_t pic2_imr = inb(0xA1); + printk("8259A IMR: Master=0x%02x, Slave=0x%02x\n", pic1_imr, pic2_imr); + + // 检查IOAPIC是否响应 + volatile uint32_t* ioapic = (volatile uint32_t*)system.ioapic_map->io_reg_sel; + ioapic[0] = 0x01; // 选择版本寄存器 + uint32_t version = ioapic[4]; + printk("IOAPIC version: 0x%08x\n", version); +#endif +#if 1 irq_desc_t* p = irq_desc + irq; irq_action_t* action = p->action; @@ -51,9 +82,6 @@ __attribute__((regparm(1))) void irq_handler(pt_regs_t* regs) { // TODO 判断打断的是否是内核态代码 - // 发送EOI - p->chip->ack(irq); - // 屏蔽当前中断 // p->chip->disable(irq); @@ -79,6 +107,10 @@ __attribute__((regparm(1))) void irq_handler(pt_regs_t* regs) { // 代表当前中断程序打断了前一个中断程序的“开中断处理的底半部分逻辑” // 即前一个中断处理尚未完全完成 assert(irq_disabled()); + + // 发送EOI + p->chip->ack(irq); + if (reenter != 0) { reenter--; return; @@ -113,6 +145,7 @@ __attribute__((regparm(1))) void irq_handler(pt_regs_t* regs) { // 如果需要调度程序 schedule(); +#endif } extern uint32_t jiffies; diff --git a/kernel/setup.c b/kernel/setup.c index 6cd244a..ffb4b3e 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -135,9 +135,10 @@ void setup_kernel() { setup_i8254(100); setup_irqs(); +#if !DISABLE_IDE void ide_init(); ide_init(); - +#endif void init_sata(); init_sata(); diff --git a/kernel/system.c b/kernel/system.c index f8382e7..14bdfd8 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -225,3 +225,7 @@ int sysc_reboot(int mode) { return 0; } + +void io_mfence() { + asm volatile("mfence" ::: "memory"); +} diff --git a/kernel/task_disk.c b/kernel/task_disk.c index 094acd7..5623a1b 100644 --- a/kernel/task_disk.c +++ b/kernel/task_disk.c @@ -17,6 +17,9 @@ void ata_pio_read_data(int drvid, int sect_cnt, void* dst); void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void* dest); int send_disk_request(disk_request_t* r) { +#if DISABLE_IDE + return 0; +#endif if (NULL == r) { panic("null disk request"); } diff --git a/kernel/task_init.c b/kernel/task_init.c index 7b0eae7..2dab08b 100644 --- a/kernel/task_init.c +++ b/kernel/task_init.c @@ -174,6 +174,7 @@ void init_task_entry() { void init_rootfs(); init_rootfs(); +#if !DISABLE_IDE #if 1 kernel_task("ide/0", disk_task_entry, (void*)0); @@ -183,6 +184,7 @@ void init_task_entry() { void ata_read_ext2_sb(); ata_read_ext2_sb(); #endif +#endif #if 0 extern int ide_read_partions_done; @@ -193,7 +195,9 @@ void init_task_entry() { #endif #if 1 +#if !DISABLE_IDE kernel_task("ide/1", disk_task_entry, (void*)1); +#endif kernel_task("user", user_task_entry, NULL); kernel_task("tskA", taskA_entry, NULL); kernel_task("tskB", taskB_entry, NULL);