]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix: replace pmm_alloc_page_low with pmm_alloc_page — fix fork OOM
authorTulio A M Mendes <[email protected]>
Mon, 16 Feb 2026 17:47:10 +0000 (14:47 -0300)
committerTulio A M Mendes <[email protected]>
Mon, 16 Feb 2026 17:47:10 +0000 (14:47 -0300)
The below-16MB page allocator (pmm_alloc_page_low) randomly sampled
pages and discarded any above 16MB.  With 100 zombie children holding
CoW address spaces, the low-memory pool exhausted and fork() returned
-ENOMEM, killing init before the SIGSEGV/waitpid-100/echo.elf tests.

On 32-bit PAE all physical addresses are below 4GB, so the 16MB
restriction is unnecessary for PDPTs, page directories, page tables,
and user frames.

Changes:
- vmm.c: replace all pmm_alloc_page_low() with pmm_alloc_page(),
  remove the dead pmm_alloc_page_low function
- usermode.c: replace pmm_alloc_page_low_16mb() with pmm_alloc_page(),
  remove the dead function
- init.c: make SIGSEGV test failure non-fatal (goto instead of
  sys_exit) so subsequent tests still run

83/83 smoke tests pass (10s), cppcheck clean.

src/arch/x86/usermode.c
src/arch/x86/vmm.c
user/init.c

index 28a154720bedade604b9b5b744ecc10f35265310..8638684100e521431dd93c6e809bf91721919097 100644 (file)
@@ -60,17 +60,7 @@ static void patch_rel8(uint8_t* buf, size_t at, size_t target) {
     buf[at] = (uint8_t)(int8_t)rel;
 }
 
-static void* pmm_alloc_page_low_16mb(void) {
-    for (int tries = 0; tries < 4096; tries++) {
-        void* p = pmm_alloc_page();
-        if (!p) return NULL;
-        if ((uintptr_t)p < 0x01000000U) {
-            return p;
-        }
-        pmm_free_page(p);
-    }
-    return NULL;
-}
+/* User pages can be anywhere in physical memory on 32-bit PAE. */
 
 __attribute__((noreturn)) void x86_enter_usermode(uintptr_t user_eip, uintptr_t user_esp) {
     kprintf("[USER] enter ring3 eip=0x%x esp=0x%x\n",
@@ -148,8 +138,8 @@ void x86_usermode_test_start(void) {
     const uintptr_t user_code_vaddr = 0x00400000U;
     const uintptr_t user_stack_vaddr = 0x00800000U;
 
-    void* code_phys = pmm_alloc_page_low_16mb();
-    void* stack_phys = pmm_alloc_page_low_16mb();
+    void* code_phys = pmm_alloc_page();
+    void* stack_phys = pmm_alloc_page();
     if (!code_phys || !stack_phys) {
         kprintf("[USER] OOM allocating user pages.\n");
         return;
index 1e5da38f44859367ca90364e80fc076c97e8fa05..cc3c76db94cc2907c818951cd0c743e01a2fd9d5 100644 (file)
@@ -101,18 +101,6 @@ static uint64_t vmm_flags_to_x86(uint32_t flags) {
     return x86_flags;
 }
 
-/* --- Low-memory page allocator --- */
-
-static void* pmm_alloc_page_low(void) {
-    for (int tries = 0; tries < 1024; tries++) {
-        void* p = pmm_alloc_page();
-        if (!p) return 0;
-        if ((uintptr_t)p < 0x01000000) return p;
-        pmm_free_page(p);
-    }
-    return 0;
-}
-
 /* User space covers PDPT indices 0-2 (0x00000000 - 0xBFFFFFFF).
  * PDPT[3] is kernel (0xC0000000 - 0xFFFFFFFF). */
 #define PAE_USER_PDPT_MAX 3
@@ -225,7 +213,7 @@ uintptr_t vmm_as_create_kernel_clone(void) {
     uintptr_t irqf = spin_lock_irqsave(&vmm_lock);
 
     /* Allocate PDPT (32 bytes, but occupies one page for simplicity) */
-    uint32_t pdpt_phys = (uint32_t)(uintptr_t)pmm_alloc_page_low();
+    uint32_t pdpt_phys = (uint32_t)(uintptr_t)pmm_alloc_page();
     if (!pdpt_phys) {
         spin_unlock_irqrestore(&vmm_lock, irqf);
         return 0;
@@ -234,7 +222,7 @@ uintptr_t vmm_as_create_kernel_clone(void) {
     /* Allocate 4 page directories */
     uint32_t pd_phys[4];
     for (int i = 0; i < 4; i++) {
-        pd_phys[i] = (uint32_t)(uintptr_t)pmm_alloc_page_low();
+        pd_phys[i] = (uint32_t)(uintptr_t)pmm_alloc_page();
         if (!pd_phys[i]) {
             for (int j = 0; j < i; j++) pmm_free_page((void*)(uintptr_t)pd_phys[j]);
             pmm_free_page((void*)(uintptr_t)pdpt_phys);
@@ -366,7 +354,7 @@ uintptr_t vmm_as_clone_user(uintptr_t src_as) {
                 if (pte & X86_PTE_RW)   flags |= VMM_FLAG_RW;
                 if (pte & X86_PTE_USER) flags |= VMM_FLAG_USER;
 
-                void* dst_frame = pmm_alloc_page_low();
+                void* dst_frame = pmm_alloc_page();
                 if (!dst_frame) {
                     vmm_as_activate(old_as);
                     spin_unlock_irqrestore(&vmm_lock, irqf);
index 819298ae1a814a7ed3c9b49e82da5b3d278ff14c..b36fa42b715912d00d397a058b8717f418b98dd6 100644 (file)
@@ -3742,7 +3742,7 @@ void _start(void) {
         if (pid < 0) {
             static const char msg[] = "[init] sigsegv test fork failed\n";
             (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
-            sys_exit(1);
+            goto sigsegv_done;
         }
 
         if (pid == 0) {
@@ -3770,8 +3770,8 @@ void _start(void) {
         } else {
             static const char msg[] = "[init] SIGSEGV failed\n";
             (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
-            sys_exit(1);
         }
+    sigsegv_done:;
     }
 
     int ok = 1;