]> git.corax.cc Git - corax/commitdiff
Fix several paging-related issues; implement functions to get the addresses of the...
authorMatthias Kruk <m@m10k.eu>
Tue, 24 Sep 2019 08:39:34 +0000 (17:39 +0900)
committerMatthias Kruk <m@m10k.eu>
Tue, 24 Sep 2019 08:39:51 +0000 (17:39 +0900)
kernel/arch/paging.c
kernel/arch/paging.h

index ee1587bfa4421def52becbe61dd3291c2c4316c1..d7ff02e7ed674ceb90ec469ac5191ad9ff210708 100644 (file)
@@ -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;
index 9750143f81b40942fe6d664d4036087e34b3e688..da4a6e4253076b0fd73daa4ca63bb79cbfe66845 100644 (file)
@@ -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 */