]> Zhao Yanbai Git Server - kernel.git/commitdiff
添加iounmap功能
authoracevest <zhaoyanbai@126.com>
Thu, 8 Jan 2026 01:13:50 +0000 (09:13 +0800)
committeracevest <zhaoyanbai@126.com>
Thu, 8 Jan 2026 01:13:50 +0000 (09:13 +0800)
include/ioremap.h
include/system.h
include/vmalloc.h
kernel/apic.c
kernel/ioremap.c
kernel/vmalloc.c

index a85498e764e1d869dc8cc485d2558d7841e85383..af473c679dad9007f17e1e3830d383d16ccbd6a7 100644 (file)
@@ -12,4 +12,4 @@
 #include <vmalloc.h>
 
 void* ioremap(paddr_t paddr, size_t size);
-void iounmap(void* vaddr);
+void iounmap(vaddr_t vaddr);
index 5d177a0ca42ac9bf5c44d9239520fde76eecfec5..d5c5ef1d7f8b2c6f0173624a67c801c29c2c7f0c 100644 (file)
@@ -158,8 +158,6 @@ typedef struct system {
 
     dev_t root_dev;
 
-    vaddr_t hpet_base;
-
     // 按理这些信息应该按CPU存储,简化实现
     lapic_t* lapic;
     paddr_t lapic_addr;
index 348da4133e3ac93544ca766800d5acb183193f3d..898ba0300117057675b76a85a876f2933f60b551 100644 (file)
@@ -23,7 +23,7 @@ typedef struct vm_struct {
     struct vm_struct* vm_next;
 } vm_struct_t;
 
-vm_struct_t* get_vm_area(size_t size, uint32_t flags);
+vm_struct_t* alloc_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 aaab186a0bb6187fce402aca0b3c1317a89f4340..8f3045e528664ea3bdd02f5464451ce73c020482 100644 (file)
@@ -257,18 +257,11 @@ void hpet0_bh_handler() {
 void hpet0_irq_handler(unsigned int irq, pt_regs_t* regs, void* dev_id) {
     hpet_ticks++;
 
-    vaddr_t hpet_base = system.hpet_base;
-    assert(hpet_base != 0);
-
     uint8_t* p = (uint8_t*)0xC00B8002;
     *p = *p == ' ' ? 'E' : ' ';
 
     add_irq_bh_handler(hpet0_bh_handler, NULL);
 
-    // uint64_t main_cnt = *(volatile uint64_t*)(hpet_base + 0xF0);
-    // uint64_t counter = *(volatile uint64_t*)(hpet_base + 0x108);
-    // printk("main_cnt: %lu counter: %lu abc\n", main_cnt, counter);
-
     system.lapic->write(LAPIC_EOI, 0);
 }
 
@@ -325,9 +318,8 @@ void ioapic_init() {
     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);
+    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
@@ -338,12 +330,12 @@ void ioapic_init() {
     // bit[15:10]: 保留
     //
     // 上面得搞成ioremap映射, 因为0x31FE这个超过一页也就是4K了。
-    uint16_t* pOIC = (uint16_t*)((uint8_t*)rcba_virt_base + 0x31FE);
+    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);
-    // TODO
-    // iounmap(rcba_virt_base);
+
+    iounmap(rcba_virt_base);
 
     uint64_t dst_cpuid = 0;
 
@@ -357,6 +349,11 @@ 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] 地址映射范围选择域
     //       取值      地址映射范围
@@ -371,9 +368,9 @@ void ioapic_init() {
     *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);
-    system.hpet_base = hpet_base;
     printk("HPET base %08x mapped to %08x\n", 0xFED00000, hpet_base);
 
     uint64_t GEN_CONF = *(volatile uint64_t*)(hpet_base + 0x10);
@@ -455,6 +452,7 @@ void ioapic_init() {
     printk("TIM0_CONF: 0x%08x%08x\n", (uint32_t)(TIM0_CONF >> 32), (uint32_t)TIM0_CONF);
 
     uint64_t x = freq_mhz * 1000000ULL;
+    x >>= 1;
     *(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;
index 341f10c7f565d1117a65c74981e57bf71aa572e9..783298c0f5be23bb0555d25c2c6bcae6c439fda2 100644 (file)
@@ -20,10 +20,18 @@ void ioremap_page_range(vaddr_t vaddr, paddr_t paddr, size_t size) {
     }
 }
 
+void ioremap_page_range_clear(vaddr_t vaddr, size_t size) {
+    assert(PAGE_DOWN(size) == size);
+
+    for (int i = 0; i < size / PAGE_SIZE; i++) {
+        page_map(vaddr + i * PAGE_SIZE, 0, 0);
+    }
+}
+
 void* ioremap(paddr_t phys_addr, size_t size) {
     size = PAGE_UP(size);
 
-    vm_struct_t* vm_area = get_vm_area(size, VM_IOREMAP);
+    vm_struct_t* vm_area = alloc_vm_area(size, VM_IOREMAP);
     if (!vm_area) {
         return NULL;
     }
@@ -39,15 +47,14 @@ void* ioremap(paddr_t phys_addr, size_t 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;
-    // }
+void iounmap(vaddr_t vaddr) {
+    vm_struct_t* vm_area = find_vm_area(vaddr);
+    assert(vm_area != NULL);
+    assert(vm_area->vm_flags & VM_IOREMAP);
+
+    printk("iounmap: 0x%08x size %u\n", vm_area->vm_vaddr, vm_area->vm_size);
 
-    // if (!(vm_area->vm_flags & VM_IOREMAP)) {
-    //     return;
-    // }
+    free_vm_area(vm_area);
 
-    // free_vm_area(vm_area);
+    ioremap_page_range_clear(vm_area->vm_vaddr, vm_area->vm_size);
 }
index 605cae8c2a753ae3fa0f4de06acdbf4bb516251d..a5e390173a22f7d3b7de96257075c9474447acfc 100644 (file)
 #include <irq.h>
 #include <page.h>
 #include <assert.h>
+#include <string.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) {
+vm_struct_t* alloc_vm_area(size_t size, uint32_t flags) {
     // assert size是页对齐
     assert(PAGE_DOWN(size) == size);
     assert(vm_vaddr_base < vm_vaddr_end);
@@ -96,6 +97,9 @@ vm_struct_t* find_vm_area(vaddr_t vaddr) {
     assert(vaddr < vm_vaddr_end);
     assert(vm_area_list != NULL);
 
+    uint32_t eflags;
+    irq_save(eflags);
+
     vm_struct_t* curt = vm_area_list;
 
     while (curt != NULL) {
@@ -104,6 +108,7 @@ vm_struct_t* find_vm_area(vaddr_t vaddr) {
         assert(curt->vm_vaddr + curt->vm_size <= vm_vaddr_end);
 
         if (vaddr == curt->vm_vaddr) {
+            irq_restore(eflags);
             return curt;
         }
 
@@ -112,16 +117,56 @@ vm_struct_t* find_vm_area(vaddr_t vaddr) {
         curt = curt->vm_next;
     }
 
+    irq_restore(eflags);
+
     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_size % PAGE_SIZE == 0);
+    assert(vm_area->vm_size >= (2 * PAGE_SIZE));
     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
+
+    uint32_t eflags;
+    irq_save(eflags);
+
+    vm_struct_t* prev = NULL;
+    vm_struct_t* curt = vm_area_list;
+
+    while (curt != NULL) {
+        if (curt == vm_area) {
+            if (prev == NULL) {
+                // 只有链表上仅有一个节点,且这个节点就是要删除的节点的情况下prev才可能为NULL
+                assert(vm_area_list == vm_area);
+                assert(vm_area->vm_next == NULL);
+
+                //
+                vm_area_list = curt->vm_next;
+            } else {
+                prev->vm_next = curt->vm_next;
+            }
+
+            // 释放前先清空vm_struct避免连续二次释放
+            memset(curt, 0, sizeof(vm_struct_t));
+
+            kfree(curt);
+
+            irq_restore(eflags);
+            return;
+        }
+
+        prev = curt;
+        curt = curt->vm_next;
+    }
+
+    // 不应该出现这种情况
+    assert(0 && "vm_area not found");
+    irq_restore(eflags);
 }
 
 void* vmalloc(size_t size) {