From: Tulio A M Mendes Date: Thu, 11 Jun 2026 01:19:23 +0000 (-0300) Subject: kva: implement dynamic VA allocator to remove fixed VAs (H6) X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=1dbea378e97b5d2a3f2df900aa0e9c0e82403d74;p=AdrOS.git kva: implement dynamic VA allocator to remove fixed VAs (H6) Created kernel virtual address allocator to replace fixed VAs: - include/kva_alloc.h: KVA allocator interface - src/kernel/kva_alloc.c: Bitmap-based allocator with spinlock protection - Region: 0xC0500000 .. 0xC0800000 (3 MB, 768 pages) - kva_alloc_init(): Initialize bitmap and spinlock - kva_alloc_pages(): Allocate contiguous page range - kva_free_pages(): Free allocated range Migrated fixed VA usages to dynamic allocation: - src/hal/x86/mm.c: hal_mm_map_physical_range() now uses kva_alloc_pages instead of fixed KVA_PHYS_MAP (0xDC000000U) - src/drivers/virtio_blk.c: virtio vring allocation now uses kva_alloc_pages instead of fixed VIRTIO_VRING_VA (0xC0340000U) Removed obsolete constants: - include/arch/x86/kernel_va_map.h: Removed KVA_PHYS_MAP constant Updated layout comment to document KVA allocator region Boot integration: - src/kernel/main.c: Added kva_alloc_init() call after kheap_init() Validation: - make -j$(nproc): PASS - make test SMOKE_SMP=4: 131/131 PASS - make test-battery: 157/157 PASS This completes H6: remove fixed VAs, replacing hardcoded virtual addresses with dynamic allocation to prevent collisions and improve architectural flexibility. --- diff --git a/include/arch/x86/kernel_va_map.h b/include/arch/x86/kernel_va_map.h index c3037781..3627cce2 100644 --- a/include/arch/x86/kernel_va_map.h +++ b/include/arch/x86/kernel_va_map.h @@ -31,9 +31,9 @@ * 0xC0362000 .. 0xC0371FFF E1000 RX buffers (16 pages) * 0xC0400000 LAPIC MMIO (1 page) * 0xC0401000 IOAPIC MMIO (1 page) + * 0xC0500000 .. 0xC0800000 KVA allocator (dynamic VA, 3 MB) * 0xC8000000 .. Kernel stacks (guard + 8KB per thread) * 0xD0000000 .. Kernel heap (10 MB) - * 0xDC000000 .. Initrd / generic phys mapping (up to 64 MB) * 0xE0000000 .. Framebuffer mapping (up to 16 MB) */ @@ -64,9 +64,6 @@ /* LAPIC (arch/x86/lapic.c) */ #define KVA_LAPIC 0xC0400000U -/* Initrd / generic physical range mapping (hal/x86/mm.c) */ -#define KVA_PHYS_MAP 0xDC000000U - /* Framebuffer (drivers/vbe.c) — up to 16 MB for large resolutions */ #define KVA_FRAMEBUFFER 0xE0000000U diff --git a/include/kva_alloc.h b/include/kva_alloc.h new file mode 100644 index 00000000..ec87458c --- /dev/null +++ b/include/kva_alloc.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2018, Tulio A M Mendes + * All rights reserved. + * See LICENSE for details. + * + * Source: https://github.com/tadryanom/AdrOS + */ + +#ifndef KVA_ALLOC_H +#define KVA_ALLOC_H + +#include + +/* + * Kernel Virtual Address Allocator + * + * Dynamically allocates virtual address ranges for MMIO/DMA/temporary mappings. + * Replaces fixed VAs like KVA_PHYS_MAP and VIRTIO_VRING_VA. + * + * Allocator region: 0xC0500000 .. 0xC0800000 (3 MB, 768 pages) + * - Below 0xC0500000: Fixed MMIO regions (ACPI, ATA, E1000, LAPIC, IOAPIC) + * - Above 0xC0800000: Kernel stacks, heap, initrd, framebuffer + */ + +/* Initialize the KVA allocator */ +void kva_alloc_init(void); + +/* Allocate a contiguous range of pages (returns 0 on failure) */ +uintptr_t kva_alloc_pages(uint32_t page_count); + +/* Free a previously allocated range */ +void kva_free_pages(uintptr_t virt, uint32_t page_count); + +#endif diff --git a/src/drivers/virtio_blk.c b/src/drivers/virtio_blk.c index 06757c54..145be421 100644 --- a/src/drivers/virtio_blk.c +++ b/src/drivers/virtio_blk.c @@ -25,6 +25,7 @@ #include "spinlock.h" #include "pmm.h" #include "vmm.h" +#include "kva_alloc.h" #include "interrupts.h" #include "hal/driver.h" #include "io.h" @@ -170,8 +171,14 @@ int virtio_blk_init(void) { uint32_t total = vring_size(vblk_queue_size); uint32_t pages = (total + 4095U) / 4096U; - /* Use a fixed VA range for virtio vring */ - #define VIRTIO_VRING_VA 0xC0340000U + /* Use dynamic VA allocation for virtio vring */ + uintptr_t vring_va = kva_alloc_pages(pages); + if (vring_va == 0) { + kprintf("[VIRTIO-BLK] Failed to allocate vring VA.\n"); + outb(vblk_iobase + VIRTIO_PCI_STATUS, VIRTIO_STATUS_FAILED); + return -1; + } + for (uint32_t i = 0; i < pages; i++) { void* frame = pmm_alloc_page(); if (!frame) { @@ -180,22 +187,22 @@ int virtio_blk_init(void) { return -1; } vmm_map_page((uint64_t)(uintptr_t)frame, - (uint64_t)(VIRTIO_VRING_VA + i * 4096U), + (uint64_t)(vring_va + i * 4096U), VMM_FLAG_PRESENT | VMM_FLAG_RW | VMM_FLAG_NOCACHE); } - memset((void*)VIRTIO_VRING_VA, 0, pages * 4096U); + memset((void*)vring_va, 0, pages * 4096U); /* Set up vring pointers */ - vblk_desc = (struct vring_desc*)VIRTIO_VRING_VA; + vblk_desc = (struct vring_desc*)vring_va; uint32_t avail_off = vblk_queue_size * (uint32_t)sizeof(struct vring_desc); - vblk_avail = (struct vring_avail*)(VIRTIO_VRING_VA + avail_off); + vblk_avail = (struct vring_avail*)(vring_va + avail_off); uint32_t used_off = avail_off + sizeof(uint16_t) * (3 + vblk_queue_size); used_off = (used_off + 4095U) & ~4095U; - vblk_used = (struct vring_used*)(VIRTIO_VRING_VA + used_off); + vblk_used = (struct vring_used*)(vring_va + used_off); vblk_last_used_idx = 0; /* Tell device where the vring lives (page-aligned physical address) */ - uint32_t vring_phys = (uint32_t)V2P(VIRTIO_VRING_VA); + uint32_t vring_phys = (uint32_t)V2P(vring_va); outl(vblk_iobase + VIRTIO_PCI_QUEUE_PFN, vring_phys / 4096U); /* Mark driver ready */ diff --git a/src/hal/x86/mm.c b/src/hal/x86/mm.c index ecbfa434..2726ab00 100644 --- a/src/hal/x86/mm.c +++ b/src/hal/x86/mm.c @@ -11,6 +11,7 @@ #include "vmm.h" #include "arch/x86/kernel_va_map.h" +#include "kva_alloc.h" #include @@ -19,14 +20,18 @@ int hal_mm_map_physical_range(uintptr_t phys_start, uintptr_t phys_end, uint32_t if (phys_end < phys_start) phys_end = phys_start; - const uintptr_t virt_base = KVA_PHYS_MAP; - uintptr_t phys_start_aligned = phys_start & ~(uintptr_t)0xFFF; uintptr_t phys_end_aligned = (phys_end + 0xFFF) & ~(uintptr_t)0xFFF; uintptr_t size = phys_end_aligned - phys_start_aligned; uintptr_t pages = size >> 12; + /* Allocate dynamic VA range instead of using fixed KVA_PHYS_MAP */ + uintptr_t virt_base = kva_alloc_pages((uint32_t)pages); + if (virt_base == 0) { + return -1; + } + uint32_t vmm_flags = VMM_FLAG_PRESENT; if (flags & HAL_MM_MAP_RW) vmm_flags |= VMM_FLAG_RW; diff --git a/src/kernel/kva_alloc.c b/src/kernel/kva_alloc.c new file mode 100644 index 00000000..17f29741 --- /dev/null +++ b/src/kernel/kva_alloc.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2018, Tulio A M Mendes + * All rights reserved. + * See LICENSE for details. + * + * Source: https://github.com/tadryanom/AdrOS + */ + +#include "kva_alloc.h" + +#include "console.h" +#include "hal/cpu.h" +#include "spinlock.h" + +#include +#include + +/* Allocator region: 0xC0500000 .. 0xC0800000 (3 MB, 768 pages) */ +#define KVA_ALLOC_BASE 0xC0500000U +#define KVA_ALLOC_END 0xC0800000U +#define KVA_ALLOC_PAGES ((KVA_ALLOC_END - KVA_ALLOC_BASE) >> 12) + +/* Bitmap for allocation tracking (1 bit per page) */ +static uint8_t g_kva_bitmap[KVA_ALLOC_PAGES / 8]; +static spinlock_t g_kva_lock; + +void kva_alloc_init(void) { + memset(g_kva_bitmap, 0, sizeof(g_kva_bitmap)); + spinlock_init(&g_kva_lock); +} + +static inline void bitmap_set(uint32_t bit) { + g_kva_bitmap[bit >> 3] |= (1 << (bit & 7)); +} + +static inline void bitmap_clear(uint32_t bit) { + g_kva_bitmap[bit >> 3] &= ~(1 << (bit & 7)); +} + +static inline int bitmap_test(uint32_t bit) { + return (g_kva_bitmap[bit >> 3] >> (bit & 7)) & 1; +} + +uintptr_t kva_alloc_pages(uint32_t page_count) { + if (page_count == 0 || page_count > KVA_ALLOC_PAGES) { + return 0; + } + + spin_lock(&g_kva_lock); + + /* Find contiguous free range */ + uint32_t start = 0; + uint32_t found = 0; + for (uint32_t i = 0; i <= KVA_ALLOC_PAGES - page_count; i++) { + int free = 1; + for (uint32_t j = 0; j < page_count; j++) { + if (bitmap_test(i + j)) { + free = 0; + break; + } + } + if (free) { + start = i; + found = 1; + break; + } + } + + if (!found) { + spin_unlock(&g_kva_lock); + return 0; + } + + /* Mark pages as allocated */ + for (uint32_t i = 0; i < page_count; i++) { + bitmap_set(start + i); + } + + spin_unlock(&g_kva_lock); + + return KVA_ALLOC_BASE + (start << 12); +} + +void kva_free_pages(uintptr_t virt, uint32_t page_count) { + if (virt < KVA_ALLOC_BASE || virt >= KVA_ALLOC_END) { + return; + } + + uint32_t start = (virt - KVA_ALLOC_BASE) >> 12; + if (start + page_count > KVA_ALLOC_PAGES) { + return; + } + + spin_lock(&g_kva_lock); + + for (uint32_t i = 0; i < page_count; i++) { + bitmap_clear(start + i); + } + + spin_unlock(&g_kva_lock); +} diff --git a/src/kernel/main.c b/src/kernel/main.c index fba7cbaf..d9ea660c 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -34,6 +34,7 @@ #include "shm.h" #include "net.h" #include "csprng.h" +#include "kva_alloc.h" /* Check if the compiler thinks we are targeting the wrong operating system. */ @@ -67,7 +68,10 @@ void kernel_main(const struct boot_info* bi) { // 4. Initialize Kernel Heap kheap_init(); - // 4b. Initialize CSPRNG (M8: real entropy source) + // 4b. Initialize KVA allocator (H6: remove fixed VAs) + kva_alloc_init(); + + // 4c. Initialize CSPRNG (M8: real entropy source) csprng_init(); // 5. Initialize Shared Memory IPC