/* Compatibility wrappers for legacy paging symbols expected by older code. */ #include #include #include #include #include #include #include #include static void serial_putc_raw(char c) { uint16 port = SERIAL_COM1; int timeout = 100000; while (timeout--) { if (inportb(SERIAL_LINE_STATUS(port)) & SERIAL_THRE) break; } outportb(SERIAL_DATA_PORT(port), (uint8)c); } static void serial_puts_unsafe(const char* s) { if (!s) return; while (*s) { serial_putc_raw(*s++); } } static void serial_put_hex32(uint32 v) { static const char* hex = "0123456789ABCDEF"; serial_puts_unsafe("0x"); for (int i = 28; i >= 0; i -= 4) { char c = hex[(v >> (unsigned)i) & 0xFu]; serial_putc_raw(c); } } /* Legacy page fault handler signature used by ISR 14. */ void page_fault_handler(regs_t* r) { uintptr fault_addr; asm volatile("mov %%cr2, %0" : "=r"(fault_addr)); if (!r) { PANICF("PAGE FAULT (unknown regs): addr=0x%08X", (unsigned)fault_addr); } /* * SECURITY-INVARIANT: A page fault taken in CPL0 is a kernel bug. * * Why: Retrying a faulting kernel instruction can re-enter #PF paths and * drive secondary faults (e.g. during swap/IO/accounting), leaving the * system in an increasingly corrupted state. * * Invariant: Kernel-mode #PF triggers an immediate panic with a minimal * diagnostic payload. User-mode faults continue through the VMM handler. */ if (r && ((r->cs & 3u) != 3u)) { // Emit a minimal serial line first in case VGA output is unavailable. serial_puts_unsafe("[PF] addr="); serial_put_hex32((uint32)fault_addr); serial_puts_unsafe(" eip="); serial_put_hex32(r->eip); serial_puts_unsafe(" err="); serial_put_hex32(r->err_code); serial_puts_unsafe("\n"); PANICF("PAGE FAULT (kernel): addr=0x%08X eip=0x%08X err=0x%08X cs=0x%08X esp=0x%08X", (unsigned)fault_addr, (unsigned)r->eip, (unsigned)r->err_code, (unsigned)r->cs, (unsigned)r->esp); } vmm_page_fault_handler(r->err_code, (uint32)fault_addr, r->eip); } /* Legacy guard: ensure page 0 is unmapped. */ void paging_install_null_guard(void) { vmm_unmap_page(&vmm_kernel_as, 0x0); vm_invalidate_page((void*)0x0); } /* Legacy guard: mark kernel .text (and .rodata) read-only. */ void paging_protect_kernel_text_ro(void) { extern uint32 __kernel_text_start; extern uint32 __kernel_text_end; extern uint32 __kernel_rodata_start; extern uint32 __kernel_rodata_end; uintptr text_start_ptr = (uintptr)&__kernel_text_start; uintptr text_end_ptr = (uintptr)&__kernel_text_end; uint32 start = (uint32)(text_start_ptr & ~((uintptr)PAGE_SIZE - 1u)); uint32 end = (uint32)text_end_ptr; for (uint32 va = start; va < end; va += PAGE_SIZE) { pte_t* pte = vmm_walk_page_tables(&vmm_kernel_as, va, 0); if (pte && (*pte & PTE_PRESENT)) { *pte &= ~PTE_RW; } } vm_invalidate_range((void*)(uintptr)start, (size_t)(end - start)); uintptr rodata_start_ptr = (uintptr)&__kernel_rodata_start; uintptr rodata_end_ptr = (uintptr)&__kernel_rodata_end; start = (uint32)(rodata_start_ptr & ~((uintptr)PAGE_SIZE - 1u)); end = (uint32)rodata_end_ptr; for (uint32 va = start; va < end; va += PAGE_SIZE) { pte_t* pte = vmm_walk_page_tables(&vmm_kernel_as, va, 0); if (pte && (*pte & PTE_PRESENT)) { *pte &= ~PTE_RW; } } vm_invalidate_range((void*)(uintptr)start, (size_t)(end - start)); }