]> Zhao Yanbai Git Server - kernel.git/commitdiff
整理HPET相关代码逻辑
authoracevest <zhaoyanbai@126.com>
Thu, 8 Jan 2026 11:30:10 +0000 (19:30 +0800)
committeracevest <zhaoyanbai@126.com>
Thu, 8 Jan 2026 11:30:10 +0000 (19:30 +0800)
drivers/pci.c
include/apic.h
include/fixmap.h
include/hpet.h [new file with mode: 0644]
include/pci.h
include/system.h
kernel/apic.c
kernel/hpet.c [new file with mode: 0644]
kernel/setup.c
kernel/system.c

index ad13bf6661fb0ad2312c68656805b26520452985..c34bc082033879aca83c7f5255d453977004abab 100644 (file)
@@ -239,6 +239,15 @@ err:
     return 0;
 }
 
+uint32_t pci_get_rcba() {
+    // Root Complex Base Address寄存器
+
+    uint32_t cmd = PCI_CMD(0, 31, 0, 0xF0);
+    uint32_t RCBA = pci_read_config_long(cmd);
+
+    return RCBA;
+}
+
 void setup_pci() {
     if (!probe_pci_bus()) {
         return;
index c023249750a63b4cdc8915f088e6e88d7125bfd5..8a34a176f55f0e145e3f29b6b61e18e492bcb579 100644 (file)
@@ -187,6 +187,9 @@ union ioapic_rte {
 
 typedef union ioapic_rte ioapic_rte_t;
 
+uint64_t ioapic_rte_read(uint32_t index);
+void ioapic_rte_write(uint32_t index, uint64_t v);
+
 union hpet_timn_conf_cap {
     uint64_t value;
     struct {
index 21b5b354f15b233bfb7d2c31bca00b5de1b6d0d1..985e325019eb0ecb89407ef42cf318378fe084c4 100644 (file)
@@ -27,6 +27,8 @@ enum {
     FIX_IO_APIC_BASE,
     FIX_IO_APIC_END = FIX_IO_APIC_BASE + MAX_IO_APIC_CNT - 1,
 
+    FIX_HPET_BASE,
+
     FIX_END_PAD,
 };
 
diff --git a/include/hpet.h b/include/hpet.h
new file mode 100644 (file)
index 0000000..bbe6b00
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: hpet.h
+ *      Author: Zhao Yanbai
+ *              2026-01-08 19:28:25 Thursday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+void hpet_init();
index 724c2df2f2b230fac62a6a6ef580d2bc334e8dce..773cac86cb8813a8af6685c005a5b322eb620767 100644 (file)
@@ -344,3 +344,7 @@ typedef union pci_bridge
     };
 } __attribute__((packed)) pci_bridge_t;
 #endif
+
+// 读取RCBA寄存器的值
+// Root Complex Base Address
+uint32_t pci_get_rcba();
index 4c5dc1c24a46b4e8d727aa05ddf63188d544a746..a32843743d7d94ef8c7b15545493ca2e1bbc82fd 100644 (file)
@@ -265,6 +265,8 @@ extern volatile int reenter;
 void boot_delay(int ticks);
 
 void io_mfence();
+
+paddr_t get_rcba_paddr();
 #endif
 
 #define DISABLE_IDE 1
index c4aa8ac3d499ff06c6eb778ad9a41ba1aa9449a4..802f02d0260cae013357fedee517a2f85d5fe391 100644 (file)
@@ -247,34 +247,30 @@ void ioapic_rte_write(uint32_t index, uint64_t v) {
     io_mfence();
 }
 
-static uint64_t hpet_ticks = 0;
+void ioapic_enable() {
+    uint32_t rcba_phys_base = (uint32_t)get_rcba_paddr();
 
-void hpet0_bh_handler() {
-    // hpet_ticks++;
-    printlxy(MPL_IRQ, MPO_HPET, "HPET: %lu", hpet_ticks);
-}
-
-void hpet0_irq_handler(unsigned int irq, pt_regs_t* regs, void* dev_id) {
-    hpet_ticks++;
+    uint32_t map_offset = 3 * PAGE_SIZE;
+    vaddr_t rcba_virt_base = (vaddr_t)ioremap(rcba_phys_base + map_offset, 4 * PAGE_SIZE - map_offset);
 
-    uint8_t* p = (uint8_t*)0xC00B8002;
-    *p = *p == ' ' ? 'E' : ' ';
+    printk("RCBA %08x %08x mapped to %08x\n", rcba_phys_base, rcba_phys_base + map_offset, rcba_virt_base);
 
-    add_irq_bh_handler(hpet0_bh_handler, NULL);
+    // OIC
+    // 位于RCBA 的 0x31FE 偏移处,是一个16位寄存器
+    // bit[7:0]: APIC映射区。决定了IO APIC的间接访问寄存器的地址区间。只有在禁用IO APIC的情况下才能修改。
+    // bit[8]: IO APIC使能标志位。 置位使能 复位禁用
+    // bit[9] 协处理器错误使能标志位
+    // bit[15:10]: 保留
+    //
+    uint16_t* pOIC = (uint16_t*)((uint8_t*)rcba_virt_base + 0x31FE - map_offset);
+    printk("OIC: %04x\n", *pOIC);
+    *pOIC = *pOIC | (1 << 8);
+    printk("OIC: %04x\n", *pOIC);
 
-    system.lapic->write(LAPIC_EOI, 0);
+    iounmap(rcba_virt_base);
 }
 
 void ioapic_init() {
-    // 先找到RCBA: Root Complex Base Address寄存器
-    uint32_t cmd = PCI_CMD(0, 31, 0, 0xF0);
-    printk("CMD: %08x\n", cmd);
-    uint32_t RCBA = pci_read_config_long(cmd);
-
-    if ((RCBA & 1) == 0) {
-        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);
@@ -308,34 +304,9 @@ void ioapic_init() {
         ioapic_rte_write(IOAPIC_RTE(i), IOAPIC_RTE_MASK | irq);
     }
 
-    // RCBA
-    // bit[0]: 使能位
-    // bit[13:1]: 保留
-    // bit[31:14]: RCBA物理基地址
-    // 0x3FFF == (1 << 14) - 1
-    uint32_t rcba_phys_base = RCBA & (~0x3FFF);
-
-    printk("RCBA: %08x %08x\n", RCBA, rcba_phys_base);
-
-    // 把RCBA物理基地址映射到内核空间
-    uint32_t rcba_page_offset = 3 * PAGE_SIZE;
-    vaddr_t rcba_virt_base = (vaddr_t)ioremap(rcba_phys_base, 4 * PAGE_SIZE - rcba_page_offset);
-    printk("RCBA base %08x mapped to %08x\n", rcba_phys_base, rcba_virt_base);
-
-    // OIC
-    // 位于RCBA 的 0x31FE 偏移处,是一个16位寄存器
-    // bit[7:0]: APIC映射区。决定了IO APIC的间接访问寄存器的地址区间。只有在禁用IO APIC的情况下才能修。
-    // bit[8]: IO APIC使能标志位。 置位使能 复位禁用
-    // bit[9] 协处理器错误使能标志位
-    // bit[15:10]: 保留
-    //
-    // 上面得搞成ioremap映射, 因为0x31FE这个超过一页也就是4K了。
-    uint16_t* pOIC = (uint16_t*)((uint8_t*)rcba_virt_base + 0x31FE - rcba_page_offset);
-    printk("OIC: %04x\n", *pOIC);
-    *pOIC = *pOIC | (1 << 8);
-    printk("OIC: %04x\n", *pOIC);
+    uint32_t rcba_phys_base = (uint32_t)get_rcba_paddr();
 
-    iounmap(rcba_virt_base);
+    ioapic_enable();
 
     uint64_t dst_cpuid = 0;
 
@@ -350,164 +321,6 @@ void ioapic_init() {
     irq_set_chip(0x00, &ioapic_chip);
     irq_set_chip(0x01, &ioapic_chip);
 #endif
-
-    rcba_phys_base = RCBA & (~0x3FFF);
-    printk("RCBA: %08x %08x\n", RCBA, rcba_phys_base);
-    rcba_virt_base = (vaddr_t)ioremap(rcba_phys_base, 4 * PAGE_SIZE - rcba_page_offset);
-    printk("RCBA base %08x mapped to %08x\n", rcba_phys_base, rcba_virt_base);
-    // HPTC: High Precision Timer Control Register
-    // bit[1:0] 地址映射范围选择域
-    //       取值      地址映射范围
-    //        00: 0xFED00000 - 0xFED003FF
-    //        01: 0xFED01000 - 0xFED013FF
-    //        10: 0xFED02000 - 0xFED023FF
-    //        11: 0xFED03000 - 0xFED033FF
-    // bit[7] 地址映射使能标志位,用于控制HPET设备访问地址的开启与否
-    //        只有它置位时芯片组才会将HPET配置寄存器映射到内存空间
-    uint32_t* pHPTC = (uint32_t*)((uint8_t*)rcba_virt_base + 0x3404);
-    printk("HPTC: %08x %08x\n", *pHPTC, pHPTC);
-    *pHPTC = *pHPTC | (1 << 7) | (0x00);
-    io_mfence();
-    printk("HPTC: %08x\n", *pHPTC);
-    iounmap(rcba_virt_base);
-
-    vaddr_t hpet_base = (vaddr_t)ioremap(0xFED00000, 0x3FF);
-    printk("HPET base %08x mapped to %08x\n", 0xFED00000, hpet_base);
-
-    uint64_t GEN_CONF = *(volatile uint64_t*)(hpet_base + 0x10);
-    printk("GEN_CONF: 0x%08x%08x\n", (uint32_t)(GEN_CONF >> 32), (uint32_t)GEN_CONF);
-    // // DISABLE HPET
-    // *(volatile uint64_t*)(hpet_base + 0x10) &= ~(1 << 0);
-    // io_mfence();
-
-    // 获取HPET的频率
-    uint64_t GCAP_ID = *(volatile uint64_t*)(hpet_base + 0);
-    // printk("GCAP_ID: %016x\n", GCAP_ID);
-    printk("GCAP_ID: 0x%08x%08x\n", (uint32_t)(GCAP_ID >> 32), (uint32_t)GCAP_ID);
-    uint32_t clock_period = (GCAP_ID >> 32);
-    uint64_t freq_mhz = 1000000000U / clock_period;
-    printk("HPET clock period: %08x\n", clock_period);
-    printk("HPET clock %s compatible\n", (GCAP_ID & (1 << 15)) == 0 ? "not" : "");
-    printk("HPET clock %s 64-bit capable\n", (GCAP_ID & (1 << 13)) == 0 ? "not" : "");
-    printk("HPET clock timer count: %d\n", ((GCAP_ID >> 8) & 0x1F) + 1);
-    printk("HPET clock frequency: %u MHz\n", freq_mhz);
-
-    GEN_CONF = *(volatile uint64_t*)(hpet_base + 0x10);
-    printk("GEN_CONF: 0x%08x%08x\n", (uint32_t)(GEN_CONF >> 32), (uint32_t)GEN_CONF);
-    printk("HPET enabled: %s\n", (GEN_CONF & (1 << 0)) == 0 ? "no" : "yes");
-    printk("HPET legacy replacement: %s\n", (GEN_CONF & (1 << 1)) == 0 ? "no" : "yes");
-
-    uint32_t cpu_irq_vec = 0;
-    uint32_t ioapic_irq = 23;
-
-    // TIM0_CONF
-    uint64_t TIM0_CONF = *(volatile uint64_t*)(hpet_base + 0x100);
-    printk("TIM0_CONF: 0x%08x%08x\n", (uint32_t)(TIM0_CONF >> 32), (uint32_t)TIM0_CONF);
-
-    request_irq(cpu_irq_vec, hpet0_irq_handler, "HPET#0", "HPET#0");
-    // HEPT TIM0 连在 IO-APIC的2号引脚上
-    // ioapic_rte_write(IOAPIC_RTE(2), 0x20 + 3 | (dst_cpuid << 56));
-
-#define TRIGGER_MODE IOAPIC_TRIGGER_MODE_EDGE
-    ioapic_rte_t rte;
-    printk("sizeof(ioapic_rte_t): %d\n", sizeof(ioapic_rte_t));
-    assert(sizeof(ioapic_rte_t) == 8);
-    rte.value = 0;
-    rte.vector = 0x20 + cpu_irq_vec;
-    rte.delivery_mode = IOAPIC_DELIVERY_MODE_FIXED;
-    rte.destination_mode = IOAPIC_PHYSICAL_DESTINATION;
-    rte.trigger_mode = TRIGGER_MODE;
-    rte.mask = IOAPIC_INT_UNMASKED;
-    rte.destination = dst_cpuid;
-
-    printk("RTE VALUE %08x", rte.value);
-
-    ioapic_rte_write(IOAPIC_RTE(ioapic_irq), rte.value);
-    irq_set_chip(cpu_irq_vec, &ioapic_chip);
-
-    // DISABLE HPET
-    *(volatile uint64_t*)(hpet_base + 0x10) &= ~(1ULL << 0);
-    io_mfence();
-
-    hpet_timn_conf_cap_t tim0_conf_cap;
-    assert(sizeof(tim0_conf_cap) == 8);
-    tim0_conf_cap.value = TIM0_CONF;
-    tim0_conf_cap.trigger_mode = TRIGGER_MODE;
-    tim0_conf_cap.enable_int = 1;  // enable
-    tim0_conf_cap.type = 1;        // periodic
-    tim0_conf_cap.periodic = 0;    // readonly
-    tim0_conf_cap.bit_size = 1;    // 0 32bit; 1 64bit
-    tim0_conf_cap.val_set = 1;
-
-    tim0_conf_cap.counter_bit_size = 0;  // 1 32 0 64
-    tim0_conf_cap.int_route = ioapic_irq;
-    tim0_conf_cap.fsb_en = 0;
-    tim0_conf_cap.fsb_delivery_status = 0;  // read only
-    tim0_conf_cap.reserved0 = 0;
-    tim0_conf_cap.reserved1 = 0;
-    tim0_conf_cap.reserved2 = 0;
-    tim0_conf_cap.int_route_cap = 0;
-
-    TIM0_CONF = tim0_conf_cap.value;
-
-    printk("TIM0_CONF: 0x%08x%08x\n", (uint32_t)(TIM0_CONF >> 32), (uint32_t)TIM0_CONF);
-
-    // uint64_t x = freq_mhz * 1000000ULL;
-    uint64_t x = freq_mhz * 10000ULL;
-    *(volatile uint32_t*)(hpet_base + 0x108 + 0x04) = (uint32_t)(x >> 32);
-    *(volatile uint32_t*)(hpet_base + 0x108 + 0x00) = (uint32_t)(x & 0xFFFFFFFF);
-    // *(volatile uint64_t*)(hpet_base + 0x108) = x;
-    io_mfence();
-
-    *(volatile uint32_t*)(hpet_base + 0x100 + 0x04) = (uint32_t)(TIM0_CONF >> 32);
-    *(volatile uint32_t*)(hpet_base + 0x100 + 0x00) = (uint32_t)(TIM0_CONF & 0xFFFFFFFF);
-    // *(volatile uint64_t*)(hpet_base + 0x100) = TIM0_CONF;
-    io_mfence();
-
-    // 如果TIMn_CONF的bit6置位(只能在周期模式下置位)的话,这个比较寄存器要写两次
-    // 第一次是初始值
-    // 第二次是累加值,也就是当MAIN_CNT达到比较寄存器的值时,会自动加上这个
-    // 需要说明的是: 第一次要在写TIMn_CONF之前写入
-    // 在<<Softwater Developers HPET Specification>>中是这样描述bit6的
-    // Software uses this read/write bit only for timers that have been set to periodic mode.
-    // By writing this bit to a 1, the software is then allowed to directly set a periodic timer's accumulator.
-    *(volatile uint32_t*)(hpet_base + 0x108 + 0x04) = (uint32_t)(x >> 32);
-    *(volatile uint32_t*)(hpet_base + 0x108 + 0x00) = (uint32_t)(x & 0xFFFFFFFF);
-    // *(volatile uint64_t*)(hpet_base + 0x108) = x;
-    io_mfence();
-
-    // *(volatile uint32_t*)(hpet_base + 0x108 + 0x04) = (uint32_t)(x >> 32);
-    // *(volatile uint32_t*)(hpet_base + 0x108 + 0x00) = (uint32_t)(x & 0xFFFFFFFF);
-    // // *(volatile uint64_t*)(hpet_base + 0x108) = x;
-    // io_mfence();
-
-    // MAIN_CNT
-    *(volatile uint64_t*)(hpet_base + 0xF0) = 0;
-    // *(volatile uint32_t*)(hpet_base + 0xF0) = 0;
-    io_mfence();
-
-    // ENABLE HPET
-    *(volatile uint64_t*)(hpet_base + 0x10) |= (1ULL << 0);
-    io_mfence();
-
-    // // 禁用 Legacy Replacement 模式
-    // *(volatile uint64_t*)(hpet_base + 0x10) &= ~(1ULL << 1);
-    // io_mfence();
-
-    TIM0_CONF = *(volatile uint64_t*)(hpet_base + 0x100);
-
-    uint32_t ESR = system.lapic->read(LAPIC_ESR);
-    uint64_t TPR = system.lapic->read(LAPIC_TPR);
-    uint32_t PPR = system.lapic->read(LAPIC_PPR);
-    printk("ESR: %08x TPR: %08x PPR: %08x\n", ESR, TPR, PPR);
-    printk("AFTER TIM0_CONF: 0x%08x%08x\n", (uint32_t)(TIM0_CONF >> 32), (uint32_t)TIM0_CONF);
-
-    // while (1) {
-    //     asm("sti");
-    //     asm("hlt;");
-    // }
-    // TODO
-    // iounmap(hpet_base);
 }
 
 void prepare_ap_code(paddr_t paddr) {
@@ -625,12 +438,6 @@ void init_apic() {
     prepare_ap_code(ap_code_addr);
     wakeup_ap(ap_code_addr);
 
-    printk("wait AP ready...");
-    extern bool ap_ready();
-    while (!ap_ready()) {
-        asm("pause");
-    }
-    printk("AP ready\n");
 }
 
 // ## 中断路由路径配置矩阵
diff --git a/kernel/hpet.c b/kernel/hpet.c
new file mode 100644 (file)
index 0000000..00603a9
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: hpet.c
+ *      Author: Zhao Yanbai
+ *              2026-01-08 15:59:34 Thursday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <system.h>
+#include <ioremap.h>
+#include <fixmap.h>
+#include <apic.h>
+#include <assert.h>
+#include <irq.h>
+
+const static paddr_t hpet_phys_addrs[] = {
+    0xFED00000,
+    0xFED01000,
+    0xFED02000,
+    0xFED03000,
+};
+const static int hpet_use_phys_addr_index = 0;
+
+const static int hpet_trigger_mode = IOAPIC_TRIGGER_MODE_EDGE;
+
+static paddr_t hpet_phys_addr = 0;
+
+void hpet_hw_enable() {
+    uint32_t map_offset = 3 * PAGE_SIZE;
+    vaddr_t rcba_phys_base = (vaddr_t)get_rcba_paddr();
+
+    vaddr_t rcba_virt_base = (vaddr_t)ioremap(rcba_phys_base + map_offset, 4 * PAGE_SIZE - map_offset);
+
+    printk("RCBA %08x %08x mapped to %08x\n", rcba_phys_base, rcba_phys_base + map_offset, rcba_virt_base);
+
+    // HPTC: High Precision Timer Control Register
+    // bit[1:0] 地址映射范围选择域
+    //       取值      地址映射范围
+    //        00: 0xFED00000 - 0xFED003FF
+    //        01: 0xFED01000 - 0xFED013FF
+    //        10: 0xFED02000 - 0xFED023FF
+    //        11: 0xFED03000 - 0xFED033FF
+    // bit[7] 地址映射使能标志位,用于控制HPET设备访问地址的开启与否
+    //        只有它置位时芯片组才会将HPET配置寄存器映射到内存空间
+    uint32_t* pHPTC = (uint32_t*)((uint8_t*)rcba_virt_base + 0x3404 - map_offset);
+    printk("HPTC: %08x %08x\n", *pHPTC, pHPTC);
+    *pHPTC = *pHPTC | (1 << 7) | (hpet_use_phys_addr_index << 0);
+    io_mfence();
+    printk("HPTC: %08x\n", *pHPTC);
+    iounmap(rcba_virt_base);
+}
+
+vaddr_t hpet_base() {
+    return fixid_to_vaddr(FIX_HPET_BASE);
+}
+
+uint64_t hpet_read(uint32_t regoffset) {
+    return *(uint64_t*)(hpet_base() + regoffset);
+}
+
+uint64_t hpet_write(uint32_t regoffset, uint64_t value) {
+    *(volatile uint64_t*)(hpet_base() + regoffset) = value;
+    return value;
+}
+
+#define HPET_REG_CAPABILITY_ID 0x0
+#define HPET_REG_CONFIG 0x10
+#define HPET_REG_INTERRUPT_STATUS 0x20
+#define HPET_REG_MAIN_COUNTER_VALUE 0xF0
+#define HPET_REG_TIMn_CONFIG_CAPABILITY(n) (0x100 + (n) * 0x20)
+#define HPET_REG_TIMn_COMPARATOR(n) (0x108 + (n) * 0x20)
+#define HPET_REG_TIMn_FSB_INTERRUPT_ROUTE(n) (0x110 + (n) * 0x20)
+
+void hpet_enable() {
+    hpet_write(HPET_REG_CONFIG, hpet_read(HPET_REG_CONFIG) | (1ULL << 0));
+    io_mfence();
+}
+
+void hpet_disable() {
+    hpet_write(HPET_REG_CONFIG, hpet_read(HPET_REG_CONFIG) & ~(1ULL << 0));
+    io_mfence();
+}
+
+uint32_t hpet_clock_period = 0;
+uint64_t hpet_clock_mhz_freq = 0;  // 32位系统不支持64位除法,所以用MHz为单位
+
+static uint64_t hpet_ticks = 0;
+void hpet0_bh_handler() {
+    // hpet_ticks++;
+    printlxy(MPL_IRQ, MPO_HPET, "HPET: %lu", hpet_ticks);
+}
+void hpet0_irq_handler(unsigned int irq, pt_regs_t* regs, void* dev_id) {
+    hpet_ticks++;
+
+    uint8_t* p = (uint8_t*)0xC00B8002;
+    *p = *p == ' ' ? 'E' : ' ';
+
+    add_irq_bh_handler(hpet0_bh_handler, NULL);
+
+    system.lapic->write(LAPIC_EOI, 0);
+}
+
+extern irq_chip_t ioapic_chip;
+void hpet_init() {
+    assert(hpet_use_phys_addr_index < sizeof(hpet_phys_addrs) / sizeof(hpet_phys_addrs[0]));
+    hpet_phys_addr = hpet_phys_addrs[hpet_use_phys_addr_index];
+
+    set_fixmap(FIX_HPET_BASE, hpet_phys_addr);
+    printk("HPET base %08x mapped to %08x\n", hpet_phys_addr, hpet_base());
+
+    //
+    hpet_hw_enable();
+
+    uint64_t capid = hpet_read(HPET_REG_CAPABILITY_ID);
+    hpet_clock_period = capid >> 32;
+    hpet_clock_mhz_freq = 1000000000U / hpet_clock_period;  // 32位除法
+    printk("HPET Capability and ID: 0x%08x%08x\n", (uint32_t)(capid >> 32), (uint32_t)capid);
+    printk("HPET legacy replacement route capable: %s\n", (capid & (1ULL << 15)) ? "Y" : "N");
+    printk("HPET 64bit capable: %s\n,", (capid & (1ULL << 13)) ? "Y" : "N");
+    printk("HPET timer count: %d\n", ((capid >> 8) & 0x1F) + 1);
+    printk("HPET clock period: %u ns\n", hpet_clock_period);
+    printk("HPET clock frequency: %u MHz\n", hpet_clock_mhz_freq);
+
+    uint64_t config = hpet_read(HPET_REG_CONFIG);
+    printk("HPET Configuration: 0x%08x%08x\n", (uint32_t)(config >> 32), (uint32_t)config);
+    printk("HPET enabled: %s\n", (config & (1ULL << 0)) ? "Y" : "N");
+    printk("HPET legacy replacement: %s\n", (config & (1ULL << 1)) ? "Y" : "N");
+
+    //
+    hpet_disable();
+
+    //
+    uint32_t irq = 0;
+    uint32_t ioapic_irq = 23;
+
+    //
+    uint32_t cpu_irq_vec = 0;
+    request_irq(cpu_irq_vec, hpet0_irq_handler, "HPET#0", "HPET#0");
+
+    uint64_t dst_cpuid = 0;
+    ioapic_rte_t rte;
+    printk("sizeof(ioapic_rte_t): %d\n", sizeof(ioapic_rte_t));
+    assert(sizeof(ioapic_rte_t) == 8);
+    rte.value = 0;
+    rte.vector = 0x20 + irq;
+    rte.delivery_mode = IOAPIC_DELIVERY_MODE_FIXED;
+    rte.destination_mode = IOAPIC_PHYSICAL_DESTINATION;
+    rte.trigger_mode = hpet_trigger_mode;
+    rte.mask = IOAPIC_INT_UNMASKED;
+    rte.destination = dst_cpuid;
+
+    printk("HPET#0 IOAPIC RTE VALUE %08x\n", rte.value);
+
+    ioapic_rte_write(IOAPIC_RTE(ioapic_irq), rte.value);
+    irq_set_chip(irq, &ioapic_chip);
+
+    uint64_t counter = hpet_clock_mhz_freq * 1000000ULL;
+
+    // 配置HPET#0
+    uint64_t tim0_config = 0;
+    tim0_config |= (hpet_trigger_mode << 1);
+    tim0_config |= (1 << 2);  // enable interrupt
+    tim0_config |= (1 << 3);  // periodic
+    tim0_config |= (1 << 5);  // 64bit
+    // tim0_config |= (1 << 6);           // ....
+    tim0_config |= (ioapic_irq << 9);  // ioapic irq
+
+    printk("TIM0_CONF: 0x%08x%08x\n", (uint32_t)(tim0_config >> 32), (uint32_t)tim0_config);
+
+    hpet_write(HPET_REG_TIMn_CONFIG_CAPABILITY(0), tim0_config);
+    io_mfence();
+
+    hpet_write(HPET_REG_TIMn_COMPARATOR(0), counter);
+    io_mfence();
+
+    hpet_write(HPET_REG_MAIN_COUNTER_VALUE, 0);
+    io_mfence();
+
+    hpet_enable();
+}
index 6c2de7221616e5175237a55846785790c13b24c1..60171440053431b7c929f83e30cfedaf0f536ea7 100644 (file)
@@ -18,6 +18,7 @@
 #include <string.h>
 #include <system.h>
 #include <tty.h>
+#include <hpet.h>
 
 extern void init_mm();
 extern void init_buffer();
@@ -74,6 +75,15 @@ void print_kernel_version() {
     printk(version);
 }
 
+void wait_ap_boot() {
+    printk("wait AP ready...");
+    extern bool ap_ready();
+    while (!ap_ready()) {
+        asm("pause");
+    }
+    printk("AP ready\n");
+}
+
 void setup_kernel() {
     printk("sysenter esp mode: fixed to &tss.esp0\n");
 
@@ -130,6 +140,12 @@ void setup_kernel() {
     init_apic();
 #endif
 
+    wait_ap_boot();
+
+#if 1
+    hpet_init();
+#endif
+
 #if !DISABLE_IDE
     void ide_init();
     ide_init();
index 2afd1ee9a20c4334acce461bf5134d6c9042f13f..25aad4c0a57d5ca8f049c6486c63f6476a792779 100644 (file)
@@ -26,6 +26,7 @@
 #include <syscall.h>
 #include <system.h>
 #include <linkage.h>
+#include <pci.h>
 
 system_t system;
 tss_t tss;
@@ -232,3 +233,21 @@ int sysc_reboot(int mode) {
 void io_mfence() {
     asm volatile("mfence" ::: "memory");
 }
+
+paddr_t get_rcba_paddr() {
+    uint32_t rcba = pci_get_rcba();
+
+    if ((rcba & 1) == 0) {
+        panic("RCBA not enabled\n");
+    }
+
+    // RCBA
+    // bit[0]: 使能位
+    // bit[13:1]: 保留
+    // bit[31:14]: RCBA物理基地址
+    // 0x3FFF == (1 << 14) - 1
+
+    paddr_t rcba_paddr = rcba & (~0x3FFF);
+
+    return rcba_paddr;
+}