diff --git a/kernel/inc/mm/page_map.h b/kernel/inc/mm/page_map.h new file mode 100644 index 0000000..faec013 --- /dev/null +++ b/kernel/inc/mm/page_map.h @@ -0,0 +1,58 @@ +/* Copyright (C) Antifallobst + * + * NoxOS is free software: + * you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * NoxOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef NOX_PAGE_MAP_H +#define NOX_PAGE_MAP_H + +#include "utils/stdtypes.h" +#include "boot/boot_info.h" + +#define VIRTUAL_ADDRESS_MAX 0x1000000000000 // 256 TB (the limit of PML4s) + +typedef enum { + PM_FLAG_PRESENT = 0b0000000000000001, // 1 << 0 + PM_FLAG_READ_WRITE = 0b0000000000000010, // 1 << 1 + PM_FLAG_USER_SUPER = 0b0000000000000100, // 1 << 2 + PM_FLAG_WRITE_THROUGH = 0b0000000000001000, // 1 << 3 + PM_FLAG_CACHE_DISABLED = 0b0000000000010000, // 1 << 4 + PM_FLAG_ACCESSED = 0b0000000000100000, // 1 << 5 + PM_FLAG_LARGER_PAGES = 0b0000000010000000, // 1 << 7 + PM_FLAG_CUSTOM_0 = 0b0000001000000000, // 1 << 9 + PM_FLAG_CUSTOM_1 = 0b0000010000000000, // 1 << 10 + PM_FLAG_CUSTOM_2 = 0b0000100000000000, // 1 << 11 + PM_FLAG_NO_EXECUTE = 0x8000000000000000 // 1 << 63 +} page_map_flag_E; + +typedef struct { + uint64_t entries[512]; +}__attribute__((aligned(0x1000))) page_map_T; + +page_map_T* page_map_create (); +extern page_map_T* page_map_fetch_current (); +extern void page_map_load (page_map_T* page_map); +void page_map_map_memory (page_map_T* page_map, void* virtual_address, void* physical_address, uint64_t flags); +void page_map_unmap_memory (page_map_T* page_map, void* virtual_address); +void page_map_destruct (page_map_T* page_map); + +void page_map_entry_set_flags (uint64_t* entry, uint64_t flags); +bool page_map_entry_get_flag (uint64_t* entry, page_map_flag_E flag); +void page_map_entry_set_address (uint64_t* entry, void* address); +void* page_map_entry_get_address (uint64_t* entry); + +void paging_init (boot_info_T* boot_info); + +extern page_map_T* g_kernel_page_map; + +#endif //NOX_PAGE_MAP_H diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index c363875..111eb9b 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -19,6 +19,9 @@ #include "platform/gdt.h" #include "platform/interrupts.h" #include "mm/page_frame.h" +#include "mm/page_map.h" + +#include "utils/memory.h" void limine_terminal_print(boot_info_T* boot_info, string_t string) { boot_info->terminal->write(boot_info->terminal->terminals[0], string, string_length(string)); @@ -28,6 +31,7 @@ void kernel_init(boot_info_T* boot_info) { gdt_init(); pframe_manager_init(boot_info); idt_init(); + paging_init(boot_info); } void kmain(boot_info_T boot_info) { @@ -38,7 +42,12 @@ void kmain(boot_info_T boot_info) { kernel_init(&boot_info); // this should cause a kernel panic - int x = 1312 / 0; +// int x = 1312 / 0; + + page_map_map_memory(g_kernel_page_map, (void*)0x100000000000, pframe_request(), PM_FLAG_READ_WRITE); + memory_copy("test string", (void*)0x100000000000, 13); + log(LOG_DEBUG, (string_t)0x100000000000); + CORE_HALT_FOREVER } diff --git a/kernel/src/mm/page_map.c b/kernel/src/mm/page_map.c new file mode 100644 index 0000000..486f6de --- /dev/null +++ b/kernel/src/mm/page_map.c @@ -0,0 +1,97 @@ +/* Copyright (C) Antifallobst + * + * NoxOS is free software: + * you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * NoxOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#include "mm/page_map.h" +#include "mm/page_frame.h" +#include "mm/memory_map.h" +#include "utils/memory.h" +#include "utils/math.h" +#include "utils/logger.h" + +page_map_T* g_kernel_page_map; + +page_map_T* page_map_create() { + page_map_T* page_map = pframe_request(); + memory_set(page_map, 0, PFRAME_SIZE); + + return page_map; +} + +page_map_T* page_map_request_entry(page_map_T* page_map, uint16_t index) { + uint64_t* entry = &page_map->entries[index]; + + if (page_map_entry_get_flag(entry, PM_FLAG_PRESENT)) { + return page_map_entry_get_address(entry); + } + + page_map_T* table = pframe_request(); + memory_set(table, 0, PFRAME_SIZE); + page_map_entry_set_address(entry, (void*)((uint64_t)table >> 12)); + + page_map_entry_set_flags(entry, PM_FLAG_PRESENT | PM_FLAG_READ_WRITE); + + return table; +} + +void page_map_map_memory(page_map_T* page_map, void* virtual_address, void* physical_address, uint64_t flags) { + virtual_address = (void*)FLOOR_TO((uint64_t)virtual_address, PFRAME_SIZE); + + // Intel's Developer Manual has a nice graph, that explains how these indexes are calculated + uint16_t page_index = ((uint64_t)virtual_address >> 12) & 0x1FF; + uint16_t page_table_index = ((uint64_t)virtual_address >> 21) & 0x1FF; + uint16_t page_directory_index = ((uint64_t)virtual_address >> 30) & 0x1FF; + uint16_t page_directory_page_index = ((uint64_t)virtual_address >> 39) & 0x1FF; + page_map_T* page_directory_page = page_map_request_entry(page_map, page_directory_page_index); + page_map_T* page_directory = page_map_request_entry(page_directory_page, page_directory_index); + page_map_T* page_table = page_map_request_entry(page_directory, page_table_index); + uint64_t* page = &page_table->entries[page_index]; + + page_map_entry_set_address(page, (void*)((uint64_t)physical_address >> 12)); + page_map_entry_set_flags(page, PM_FLAG_PRESENT | flags); +} + +void page_map_unmap_memory(page_map_T* page_map, void* virtual_address) { + +} + +void page_map_destruct(page_map_T* page_map) { + +} + +void page_map_entry_set_flags(uint64_t* entry, uint64_t flags) { + *entry |= flags; +} + +bool page_map_entry_get_flag(uint64_t* entry, page_map_flag_E flag) { + return ((*entry & flag) > 0); +} + +void page_map_entry_set_address(uint64_t* entry, void* address) { + uint64_t masked_address = (uint64_t)address & 0x000000ffffffffff; + + *entry &= 0xfff0000000000fff; + *entry |= (masked_address << 12); +} + +void* page_map_entry_get_address(uint64_t* entry) { + return (void*)(*entry & 0x000ffffffffff000); +} + +void paging_init(boot_info_T* boot_info) { + // fetching the page map that was created by the bootloader + g_kernel_page_map = page_map_fetch_current(); + + log(LOG_INFO, "Paging Initialized"); +} diff --git a/kernel/src/platform/x86/paging.asm b/kernel/src/platform/x86/paging.asm new file mode 100644 index 0000000..3ff97ab --- /dev/null +++ b/kernel/src/platform/x86/paging.asm @@ -0,0 +1,9 @@ +page_map_load: + mov cr3, rax + ret +GLOBAL page_map_load + +page_map_fetch_current: + mov rax, cr3 + ret +GLOBAL page_map_fetch_current \ No newline at end of file