aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2014-12-02 18:10:14 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2014-12-02 18:10:14 +0100
commit456fc99e8feac598f7c6f1a3aaa82bf994404e39 (patch)
treec2aaf5b8225f7873f8189c5606bfe9041a7fa582 /kernel
parent76795abc2f08f180b7a895aaf26e80b971caa81c (diff)
downloadkogata-456fc99e8feac598f7c6f1a3aaa82bf994404e39.tar.gz
kogata-456fc99e8feac598f7c6f1a3aaa82bf994404e39.zip
Begin implementation of paging
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile4
-rw-r--r--kernel/include/paging.h25
-rw-r--r--kernel/l0/kmain.c5
-rw-r--r--kernel/l0/loader.s9
-rw-r--r--kernel/l0/paging.c135
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 :*/