From: acevest Date: Thu, 8 Jan 2026 01:13:50 +0000 (+0800) Subject: 添加iounmap功能 X-Git-Url: http://repos.zhaoyanbai.com/?a=commitdiff_plain;h=2260ad74872322df6bb86239b28deb3f61a8c53a;p=kernel.git 添加iounmap功能 --- diff --git a/include/ioremap.h b/include/ioremap.h index a85498e..af473c6 100644 --- a/include/ioremap.h +++ b/include/ioremap.h @@ -12,4 +12,4 @@ #include void* ioremap(paddr_t paddr, size_t size); -void iounmap(void* vaddr); +void iounmap(vaddr_t vaddr); diff --git a/include/system.h b/include/system.h index 5d177a0..d5c5ef1 100644 --- a/include/system.h +++ b/include/system.h @@ -158,8 +158,6 @@ typedef struct system { dev_t root_dev; - vaddr_t hpet_base; - // 按理这些信息应该按CPU存储,简化实现 lapic_t* lapic; paddr_t lapic_addr; diff --git a/include/vmalloc.h b/include/vmalloc.h index 348da41..898ba03 100644 --- a/include/vmalloc.h +++ b/include/vmalloc.h @@ -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); diff --git a/kernel/apic.c b/kernel/apic.c index aaab186..8f3045e 100644 --- a/kernel/apic.c +++ b/kernel/apic.c @@ -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; diff --git a/kernel/ioremap.c b/kernel/ioremap.c index 341f10c..783298c 100644 --- a/kernel/ioremap.c +++ b/kernel/ioremap.c @@ -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); } diff --git a/kernel/vmalloc.c b/kernel/vmalloc.c index 605cae8..a5e3901 100644 --- a/kernel/vmalloc.c +++ b/kernel/vmalloc.c @@ -12,13 +12,14 @@ #include #include #include +#include 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) {