]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
kva: implement dynamic VA allocator to remove fixed VAs (H6)
authorTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 01:19:23 +0000 (22:19 -0300)
committerTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 01:19:23 +0000 (22:19 -0300)
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.

include/arch/x86/kernel_va_map.h
include/kva_alloc.h [new file with mode: 0644]
src/drivers/virtio_blk.c
src/hal/x86/mm.c
src/kernel/kva_alloc.c [new file with mode: 0644]
src/kernel/main.c

index c30377812b647f95eb129e82407b2d759afdf094..3627cce260789266a4851d34f45a2e38e9e11e0e 100644 (file)
@@ -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 (file)
index 0000000..ec87458
--- /dev/null
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2018, Tulio A M Mendes <[email protected]>
+ * All rights reserved.
+ * See LICENSE for details.
+ *
+ * Source: https://github.com/tadryanom/AdrOS
+ */
+
+#ifndef KVA_ALLOC_H
+#define KVA_ALLOC_H
+
+#include <stdint.h>
+
+/*
+ * 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
index 06757c54528c76146128738b1de624888763584a..145be4213a7f62990c525fa140e5422cf5c23540 100644 (file)
@@ -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 */
index ecbfa4347bfb21595c5aeff4ba58168b239603e3..2726ab005acb58d88942b7646dfab72e96b5e91f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "vmm.h"
 #include "arch/x86/kernel_va_map.h"
+#include "kva_alloc.h"
 
 #include <stddef.h>
 
@@ -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 (file)
index 0000000..17f2974
--- /dev/null
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2018, Tulio A M Mendes <[email protected]>
+ * 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 <stddef.h>
+#include <string.h>
+
+/* 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);
+}
index fba7cbaf09cd590e1c8af72fbfce086a47a33605..d9ea660c8e58976358a5a427f5adc1d4f66c9f28 100644 (file)
@@ -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