]> git.corax.cc Git - corax/commitdiff
Dynamically allocate the region structures that are associated with page directories
authorMatthias Kruk <m@m10k.eu>
Thu, 19 Sep 2019 05:33:12 +0000 (14:33 +0900)
committerMatthias Kruk <m@m10k.eu>
Thu, 19 Sep 2019 05:33:12 +0000 (14:33 +0900)
kernel/arch/paging.c

index 7991817df7e44a1da51d3c2032c6a6f67f8724b9..2ce5d49f2815b663fb5ac0e8e95517e746c13f40 100644 (file)
 #define _frame_clear(addr)  _frame_map[(addr) >> 17] &= ~(1 << (((addr) >> 12) & 0x1f))
 #define _frame_get(addr)    (_frame_map[(addr) >> 17] & (1 << (((addr) >> 12) & 0x1f)))
 
+extern u32_t _corax_rodata;
+extern u32_t _corax_data;
+extern u32_t _corax_bss;
 extern u32_t _mem_start;
 
+#define TEXT_BASE   ((void*)0x100000)
+#define TEXT_SIZE   ((u32_t)&_corax_rodata - 0x100000)
+#define RODATA_BASE (&_corax_rodata)
+#define RODATA_SIZE ((u32_t)&_corax_data - (u32_t)&_corax_rodata)
+#define DATA_BASE   (&_corax_data)
+#define DATA_SIZE   ((u32_t)&_corax_bss - (u32_t)&_corax_data)
+#define BSS_BASE    (&_corax_bss)
+#define BSS_SIZE    ((u32_t)&_mem_start - (u32_t)&_corax_bss)
+
 static u32_t _kernel_cr3 = 0;
 static u32_t _pg_flags = 0;
 static u32_t *_frame_map;
 static u32_t _nframes;
-static struct pagedir *_kernel_pgdir;
+static struct pagedir _kernel_pgdir;
 
 static const char *_str_pg_mode[] = {
     "legacy IA-32 mode",
@@ -44,6 +56,8 @@ static const char *_str_pg_mode[] = {
     "Intel64 mode"
 };
 
+static int _pg_dir_add_region(pg_dir_t*, void*, u32_t, u32_t, u32_t);
+
 static void* _phys_alloc(u32_t size, u32_t align)
 {
     extern u32_t _mem_start;
@@ -255,31 +269,26 @@ void* pg_init(struct multiboot_info *info)
         }
     }
 
-       _kernel_pgdir = _phys_alloc(sizeof(*_kernel_pgdir), ARCH_ALIGN);
-
-       _kernel_pgdir->pd_base = (void*)cr3;
-       _kernel_pgdir->pd_regions[REGION_TEXT].reg_base = (void*)0x100000;
-       _kernel_pgdir->pd_regions[REGION_TEXT].reg_size = (u32_t)&_mem_start - 0x100000;
-       _kernel_pgdir->pd_regions[REGION_TEXT].reg_pgsize = PAGE_SIZE;
-       _kernel_pgdir->pd_regions[REGION_TEXT].reg_attrs = PAGE_ATTR_PRESENT | PAGE_ATTR_USER;
-
-       /* what about the area between &_mem_start and _mem_start? */
-
-       _kernel_pgdir->pd_regions[REGION_HEAP].reg_base = (void*)ALIGN((u32_t)_mem_start, PAGE_SIZE);
-       _kernel_pgdir->pd_regions[REGION_HEAP].reg_size = ALIGN(CONFIG_KERNEL_HEAP_SIZE, PAGE_SIZE);
-       _kernel_pgdir->pd_regions[REGION_HEAP].reg_pgsize = PAGE_SIZE;
-       _kernel_pgdir->pd_regions[REGION_HEAP].reg_attrs = PAGE_ATTR_PRESENT | PAGE_ATTR_WRITABLE;
-
-       _kernel_pgdir->pd_regions[REGION_STACK].reg_base = &(_cpu[CPU_ID].cpu_stack0);
-       _kernel_pgdir->pd_regions[REGION_STACK].reg_size = STACK0_SIZE;
-       _kernel_pgdir->pd_regions[REGION_STACK].reg_pgsize = PAGE_SIZE;
-       _kernel_pgdir->pd_regions[REGION_STACK].reg_attrs = PAGE_ATTR_PRESENT | PAGE_ATTR_WRITABLE;
-
-       heap_init(_kernel_pgdir->pd_regions[REGION_HEAP].reg_base,
-                         _kernel_pgdir->pd_regions[REGION_HEAP].reg_size);
-
-    /* mark all page frames from 0x0 to the end of the last kernel page dir/table as used */
-    for(i = 0; i < _mem_start; i += PAGE_SIZE) {
+       /* initialize the heap, since we'll need it now */
+       heap_init((void*)_mem_start, CONFIG_KERNEL_HEAP_SIZE);
+
+       _kernel_pgdir.pd_base = (void*)cr3;
+
+       _pg_dir_add_region(&_kernel_pgdir, TEXT_BASE, TEXT_SIZE,
+                                          REGION_TEXT, PAGE_ATTR_USER);
+       _pg_dir_add_region(&_kernel_pgdir, RODATA_BASE, RODATA_SIZE,
+                                          REGION_RODATA, PAGE_ATTR_NO_EXEC);
+       _pg_dir_add_region(&_kernel_pgdir, DATA_BASE, DATA_SIZE,
+                                          REGION_DATA, PAGE_ATTR_WRITABLE | PAGE_ATTR_NO_EXEC);
+       _pg_dir_add_region(&_kernel_pgdir, BSS_BASE, BSS_SIZE,
+                                          REGION_BSS, PAGE_ATTR_WRITABLE | PAGE_ATTR_NO_EXEC);
+       /* heap region also includes allocations from _phys_alloc() */
+       _pg_dir_add_region(&_kernel_pgdir, &_mem_start,
+                                          _mem_start - (u32_t)&_mem_start + CONFIG_KERNEL_HEAP_SIZE,
+                                          REGION_HEAP, PAGE_ATTR_WRITABLE | PAGE_ATTR_NO_EXEC);
+
+    /* mark all page frames from 0x0 to the end of the kernel heap as used */
+    for(i = 0; i < _mem_start + CONFIG_KERNEL_HEAP_SIZE; i += PAGE_SIZE) {
         _frame_set(i);
     }
 
@@ -299,6 +308,8 @@ int pg_dir_alloc(pg_dir_t **dst)
        ret_val = -ENOMEM;
 
        if(dir) {
+               struct region *reg;
+
                switch(_pg_flags & PG_MODE_MASK) {
                case PG_MODE_LEGACY:
                case PG_MODE_PAE:
@@ -321,11 +332,21 @@ int pg_dir_alloc(pg_dir_t **dst)
 
                /* we have an empty page directory now - populate it */
 
-               /* map the kernel text into the new pagedir */
-               ret_val = pg_dir_map(dir, _kernel_pgdir->pd_regions[REGION_TEXT].reg_base,
-                                                        _kernel_pgdir->pd_regions[REGION_TEXT].reg_base,
-                                                        _kernel_pgdir->pd_regions[REGION_TEXT].reg_size,
-                                                        _kernel_pgdir->pd_regions[REGION_TEXT].reg_attrs);
+               /*
+                * FIXME: Should we really map the kernel text segment into the pagedir?
+                * We should probably cleanly separate the two, to avoid design flaws
+                * with speculative execution behavior of certain processors
+                */
+               for(reg = _kernel_pgdir.pd_regions; reg; reg = reg->reg_next) {
+                       switch(reg->reg_flags) {
+                       case REGION_TEXT:
+                               ret_val = pg_dir_map(dir, reg->reg_base, reg->reg_base, reg->reg_size, reg->reg_attrs);
+                               break;
+
+                       default:
+                               break;
+                       }
+               }
 
                if(ret_val) {
                        /* couldn't create the page dir - free allocations */
@@ -503,3 +524,28 @@ int pg_dir_map(pg_dir_t *pd, const void *phys, const void *virt, const u32_t siz
 
        return(ret_val);
 }
+
+static int _pg_dir_add_region(pg_dir_t *pd, void *base, u32_t size, u32_t flags, u32_t attrs)
+{
+       struct region *reg;
+       int ret_val;
+
+       ret_val = -ENOMEM;
+       reg = kmalloc(sizeof(*reg));
+
+       if(reg) {
+               dbg_printf("Region type %02x at 0x%08x:%08x\n", flags, base, size);
+               reg->reg_base = base;
+               reg->reg_size = size;
+               reg->reg_pgsize = PAGE_SIZE;
+               reg->reg_flags = flags;
+               reg->reg_attrs = attrs;
+
+               reg->reg_next = pd->pd_regions;
+               pd->pd_regions = reg;
+
+               ret_val = 0;
+       }
+
+       return(ret_val);
+}