cowos

custom OS from scratch in C
git clone git://git.daat.foo/cowos.git
Log | Files | Refs | README | LICENSE

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 }