paging.c (4113B)
1 #include <stdint.h> 2 #include <stddef.h> 3 #include <limine.h> 4 #include <mm/paging.h> 5 6 #define PAGE_PRESENT (1ULL << 0) 7 #define PAGE_WRITABLE (1ULL << 1) 8 #define PAGE_USER (1ULL << 2) 9 #define PAGE_SIZE_2MB (1ULL << 7) 10 #define PAGE_SIZE 4096 11 12 // Get hhdm offset 13 extern volatile struct limine_hhdm_request hhdm_request; 14 extern volatile struct limine_kernel_address_request kernel_address_request; 15 16 // Static storage for page tables 17 static uint64_t pdpt[512] __attribute__((aligned(4096))); 18 static uint64_t pd[512] __attribute__((aligned(4096))); 19 20 // Get current cr3 value (PML address) 21 static uint64_t 22 get_cr3(void) 23 { 24 uint64_t cr3; 25 __asm__ volatile("mov %%cr3, %0" : "=r"(cr3)); 26 return cr3; 27 } 28 29 // Set cr3 to flush TLB 30 static void 31 set_cr3(uint64_t cr3) 32 { 33 __asm__ volatile("mov %0, %%cr3" : : "r"(cr3) : "memory"); 34 } 35 36 // Convert physical address to virt address using hhdm 37 static void* 38 phys_to_virt(uint64_t phys) 39 { 40 if (hhdm_request.response == NULL) { 41 // Fallback if hhdm is not available 42 return (void *)(phys + 0xffff800000000000ULL); 43 } 44 return (void *)(phys + hhdm_request.response->offset); 45 } 46 47 // Convert virt address to physical address 48 static uint64_t 49 virt_to_phys(void *virt) 50 { 51 uint64_t addr = (uint64_t)virt; 52 53 // Check if this is a kernel address 54 if (kernel_address_request.response != NULL) { 55 uint64_t kernel_virt_base = kernel_address_request.response->virtual_base; 56 uint64_t kernel_phys_base = kernel_address_request.response->physical_base; 57 58 // If address is in kernel space, convert using kernel base 59 if (addr >= kernel_virt_base && addr < kernel_virt_base + 0x200000) { 60 return kernel_phys_base + (addr - kernel_virt_base); 61 } 62 } 63 64 // Otherwise, in hhdm range 65 if (hhdm_request.response == NULL) { 66 // Fallback to default if hhdm not avail 67 return (addr - 0xffff800000000000ULL); 68 } 69 return (addr - hhdm_request.response->offset); 70 } 71 72 void 73 map_vga_memory(void) 74 { 75 // Get current PML4 from cr3 76 uint64_t cr3 = get_cr3(); 77 uint64_t *pml4 = (uint64_t *)phys_to_virt(cr3 & ~0xFFF); 78 79 // VGA memory starts at 0xA0000 (640KB) 80 // Map entire lower 1MB region for simplcity 81 82 /* For address 0xA0000: 83 * PML4 index = 0 (bits 47-39) 84 * PDPT index = 0 (bits 38-30) 85 * PD index = 0 (bits 29-21) 86 * PT index = 160 (0xA0) (bits 20-12) 87 */ 88 89 // Check if PML4[0] is present 90 if (!(pml4[0] & PAGE_PRESENT)) { 91 // Clear PDPT 92 for (int i = 0; i < 512; i++) { 93 pdpt[i] = 0; 94 } 95 // Install PDPT (use physical address) 96 pml4[0] = virt_to_phys(pdpt) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; 97 } 98 99 // Get PDPT (convert physical address from entry to virt for access) 100 uint64_t *pdpt_ptr = (uint64_t *)phys_to_virt(pml4[0] & ~0xFFF); 101 102 // Check if PDPT[0] is present 103 if (!(pdpt_ptr[0] & PAGE_PRESENT)) { 104 // Clear pd 105 for (int i = 0; i < 512; i++) { 106 pd[i] = 0; 107 } 108 // Install pd (use physical address) 109 pdpt_ptr[0] = virt_to_phys(pd) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; 110 } 111 112 // Get pd (convert physical address from entry to virt for access) 113 uint64_t *pd_ptr = (uint64_t *)phys_to_virt(pdpt_ptr[0] & ~0xFFF); 114 115 // Check if we can use 2MB pages 116 if (!(pd_ptr[0] & PAGE_PRESENT)) { 117 // Map the first 2MB as a large page (0x0 - 0x200000) 118 // This include VGA memory at 0xA0000-0xBFFFF 119 pd_ptr[0] = 0x0 | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER | PAGE_SIZE_2MB; 120 } 121 122 // Flush TLB 123 set_cr3(cr3); 124 125 }