diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2014-12-02 18:10:14 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2014-12-02 18:10:14 +0100 |
commit | 456fc99e8feac598f7c6f1a3aaa82bf994404e39 (patch) | |
tree | c2aaf5b8225f7873f8189c5606bfe9041a7fa582 /kernel | |
parent | 76795abc2f08f180b7a895aaf26e80b971caa81c (diff) | |
download | kogata-456fc99e8feac598f7c6f1a3aaa82bf994404e39.tar.gz kogata-456fc99e8feac598f7c6f1a3aaa82bf994404e39.zip |
Begin implementation of paging
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 4 | ||||
-rw-r--r-- | kernel/include/paging.h | 25 | ||||
-rw-r--r-- | kernel/l0/kmain.c | 5 | ||||
-rw-r--r-- | kernel/l0/loader.s | 9 | ||||
-rw-r--r-- | kernel/l0/paging.c | 135 |
5 files changed, 173 insertions, 5 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index 572bb3a..dec8686 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,7 +3,7 @@ AS = nasm ASFLAGS = -felf -g CC = i586-elf-gcc -CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I . -I ./include -g +CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I . -I ./include -g -Wno-unused-parameter # CXX = i586-elf-g++ # CXFLAGS = -ffreestanding -O3 -Wall -Wextra -I . -I ./include -fno-exceptions -fno-rtti LD = i586-elf-gcc @@ -12,7 +12,7 @@ LDFLAGS = -T linker.ld -ffreestanding -O2 -nostdlib -lgcc OBJ = lib/string.o lib/printf.o \ l0/loader.o l0/kmain.o l0/dbglog.o l0/sys.o \ l0/gdt.o l0/idt.o l0/interrupt.o \ - l0/frame.o + l0/frame.o l0/paging.o OUT = kernel.bin all: $(OUT) diff --git a/kernel/include/paging.h b/kernel/include/paging.h new file mode 100644 index 0000000..5766e65 --- /dev/null +++ b/kernel/include/paging.h @@ -0,0 +1,25 @@ +#pragma once + +#include <sys.h> + +struct page_directory; +typedef struct page_directory pagedir_t; + + +void paging_setup(void* kernel_data_end); + +pagedir_t *get_current_pagedir(); +pagedir_t *get_kernel_pagedir(); + +void switch_pagedir(pagedir_t *pd); + +uint32_t pd_get_frame(pagedir_t *pd, size_t vaddr); // get physical frame for virtual address +int pd_map_page(pagedir_t *pd, + size_t vaddr, uint32_t frame_id, + uint32_t rw); // returns nonzero on error +void pd_unmap_page(pagedir_t *pd, size_t vaddr); // does nothing if page wasn't mapped + +pagedir_t *create_pagedir(); // returns zero on error +void delete_pagedir(pagedir_t *pd); + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/l0/kmain.c b/kernel/l0/kmain.c index b4e2ef1..f6cda4e 100644 --- a/kernel/l0/kmain.c +++ b/kernel/l0/kmain.c @@ -6,6 +6,7 @@ #include <gdt.h> #include <idt.h> #include <frame.h> +#include <paging.h> void breakpoint_handler(registers_t *regs) { dbg_printf("Breakpoint! (int3)\n"); @@ -34,10 +35,14 @@ void kmain(struct multiboot_info_t *mbd, int32_t mb_magic) { // a pointer to this pointer is passed to the functions that might have // to allocate memory ; they just increment it of the allocated quantity void* kernel_data_end = (void*)K_END_ADDR; + frame_init_allocator(total_ram, &kernel_data_end); dbg_printf("kernel_data_end: 0x%p\n", kernel_data_end); dbg_print_frame_stats(); + paging_setup(kernel_data_end); + dbg_printf("Paging seems to be working!\n"); + // TODO: // - setup allocator for physical pages (eg: buddy allocator, see OSDev wiki) // - setup allocator for virtual memory space diff --git a/kernel/l0/loader.s b/kernel/l0/loader.s index 0f57549..e4c4611 100644 --- a/kernel/l0/loader.s +++ b/kernel/l0/loader.s @@ -1,5 +1,6 @@ [EXTERN kmain] ; kmain is defined in kmain.c [GLOBAL loader] ; making entry point visible to linker +[GLOBAL kernel_pagedir] ; make kernel page directory visible ; higher-half kernel setup K_HIGHHALF_ADDR equ 0xC0000000 @@ -24,7 +25,8 @@ multiboot_header: loader: ; setup the boot page directory used for higher-half - mov ecx, boot_pagedir + mov ecx, kernel_pagedir + sub ecx, K_HIGHHALF_ADDR ; access its lower-half address mov cr3, ecx ; Set PSE bit in CR4 to enable 4MB pages. @@ -41,8 +43,9 @@ loader: lea ecx, [higherhalf] jmp ecx +[section .data] align 0x1000 -boot_pagedir: +kernel_pagedir: ; uses 4MB pages ; identity-maps the first 4Mb of RAM, and also maps them with offset += k_highhalf_addr dd 0x00000083 @@ -53,7 +56,7 @@ boot_pagedir: [section .text] higherhalf: ; now we're running in higher half ; unmap first 4Mb - mov dword [boot_pagedir], 0 + mov dword [kernel_pagedir], 0 invlpg [0] mov esp, stack_top ; set up the stack diff --git a/kernel/l0/paging.c b/kernel/l0/paging.c new file mode 100644 index 0000000..9e9df6b --- /dev/null +++ b/kernel/l0/paging.c @@ -0,0 +1,135 @@ +#include <paging.h> +#include <frame.h> + +typedef union page { + struct { + uint32_t present : 1; + uint32_t rw : 1; + uint32_t user : 1; + uint32_t write_through : 1; + uint32_t disable_cache : 1; + uint32_t accessed : 1; + uint32_t dirty : 1; // only PTE + uint32_t size_4m : 1; // only PDE + uint32_t global : 1; // only PTE + uint32_t rsvd : 3; + uint32_t frame : 20; + }; + uint32_t as_int32; +} page_t; + +typedef struct page_table { + page_t page[1024]; +} pagetable_t; + +struct page_directory { + pagetable_t *pt[1024]; // virtual addresses of each page table + pagetable_t *dir; // virtual address of page directory + size_t phys_addr; // physical address of page directory +}; + + +// access kernel page directory page defined in loader.s +// (this is a correct higher-half address) +extern pagetable_t kernel_pagedir; + +static pagetable_t __attribute__((aligned(PAGE_SIZE))) kernel_pt768; +static pagedir_t kernel_pd; + +static pagedir_t *current_pd; + +void paging_setup(void* kernel_data_end) { + size_t n_kernel_pages = + PAGE_ALIGN_UP((size_t)kernel_data_end - K_HIGHHALF_ADDR)/PAGE_SIZE; + + ASSERT(n_kernel_pages <= 1024); + + // setup kernel_pd structure + kernel_pd.dir = &kernel_pagedir; + kernel_pd.phys_addr = (size_t)kernel_pd.dir - K_HIGHHALF_ADDR; + for (size_t i = 0; i < 1024; i++) kernel_pd.pt[i] = 0; + + // setup kernel_pt768 + for (size_t i = 0; i < n_kernel_pages; i++) { + kernel_pt768.page[i].as_int32 = 0; // clear any junk + kernel_pt768.page[i].present = 1; + kernel_pt768.page[i].user = 0; + kernel_pt768.page[i].rw = 1; + kernel_pt768.page[i].frame = i; + } + for (size_t i = n_kernel_pages; i < 1024; i++){ + kernel_pt768.page[i].as_int32 = 0; + } + + // replace 4M mapping by kernel_pt768 + kernel_pd.pt[768] = &kernel_pt768; + kernel_pd.dir->page[768].as_int32 = + (((size_t)&kernel_pt768 - K_HIGHHALF_ADDR) & PAGE_MASK) | 0x07; + + current_pd = &kernel_pd; + + // paging already enabled in loader, nothing to do. + + // disable 4M pages (remove PSE bit in CR4) + uint32_t cr4; + asm volatile("movl %%cr4, %0": "=r"(cr4)); + cr4 &= ~0x00000010; + asm volatile("movl %0, %%cr4":: "r"(cr4)); + + // TODO : setup page fault handler +} + +pagedir_t *get_current_pagedir() { + return current_pd; +} + +pagedir_t *get_kernel_pagedir() { + return &kernel_pd; +} + +void switch_pagedir(pagedir_t *pd) { + asm volatile("movl %0, %%cr3":: "r"(pd->phys_addr)); +} + +// ============================== // +// Mapping and unmapping of pages // +// ============================== // + +uint32_t pd_get_frame(pagedir_t *pd, size_t vaddr) { + uint32_t page = vaddr / PAGE_SIZE; + uint32_t pt = page / PAGE_SIZE; + uint32_t pt_page = page % PAGE_SIZE; + + if (pd == 0) return 0; + if (pd->pt[pt] == 0) return 0; + if (!pd->pt[pt]->page[pt_page].present) return 0; + return pd->pt[pt]->page[pt_page].frame; +} + +int pd_map_page(pagedir_t *pd, size_t vaddr, uint32_t frame_id, uint32_t rw) { + return 1; // TODO +} + +void pd_unmap_page(pagedir_t *pd, size_t vaddr) { + uint32_t page = vaddr / PAGE_SIZE; + uint32_t pt = page / PAGE_SIZE; + uint32_t pt_page = page % PAGE_SIZE; + + if (pd == 0) return; + if (pd->pt[pt] == 0) return; + if (!pd->pt[pt]->page[pt_page].present) return; + pd->pt[pt]->page[pt_page].as_int32 = 0; + + // TODO (?) : if pagetable is completely empty, free it +} + +// Creation and deletion of page directories + +pagedir_t *create_pagedir() { + return 0; // TODO +} +void delete_pagedir(pagedir_t *pd) { + return; // TODO +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ |