diff --git a/.vscode/settings.json b/.vscode/settings.json index 8ce5afb..4fdf5e5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,6 +15,9 @@ "unordered_set": "c", "vector": "c", "any": "c", - "system_error": "c" + "system_error": "c", + "std.h": "c", + "panic.h": "c", + "pmm.h": "c" } } \ No newline at end of file diff --git a/src/arch/x86_64/arch.c b/src/arch/x86_64/arch.c index d62bbb5..773fbd6 100644 --- a/src/arch/x86_64/arch.c +++ b/src/arch/x86_64/arch.c @@ -1,6 +1,6 @@ #include "arch.h" #include "console.h" -#include "mem.h" +#include "mem/pmm.h" #include "panic.h" #include "util.h" diff --git a/src/arch/x86_64/main.c b/src/arch/x86_64/main.c index ad45f71..2516aa4 100644 --- a/src/arch/x86_64/main.c +++ b/src/arch/x86_64/main.c @@ -2,7 +2,7 @@ #include "interrupts/idt.h" #include "interrupts/irq.h" #include "kernel.h" -#include "mem.h" +#include "mem/pmm.h" #include "panic.h" #include "util.h" @@ -24,7 +24,7 @@ void x86_64_main(u32 magic, multiboot_info_t* info) remap_pic(); enable_interrupts(); - mem_init(info); + pmm_init(info); kernel_main(); } diff --git a/src/arch/x86_64/mem.h b/src/arch/x86_64/mem.h deleted file mode 100644 index 7cb863f..0000000 --- a/src/arch/x86_64/mem.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#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) - -// Fixed at 2mb for now -#define PAGE_SIZE MiB(2) -// Defines the theoretical max memory the kernel can allocate, not the actual memory of the system -// The value must be a multible of 8 -#define MAX_MEMORY GiB(64) - -void mem_init(multiboot_info_t* info); - -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 diff --git a/src/arch/x86_64/mem.c b/src/arch/x86_64/mem/pmm.c similarity index 50% rename from src/arch/x86_64/mem.c rename to src/arch/x86_64/mem/pmm.c index c310898..350d49d 100644 --- a/src/arch/x86_64/mem.c +++ b/src/arch/x86_64/mem/pmm.c @@ -1,4 +1,4 @@ -#include "mem.h" +#include "pmm.h" #include "x86_64/panic.h" typedef struct @@ -25,20 +25,7 @@ static u8 page_bitmap[BITMAP_SIZE]; static u64 total_pages = 0; static u64 free_pages = 0; -#define PML4_INDEX(addr) (((addr) >> 39) & 0x1FF) -#define PDPT_INDEX(addr) (((addr) >> 30) & 0x1FF) -#define PD_INDEX(addr) (((addr) >> 21) & 0x1FF) - -#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) +void pmm_init(multiboot_info_t* info) { if (!(info->flags & (1 << 6))) { @@ -115,7 +102,7 @@ void mem_init(multiboot_info_t* info) } } -u64 mem_alloc_2mb_physical_page() +u64 pmm_alloc() { for (size_t i = 0; i < BITMAP_SIZE; i++) { @@ -136,7 +123,7 @@ u64 mem_alloc_2mb_physical_page() return 0; } -void mem_free_2mb_physical_page(u64 address) +void pmm_free(u64 address) { u64 page = address / PAGE_SIZE; if (page < BITMAP_SIZE * 8) @@ -147,103 +134,4 @@ void mem_free_2mb_physical_page(u64 address) free_pages++; } } -} - -static u64 create_pte(u64 physical_address) -{ - if (physical_address & (PAGE_SIZE - 1)) - { - printf("Physical address not page 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/pmm.h b/src/arch/x86_64/mem/pmm.h new file mode 100644 index 0000000..dc195cb --- /dev/null +++ b/src/arch/x86_64/mem/pmm.h @@ -0,0 +1,19 @@ +#pragma once + +#include "std.h" +#include "x86_64/multiboot.h" + +// Fixed at 2mb for now +#define PAGE_SIZE MiB(2) + +// Defines the theoretical max memory the kernel can allocate, not the actual memory of the system +// The value must be a multible of 8 +#define MAX_MEMORY GiB(64) + +void pmm_init(multiboot_info_t* info); + +// Allocate a 2mb physical page +u64 pmm_alloc(); + +// Free the 2mb physical page at the specified address +void pmm_free(u64 address); \ No newline at end of file diff --git a/src/arch/x86_64/mem/vmm.c b/src/arch/x86_64/mem/vmm.c new file mode 100644 index 0000000..5f4bdac --- /dev/null +++ b/src/arch/x86_64/mem/vmm.c @@ -0,0 +1,115 @@ +#include "vmm.h" +#include "pmm.h" +#include "x86_64/panic.h" + +#define PML4_INDEX(addr) (((addr) >> 39) & 0x1FF) +#define PDPT_INDEX(addr) (((addr) >> 30) & 0x1FF) +#define PD_INDEX(addr) (((addr) >> 21) & 0x1FF) + +#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[]; + +static u64 create_pte(u64 physical_address) +{ + if (physical_address & (PAGE_SIZE - 1)) + { + printf("Physical address not page aligned (0x%x)\n", physical_address); + panic("Failed to create PTE"); + } + + return (physical_address & PTE_MASK) | PTE_PRESENT | PTE_WRITABLE | PTE_PS; +} + +void vmm_map(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 vmm_unmap(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* vmm_alloc(u64 virtual_address) +{ + u64 phys = pmm_alloc(); + if (!phys) + { + panic("Out of physical memory"); + } + + vmm_map(virtual_address, phys); + return (void*)virtual_address; +} + +void vmm_free(u64 virtual_address) +{ + u64 phys = vmm_unmap(virtual_address); + pmm_free(phys); +} \ No newline at end of file diff --git a/src/arch/x86_64/mem/vmm.h b/src/arch/x86_64/mem/vmm.h new file mode 100644 index 0000000..3c37d6d --- /dev/null +++ b/src/arch/x86_64/mem/vmm.h @@ -0,0 +1,9 @@ +#pragma once + +#include "std.h" + +void vmm_map(u64 virtual_address, u64 physical_address); +u64 vmm_unmap(u64 virtual_address); + +void* vmm_alloc(u64 virtual_address); +void vmm_free(u64 virtual_address); \ No newline at end of file diff --git a/src/stdlib/def.h b/src/stdlib/def.h index 3d73020..b76c668 100644 --- a/src/stdlib/def.h +++ b/src/stdlib/def.h @@ -61,3 +61,8 @@ typedef signed long long i64; #define INTMAX_C(x) x##LL #define UINTMAX_C(x) x##ULL + +#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) \ No newline at end of file