From: Tulio A M Mendes Date: Tue, 10 Feb 2026 06:19:36 +0000 (-0300) Subject: refactor: move x86 uaccess page table walking to src/arch/x86/uaccess.c X-Git-Url: https://projects.tadryanom.me/sitemap.xml?a=commitdiff_plain;h=e7443cfc964d7f144e6efe1e780c2ee31160e299;p=AdrOS.git refactor: move x86 uaccess page table walking to src/arch/x86/uaccess.c The uaccess implementation used x86-specific recursive page table mapping (0xFFFFF000/0xFFC00000) for user_range_ok, copy_from_user, copy_to_user, and uaccess_try_recover. This is 100% arch-dependent. - Move full x86 implementation to src/arch/x86/uaccess.c (no guards) - Replace src/kernel/uaccess.c with weak stubs (simple memcpy-based) - The linker picks the arch-specific version when available Passes: make, cppcheck, QEMU smoke test. --- diff --git a/src/arch/x86/uaccess.c b/src/arch/x86/uaccess.c new file mode 100644 index 0000000..274448a --- /dev/null +++ b/src/arch/x86/uaccess.c @@ -0,0 +1,148 @@ +#include "uaccess.h" + +#include "errno.h" +#include "interrupts.h" +#include "hal/mm.h" + +#include + +static int x86_user_range_basic_ok(uintptr_t uaddr, size_t len) { + if (len == 0) return 1; + if (uaddr == 0) return 0; + if (uaddr >= hal_mm_kernel_virt_base()) return 0; + uintptr_t end = uaddr + len - 1; + if (end < uaddr) return 0; + if (end >= hal_mm_kernel_virt_base()) return 0; + return 1; +} + +static volatile int g_uaccess_active = 0; +static volatile int g_uaccess_faulted = 0; +static volatile uintptr_t g_uaccess_recover_eip = 0; + +int uaccess_try_recover(uintptr_t fault_addr, struct registers* regs) { + if (!regs) return 0; + if (g_uaccess_active == 0) return 0; + if (g_uaccess_recover_eip == 0) return 0; + + // Only recover faults on user addresses; kernel faults should still panic. + if (fault_addr >= hal_mm_kernel_virt_base()) return 0; + + g_uaccess_faulted = 1; + regs->eip = (uint32_t)g_uaccess_recover_eip; + return 1; +} + +static int x86_user_page_writable_user(uintptr_t vaddr) { + volatile uint32_t* pd = (volatile uint32_t*)0xFFFFF000U; + volatile uint32_t* pt_base = (volatile uint32_t*)0xFFC00000U; + + uint32_t pde = pd[vaddr >> 22]; + if (!(pde & 0x1)) return 0; + if (!(pde & 0x4)) return 0; + + volatile uint32_t* pt = pt_base + ((vaddr >> 22) << 10); + uint32_t pte = pt[(vaddr >> 12) & 0x3FF]; + if (!(pte & 0x1)) return 0; + if (!(pte & 0x4)) return 0; + if (!(pte & 0x2)) return 0; + return 1; +} + +static int x86_user_page_present_and_user(uintptr_t vaddr) { + volatile uint32_t* pd = (volatile uint32_t*)0xFFFFF000U; + volatile uint32_t* pt_base = (volatile uint32_t*)0xFFC00000U; + + uint32_t pde = pd[vaddr >> 22]; + if (!(pde & 0x1)) return 0; + if (!(pde & 0x4)) return 0; + + volatile uint32_t* pt = pt_base + ((vaddr >> 22) << 10); + uint32_t pte = pt[(vaddr >> 12) & 0x3FF]; + if (!(pte & 0x1)) return 0; + if (!(pte & 0x4)) return 0; + + return 1; +} + +static int x86_user_range_mapped_and_user(uintptr_t uaddr, size_t len) { + if (!x86_user_range_basic_ok(uaddr, len)) return 0; + if (len == 0) return 1; + + uintptr_t start = uaddr & ~(uintptr_t)0xFFF; + uintptr_t end = (uaddr + len - 1) & ~(uintptr_t)0xFFF; + for (uintptr_t va = start;; va += 0x1000) { + if (!x86_user_page_present_and_user(va)) return 0; + if (va == end) break; + } + return 1; +} + +static int x86_user_range_writable_user(uintptr_t uaddr, size_t len) { + if (!x86_user_range_basic_ok(uaddr, len)) return 0; + if (len == 0) return 1; + + uintptr_t start = uaddr & ~(uintptr_t)0xFFF; + uintptr_t end = (uaddr + len - 1) & ~(uintptr_t)0xFFF; + for (uintptr_t va = start;; va += 0x1000) { + if (!x86_user_page_writable_user(va)) return 0; + if (va == end) break; + } + return 1; +} + +int user_range_ok(const void* user_ptr, size_t len) { + uintptr_t uaddr = (uintptr_t)user_ptr; + return x86_user_range_mapped_and_user(uaddr, len); +} + +int copy_from_user(void* dst, const void* src_user, size_t len) { + if (len == 0) return 0; + if (!user_range_ok(src_user, len)) return -EFAULT; + + g_uaccess_faulted = 0; + g_uaccess_recover_eip = (uintptr_t)&&uaccess_fault; + g_uaccess_active = 1; + + uintptr_t up = (uintptr_t)src_user; + for (size_t i = 0; i < len; i++) { + ((uint8_t*)dst)[i] = ((const volatile uint8_t*)up)[i]; + } + + g_uaccess_active = 0; + g_uaccess_recover_eip = 0; + if (g_uaccess_faulted) return -EFAULT; + return 0; + +uaccess_fault: + g_uaccess_active = 0; + g_uaccess_faulted = 0; + g_uaccess_recover_eip = 0; + return -EFAULT; +} + +int copy_to_user(void* dst_user, const void* src, size_t len) { + if (len == 0) return 0; + + if (!x86_user_range_writable_user((uintptr_t)dst_user, len)) return -EFAULT; + + g_uaccess_faulted = 0; + g_uaccess_recover_eip = (uintptr_t)&&uaccess_fault2; + g_uaccess_active = 1; + + uintptr_t up = (uintptr_t)dst_user; + for (size_t i = 0; i < len; i++) { + ((volatile uint8_t*)up)[i] = ((const uint8_t*)src)[i]; + } + + g_uaccess_active = 0; + g_uaccess_recover_eip = 0; + if (g_uaccess_faulted) return -EFAULT; + return 0; + +uaccess_fault2: + g_uaccess_active = 0; + g_uaccess_faulted = 0; + g_uaccess_recover_eip = 0; + return -EFAULT; +} diff --git a/src/kernel/uaccess.c b/src/kernel/uaccess.c index 84e3267..28222bd 100644 --- a/src/kernel/uaccess.c +++ b/src/kernel/uaccess.c @@ -2,169 +2,49 @@ #include "errno.h" #include "interrupts.h" -#include "hal/mm.h" #include +#include -#if defined(__i386__) - -static int x86_user_range_basic_ok(uintptr_t uaddr, size_t len) { - if (len == 0) return 1; - if (uaddr == 0) return 0; - if (uaddr >= hal_mm_kernel_virt_base()) return 0; - uintptr_t end = uaddr + len - 1; - if (end < uaddr) return 0; - if (end >= hal_mm_kernel_virt_base()) return 0; - return 1; -} - -static volatile int g_uaccess_active = 0; -static volatile int g_uaccess_faulted = 0; -static volatile uintptr_t g_uaccess_recover_eip = 0; - +__attribute__((weak)) int uaccess_try_recover(uintptr_t fault_addr, struct registers* regs) { (void)fault_addr; - if (!regs) return 0; - -#if defined(__i386__) - if (g_uaccess_active == 0) return 0; - if (g_uaccess_recover_eip == 0) return 0; - - // Only recover faults on user addresses; kernel faults should still panic. - if (fault_addr >= hal_mm_kernel_virt_base()) return 0; - - g_uaccess_faulted = 1; - regs->eip = (uint32_t)g_uaccess_recover_eip; - return 1; -#else + (void)regs; return 0; -#endif -} - -static int x86_user_page_writable_user(uintptr_t vaddr) { - volatile uint32_t* pd = (volatile uint32_t*)0xFFFFF000U; - volatile uint32_t* pt_base = (volatile uint32_t*)0xFFC00000U; - - uint32_t pde = pd[vaddr >> 22]; - if (!(pde & 0x1)) return 0; - if (!(pde & 0x4)) return 0; - - volatile uint32_t* pt = pt_base + ((vaddr >> 22) << 10); - uint32_t pte = pt[(vaddr >> 12) & 0x3FF]; - if (!(pte & 0x1)) return 0; - if (!(pte & 0x4)) return 0; - if (!(pte & 0x2)) return 0; - return 1; -} - -static int x86_user_page_present_and_user(uintptr_t vaddr) { - volatile uint32_t* pd = (volatile uint32_t*)0xFFFFF000U; - volatile uint32_t* pt_base = (volatile uint32_t*)0xFFC00000U; - - uint32_t pde = pd[vaddr >> 22]; - if (!(pde & 0x1)) return 0; - if (!(pde & 0x4)) return 0; - - volatile uint32_t* pt = pt_base + ((vaddr >> 22) << 10); - uint32_t pte = pt[(vaddr >> 12) & 0x3FF]; - if (!(pte & 0x1)) return 0; - if (!(pte & 0x4)) return 0; - - return 1; -} - -static int x86_user_range_mapped_and_user(uintptr_t uaddr, size_t len) { - if (!x86_user_range_basic_ok(uaddr, len)) return 0; - if (len == 0) return 1; - - uintptr_t start = uaddr & ~(uintptr_t)0xFFF; - uintptr_t end = (uaddr + len - 1) & ~(uintptr_t)0xFFF; - for (uintptr_t va = start;; va += 0x1000) { - if (!x86_user_page_present_and_user(va)) return 0; - if (va == end) break; - } - return 1; -} - -static int x86_user_range_writable_user(uintptr_t uaddr, size_t len) { - if (!x86_user_range_basic_ok(uaddr, len)) return 0; - if (len == 0) return 1; - - uintptr_t start = uaddr & ~(uintptr_t)0xFFF; - uintptr_t end = (uaddr + len - 1) & ~(uintptr_t)0xFFF; - for (uintptr_t va = start;; va += 0x1000) { - if (!x86_user_page_writable_user(va)) return 0; - if (va == end) break; - } - return 1; } -#endif +__attribute__((weak)) int user_range_ok(const void* user_ptr, size_t len) { uintptr_t uaddr = (uintptr_t)user_ptr; - -#if defined(__i386__) - return x86_user_range_mapped_and_user(uaddr, len); -#else if (len == 0) return 1; if (uaddr == 0) return 0; uintptr_t end = uaddr + len - 1; if (end < uaddr) return 0; return 1; -#endif } +__attribute__((weak)) int copy_from_user(void* dst, const void* src_user, size_t len) { if (len == 0) return 0; if (!user_range_ok(src_user, len)) return -EFAULT; - g_uaccess_faulted = 0; - g_uaccess_recover_eip = (uintptr_t)&&uaccess_fault; - g_uaccess_active = 1; - - uintptr_t up = (uintptr_t)src_user; + const uint8_t* s = (const uint8_t*)src_user; + uint8_t* d = (uint8_t*)dst; for (size_t i = 0; i < len; i++) { - ((uint8_t*)dst)[i] = ((const volatile uint8_t*)up)[i]; + d[i] = s[i]; } - - g_uaccess_active = 0; - g_uaccess_recover_eip = 0; - if (g_uaccess_faulted) return -EFAULT; return 0; - -uaccess_fault: - g_uaccess_active = 0; - g_uaccess_faulted = 0; - g_uaccess_recover_eip = 0; - return -EFAULT; } +__attribute__((weak)) int copy_to_user(void* dst_user, const void* src, size_t len) { if (len == 0) return 0; - -#if defined(__i386__) - if (!x86_user_range_writable_user((uintptr_t)dst_user, len)) return -EFAULT; -#else if (!user_range_ok(dst_user, len)) return -EFAULT; -#endif - - g_uaccess_faulted = 0; - g_uaccess_recover_eip = (uintptr_t)&&uaccess_fault2; - g_uaccess_active = 1; - uintptr_t up = (uintptr_t)dst_user; + uint8_t* d = (uint8_t*)dst_user; + const uint8_t* s = (const uint8_t*)src; for (size_t i = 0; i < len; i++) { - ((volatile uint8_t*)up)[i] = ((const uint8_t*)src)[i]; + d[i] = s[i]; } - - g_uaccess_active = 0; - g_uaccess_recover_eip = 0; - if (g_uaccess_faulted) return -EFAULT; return 0; - -uaccess_fault2: - g_uaccess_active = 0; - g_uaccess_faulted = 0; - g_uaccess_recover_eip = 0; - return -EFAULT; }