// // Created by rick on 21-02-21. // #include #include #include #include #define PAGING_DIR_INDEX(virt) ((virt) >> 22) #define PAGING_TABLE_INDEX(virt) ((virt) >> 12 & 0x03FF) #define KERNEL_OFFSET 0xC0000000 // One page table, only 4M #define PAGING_STATE_EARLY 0 #define PAGING_STATE_FULL 60 page_directory_entry att_aligned(4096) kernel_page_directory[DIRECTORY_SIZE] = {0}; int paging_state = PAGING_STATE_EARLY; void paging_load_directory(uintptr_t physical_address) { asm volatile("mov %%eax, %%cr3" : : "a" (physical_address)); } uintptr_t paging_get_current_directory_physical() { uintptr_t directory_address; asm volatile("mov %%cr3, %%eax" : "=a" (directory_address)); return directory_address; } page_directory_entry *paging_get_current() { return kernel_page_directory; } int paging_map_4m(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) { if (virtual_address & ~PAGING_MASK_4M || physical_address & PAGING_MASK_4M) { // address not 4M aligned return PAGING_RESULT_ALIGN; } page_directory_entry *dir = paging_get_current(); for (int i = 0; i < count; ++i) { page_directory_entry current_val = dir[PAGING_DIR_INDEX(virtual_address) + i]; if (current_val & DIRECTORY_PRESENT_MASK) { return PAGING_RESULT_INUSE; } } page_directory_entry mask = DIRECTORY_PAGE_SIZE_MASK; if (mode & PAGING_MODE_RW) { mask |= DIRECTORY_RW_MASK; } if (mode & PAGING_MODE_US) { mask |= DIRECTORY_US_MASK; } for (int i = 0; i < count; ++i) { dir[PAGING_DIR_INDEX(virtual_address) + i] = physical_address & mask; } paging_load_directory((uintptr_t) dir); return PAGING_RESULT_OK; } int paging_map_memory(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) { if (mode & PAGING_MODE_4M) { return paging_map_4m(physical_address, virtual_address, count, mode); } if (paging_state < PAGING_STATE_FULL) { // can't allocate 4K pages yet if ((virtual_address & ~PAGING_MASK_4M) != (physical_address & ~PAGING_MASK_4M)) { return PAGING_RESULT_ERR; // not in same pos in 4M page } int table_index = PAGING_TABLE_INDEX(virtual_address); int pages = DIV_ROUND_UP(table_index + count, 1024); return paging_map_4m(physical_address & PAGING_MASK_4M, virtual_address & PAGING_MASK_4M, pages, mode | PAGING_MODE_4M); } return PAGING_RESULT_ERR; }