#include "platform/paging.h" #include "string.h" #include struct page_table_entry_t { uint32_t present : 1; uint32_t rw : 1; uint32_t usermode : 1; uint32_t write_through : 1; uint32_t cache_disable : 1; uint32_t accessed : 1; uint32_t dirty : 1; uint32_t pat : 1; uint32_t global : 1; uint32_t shared : 1; uint32_t type : 2; uint32_t physical_address : 20; }; extern int _kernel_start; const size_t page_size = 4096; const size_t page_bits = 12; const size_t page_table_levels = 2; struct page_table_entry_t *page_tables = (struct page_table_entry_t *)0xFFC00000; struct page_table_entry_t *page_directory = (struct page_table_entry_t *)0xFFFFF000; struct page_table_entry_t *get_pte_pointer(void *page, int level) { unsigned int directory_index = (unsigned int)page >> 22; struct page_table_entry_t *entry = NULL; if(level == 0) { entry = &page_directory[directory_index]; } else if(level == 1 && page_directory[directory_index].present) { unsigned int page_index = (unsigned int)page >> page_bits; entry = &page_tables[page_index]; } return entry; } int start_paging(void *linear_addr, physaddr_t start, physaddr_t end, uint32_t *directory, uint32_t *table, uint32_t *identity_table) { unsigned int directory_index = (unsigned int) linear_addr >> 22; physaddr_t p = start; size_t count = 0; while (p < end) { uint32_t table_entry = p + 3; int index = p / page_size; table[index - start / page_size] = table_entry; identity_table[index] = table_entry; p += page_size; count++; } directory[0] = ((uint32_t)identity_table) + 3; directory[directory_index] = ((uint32_t)table) + 3 + 1024; directory[1023] = ((uint32_t)directory) + 3; asm("mov %0, %%cr3" : : "r"(directory)); asm("mov %%cr0, %%eax \n" "or $0x80010000, %%eax \n" "mov %%eax, %%cr0" : : : "eax"); return count; } int paging_init_top_table(physaddr_t table) { struct page_table_entry_t buffer = page_directory[0]; page_directory[0].physical_address = table >> page_bits; asm volatile("invlpg 0xFFC00000" :: : "memory"); memset((void *)page_tables, 0, page_size); int last_index = (page_size / sizeof(struct page_table_entry_t)) - 1; int kernel_index = (size_t)&_kernel_start >> 22; for(int i = kernel_index; i < last_index; i++) { page_tables[i] = page_directory[i]; } page_tables[last_index].physical_address = table >> page_bits; page_tables[last_index].present = 1; page_tables[last_index].rw = 1; page_directory[0] = buffer; asm volatile("invlpg 0xFFC00000" :: : "memory"); return 0; } physaddr_t paging_current_address_space() { return page_directory[1023].physical_address << page_bits; } void paging_load_address_space(physaddr_t table) { asm volatile("mov %0, %%cr3" : : "r"(table) : "memory"); } int get_pte_type(void *page, int level) { struct page_table_entry_t *entry = get_pte_pointer(page, level); if(entry != NULL) { int flags = (entry->present ? PAGE_PRESENT | PAGE_EXECUTABLE : 0) | (entry->rw ? PAGE_RW : 0) | (entry->usermode ? PAGE_USERMODE : 0); return flags; } else { return 0; } } int set_pte_type(void *page, int level, int flags) { struct page_table_entry_t *entry = get_pte_pointer(page, level); if(entry != NULL) { entry->present = PAGE_PRESENT ? 1 : 0; entry->rw = PAGE_RW ? 1 : 0; entry->usermode = PAGE_USERMODE ? 1 : 0; return 0; } else { return -1; } } physaddr_t get_pte_address(void *page, int level) { struct page_table_entry_t *entry = get_pte_pointer(page, level); if(entry != NULL) { return entry->physical_address << page_bits | ((size_t)page & 0xFFF); } else { return -1; } } int set_pte_address(void *page, int level, physaddr_t addr) { struct page_table_entry_t *entry = get_pte_pointer(page, level); if(entry != NULL) { entry->physical_address = addr >> page_bits; return 0; } else { return -1; } } int set_pte(void *page, int level, int flags, physaddr_t addr) { if(set_pte_address(page, level, addr) == 0) { return set_pte_type(page, level, flags); } else { return -1; } } void wipe_page_table(void *page, int level) { if(level == 1 && (get_pte_type(page, 0) & PAGE_PRESENT) != 0) { unsigned int table_index = ((unsigned int)page >> page_bits) & ~0x3FF; for(int i = 0; i < 1024; i++) { page_tables[table_index + i].present = 0; page_tables[table_index + i].physical_address = 0; } } }