diff --git a/src/kernel/boot/kmain.c b/src/kernel/boot/kmain.c index d0c304d..d488afb 100644 --- a/src/kernel/boot/kmain.c +++ b/src/kernel/boot/kmain.c @@ -30,17 +30,9 @@ void kmain(uint64_t multiboot_magic, void *multiboot_data) debug_info("Kernel loaded with command line: \"%s\" by <%s>\n", kernel_boot_data.commandline, kernel_boot_data.bootloader); - debug_info("Memory areas:\n"); - size_t index = 0; - uintptr_t start, end; - uint32_t type; - while(!multiboot_get_memory_area(index++, &start, &end, &type)) - { - debug_info("%d %x-%x\n", type, start, end); - } - bind_interrupt(0, divbyzero); + memory_init(); - debug("Hello, world!"); + bind_interrupt(0, divbyzero); // Force a divide by zero error divide(5, 0); diff --git a/src/kernel/include/memory.h b/src/kernel/include/memory.h index 2a73ca2..2352d15 100644 --- a/src/kernel/include/memory.h +++ b/src/kernel/include/memory.h @@ -2,31 +2,54 @@ #define KERNEL_OFFSET 0xFFFFFF8000000000 -#ifdef __ASSEMBLER__ -#define V2P(a) ((a) - KERNEL_OFFSET) -#define P2V(a) ((a) + KERNEL_OFFSET) -#else -#include -#define V2P(a) ((uintptr_t)(a) &~KERNEL_OFFSET) -#define P2V(a) ((void *)((uintptr_t)(a) | KERNEL_OFFSET)) - -#define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n))) -#endif - - #define PAGE_PRESENT 0x001 #define PAGE_WRITE 0x002 #define PAGE_SIZE 0x1000 #define ENTRIES_PER_PT 512 -#ifndef __ASSEMBLER__ -#include +#ifdef __ASSEMBLER__ + #define V2P(a) ((a) - KERNEL_OFFSET) + #define P2V(a) ((a) + KERNEL_OFFSET) +#else + #include + #include + #define V2P(a) ((uintptr_t)(a) &~KERNEL_OFFSET) + #define P2V(a) ((void *)((uintptr_t)(a) | KERNEL_OFFSET)) -void *memcpy(void *dst, const void *src, size_t n); -void *memset(void *s, int c, size_t n); -void *memmove(void *dest, const void *src, size_t n); -int memcmp(const void *s1, const void *s2, size_t n); -size_t strlen(const char *s); + #define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n))) + + #define P1_OFFSET(a) (((a)>>12) & 0x1FF) + #define P2_OFFSET(a) (((a)>>21) & 0x1FF) + #define P3_OFFSET(a) (((a)>>30) & 0x1FF) + #define P4_OFFSET(a) (((a)>>39) & 0x1FF) + + // memory/memory.c + void memory_init(); + extern uint64_t kernel_P4; + + // memory/vmm.c + void vmm_init(); + uint64_t vmm_get_page(uint64_t P4, uint64_t addr); + int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags); + void vmm_clear_page(uint64_t P4, uint64_t addr, int free); + + // memory/pmm.c + void pmm_free(uint64_t page); + uint64_t pmm_alloc(); + uint64_t pmm_calloc(); + + // memory/string.c + void *memcpy(void *dst, const void *src, size_t n); + void *memset(void *s, int c, size_t n); + void *memmove(void *dest, const void *src, size_t n); + int memcmp(const void *s1, const void *s2, size_t n); + size_t strlen(const char *s); + + // Link.ld + extern int kernel_start, kernel_end; + + // boot/boot_PT.s + extern uint64_t BootP4; #endif \ No newline at end of file diff --git a/src/kernel/include/multiboot.h b/src/kernel/include/multiboot.h index 76c425b..7078b18 100644 --- a/src/kernel/include/multiboot.h +++ b/src/kernel/include/multiboot.h @@ -22,6 +22,8 @@ struct kernel_boot_data_st{ void *mmap; }; +#define MMAP_FREE 1 + extern struct kernel_boot_data_st kernel_boot_data; int multiboot_init(uint64_t magic, void *mboot_info); diff --git a/src/kernel/memory/memory.c b/src/kernel/memory/memory.c new file mode 100644 index 0000000..3b9d77f --- /dev/null +++ b/src/kernel/memory/memory.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + + +uint64_t kernel_P4; + +void memory_init() +{ + kernel_P4 = (uint64_t)&BootP4; + + uint64_t start, end; + uint32_t type, i = 0; + debug_info("Parsing memory map\n"); + while(!multiboot_get_memory_area(i++, &start, &end, &type)) + { + debug("0x%016x-0x%016x (%d)\n", start, end, type); + + for(uint64_t p = start; p < end; p += PAGE_SIZE) + { + if(p >= V2P(&kernel_start) && p < V2P(&kernel_end)) + continue; + + uint64_t vaddr = (uint64_t)P2V(p); + uint64_t page = vmm_get_page(kernel_P4, vaddr); + if(page == (uint64_t)-1 || !(page & PAGE_PRESENT)) + { + uint16_t flags = PAGE_WRITE | PAGE_PRESENT; + vmm_set_page(kernel_P4, vaddr, p, flags); + } + + if(type == MMAP_FREE) + pmm_free(p); + } + } +} \ No newline at end of file diff --git a/src/kernel/memory/pmm.c b/src/kernel/memory/pmm.c new file mode 100644 index 0000000..ce9191f --- /dev/null +++ b/src/kernel/memory/pmm.c @@ -0,0 +1,26 @@ +#include +#include + +// Physical address of next page +uint64_t next = 0; + +void pmm_free(uint64_t page) +{ + *(uint64_t *)P2V(page) = next; + next = page; +} + +uint64_t pmm_alloc() +{ + if(!next) return 0; + uint64_t page = next; + next = *(uint64_t *)P2V(page); + return page; +} + +uint64_t pmm_calloc() +{ + uint64_t page = pmm_alloc(); + memset(P2V(page), 0, PAGE_SIZE); + return page; +} \ No newline at end of file diff --git a/src/kernel/memory/vmm.c b/src/kernel/memory/vmm.c new file mode 100644 index 0000000..a6c40d8 --- /dev/null +++ b/src/kernel/memory/vmm.c @@ -0,0 +1,94 @@ +#include +#include +#include + +#define FLAGS_MASK (PAGE_SIZE-1) +#define MASK_FLAGS(addr) ((uint64_t)addr & ~FLAGS_MASK) + +#define PRESENT(p) (p & PAGE_PRESENT) + +#define PT(ptr) ((uint64_t *)P2V(MASK_FLAGS(ptr))) + +#define P4E(P4, addr) (PT(P4)[P4_OFFSET(addr)]) +#define P3E(P4, addr) (PT(P4E(P4, addr))[P3_OFFSET(addr)]) +#define P2E(P4, addr) (PT(P3E(P4, addr))[P2_OFFSET(addr)]) +#define P1E(P4, addr) (PT(P2E(P4, addr))[P1_OFFSET(addr)]) + + +static int P1_exists(uint64_t P4, uint64_t addr) +{ + + if (P4 && PRESENT(P4E(P4, addr)) && PRESENT(P3E(P4, addr)) && PRESENT(P2E(P4, addr))) + return 1; + return 0; +} + +static int touch_P1(uint64_t P4, uint64_t addr, uint16_t flags) +{ + if (!P4) return -1; + + if(!PRESENT(P4E(P4, addr)) && (!(P4E(P4,addr) = pmm_calloc()))) + return -1; + P4E(P4, addr) |= flags | PAGE_PRESENT; + + if(!PRESENT(P3E(P4, addr)) && (!(P3E(P4, addr) = pmm_calloc()))) + return -1; + P3E(P4, addr) |= flags | PAGE_PRESENT; + + if(!PRESENT(P2E(P4, addr)) && (!(P2E(P4, addr) = pmm_calloc()))) + return -1; + P2E(P4, addr) |= flags | PAGE_PRESENT; + + return 0; +} + +uint64_t vmm_get_page(uint64_t P4, uint64_t addr) +{ + if(P1_exists(P4, addr)) + return P1E(P4, addr); + return -1; +} + +int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags) +{ + if(!P1_exists(P4, addr)) + if(touch_P1(P4, addr, flags)) + return -1; + + P1E(P4, addr) = page | flags; + return 0; +} + +void vmm_clear_page(uint64_t P4, uint64_t addr, int free) +{ + if(!P1_exists(P4, addr)) + return; + + uint64_t *pt; + + P1E(P4, addr) = 0; + + if(!free) + return; + + pt = PT(P2E(P4, addr)); + for(int i = 0; i < ENTRIES_PER_PT; i++) + if(pt[i]) + return; + pmm_free(MASK_FLAGS(P2E(P4, addr))); + P2E(P4, addr) = 0; + + pt = PT(P3E(P4, addr)); + for(int i = 0; i < ENTRIES_PER_PT; i++) + if(pt[i]) + return; + pmm_free(MASK_FLAGS(P3E(P4, addr))); + P3E(P4, addr) = 0; + + pt = PT(P4E(P4, addr)); + for(int i = 0; i < ENTRIES_PER_PT; i++) + if(pt[i]) + return; + pmm_free(MASK_FLAGS(P4E(P4, addr))); + P4E(P4, addr) = 0; +} \ No newline at end of file