diff --git a/kernel/include/kernel.h b/kernel/include/kernel.h index 1add0d5..f75c35c 100644 --- a/kernel/include/kernel.h +++ b/kernel/include/kernel.h @@ -4,6 +4,17 @@ // Null definition #define NULL ((void*)0) +/* + * Virtual memory addresses + */ +#define USER_HEAP 0x10000000 +#define USER_STACK 0xBF000000 +#define USER_SHARED 0xA0000000 +#define KERNEL_BASE 0xC0000000 +#define KERNEL_HEAP 0xD0000000 +#define KERNEL_SHARED 0xF0000000 +#define KERNEL_FRAMEBUF 0xC8000000 + /* * Variable arguments */ diff --git a/kernel/include/paging.h b/kernel/include/paging.h index 963abfb..117cbe1 100644 --- a/kernel/include/paging.h +++ b/kernel/include/paging.h @@ -3,9 +3,13 @@ #include -#define PAGE_SIZE 4096 +#define PHYS_ADDR(_a) ((_a) & ~0xFFF) -#define PHYS_ADDR(_a) ((_a) & ~0xfff) +// The kernels pagedir +#define PAGEDIR ((uint32_t*)(0xFFFFF000)) +#define PAGETAB(_i) ((uint32_t*)(0xFFC00000 + ((_i) << 12))) + +#define PAGE_SIZE 4096 #define PAGE_FLAG_PRESENT (1 << 0) #define PAGE_FLAG_WRITE (1 << 1) @@ -13,13 +17,23 @@ #define PAGE_FLAG_PWT (1 << 3) #define PAGE_FLAG_NOCACHE (1 << 4) #define PAGE_FLAG_ACCESSED (1 << 5) -#define PAGE_FLAG_DIRTY (1 << 6) -#define PAGE_FLAG_4MB (1 << 7) +#define PAGE_FLAG_DIRTY (1 << 6) // AVL in PDE where PS = 0 +#define PAGE_FLAG_PS (1 << 7) // If PS = 1 then directly maps a 4MB page #define PAGE_FLAG_GLOBAL (1 << 8) +// bits 9-11 are AVL - OS is free to use these as its own flags +#define PAGE_FLAG_OWNER (1 << 9) -// Defined in entry.s for initial paging -extern uint32_t init_pagedir[1024]; +extern uint32_t init_pagedir[1024]; // Defined in entry.s for initial paging +extern size_t pag_pageCount; int pag_init(void); +void pag_mapPage(uint32_t vaddr, uint32_t paddr, uint32_t flags); +uint32_t pag_umapPage(uint32_t vaddr); +void* pag_virtToPhys(uint32_t vaddr); +uint32_t* pag_getPagedir(); +void pag_setPagedir(uint32_t* pagedir); +void pag_syncPagedir(); +uint32_t* pag_allocPagedir(); +void pag_freePagedir(uint32_t* pagedir); #endif diff --git a/kernel/src/entry.s b/kernel/src/entry.s index cdd5d52..85b46b2 100644 --- a/kernel/src/entry.s +++ b/kernel/src/entry.s @@ -62,8 +62,9 @@ section .data align 4096 global init_pagedir init_pagedir: - dd 0b10000011 - times 768-1 dd 0 + dd 0b10000011 ; Identity map first 4MB + times 768-1 dd 0 + ; Map first 16MB of kernel to 0xC0000000 dd (0 << 22) | 0b10000011 dd (1 << 22) | 0b10000011 dd (2 << 22) | 0b10000011 diff --git a/kernel/src/kernel.c b/kernel/src/kernel.c index 25df395..4a46101 100644 --- a/kernel/src/kernel.c +++ b/kernel/src/kernel.c @@ -15,8 +15,6 @@ void kmain(void* ptr, uint32_t magic) { // Serial console for debugging serial_init(COM1); - // ESC[H moves cursor to (0,0), ESC[J clears from cursor to end of screen - // ESC[m sets graphics mode, 0 - reset, 36 - cyan debugf("\x1b[H\x1b[J\x1b[0mkern. \x1b[36m(serial console)\x1b[0m\n\n"); // VGA tty thingy @@ -24,8 +22,8 @@ void kmain(void* ptr, uint32_t magic) { tty_puts("kern.\n\n"); // Memory manager init - // pmm_init(); - // vmm_init(); + //pmm_init(); + //vmm_init(); gdt_init(); isr_init(); diff --git a/kernel/src/paging.c b/kernel/src/paging.c index aca10d3..b0ad0b5 100644 --- a/kernel/src/paging.c +++ b/kernel/src/paging.c @@ -1,7 +1,16 @@ #include #include +#include + #include +#define PAGE_DIR_COUNT 256 +static uint32_t pagedirs[PAGE_DIR_COUNT][1024] __align(4096); +static uint8_t pagedirUsed[PAGE_DIR_COUNT]; + +// TODO: Should this be initialized? If so, to what? +size_t pag_pageCount; + // Invalidates the pagedir entry in the CPUs TLB cache static inline void invalidate(uint32_t vaddr) { __asm__ volatile ("invlpg %0" : : "m"(vaddr)); @@ -18,10 +27,199 @@ int pag_init(void) { * as a pagetab even though it's a pagedir. This maps it to * the virtual address 0xFFFFF000. */ - init_pagedir[1023] = ((uint32_t)init_pagedir - 0xC0000000) | + init_pagedir[1023] = ((uint32_t)init_pagedir - KERNEL_BASE) | PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE; invalidate(0xFFFFF000); + memset(pagedirs, 0, PAGE_SIZE * PAGE_DIR_COUNT); + memset(pagedirUsed, 0, PAGE_DIR_COUNT); + return 0; } +void pag_mapPage(uint32_t vaddr, uint32_t paddr, uint32_t flags) { + // Save the pagedir we were in + uint32_t* prevpd = NULL; + + // Switch to the init pagedir if in kernel memory + if (vaddr >= KERNEL_BASE) { + prevpd = pag_getPagedir(); + + if (prevpd != init_pagedir) pag_setPagedir(init_pagedir); + } + + // Extract indecies + size_t pdi = vaddr >> 22; + size_t pti = vaddr >> 12 & 0x3FF; + + uint32_t* pagedir = PAGEDIR; + uint32_t* pagetab = PAGETAB(pdi); + + // Allocate a pagetab if it didn't exist + if (!(pagedir[pdi] & PAGE_FLAG_PRESENT)) { + uint32_t tabaddr = (uint32_t)pmm_alloc(1); + pagedir[pdi] = tabaddr | + PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE | PAGE_FLAG_OWNER | flags; + invalidate(vaddr); + + for (size_t i = 0; i < 1024; i++) { + pagetab[i] = 0; + } + } + + // The actuall mapping + pagetab[pti] = paddr | PAGE_FLAG_PRESENT | flags; + pag_pageCount++; + invalidate(vaddr); + + // Do we need to return to the original pagedir? + if (prevpd != NULL) { + pag_syncPagedir(); // Sync it to other pagedirs + if (prevpd != init_pagedir) pag_setPagedir(prevpd); + } +} + +uint32_t pag_umapPage(uint32_t vaddr) { + // Same saving as in pag_mapPage() + uint32_t* prevpd = NULL; + + if (vaddr >= KERNEL_BASE) { + prevpd = pag_getPagedir(); + + if (prevpd != init_pagedir) pag_setPagedir(init_pagedir); + } + + // Extract indecies + size_t pdi = vaddr >> 22; + size_t pti = vaddr >> 12 & 0x3FF; + + uint32_t* pagedir = PAGEDIR; + uint32_t* pagetab = PAGETAB(pdi); + + uint32_t pte = pagetab[pti]; + pagetab[pti] = 0; + pag_pageCount--; + + // Look if we can free the pagetab + int remove = 1; + for (size_t i = 0; i < 1024; i++) { + if (!(pagetab[i] & PAGE_FLAG_PRESENT)) continue; + remove = 0; + break; + } + + // Free the pagetab if possible + uint32_t pde = pagedir[pdi]; + if (remove && pde & PAGE_FLAG_OWNER) { + uint32_t tabaddr = PHYS_ADDR(pde); + pmm_free((void*)tabaddr, 1); + pagedir[pdi] = 0; + } + + invalidate(vaddr); + + // Free the page frame + if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte), 1); + + if (prevpd != NULL) { + pag_syncPagedir(); // Sync it to other pagedirs + if (prevpd != init_pagedir) pag_setPagedir(prevpd); + } + + return pte; +} + +void* pag_virtToPhys(uint32_t vaddr) { + uint32_t pdi = vaddr >> 22; + uint32_t pti = vaddr >> 12 & 0x3FF; + + uint32_t* pagetab = PAGETAB(pdi); + + return (void*)((pagetab[pti] & ~0xFFF) + ((uint32_t)vaddr & 0xFFF)); +} + +uint32_t* pag_getPagedir() { + uint32_t pagedir; + __asm__ volatile ("mov %%cr3, %0" : "=r"(pagedir)); + pagedir += KERNEL_BASE; + return (uint32_t*)pagedir; +} + +void pag_setPagedir(uint32_t* pagedir) { + pagedir = (uint32_t*)((uint32_t)pagedir - KERNEL_BASE); + __asm__ volatile ( + "mov %0, %%eax\n" + "mov %%eax, %%cr3" + : : "m"(pagedir) + ); +} + +void pag_syncPagedir() { + for (size_t i = 0; i < PAGE_DIR_COUNT; i++) { + if (!pagedirUsed[i]) continue; + + uint32_t* pagedir = pagedirs[i]; + + // Sync ONLY the kernel pages so 768 has base at 0xC0000000 + // Also don't sync the recursive mapping in the last page + for (size_t i = 768; i < 1023; i++) { + pagedir[i] = init_pagedir[i] & ~PAGE_FLAG_OWNER; + } + } +} + +uint32_t* pag_allocPagedir() { + // Find the first unused page + for (size_t i = 0; i < PAGE_DIR_COUNT; i++) { + if (pagedirUsed[i]) continue; + pagedirUsed[i] = 1; + + uint32_t* pagedir = pagedirs[i]; + memset(pagedir, 0, PAGE_SIZE); + + // First 768 entries are user pagetabs (3:1 memory split) + for (size_t i = 0; i < 768; i++) pagedir[i] = 0; + + // Next 255 are kernel space + for (size_t i = 768; i < 1023; i++) pagedir[i] = init_pagedir[i] & ~PAGE_FLAG_OWNER; + + // Last page is the recursive table mapping + pagedir[1023] = ((uint32_t)pagedir - KERNEL_BASE) | + PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE; + + return pagedir; + } + + // No pages left - out of memory + return NULL; +} + +void pag_freePagedir(uint32_t* pagedir) { + uint32_t* prevpd = pag_getPagedir(); + pag_setPagedir(pagedir); + + uint32_t pdi = (uint32_t)pagedir - (uint32_t)pagedirs; + pdi /= PAGE_SIZE; + + // Free all allocated page frames & pagetabs + uint32_t* pd = PAGEDIR; + for (int i = 0; i < 768; i++) { + uint32_t pde = pd[i]; + if (pde == 0) continue; + + uint32_t* pagetab = PAGETAB(i); + for (size_t j = 0; j < 1024; j++) { + uint32_t pte = pagetab[j]; + + if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte), 1); + } + memset(pagetab, 0, PAGE_SIZE); + + if (pde & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pde), 1); + pd[i] = 0; + } + + pagedirUsed[pdi] = 0; + pag_setPagedir(prevpd); +} +