#include "paging32.h" #include #include #include #include #include #include #include #include "memory.h" #include "parse/elf.h" #include "x86/asm.h" #include "x86/paging32.h" static page_t *pdpt; static u32 table_type(bool is_kernel) { if (is_kernel) { return E820_KERNEL; } return E820_PAGE_TABLE; } static page_t *walk_pdpt(size_t index, bool is_kernel) { page_t *pd; if (pdpt[index] & PT_PRESENT) { pd = (page_t *)(uintptr_t)page_get_paddr(&pdpt[index]); } else { u32 type = table_type(is_kernel); pd = (page_t *)mmap_alloc_top(PAGE_4KIB, type, PAGE_4KIB, LINEAR_MAP_OFFSET_32); memset(pd, 0, PAGE_4KIB); page_set_paddr(&pdpt[index], (page_t)(uintptr_t)pd); pdpt[index] |= PT_PRESENT; } return pd; } static page_t *walk_pd(page_t *pd, size_t index, bool is_kernel) { page_t *pt; if (pd[index] & PT_PRESENT) { pt = (page_t *)(uintptr_t)page_get_paddr(&pd[index]); } else { u32 type = table_type(is_kernel); pt = (page_t *)mmap_alloc_top(PAGE_4KIB, type, PAGE_4KIB, LINEAR_MAP_OFFSET_32); memset(pt, 0, PAGE_4KIB); page_set_paddr(&pd[index], (page_t)(uintptr_t)pt); pd[index] |= PT_PRESENT; pd[index] |= PT_WRITE; } return pt; } static void reserve_window(void) { u32 base = PHYS_WINDOW_BASE_32; u32 size = PHYS_WINDOW_SIZE_32; for (u32 offset = 0; offset < size; offset += PAGE_2MIB) { u32 vaddr = base + offset; size_t pdpt_index = GET_LVL3_INDEX(vaddr); size_t pd_index = GET_LVL2_INDEX(vaddr); page_t *pd = walk_pdpt(pdpt_index, false); if (pd[pd_index] & PT_PRESENT) { continue; } page_t *pt = (page_t *)mmap_alloc_top(PAGE_4KIB, E820_PAGE_TABLE, PAGE_4KIB, LINEAR_MAP_OFFSET_32); memset(pt, 0, PAGE_4KIB); page_set_paddr(&pd[pd_index], (page_t)(uintptr_t)pt); pd[pd_index] |= PT_PRESENT; pd[pd_index] |= PT_WRITE; } } void map_page_32(size_t size, u32 vaddr, u64 paddr, u64 flags, bool is_kernel) { size_t lvl3_index = GET_LVL3_INDEX(vaddr); size_t lvl2_index = GET_LVL2_INDEX(vaddr); size_t lvl1_index = GET_LVL1_INDEX(vaddr); page_t *pd = walk_pdpt(lvl3_index, is_kernel); if (size == PAGE_2MIB) { page_t *dir_entry = &pd[lvl2_index]; paddr = ALIGN_DOWN(paddr, PAGE_2MIB); page_set_paddr(dir_entry, (page_t)paddr); flags |= PT_HUGE; flags |= PT_PRESENT; *dir_entry |= flags & FLAGS_MASK; return; } page_t *pt = walk_pd(pd, lvl2_index, is_kernel); page_t *entry = &pt[lvl1_index]; page_set_paddr(entry, (page_t)paddr); flags |= PT_PRESENT; *entry |= flags & FLAGS_MASK; } void map_region_32(size_t size, u32 vaddr, u64 paddr, u64 flags, bool is_kernel) { for (size_t i = 0; i < DIV_ROUND_UP(size, PAGE_4KIB); i++) { u32 page_vaddr = vaddr + (u32)(i * PAGE_4KIB); u64 page_paddr = paddr + (u64)(i * PAGE_4KIB); map_page_32(PAGE_4KIB, page_vaddr, page_paddr, flags, is_kernel); } } void identity_map_32(u32 top_address, u32 offset, bool is_kernel) { u32 map_top = top_address; if (map_top > LINEAR_MAP_OFFSET_32) { map_top = LINEAR_MAP_OFFSET_32; } for (u32 i = 0; i < map_top; i += PAGE_2MIB) { map_page_32(PAGE_2MIB, i + offset, (u64)i, PT_WRITE, is_kernel); } } void setup_paging_32(void) { pdpt = (page_t *)mmap_alloc_top(PAGE_4KIB, E820_KERNEL, PAGE_4KIB, LINEAR_MAP_OFFSET_32); memset(pdpt, 0, PAGE_4KIB); write_cr3((u32)(uintptr_t)pdpt); reserve_window(); } void init_paging_32(void) { u32 cr4 = read_cr4(); write_cr4(cr4 | CR4_PAE | CR4_PSE); u32 cr0 = read_cr0(); write_cr0(cr0 | CR0_PG); } static page_t elf_flags(u32 elf_flags) { u64 flags = PT_PRESENT; if (elf_flags & PF_W) { flags |= PT_WRITE; } return flags; } struct elf_load_ctx32 { void *elf; }; static bool load_segment_32(const elf_segment_t *seg, void *ctx_ptr) { struct elf_load_ctx32 *load_ctx = ctx_ptr; u32 size = ALIGN((u32)seg->mem_size, PAGE_4KIB); u64 flags = elf_flags(seg->flags); u64 pbase = (u64)(uintptr_t)mmap_alloc(size, E820_KERNEL, (size_t)seg->align); u32 vbase = (u32)seg->vaddr; map_region_32(size, vbase, pbase, flags, true); memcpy((void *)(uintptr_t)pbase, (u8 *)load_ctx->elf + seg->offset, (size_t)seg->file_size); size_t zero_len = (size_t)(seg->mem_size - seg->file_size); memset((u8 *)(uintptr_t)pbase + seg->file_size, 0, zero_len); return true; } u32 load_elf_sections_32(void *elf_file) { struct elf_load_ctx32 ctx = { .elf = elf_file, }; elf_info_t info = { 0 }; if (!elf_foreach_segment(elf_file, 0, load_segment_32, &ctx, &info)) { return 0; } if (info.is_64) { return 0; } return (u32)info.entry; }