]> Zhao Yanbai Git Server - kernel.git/commitdiff
简单支持ioremap,通过ACPI读到IO APIC的物理基地址
authoracevest <zhaoyanbai@126.com>
Fri, 2 Jan 2026 07:08:09 +0000 (15:08 +0800)
committeracevest <zhaoyanbai@126.com>
Fri, 2 Jan 2026 07:08:09 +0000 (15:08 +0800)
boot/acpi.c
include/ioremap.h [new file with mode: 0644]
include/kdef.h
include/system.h
include/vmalloc.h [new file with mode: 0644]
kernel/apic.c
kernel/ioremap.c [new file with mode: 0644]
kernel/setup.c
kernel/vmalloc.c [new file with mode: 0644]

index 7957c0a40c174cc59c72251eca098d01616152e2..2fffd0361367dcc3d2a3aebb6e38e9deb337e8c4 100644 (file)
@@ -11,6 +11,7 @@
 #include <string.h>
 #include <system.h>
 #include <page.h>
+#include <ioremap.h>
 
 typedef struct {
     char signature[8];   // "RSD PTR "
@@ -46,16 +47,18 @@ typedef struct {
     // 后面跟着可变长度的结构
 } __attribute__((packed)) madt_t;
 
-void parse_madt(paddr_t addr) {
+void parse_madt(vaddr_t addr) {
     if (0 == addr) {
         printk("MADT addr is null\n");
         return;
     }
 
-    page_map(addr, addr, PAGE_P | PAGE_WR);
-
+    printk("MADT vaddr %08x\n", addr);
     madt_t* madt = (madt_t*)addr;
     printk("MADT LAPIC addr %08x flags %08x\n", madt->lapic_addr, madt->flags);
+    printk("MADT header size %u total length %u\n", sizeof(madt_t), madt->header.length);
+
+    system.lapic_addr = madt->lapic_addr;
 
     uint8_t* ptr = (uint8_t*)(madt + 1);  // 跳过表头
     uint8_t* end = (uint8_t*)madt + madt->header.length;
@@ -90,6 +93,12 @@ void parse_madt(paddr_t addr) {
             uint32_t ioapic_addr = *(uint32_t*)(ptr + 4);
             uint32_t global_irq_base = *(uint32_t*)(ptr + 8);
             ioapic_cnt++;
+            if (ioapic_cnt == 1) {
+                system.ioapic_addr = ioapic_addr;
+            } else {
+                // 多个IO-APIC,就不支持了
+                panic("multiple IO-APIC not supported\n");
+            }
             printk("IOAPIC id %u addr %08x global_irq_base %u\n", ioapic_id, ioapic_addr, global_irq_base);
         } break;
         case 2: {  // IO APIC 中断源重映射
@@ -124,9 +133,10 @@ void parse_rsdt(paddr_t addr) {
         return;
     }
 
-    page_map(addr, addr, PAGE_P | PAGE_WR);
+    printk("parse rsdt\n");
+    rsdt_t* rsdt = (rsdt_t*)(ioremap(PAGE_ALIGN(addr), PAGE_SIZE) + (addr - PAGE_ALIGN(addr)));
+    assert(rsdt != NULL);
 
-    rsdt_t* rsdt = (rsdt_t*)addr;
     // 验证签名
     if (memcmp(rsdt->header.signature, "RSDT", 4) != 0) {
         panic("ACPI RSDT invalid\n");
@@ -142,9 +152,10 @@ void parse_rsdt(paddr_t addr) {
 
     for (int i = 0; i < table_count; i++) {
         uint32_t table_phys_addr = rsdt->table_ptrs[i];
-        page_map((vaddr_t)table_phys_addr, (paddr_t)table_phys_addr, PAGE_P | PAGE_WR);
-
-        acpi_sdt_header_t* table = (acpi_sdt_header_t*)table_phys_addr;
+        // TODO unioremap
+        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) {
             printk("ACPI table %u:%x is null\n", i, table_phys_addr);
             continue;
@@ -157,11 +168,16 @@ void parse_rsdt(paddr_t addr) {
         }
         printk("ACPI table %u signature %s addr %08x len %u\n", i, sig, table_phys_addr, table->length);
         if (memcmp(sig, "APIC", 4) == 0) {
-            parse_madt((paddr_t)table);
+            printk("found MADT table, length %u\n", table->length);
+            parse_madt((vaddr_t)table);
         }
     }
 }
 
+void init_acpi() {
+    parse_rsdt((paddr_t)system.rsdt_addr);
+}
+
 void parse_acpi(void* tag) {
     printk("ACPI[old].RSDP ");
     struct multiboot_tag_old_acpi* acpi_tag = (struct multiboot_tag_old_acpi*)tag;
diff --git a/include/ioremap.h b/include/ioremap.h
new file mode 100644 (file)
index 0000000..a85498e
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: ioremap.h
+ *      Author: Zhao Yanbai
+ *              2026-01-02 13:38:08 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+#include <vmalloc.h>
+
+void* ioremap(paddr_t paddr, size_t size);
+void iounmap(void* vaddr);
index f27aaaa717d8ca8fe5bc379bc933a7b270cb814c..c68904b53cb934def3b430df7e2b16d6b5ea6dc1 100644 (file)
@@ -18,6 +18,9 @@
 // 后续内核不映射显存了,以后可以提供映射到用户空间的功能,由用户态程序操作
 #define VRAM_VADDR_SIZE (16 << 20)
 
+// VMALLOC区 128MB
+#define VMALLOC_VADDR_SIZE (128 << 20)
+
 // 最大支持的线性地址空间为1G
 // 这里这样实现是为了简单,与Linux内核实现有显著不同
 // Linux内核还把内存大致分为了 DMA(<16MB), NORMAL(<896MB), HIGHMEM(896~4G)的内存分区(zone)
 
 // 把内核线性地址的最高部分留给显存
 // 余下的部分为支持映射其它物理内存的空间
-#define MAX_SUPT_PHYMM_SIZE (MAX_SUPT_VADDR_SIZE - VRAM_VADDR_SIZE - FIX_MAP_VADDR_SIZE)
+#define MAX_SUPT_PHYMM_SIZE (MAX_SUPT_VADDR_SIZE - VMALLOC_VADDR_SIZE - VRAM_VADDR_SIZE - FIX_MAP_VADDR_SIZE)
+
+// 算出VMALLOC区的线性地址
+#define VMALLOC_VADDR_BASE (KERNEL_VADDR_BASE + MAX_SUPT_PHYMM_SIZE)
+#define VMALLOC_VADDR_END (VMALLOC_VADDR_BASE + VMALLOC_VADDR_SIZE)
 
 // 算出显存的线性地址
 // 之后要将这个地址映射到显存的物理地址
-#define VRAM_VADDR_BASE (PAGE_OFFSET + MAX_SUPT_PHYMM_SIZE)
+#define VRAM_VADDR_BASE (VMALLOC_VADDR_END)
 #define VRAM_VADDR_END (VRAM_VADDR_BASE + VRAM_VADDR_SIZE)
 
 // 算出固定映射区的线性地址
index 9502b9eee46d8e292db7f8c2e1e4f58fbc735b70..bcbb8e1f7ec6e05237b62da07e5e64bea220db88 100644 (file)
@@ -158,8 +158,12 @@ typedef struct system {
 
     dev_t root_dev;
 
-    // æ\8c\89ç\90\86è¿\99个信息应该按CPU存储,简化实现
+    // æ\8c\89ç\90\86è¿\99äº\9b信息应该按CPU存储,简化实现
     lapic_t* lapic;
+    paddr_t lapic_addr;
+
+    //
+    paddr_t ioapic_addr;
 
 #define CMD_LINE_SIZE 128
     const char* cmdline;
diff --git a/include/vmalloc.h b/include/vmalloc.h
new file mode 100644 (file)
index 0000000..348da41
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: vmalloc.h
+ *      Author: Zhao Yanbai
+ *              2026-01-02 12:21:21 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+#include <types.h>
+#include <kdef.h>
+
+#define VM_ALLOC 0x01
+#define VM_IOREMAP 0x02
+
+typedef struct vm_struct {
+    vaddr_t vm_vaddr;
+    size_t vm_size;
+    paddr_t vm_paddr;
+    uint32_t vm_flags;
+    struct vm_struct* vm_next;
+} vm_struct_t;
+
+vm_struct_t* get_vm_area(size_t size, uint32_t flags);
+vm_struct_t* find_vm_area(vaddr_t vaddr);
+
+void free_vm_area(vm_struct_t* vm);
index 153b17960257686447b26b4a5ccf95926beaddb0..24bdc899b52f0a7cf27477b09f7f36a9f65ce344 100644 (file)
@@ -12,6 +12,8 @@
 #include <system.h>
 #include <fixmap.h>
 #include <apic.h>
+#include <pci.h>
+#include <ioremap.h>
 
 static inline uint32_t apic_offset_to_msr(uint32_t offset) {
     return 0x800 + (offset >> 4);
@@ -189,6 +191,46 @@ void lapic_init() {
     uint32_t PPR = lapic->read(LAPIC_PPR);
 }
 
+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");
+    }
+
+    // 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物理基地址映射到内核空间
+    vaddr_t rcba_virt_base = (vaddr_t)ioremap(rcba_phys_base, 4 * PAGE_SIZE);
+    // set_fixmap(FIX_RCBA_BASE, rcba_phys_base);
+    // uint32_t rcba_virt_base = fixid_to_vaddr(FIX_RCBA_BASE);
+    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);
+    printk("OIC: %04x\n", *pOIC);
+    *pOIC = *pOIC | (1 << 8);
+    printk("OIC: %04x\n", *pOIC);
+}
+
 void init_apic() {
+    lapic_init();
     ioapic_init();
 }
diff --git a/kernel/ioremap.c b/kernel/ioremap.c
new file mode 100644 (file)
index 0000000..341f10c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: ioremap.c
+ *      Author: Zhao Yanbai
+ *              2026-01-02 13:38:43 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <ioremap.h>
+#include <page.h>
+#include <assert.h>
+#include <printk.h>
+
+void ioremap_page_range(vaddr_t vaddr, paddr_t paddr, size_t size) {
+    assert(PAGE_DOWN(size) == size);
+
+    for (int i = 0; i < size / PAGE_SIZE; i++) {
+        page_map(vaddr + i * PAGE_SIZE, paddr + i * PAGE_SIZE, PAGE_P | PAGE_WR);
+    }
+}
+
+void* ioremap(paddr_t phys_addr, size_t size) {
+    size = PAGE_UP(size);
+
+    vm_struct_t* vm_area = get_vm_area(size, VM_IOREMAP);
+    if (!vm_area) {
+        return NULL;
+    }
+
+    // 映射物理地址到虚拟地址
+    vm_area->vm_paddr = phys_addr;
+    vm_area->vm_flags |= VM_IOREMAP;
+
+    printk("ioremap: 0x%08x -> 0x%08x size %u\n", phys_addr, vm_area->vm_vaddr, vm_area->vm_size);
+
+    ioremap_page_range(vm_area->vm_vaddr, vm_area->vm_paddr, vm_area->vm_size);
+
+    return (void*)vm_area->vm_vaddr;
+}
+
+void iounmap(void* addr) {
+    // vm_struct_t* vm_area = find_vm_area((vaddr_t)addr);
+    // if (!vm_area) {
+    //     return;
+    // }
+
+    // if (!(vm_area->vm_flags & VM_IOREMAP)) {
+    //     return;
+    // }
+
+    // free_vm_area(vm_area);
+}
index 83b65da34dfefa5be72047c68bbabba2b94cc25c..6cd244ae9fd1bb71f929fb2ee1c60da6f4feb72e 100644 (file)
@@ -74,8 +74,6 @@ void print_kernel_version() {
     printk(version);
 }
 
-void parse_rsdt(void* addr);
-
 void setup_kernel() {
     printk("sysenter esp mode: %s\n",
 #if FIXED_SYSENTER_ESP_MODE
@@ -88,8 +86,9 @@ void setup_kernel() {
     init_mm();
 
     init_buffer();
-#if 0
-    parse_rsdt(system.rsdt_addr);
+#if 1
+    void init_acpi();
+    init_acpi();
 #endif
 #if 1
     void init_apic();
diff --git a/kernel/vmalloc.c b/kernel/vmalloc.c
new file mode 100644 (file)
index 0000000..605cae8
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: vmalloc.c
+ *      Author: Zhao Yanbai
+ *              2026-01-02 12:21:28 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <vmalloc.h>
+#include <assert.h>
+#include <irq.h>
+#include <page.h>
+#include <assert.h>
+
+static vm_struct_t* vm_area_list = NULL;
+
+vaddr_t vm_vaddr_base = VMALLOC_VADDR_BASE + (8 * 1024 * 1024);
+vaddr_t vm_vaddr_end = VMALLOC_VADDR_END;
+
+vm_struct_t* get_vm_area(size_t size, uint32_t flags) {
+    // assert size是页对齐
+    assert(PAGE_DOWN(size) == size);
+    assert(vm_vaddr_base < vm_vaddr_end);
+
+    size += PAGE_SIZE;  // 尾部添加一个空页
+
+    vaddr_t vm_area_gap_bgn = 0;
+    vaddr_t vm_area_gap_end = 0;
+
+    uint32_t eflags;
+    irq_save(eflags);
+
+    vm_struct_t* prev = NULL;
+    vm_struct_t* curt = vm_area_list;
+
+    while (curt != NULL) {
+        assert(curt->vm_vaddr >= vm_vaddr_base);
+        assert(curt->vm_vaddr + curt->vm_size <= vm_vaddr_end);
+
+        //
+        vm_area_gap_bgn = prev == NULL ? vm_vaddr_base : prev->vm_vaddr + prev->vm_size;
+        vm_area_gap_end = curt->vm_vaddr;
+
+        assert(vm_area_gap_bgn <= vm_area_gap_end);
+
+        // 找到了
+        if (vm_area_gap_end - vm_area_gap_bgn >= size) {
+            break;
+        }
+
+        prev = curt;
+        curt = curt->vm_next;
+    }
+
+    // 如果找到最后了也还没找到
+    if (curt == NULL) {
+        vm_area_gap_bgn = prev == NULL ? vm_vaddr_base : prev->vm_vaddr + prev->vm_size;
+        vm_area_gap_end = vm_vaddr_end;
+
+        assert(vm_area_gap_bgn <= vm_area_gap_end);
+
+        if (vm_area_gap_end - vm_area_gap_bgn < size) {
+            irq_restore(eflags);
+            return NULL;
+        }
+    }
+
+    // 创建一人vm_struct
+    vm_struct_t* vm_area = kmalloc(sizeof(vm_struct_t), 0);
+    if (vm_area == NULL) {
+        irq_restore(eflags);
+        return NULL;
+    }
+
+    vm_area->vm_vaddr = vm_area_gap_bgn;
+    vm_area->vm_size = size;
+    vm_area->vm_flags = flags;
+
+    // add to list
+    vm_area->vm_next = curt;
+    if (prev == NULL) {
+        vm_area_list = vm_area;
+    } else {
+        prev->vm_next = vm_area;
+    }
+
+    irq_restore(eflags);
+
+    return vm_area;
+}
+
+vm_struct_t* find_vm_area(vaddr_t vaddr) {
+    assert(PAGE_DOWN(vaddr) == vaddr);
+    assert(vaddr >= vm_vaddr_base);
+    assert(vaddr < vm_vaddr_end);
+    assert(vm_area_list != NULL);
+
+    vm_struct_t* curt = vm_area_list;
+
+    while (curt != NULL) {
+        assert(curt->vm_size != 0);
+        assert(curt->vm_vaddr >= vm_vaddr_base);
+        assert(curt->vm_vaddr + curt->vm_size <= vm_vaddr_end);
+
+        if (vaddr == curt->vm_vaddr) {
+            return curt;
+        }
+
+        assert(vaddr >= curt->vm_vaddr + curt->vm_size);
+
+        curt = curt->vm_next;
+    }
+
+    return NULL;
+}
+
+void free_vm_area(vm_struct_t* vm_area) {
+    assert(vm_area != NULL);
+    assert(vm_area->vm_size != 0);
+    assert(vm_area->vm_vaddr >= vm_vaddr_base);
+    assert(vm_area->vm_vaddr + vm_area->vm_size <= vm_vaddr_end);
+    assert(vm_area_list != NULL);
+    // TODO
+}
+
+void* vmalloc(size_t size) {
+    return NULL;
+}
+
+void vfree(void* addr) {
+}