diff --git a/.vscode/settings.json b/.vscode/settings.json index bcf69d2..d3cf7ba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "files.associations": { "bitset": "c", "algorithm": "c", - "format": "c" + "format": "c", + "multiboot.h": "c" } } \ No newline at end of file diff --git a/src/arch/x86_64/main.c b/src/arch/x86_64/main.c index ef2b896..56f0bc7 100644 --- a/src/arch/x86_64/main.c +++ b/src/arch/x86_64/main.c @@ -22,9 +22,10 @@ void x86_64_main(u32 magic, multiboot_info_t* info) } idt_init(); - mem_init(info); + mem_alloc_2mb(MiB(128) + 1); + remap_pic(); enable_interrupts(); kernel_main(); diff --git a/src/arch/x86_64/mem.c b/src/arch/x86_64/mem.c index 2981373..6204eb1 100644 --- a/src/arch/x86_64/mem.c +++ b/src/arch/x86_64/mem.c @@ -18,11 +18,6 @@ typedef struct static memory_region_t usable_regions[USABLE_REGION_SIZE]; static size_t num_regions = 0; -#define KiB(count) ((u64)count * 1024) -#define MiB(count) (KiB((u64)count) * 1024) -#define GiB(count) (MiB((u64)count) * 1024) -#define TiB(count) (GiB((u64)count) * 1024) - // Fixed at 2mb for now #define PAGE_SIZE MiB(2) @@ -36,10 +31,18 @@ static u8 page_bitmap[BITMAP_SIZE]; static u64 total_pages = 0; static u64 free_pages = 0; -#define PTE_MASK 0x00000000FFFFF000 -#define PTE_PRESENT 1 +#define PML4_INDEX(addr) (((addr) >> 39) & 0x1FF) +#define PDPT_INDEX(addr) (((addr) >> 30) & 0x1FF) +#define PD_INDEX(addr) (((addr) >> 21) & 0x1FF) -extern u64* pml4; +#define PTE_MASK 0x000FFFFFFFFFF000ULL + +#define PTE_PRESENT (1ULL << 0) +#define PTE_WRITABLE (1ULL << 1) +#define PTE_USER (1ULL << 2) +#define PTE_PS (1ULL << 7) + +extern u64 pml4[]; void mem_init(multiboot_info_t* info) { @@ -118,7 +121,7 @@ void mem_init(multiboot_info_t* info) } } -u64 mem_alloc_physical_page() +u64 mem_alloc_2mb_physical_page() { for (size_t i = 0; i < BITMAP_SIZE; i++) { @@ -139,7 +142,7 @@ u64 mem_alloc_physical_page() return 0; } -void mem_free_physical_page(u64 address) +void mem_free_2mb_physical_page(u64 address) { u64 page = address / PAGE_SIZE; if (page < BITMAP_SIZE * 8) @@ -151,3 +154,102 @@ void mem_free_physical_page(u64 address) } } } + +static u64 create_pte(u64 physical_address) +{ + if (physical_address & MiB(2) - 1) + { + printf("Physical address not 2MB aligned (0x%x)\n", physical_address); + panic("Failed to create PTE"); + } + + return (physical_address & PTE_MASK) | PTE_PRESENT | PTE_WRITABLE | PTE_PS; +} + +void mem_map_2mb_page(u64 virtual_address, u64 physical_address) +{ + u64 pml4_idx = PML4_INDEX(virtual_address); + u64 pdpt_idx = PDPT_INDEX(virtual_address); + u64 pd_idx = PD_INDEX(virtual_address); + + u64 pdpt = pml4[pml4_idx]; + if (!(pdpt & PTE_PRESENT)) + { + // todo(nub31): Dynamically create a pdpt table + printf("PDPT not present at PML4 index %u\n", pml4_idx); + panic("Failed to map virtual to physical page"); + } + + u64* pdpt_phys = (u64*)(pdpt & PTE_MASK); + u64 pd = pdpt_phys[pdpt_idx]; + if (!(pd & PTE_PRESENT)) + { + // todo(nub31): Dynamically create a pd table + printf("PD not present at PDPT index %u\n", pdpt_idx); + panic("Failed to map virtual to physical page"); + } + + u64* pd_phys = (u64*)(pd & PTE_MASK); + u64 entry = pd_phys[pd_idx]; + + if (entry & PTE_PRESENT) + { + printf("Virtual address 0x%x is already mapped\n", virtual_address); + panic("Failed to map virtual to physical page"); + } + + pd_phys[pd_idx] = create_pte(physical_address); +} + +u64 mem_unmap_2mb_page(u64 virtual_address) +{ + u64 pml4_idx = PML4_INDEX(virtual_address); + u64 pdpt_idx = PDPT_INDEX(virtual_address); + u64 pd_idx = PD_INDEX(virtual_address); + + u64 pdpt_entry = pml4[pml4_idx]; + if (!(pdpt_entry & PTE_PRESENT)) + { + printf("PDPT not present at PML4 index %llu\n", pml4_idx); + panic("Failed to unmap virtual address"); + } + + u64* pdpt_phys = (u64*)(pdpt_entry & PTE_MASK); + u64 pd_entry = pdpt_phys[pdpt_idx]; + if (!(pd_entry & PTE_PRESENT)) + { + printf("PD not present at PDPT index %llu\n", pdpt_idx); + panic("Failed to unmap virtual address"); + } + + u64* pd_phys = (u64*)(pd_entry & PTE_MASK); + if (!(pd_phys[pd_idx] & PTE_PRESENT)) + { + printf("Virtual address 0x%llx is not mapped\n", virtual_address); + panic("Failed to unmap virtual address"); + } + u64 phys = pd_phys[pd_idx] & PTE_MASK; + pd_phys[pd_idx] = 0; + + __asm__ volatile("invlpg (%0)" : : "r"(virtual_address) : "memory"); + + return phys; +} + +void* mem_alloc_2mb(u64 virtual_address) +{ + u64 phys = mem_alloc_2mb_physical_page(); + if (!phys) + { + panic("Out of physical memory"); + } + + mem_map_2mb_page(virtual_address, phys); + return (void*)virtual_address; +} + +void mem_free_2mb(u64 virtual_address) +{ + u64 phys = mem_unmap_2mb_page(virtual_address); + mem_free_2mb_physical_page(phys); +} \ No newline at end of file diff --git a/src/arch/x86_64/mem.h b/src/arch/x86_64/mem.h index 7f423d8..19c0998 100644 --- a/src/arch/x86_64/mem.h +++ b/src/arch/x86_64/mem.h @@ -3,7 +3,18 @@ #include "std.h" #include "x86_64/multiboot.h" +#define KiB(count) ((u64)count * 1024) +#define MiB(count) (KiB((u64)count) * 1024) +#define GiB(count) (MiB((u64)count) * 1024) +#define TiB(count) (GiB((u64)count) * 1024) + void mem_init(multiboot_info_t* info); -u64 mem_alloc_physical_page(); -void mem_free_physical_page(u64 address); \ No newline at end of file +u64 mem_alloc_2mb_physical_page(); +void mem_free_2mb_physical_page(u64 address); + +void mem_map_2mb_page(u64 virtual_address, u64 physical_address); +u64 mem_unmap_2mb_page(u64 virtual_address); + +void* mem_alloc_2mb(u64 virtual_address); +void mem_free_2mb(u64 virtual_address); \ No newline at end of file