From 1f62bbd297bf7a0760823e9b8450a185a4f35c48 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Tue, 24 Sep 2019 17:39:34 +0900 Subject: [PATCH] Fix several paging-related issues; implement functions to get the addresses of the kernel and user-space stack that is mapped within a page directory --- kernel/arch/paging.c | 153 ++++++++++++++++++++++++++++++++++++++++++- kernel/arch/paging.h | 3 + 2 files changed, 153 insertions(+), 3 deletions(-) diff --git a/kernel/arch/paging.c b/kernel/arch/paging.c index ee1587b..d7ff02e 100644 --- a/kernel/arch/paging.c +++ b/kernel/arch/paging.c @@ -43,7 +43,7 @@ extern u32_t _mem_start; #define BSS_BASE (&_corax_bss) #define BSS_SIZE ((u32_t)&_mem_start - (u32_t)&_corax_bss) -static u32_t _kernel_cr3 = 0; +u32_t _kernel_cr3 = 0; static u32_t _pg_flags = 0; static u32_t *_frame_map; static u32_t _nframes; @@ -57,6 +57,7 @@ static const char *_str_pg_mode[] = { }; static int _pg_dir_add_region(pg_dir_t*, void*, u32_t, u32_t, u32_t); +int _pg_dir_vpxlate(pg_dir_t*, u32_t, u32_t*); static void* _phys_alloc(u32_t size, u32_t align) { @@ -406,6 +407,93 @@ void* pg_init(struct multiboot_info *info) return((void*)(cr3 | _pg_flags)); } +void* pg_dir_get_kstack(struct pagedir *pgdir) +{ + struct region *reg; + void *ret_val; + + for(ret_val = NULL, reg = pgdir->pd_regions; reg; reg = reg->reg_next) { + if(reg->reg_type == REGION_KSTACK) { + u32_t virt; + u32_t phys; + + virt = (u32_t)reg->reg_base; + _pg_dir_vpxlate(pgdir, virt, &phys); + + ret_val = (void*)phys; + break; + } + } + + return(ret_val); +} + +void* pg_dir_get_ustack(struct pagedir *pgdir) +{ + struct region *reg; + void *ret_val; + + for(ret_val = NULL, reg = pgdir->pd_regions; reg; reg = reg->reg_next) { + if(reg->reg_type == REGION_STACK) { + ret_val = reg->reg_base; + break; + } + } + + return(ret_val); +} + +int _pg_dir_vpxlate(struct pagedir *pgdir, u32_t virt, u32_t *phys) +{ + int ret_val; + + /* + * FIXME: This function will not work from any other page directory + * than _kernel_pgdir, since the other directories don't have the paging + * structures mapped + */ + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: { + struct page_table *dir; + u32_t i; + + ret_val = -EFAULT; + dir = (struct page_table*)pgdir->pd_base; + i = virt >> 22; + + /* check if the page directory entry is present */ + if(!(dir->pt_entries[i] & PAGE_ATTR_PRESENT)) { + break; + } + + /* check if a 4M page is referenced */ + if(dir->pt_entries[i] & PAGE_ATTR_SIZE) { + ret_val = 0; + *phys = (dir->pt_entries[i] & ~0x3fffff) | (virt & 0x3fffff); + break; + } + + /* get a pointer to the referenced page table */ + dir = (struct page_table*)(dir->pt_entries[i] & 0xfffff000); + i = (virt >> 12) & 0x3ff; + + /* resolve the page, if it is present */ + if(dir->pt_entries[i] & PAGE_ATTR_PRESENT) { + *phys = (dir->pt_entries[i] & 0xfffff000) | (virt & 0xfff); + ret_val = 0; + } + + break; + } + + default: + ret_val = -ENOSYS; + break; + } + + return(ret_val); +} + int _pg_dir_kstack_map(struct pagedir *pgdir) { int ret_val; @@ -424,12 +512,14 @@ int _pg_dir_kstack_map(struct pagedir *pgdir) ret_val = pg_dir_map(pgdir, frame, vaddr, PAGE_SIZE, attrs); if(ret_val < 0) { + dbg_printf("pg_dir_map() failed\n"); goto cleanup; } ret_val = _pg_dir_add_region(pgdir, vaddr, PAGE_SIZE, REGION_KSTACK, attrs); if(ret_val < 0) { + dbg_printf("_pg_dir_add_region() failed\n"); goto cleanup; } @@ -448,6 +538,49 @@ cleanup: return(ret_val); } +int _pg_dir_ustack_map(struct pagedir *pgdir) +{ + int ret_val; + void *frame; + + ret_val = -ENOMEM; + frame = pg_frame_alloc_end(); + + if(ret_val) { + u32_t attrs; + void* vaddr; + + vaddr = (void*)((u32_t)CONFIG_KERNEL_STACK_BASE - PAGE_SIZE); + attrs = PAGE_ATTR_PRESENT | PAGE_ATTR_WRITABLE | PAGE_ATTR_USER | PAGE_ATTR_NO_EXEC; + + ret_val = pg_dir_map(pgdir, frame, vaddr, PAGE_SIZE, attrs); + + if(ret_val < 0) { + goto cleanup; + } + + ret_val = _pg_dir_add_region(pgdir, vaddr, PAGE_SIZE, REGION_STACK, attrs); + + if(ret_val < 0) { + goto cleanup; + } + + ret_val = 0; + } + +cleanup: + if(ret_val < 0) { + pg_dir_unmap(pgdir, (void*)((u32_t)CONFIG_KERNEL_STACK_BASE - PAGE_SIZE), + PAGE_SIZE); + + if(frame) { + pg_frame_free(frame); + } + } + + return(ret_val); +} + int pg_dir_create(pg_dir_t **dst) { int ret_val; @@ -498,6 +631,12 @@ int pg_dir_create(pg_dir_t **dst) ret_val = pg_dir_map(dir, reg->reg_base, reg->reg_base, reg->reg_size, reg->reg_attrs); + + if(ret_val >= 0) { + ret_val = _pg_dir_add_region(dir, reg->reg_base, reg->reg_size, + reg->reg_type, reg->reg_attrs); + } + break; default: @@ -505,15 +644,22 @@ int pg_dir_create(pg_dir_t **dst) } } + /* map the vesa memory into the pagedir */ + pg_dir_map(dir, (void*)0xb8000, (void*)0xb8000, 0x2000, PAGE_ATTR_PRESENT | PAGE_ATTR_WRITABLE); + /* allocate the kernel stack */ ret_val = _pg_dir_kstack_map(dir); + /* allocate the user-space stack */ + ret_val = _pg_dir_ustack_map(dir); + #if FEATURE(DEBUG) _pg_dir_debug_regions(dir); _pg_dir_debug_arch(dir); #endif /* FEATURE(DEBUG) */ if(ret_val) { + dbg_printf("Failed to create the pagedir\n"); /* couldn't create the page dir - free allocations */ kfree(dir); dir = NULL; @@ -530,7 +676,7 @@ static int _pg_dir_map_legacy(page_table_t *pd, u32_t paddr, u32_t vaddr, { int ret_val; - ret_val = -EINVAL; + ret_val = 0; while(size > 0) { struct page_table *pt; @@ -698,7 +844,8 @@ int pg_dir_unmap(pg_dir_t *pd, const void *base, const u32_t size) return(-ENOSYS); } -static int _pg_dir_add_region(pg_dir_t *pd, void *base, u32_t size, u32_t type, u32_t attrs) +static int _pg_dir_add_region(pg_dir_t *pd, void *base, u32_t size, + u32_t type, u32_t attrs) { struct region *reg; int ret_val; diff --git a/kernel/arch/paging.h b/kernel/arch/paging.h index 9750143..da4a6e4 100644 --- a/kernel/arch/paging.h +++ b/kernel/arch/paging.h @@ -100,4 +100,7 @@ int pg_dir_create(pg_dir_t**); int pg_dir_map(pg_dir_t*, const void*, const void*, const u32_t, const u32_t); int pg_dir_unmap(pg_dir_t*, const void*, const u32_t); +void* pg_dir_get_kstack(pg_dir_t*); +void* pg_dir_get_ustack(pg_dir_t*); + #endif /* __PAGING_H */ -- 2.47.3