diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/include/comus/memory.h | 29 | ||||
-rw-r--r-- | kernel/memory/memory.c | 58 | ||||
-rw-r--r-- | kernel/memory/memory.h | 7 | ||||
-rw-r--r-- | kernel/memory/paging.c | 148 | ||||
-rw-r--r-- | kernel/memory/paging.h | 3 | ||||
-rw-r--r-- | kernel/memory/physalloc.c | 3 | ||||
-rw-r--r-- | kernel/memory/virtalloc.c | 12 | ||||
-rw-r--r-- | kernel/memory/virtalloc.h | 5 |
8 files changed, 215 insertions, 50 deletions
diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h index d91c9bb..588219e 100644 --- a/kernel/include/comus/memory.h +++ b/kernel/include/comus/memory.h @@ -126,17 +126,42 @@ void mem_unmapaddr(mem_ctx_t ctx, void *virt); /** * Allocate a single page of memory with the given paging structure * + * @param ctx - the memory context + * @param lazy - if to lazy allocate pages (alloc on fault) + * @returns the vitural address aloocated or NULL on failure + */ +void *mem_alloc_page(mem_ctx_t ctx, bool lazy); + +/** + * Allocate a single page of memory at the given vitural address with the given paging structure + * + * @param ctx - the memory context + * @param virt - the vitural address to allocate at + * @param lazy - if to lazy allocate pages (alloc on fault) * @returns the vitural address aloocated or NULL on failure */ -void *mem_alloc_page(mem_ctx_t ctx); +void *mem_alloc_page_at(mem_ctx_t ctx, void *virt, bool lazy); /** * Allocate size_t amount of contiguous virtual pages with the given paging structure * + * @param ctx - the memory context + * @param count - the number of pages to allocate + * @param lazy - if to lazy allocate pages (alloc on fault) + * @returns the address allocated or NULL on failure + */ +void *mem_alloc_pages(mem_ctx_t ctx, size_t count, bool lazy); + +/** + * Allocate size_t amount of contiguous virtual pages at a given virtural address with the given paging structure + * + * @param ctx - the memory context * @param count - the number of pages to allocate + * @param virt - the vitural address to allocate at + * @param lazy - if to lazy allocate pages (alloc on fault) * @returns the address allocated or NULL on failure */ -void *mem_alloc_pages(mem_ctx_t ctx, size_t count); +void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, bool lazy); /** * Free allocated pages with the given paging structure. diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c index 1d10414..57aa08c 100644 --- a/kernel/memory/memory.c +++ b/kernel/memory/memory.c @@ -2,6 +2,7 @@ #include <comus/asm.h> #include <comus/mboot.h> #include <comus/efi.h> +#include <comus/limits.h> #include <lib.h> #include "memory.h" @@ -9,10 +10,16 @@ #include "virtalloc.h" #include "physalloc.h" +// kernel memory context mem_ctx_t kernel_mem_ctx; static struct mem_ctx_s _kernel_mem_ctx; + +// kernel page tables extern volatile char kernel_pml4[]; -extern struct virt_ctx kernel_virt_ctx; + +// user space memory contexts +static struct mem_ctx_s user_mem_ctx[N_PROCS]; +static struct mem_ctx_s *user_mem_ctx_next = NULL; void *kmapaddr(void *phys, void *virt, size_t len, unsigned int flags) { @@ -26,12 +33,12 @@ void kunmapaddr(void *virt) void *kalloc_page(void) { - return mem_alloc_page(kernel_mem_ctx); + return mem_alloc_page(kernel_mem_ctx, false); } void *kalloc_pages(size_t count) { - return mem_alloc_pages(kernel_mem_ctx, count); + return mem_alloc_pages(kernel_mem_ctx, count, false); } void kfree_pages(void *ptr) @@ -46,7 +53,20 @@ int kload_page(void *virt) mem_ctx_t mem_ctx_alloc(void) { - panic("not yet implemented"); + mem_ctx_t ctx = user_mem_ctx_next; + if (ctx == NULL) + return NULL; + + if ((ctx->pml4 = pml4_alloc()) == NULL) + return NULL; + virtaddr_init(&ctx->virtctx); + + user_mem_ctx_next = ctx->prev; + if (ctx->prev) + ctx->prev->next = NULL; + ctx->prev = NULL; + + return ctx; } mem_ctx_t mem_ctx_clone(mem_ctx_t ctx, bool cow) @@ -59,9 +79,16 @@ mem_ctx_t mem_ctx_clone(mem_ctx_t ctx, bool cow) void mem_ctx_free(mem_ctx_t ctx) { - (void)ctx; + pml4_free(ctx->pml4); + virtaddr_cleanup(&ctx->virtctx); - panic("not yet implemented"); + if (user_mem_ctx_next == NULL) { + user_mem_ctx_next = ctx; + } else { + user_mem_ctx_next->next = ctx; + ctx->prev = user_mem_ctx_next; + user_mem_ctx_next = ctx; + } } void mem_ctx_switch(mem_ctx_t ctx) @@ -78,11 +105,10 @@ void memory_init(void) kernel_mem_ctx = &_kernel_mem_ctx; kernel_mem_ctx->pml4 = kernel_pml4; - kernel_mem_ctx->virtctx = &kernel_virt_ctx; cli(); paging_init(); - virtaddr_init(kernel_mem_ctx->virtctx); + virtaddr_init(&kernel_mem_ctx->virtctx); physalloc_init(&mmap); sti(); @@ -93,4 +119,20 @@ void memory_init(void) continue; kmapaddr((void *)seg->addr, (void *)seg->addr, seg->len, F_WRITEABLE); } + + // setup user mem ctx linked list + for (size_t i = 0; i < N_PROCS; i++) { + struct mem_ctx_s *ctx = &user_mem_ctx[i]; + ctx->next = NULL; + ctx->prev = NULL; + + if (user_mem_ctx_next == NULL) { + user_mem_ctx_next = ctx; + continue; + } + + user_mem_ctx_next->next = ctx; + ctx->prev = user_mem_ctx_next; + user_mem_ctx_next = ctx; + } } diff --git a/kernel/memory/memory.h b/kernel/memory/memory.h index c39656d..2657fc7 100644 --- a/kernel/memory/memory.h +++ b/kernel/memory/memory.h @@ -3,6 +3,11 @@ #include "virtalloc.h" struct mem_ctx_s { - struct virt_ctx *virtctx; + // page tables volatile char *pml4; + // virt addr allocator + struct virt_ctx virtctx; + // linked list + struct mem_ctx_s *next; + struct mem_ctx_s *prev; }; diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 0c74145..f6330d2 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -1,3 +1,4 @@ +#include "lib/kio.h" #include <lib.h> #include <comus/memory.h> @@ -63,63 +64,72 @@ extern volatile struct pte // paged address to read page tables // the structures are not gurenteed to be ident mapped // map them here with map_<type>(phys_addr) before useing structures -void volatile *addr_mapped = (void *)(uintptr_t)0x40004000; static volatile struct pml4e *pml4_mapped = (void *)(uintptr_t)0x40000000; static volatile struct pdpte *pdpt_mapped = (void *)(uintptr_t)0x40001000; static volatile struct pde *pd_mapped = (void *)(uintptr_t)0x40002000; static volatile struct pte *pt_mapped = (void *)(uintptr_t)0x40003000; +static volatile void *addr_mapped = (void *)(uintptr_t)0x40004000; + +// kernel start/end +extern char kernel_start[]; +extern char kernel_end[]; static inline void invlpg(volatile void *addr) { __asm__ volatile("invlpg (%0)" ::"r"(addr) : "memory"); } -static void load_addr(volatile void *phys_addr) -{ - static volatile struct pte *pt = &paging_pt[4]; - pt->address = (uint64_t)phys_addr >> 12; - pt->flags = F_PRESENT | F_WRITEABLE; - invlpg(addr_mapped); -} - -static void load_pml4(volatile void *phys) +static volatile struct pml4e *load_pml4(volatile void *phys) { static volatile struct pte *pt = &paging_pt[0]; if ((uint64_t)phys >> 12 == pt->address) - return; + return pml4_mapped; pt->address = (uint64_t)phys >> 12; pt->flags = F_PRESENT | F_WRITEABLE; invlpg(pml4_mapped); + return pml4_mapped; } -static void load_pdpt(volatile void *phys) +static volatile struct pdpte *load_pdpt(volatile void *phys) { static volatile struct pte *pt = &paging_pt[1]; if ((uint64_t)phys >> 12 == pt->address) - return; + return pdpt_mapped; pt->address = (uint64_t)phys >> 12; pt->flags = F_PRESENT | F_WRITEABLE; invlpg(pdpt_mapped); + return pdpt_mapped; } -static void load_pd(volatile void *phys) +static volatile struct pde *load_pd(volatile void *phys) { static volatile struct pte *pt = &paging_pt[2]; if ((uint64_t)phys >> 12 == pt->address) - return; + return pd_mapped; pt->address = (uint64_t)phys >> 12; pt->flags = F_PRESENT | F_WRITEABLE; invlpg(pd_mapped); + return pd_mapped; } -static void load_pt(volatile void *phys) +static volatile struct pte *load_pt(volatile void *phys) { static volatile struct pte *pt = &paging_pt[3]; if ((uint64_t)phys >> 12 == pt->address) - return; + return pt_mapped; pt->address = (uint64_t)phys >> 12; pt->flags = F_PRESENT | F_WRITEABLE; invlpg(pt_mapped); + return pt_mapped; +} + +static volatile void *load_addr(volatile void *phys_addr) +{ + static volatile struct pte *pt = &paging_pt[4]; + pt->address = (uint64_t)phys_addr >> 12; + pt->flags = F_PRESENT | F_WRITEABLE; + invlpg(addr_mapped); + return addr_mapped; } #define PAG_SUCCESS 0 @@ -488,7 +498,6 @@ static int map_pages(volatile struct pml4e *root, void *virt_start, return 0; failed: - unmap_pages(root, virt, i); return 1; @@ -498,18 +507,18 @@ void paging_init(void) { // map pdpt kernel_pml4[0].flags = F_PRESENT | F_WRITEABLE; - kernel_pml4[0].address = (uint64_t)(&kernel_pdpt_0) >> 12; + kernel_pml4[0].address = (uint64_t)(kernel_pdpt_0) >> 12; // map pd0 & pd1 kernel_pdpt_0[0].flags = F_PRESENT | F_WRITEABLE; - kernel_pdpt_0[0].address = (uint64_t)(&kernel_pd_0) >> 12; + kernel_pdpt_0[0].address = (uint64_t)(kernel_pd_0) >> 12; kernel_pdpt_0[1].flags = F_PRESENT | F_WRITEABLE; - kernel_pdpt_0[1].address = (uint64_t)(&kernel_pd_1) >> 12; + kernel_pdpt_0[1].address = (uint64_t)(kernel_pd_1) >> 12; // map pd0 entires (length N_IDENT_PTS) for (int i = 0; i < N_IDENT_PTS; i++) { kernel_pd_0[i].flags = F_PRESENT | F_WRITEABLE; - kernel_pd_0[i].address = (uint64_t)(&kernel_pd_0_ents[512 * i]) >> 12; + kernel_pd_0[i].address = (uint64_t)(kernel_pd_0_ents + 512 * i) >> 12; } // identity map kernel @@ -520,15 +529,39 @@ void paging_init(void) // map paging_pt kernel_pd_1[0].flags = F_PRESENT | F_WRITEABLE; - kernel_pd_1[0].address = (uint64_t)(&paging_pt) >> 12; + kernel_pd_1[0].address = (uint64_t)(paging_pt) >> 12; - memsetv(&paging_pt, 0, 4096); + memsetv(paging_pt, 0, 4096); // make sure we are using THESE pagetables // EFI doesnt on boot __asm__ volatile("mov %0, %%cr3" ::"r"(kernel_pml4) : "memory"); } +volatile void *pml4_alloc(void) +{ + struct pml4e *pml4_phys = alloc_phys_page(); + struct pml4e *pml4 = kmapaddr(pml4_phys, NULL, PAGE_SIZE, F_WRITEABLE); + memset(pml4, 0, PAGE_SIZE); + + if (map_pages(pml4_phys, kernel_start, kernel_start, + F_PRESENT | F_WRITEABLE, + (kernel_end - kernel_start) / PAGE_SIZE)) { + free_phys_page(pml4_phys); + kunmapaddr(pml4); + return NULL; + } + + kunmapaddr(pml4); + return pml4_phys; +} + +void pml4_free(volatile void *pml4) +{ + (void)pml4; + // TODD: free structures +} + static inline void *page_align(void *addr) { uintptr_t a = (uintptr_t)addr; @@ -552,13 +585,13 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, // get page aligned (or allocate) vitural address if (virt == NULL) - virt = virtaddr_alloc(ctx->virtctx, pages); + virt = virtaddr_alloc(&ctx->virtctx, pages); if (virt == NULL) return NULL; if (map_pages((volatile struct pml4e *)ctx->pml4, virt, aligned_phys, F_PRESENT | flags, pages)) { - virtaddr_free(ctx->virtctx, virt); + virtaddr_free(&ctx->virtctx, virt); return NULL; } @@ -567,32 +600,72 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, void mem_unmapaddr(mem_ctx_t ctx, void *virt) { - long pages = virtaddr_free(ctx->virtctx, virt); + if (virt == NULL) + return; + + long pages = virtaddr_free(&ctx->virtctx, virt); if (pages < 1) return; unmap_pages(kernel_pml4, virt, pages); } -void *mem_alloc_page(mem_ctx_t ctx) +void *mem_alloc_page(mem_ctx_t ctx, bool lazy) { - void *virt = virtaddr_alloc(ctx->virtctx, 1); + void *virt = virtaddr_alloc(&ctx->virtctx, 1); if (virt == NULL) return NULL; - if (map_page((volatile struct pml4e *)ctx->pml4, virt, NULL, F_WRITEABLE)) { - virtaddr_free(ctx->virtctx, virt); + + if (mem_alloc_page_at(ctx, virt, lazy) == NULL) { + virtaddr_free(&ctx->virtctx, virt); + return NULL; + } + + return virt; +} + +void *mem_alloc_page_at(mem_ctx_t ctx, void *virt, bool lazy) +{ + void *phys = NULL; + if (!lazy) { + if ((phys = alloc_phys_page()) == NULL) + return NULL; + } + + if (map_page((volatile struct pml4e *)ctx->pml4, virt, phys, F_WRITEABLE)) { + if (phys) + free_phys_page(phys); return NULL; } + return virt; } -void *mem_alloc_pages(mem_ctx_t ctx, size_t count) +void *mem_alloc_pages(mem_ctx_t ctx, size_t count, bool lazy) { - void *virt = virtaddr_alloc(ctx->virtctx, count); + void *virt = virtaddr_alloc(&ctx->virtctx, count); if (virt == NULL) return NULL; - if (map_pages((volatile struct pml4e *)ctx->pml4, virt, NULL, F_WRITEABLE, + + if (mem_alloc_pages_at(ctx, count, virt, lazy) == NULL) { + virtaddr_free(&ctx->virtctx, virt); + return NULL; + } + + return virt; +} + +void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, bool lazy) +{ + void *phys = NULL; + if (!lazy) { + if ((phys = alloc_phys_pages(count)) == NULL) + return NULL; + } + + if (map_pages((volatile struct pml4e *)ctx->pml4, virt, phys, F_WRITEABLE, count)) { - virtaddr_free(ctx->virtctx, virt); + if (phys) + free_phys_pages(phys, count); return NULL; } return virt; @@ -600,7 +673,10 @@ void *mem_alloc_pages(mem_ctx_t ctx, size_t count) void mem_free_pages(mem_ctx_t ctx, void *virt) { - long pages = virtaddr_free(ctx->virtctx, virt); + if (virt == NULL) + return; + + long pages = virtaddr_free(&ctx->virtctx, virt); if (pages == 1) unmap_page((volatile struct pml4e *)ctx->pml4, virt); else if (pages > 1) diff --git a/kernel/memory/paging.h b/kernel/memory/paging.h index b54d422..e2a4464 100644 --- a/kernel/memory/paging.h +++ b/kernel/memory/paging.h @@ -11,4 +11,7 @@ void paging_init(void); +volatile void *pml4_alloc(void); +void pml4_free(volatile void *pml4); + #endif /* paging.h */ diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index dc8faa8..b164358 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -112,6 +112,9 @@ void free_phys_page(void *ptr) void free_phys_pages(void *ptr, int pages) { + if (ptr == NULL) + return; + long idx = page_idx(ptr); if (idx == -1) return; diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c index 8a0d1ed..0f4de93 100644 --- a/kernel/memory/virtalloc.c +++ b/kernel/memory/virtalloc.c @@ -3,8 +3,6 @@ #include "virtalloc.h" -struct virt_ctx kernel_virt_ctx; - static struct virt_addr_node *get_node_idx(struct virt_ctx *ctx, int idx) { if (idx < BOOTSTRAP_VIRT_ALLOC_NODES) { @@ -88,7 +86,7 @@ void virtaddr_init(struct virt_ctx *ctx) .is_alloc = false, .is_used = true, }; - memsetv(ctx->bootstrap_nodes, 0, sizeof(ctx->bootstrap_nodes)); + memset(ctx, 0, sizeof(struct virt_ctx)); ctx->bootstrap_nodes[0] = init; ctx->alloc_nodes = NULL; ctx->start_node = &ctx->bootstrap_nodes[0]; @@ -169,6 +167,9 @@ void *virtaddr_alloc(struct virt_ctx *ctx, int n_pages) long virtaddr_free(struct virt_ctx *ctx, void *virtaddr) { + if (virtaddr == NULL) + return -1; + uintptr_t virt = (uintptr_t)virtaddr; if (virt % PAGE_SIZE) @@ -188,3 +189,8 @@ long virtaddr_free(struct virt_ctx *ctx, void *virtaddr) return -1; } + +void virtaddr_cleanup(struct virt_ctx *ctx) +{ + kfree(ctx->alloc_nodes); +} diff --git a/kernel/memory/virtalloc.h b/kernel/memory/virtalloc.h index 9f974c5..7bf8b91 100644 --- a/kernel/memory/virtalloc.h +++ b/kernel/memory/virtalloc.h @@ -66,4 +66,9 @@ void *virtaddr_alloc(struct virt_ctx *ctx, int pages); */ long virtaddr_free(struct virt_ctx *ctx, void *virtaddr); +/** + * Cleans up heap allocations and frees the virtalloc context + */ +void virtaddr_cleanup(struct virt_ctx *ctx); + #endif /* virtalloc.h */ |