diff options
author | Freya Murphy <freya@freyacat.org> | 2025-04-27 14:07:11 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-04-27 14:07:11 -0400 |
commit | bec577fb669910091f09719b5bb6829b963c50c6 (patch) | |
tree | 2e15a47dcd66150e567aea950b8b666c07368f5a /kernel/memory/paging.c | |
parent | new syscalls (diff) | |
download | comus-bec577fb669910091f09719b5bb6829b963c50c6.tar.gz comus-bec577fb669910091f09719b5bb6829b963c50c6.tar.bz2 comus-bec577fb669910091f09719b5bb6829b963c50c6.zip |
fix pgdir free, fix mapadder fns
Diffstat (limited to 'kernel/memory/paging.c')
-rw-r--r-- | kernel/memory/paging.c | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index d54a26b..2cc5b7e 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -600,7 +600,8 @@ static volatile struct pte *page_alloc(volatile struct pml4 *pPML4, void *vADDR, } // free a pte (page) for a vitural address -static void page_free(volatile struct pml4 *pPML4, const void *vADDR) +static void page_free(volatile struct pml4 *pPML4, const void *vADDR, + bool deallocate) { volatile struct pte *vPTE; void *pADDR; @@ -612,17 +613,19 @@ static void page_free(volatile struct pml4 *pPML4, const void *vADDR) vPTE->flags = 0; vPTE->address = 0; - pADDR = (void *)((uintptr_t)vPTE->address << 12); - free_phys_page(pADDR); + if (deallocate) { + pADDR = (void *)((uintptr_t)vPTE->address << 12); + free_phys_page(pADDR); + } } /* map & unmap pages */ static void unmap_pages(volatile struct pml4 *pPML4, const void *vADDR, - long page_count) + long page_count, bool deallocate) { for (long i = 0; i < page_count; i++) { - page_free(pPML4, vADDR); + page_free(pPML4, vADDR, deallocate); vADDR = (char *)vADDR + PAGE_SIZE; } } @@ -644,7 +647,7 @@ static int map_pages(volatile struct pml4 *pPML4, void *vADDR, void *pADDR, return 0; fail: - unmap_pages(pPML4, vADDR, page_count); + unmap_pages(pPML4, vADDR, page_count, true); return 1; } @@ -715,26 +718,17 @@ void pgdir_free(volatile void *addr) pml4_free(addr, true); } -static inline void *page_align(void *addr) -{ - uintptr_t a = (uintptr_t)addr; - a /= PAGE_SIZE; - a *= PAGE_SIZE; - return (void *)a; -} - void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, unsigned int flags) { long pages; - ptrdiff_t error; + size_t error; void *aligned_phys; - // get length and physical page aligned address - aligned_phys = page_align(phys); - error = (char *)phys - (char *)aligned_phys; + error = (size_t)phys % PAGE_SIZE; len += error; - pages = len / PAGE_SIZE + 1; + pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + aligned_phys = (char *)phys - error; // get page aligned (or allocate) vitural address if (virt == NULL) @@ -742,6 +736,9 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, if (virt == NULL) return NULL; + assert((uint64_t)virt % PAGE_SIZE == 0, + "mem_mapaddr: vitural address not page aligned"); + if (map_pages((volatile struct pml4 *)ctx->pml4, virt, aligned_phys, F_PRESENT | flags, pages)) { virtaddr_free(&ctx->virtctx, virt); @@ -751,26 +748,57 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, return (char *)virt + error; } -void *kmapuseraddr(mem_ctx_t ctx, const void *vADDR, size_t len) +void *kmapuseraddr(mem_ctx_t ctx, const void *usrADDR, size_t len) { - char *pADDR; + volatile struct pml4 *pml4; + char *pADDR, *vADDR; + size_t npages, error, i; - pADDR = mem_get_phys(ctx, vADDR); - if (pADDR == NULL) + pml4 = (volatile struct pml4 *)kernel_mem_ctx->pml4; + npages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + error = (size_t)usrADDR % PAGE_SIZE; + vADDR = virtaddr_alloc(&kernel_mem_ctx->virtctx, npages); + if (vADDR == NULL) return NULL; - return kmapaddr(pADDR, NULL, len, F_PRESENT | F_WRITEABLE); + assert((size_t)vADDR % PAGE_SIZE == 0, + "kmapuseraddr: vitural address not page aligned"); + + for (i = 0; i < npages; i++) { + pADDR = mem_get_phys(ctx, (char *)usrADDR + i * PAGE_SIZE); + if (pADDR == NULL) + goto fail; + + // page align + pADDR = (char *)(((size_t)pADDR / PAGE_SIZE) * PAGE_SIZE); + + if (map_pages(pml4, vADDR + i * PAGE_SIZE, pADDR, + F_PRESENT | F_WRITEABLE, 1)) + goto fail; + } + + return vADDR + error; + +fail: + unmap_pages(&kernel_pml4, vADDR, i, false); + virtaddr_free(&kernel_mem_ctx->virtctx, vADDR); + return NULL; } void mem_unmapaddr(mem_ctx_t ctx, const void *virt) { + long pages; + if (virt == NULL) return; - long pages = virtaddr_free(&ctx->virtctx, virt); + // page align + virt = (void *)(((size_t)virt / PAGE_SIZE) * PAGE_SIZE); + + pages = virtaddr_free(&ctx->virtctx, virt); if (pages < 1) return; - unmap_pages(&kernel_pml4, virt, pages); + unmap_pages(&kernel_pml4, virt, pages, false); } void *mem_get_phys(mem_ctx_t ctx, const void *vADDR) @@ -877,5 +905,5 @@ void mem_free_pages(mem_ctx_t ctx, const void *virt) return; long pages = virtaddr_free(&ctx->virtctx, virt); - unmap_pages((volatile struct pml4 *)ctx->pml4, virt, pages); + unmap_pages((volatile struct pml4 *)ctx->pml4, virt, pages, true); } |