#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",
"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;
}
}
- _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);
}
ret_val = -ENOMEM;
if(dir) {
+ struct region *reg;
+
switch(_pg_flags & PG_MODE_MASK) {
case PG_MODE_LEGACY:
case PG_MODE_PAE:
/* 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 */
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);
+}