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) {
void init_acpi() {
parse_rsdt((paddr_t)system.rsdt_addr);
+ // asm("cli;hlt;");
}
void parse_acpi(void* tag) {
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);
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;
//
paddr_t ioapic_addr;
+ ioapic_map_t* ioapic_map;
#define CMD_LINE_SIZE 128
const char* cmdline;
#define DEFAULT_BOOT_DELAY_TICKS 300
void boot_delay(int ticks);
+void io_mfence();
#endif
+#define DISABLE_IDE 1
+
#endif //_SYSTEM_H
#include <apic.h>
#include <pci.h>
#include <ioremap.h>
+#include <io.h>
+#include <i8259.h>
static inline uint32_t apic_offset_to_msr(uint32_t offset) {
return 0x800 + (offset >> 4);
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"}, //
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");
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 {
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);
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]: 保留
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,
+// };
// 解除屏蔽当前中断
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();
+}
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) {
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);
volatile uint32_t clk_irq_cnt = 0;
+#include <io.h>
+#include <msr.h>
+#include <fixmap.h>
__attribute__((regparm(1))) void irq_handler(pt_regs_t* regs) {
assert(current->magic == TASK_MAGIC);
unsigned int irq = regs->irq;
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;
// TODO 判断打断的是否是内核态代码
- // 发送EOI
- p->chip->ack(irq);
-
// 屏蔽当前中断
// p->chip->disable(irq);
// 代表当前中断程序打断了前一个中断程序的“开中断处理的底半部分逻辑”
// 即前一个中断处理尚未完全完成
assert(irq_disabled());
+
+ // 发送EOI
+ p->chip->ack(irq);
+
if (reenter != 0) {
reenter--;
return;
// 如果需要调度程序
schedule();
+#endif
}
extern uint32_t jiffies;
setup_i8254(100);
setup_irqs();
+#if !DISABLE_IDE
void ide_init();
ide_init();
-
+#endif
void init_sata();
init_sata();
return 0;
}
+
+void io_mfence() {
+ asm volatile("mfence" ::: "memory");
+}
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");
}
void init_rootfs();
init_rootfs();
+#if !DISABLE_IDE
#if 1
kernel_task("ide/0", disk_task_entry, (void*)0);
void ata_read_ext2_sb();
ata_read_ext2_sb();
#endif
+#endif
#if 0
extern int ide_read_partions_done;
#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);