From 8ca60f51b2566a2f839eb2b83633eab654a0d5ad Mon Sep 17 00:00:00 2001 From: =?utf8?q?Duje=20Mihanovi=C4=87?= Date: Fri, 17 Jun 2022 10:57:56 +0200 Subject: [PATCH] Enable paging in bootloader This makes interrupt handling functional. The keyboard handler also tries to read from an unmapped address to demonstrate the page fault handler. --- Makefile | 2 +- boot/x86/stage3/loader.s | 8 ++- boot/x86/stage3/paging.s | 80 ++++++++++++++++++++++++++++ include/arch/x86/mm/paging.h | 3 -- kernel/arch/x86/irq/sample_handler.c | 31 ++++++----- kernel/arch/x86/mm/paging.c | 13 ----- kernel/kernel.c | 32 +---------- kernel/linker.ld | 10 ++-- 8 files changed, 112 insertions(+), 67 deletions(-) create mode 100644 boot/x86/stage3/paging.s delete mode 100644 kernel/arch/x86/mm/paging.c diff --git a/Makefile b/Makefile index 5b40214..c823fc4 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ export GIT_REV = $(shell git describe --long HEAD) CFLAGS = -g -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\" -KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/arch/x86/mm/paging.o kernel/kernel.o +KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/kernel.o BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN diff --git a/boot/x86/stage3/loader.s b/boot/x86/stage3/loader.s index ec08c61..2967c6e 100644 --- a/boot/x86/stage3/loader.s +++ b/boot/x86/stage3/loader.s @@ -160,7 +160,11 @@ bits 32 mov ss, ax mov fs, ax mov gs, ax - call 0x100000 + + call load_paging_structs + call enable_paging + + call 0xc0000000 hlt jmp $-1 @@ -186,3 +190,5 @@ ss_s: db "SS: ", 0 space: db " ", 0 hex_delm: db "0x", 0 newline: db 0xd, 0xa, 0 + +%include "paging.s" diff --git a/boot/x86/stage3/paging.s b/boot/x86/stage3/paging.s new file mode 100644 index 0000000..004da84 --- /dev/null +++ b/boot/x86/stage3/paging.s @@ -0,0 +1,80 @@ +; Code for enabling paging before calling the kernel +; Identity maps the VGA framebuffer memory and high-half maps the kernel memory +bits 32 + +section .text + +; The problem with this code is that it assumes that the kernel's various +; sections occupy a certain number of pages. As of writing it is correct, but as +; the kernel grows this code may fail to map those pages, which is not good. The +; solution to this is to use ELF instead of a flat binary. This was not done +; before because it would require paging, but now that paging works using ELF is +; a possibility which must be exploited. + +enable_paging: + push eax + mov eax, cr0 + or eax, 0x80000000 + mov cr0, eax + pop eax + ret + +load_paging_structs: + push eax + push ebx + xor ebx, ebx +.pt_low_loop: + mov eax, ebx + shl eax, 12 + or eax, 1|2 ; P and R/W flags + mov [page_table_low+ebx*4], eax + inc ebx + cmp ebx, 0x100 + jl .pt_low_loop + + xor ebx, ebx +.pt_high_ro_loop: + mov eax, ebx + add eax, 0x100 + shl eax, 12 + or eax, 1 ; P flag + mov [page_table_high+ebx*4], eax + inc ebx + cmp ebx, 0x2 + jl .pt_high_ro_loop + + mov ebx, 0x2 +.pt_high_rw_loop: + mov eax, ebx + add eax, 0x100 + shl eax, 12 + or eax, 1|2 ; P and R/W flags + mov [page_table_high+ebx*4], eax + inc ebx + cmp ebx, 0x9 + jl .pt_high_rw_loop + + mov eax, page_table_low + and eax, 0xfffff000 + or eax, 1|2 + mov [page_directory], eax + + mov eax, page_table_high + and eax, 0xfffff000 + or eax, 1|2 + mov [page_directory+768*4], eax + + mov eax, page_directory + mov cr3, eax + pop ebx + pop eax + ret + +section .data +align 4096 +page_table_low: + times 1024 dd 0 +page_table_high: + times 1024 dd 0 +page_directory: + times 1024 dd 0 diff --git a/include/arch/x86/mm/paging.h b/include/arch/x86/mm/paging.h index 7d5d13f..a4bdf22 100644 --- a/include/arch/x86/mm/paging.h +++ b/include/arch/x86/mm/paging.h @@ -32,7 +32,4 @@ struct pf_errcode { unsigned p: 1, wr: 1, us: 1, rsvd: 1, id: 1, pk: 1, ss: 1, hlat: 1, reserved: 7, sgx: 1, reserved2: 15; } __attribute__((packed)); -extern inline void slice_linear_addr(void *address, short *pde, short *pte, short *offset); -extern inline void enable_paging(); - #endif diff --git a/kernel/arch/x86/irq/sample_handler.c b/kernel/arch/x86/irq/sample_handler.c index 66a3223..0ba0222 100644 --- a/kernel/arch/x86/irq/sample_handler.c +++ b/kernel/arch/x86/irq/sample_handler.c @@ -13,7 +13,7 @@ struct interrupt_frame { }; struct fault_frame { - uint32_t error_code; + struct pf_errcode error_code; uintptr_t eip; uint16_t cs; uint32_t eflags; @@ -27,28 +27,33 @@ void keyb_handler(struct interrupt_frame *frame) pic_send_eoi(1); kprint("Got a keyboard interrupt!\n", 0); inb(0x60); + int a = *(int *) (0xa0000000); } __attribute__((interrupt)) void pf_handler(struct fault_frame *frame) { - struct pf_errcode *errcode = &(frame->error_code); + int address; + struct pf_errcode errcode = frame->error_code; + asm ("mov %%cr2, %0": "=a" (address)); kprint("A page fault occurred!\n", VGA_COLOR_DARK_RED); - if (errcode->p) { - kprint("Attempted to access non-present page\n", 0); + kprint("Faulting address: ", 0); + kprintd(address); + kprint("\n", 0); + if (!errcode.p) { + kprint("Address points to non-mapped page\n", 0); } - if (errcode->wr) { - kprint("Kernel attempted to write to page\n", 0); - } else kprint("Kernel attempted to read from page\n", 0); - if (errcode->id) { + if (errcode.wr) { + kprint("Fault occurred while writing to memory\n", 0); + } else { + kprint("Fault occurred while reading from memory\n", 0); + } + if (errcode.id) { kprint("Fault occurred while fetching instruction\n", 0); } - int cr2; - asm ("mov %%cr2, %0": "=a" (cr2)); - kprint("CR2: ", 0); - kprintd(cr2); + asm("cli"); halt: - asm ("cli; hlt"); + asm("hlt"); goto halt; } diff --git a/kernel/arch/x86/mm/paging.c b/kernel/arch/x86/mm/paging.c deleted file mode 100644 index 9a4bc06..0000000 --- a/kernel/arch/x86/mm/paging.c +++ /dev/null @@ -1,13 +0,0 @@ -#include - -inline void slice_linear_addr(void *address, short *pde, short *pte, short *offset) -{ - *pde = (int) address >> 22; - *pte = ((int) address >> 12) & 0x3ff; - *offset = (int) address & 0xfff; -} - -inline void enable_paging(struct page_directory_entry page_dir) -{ - asm ("mov %0, %%eax; mov %%eax, %%cr3; mov %%cr0, %%eax; or $0x80000000, %%eax; mov %%eax, %%cr0": : "m" (page_dir) : "eax" ); -} diff --git a/kernel/kernel.c b/kernel/kernel.c index b274340..060051c 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -11,36 +11,13 @@ extern void pf_handler(struct fault_frame *frame); static struct idt_descriptor idt[256] __attribute__((aligned(0x10))); static struct idtr idtr __attribute__((aligned(0x10))); -static struct page_directory_entry page_dir[1024] __attribute__((aligned(0x1000))); -static struct page_table_entry page_table[1024] __attribute__((aligned(0x1000))); void kmain(void) { screen_clear(); kprint("Welcome to Nameless OS!\nRunning revision: ", 0); kprint(GIT_COMMIT, 0); - kprint("\nEnabling paging...\n", 0); - for (int i=0xb8; i < 0xc0; i++) { - page_table[i].p = 1; - page_table[i].rw = 0; - page_table[i].us = 0; - page_table[i].page_frame_addr = i; - } - for (int i=0x100; i < 0x102; i++) { - page_table[i].p = 1; - page_table[i].rw = 0; - page_table[i].us = 0; - page_table[i].page_frame_addr = i; - } - for (int i=0x102; i < 0x110; i++) { - page_table[i].p = 1; - page_table[i].rw = 1; - page_table[i].us = 0; - page_table[i].page_frame_addr = i; - } - page_dir[0].p = 1; - page_dir[0].page_table_addr = (int) &page_table >> 12; - enable_paging(page_dir); + kprint("\n", 0); kprint("Preparing IDT...\n", 0); idt_set_descriptor(idt, 8, 0x8, (uint32_t) double_fault, IDT_INTERRUPT_GATE, 0x0); idt_set_descriptor(idt, 14, 0x8, (uint32_t) pf_handler, IDT_INTERRUPT_GATE, 0x0); @@ -54,12 +31,5 @@ void kmain(void) pic_unmask(1); asm volatile ("sti"); kprint("All done\n", 0); - struct idtr curr_idtr; - asm ("sidt %0": "=m" (curr_idtr)); - kprintw(curr_idtr.limit); - kprintd(curr_idtr.base); - //kprint("Gonna force a double fault\n", 0); - //int test = 1/0; - //int test2 = *(int *) (0xa0000000); while(1); } diff --git a/kernel/linker.ld b/kernel/linker.ld index 82f6e4a..1a0107f 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -3,16 +3,16 @@ OUTPUT_FORMAT(binary) SECTIONS { - . = 0x100000; + . = 0xc0000000; __KERNEL_BASE__ = .; - .text : ALIGN(4K) { + .text : AT(ADDR(.text) - 0xbf000000) ALIGN(4K) { __TEXT_BASE__ = .; kernel/entry.o (.text) *(.text) __TEXT_END__ = .; } - .rodata : ALIGN(4K) { + .rodata : AT(ADDR(.rodata) - 0xbf000000) ALIGN(4K) { __RODATA_BASE__ = .; *(.rodata) __RODATA_END__ = .; @@ -27,12 +27,12 @@ SECTIONS * matter yet because we (currently) assume that the NX bit is not * supported anyway. */ - .data : ALIGN(4K) { + .data : AT(ADDR(.data) - 0xbf000000) ALIGN(4K) { __DATA_BASE__ = .; *(.data) __DATA_END__ = .; } - .bss : ALIGN(4K) { + .bss : AT(ADDR(.bss) - 0xbf000000) ALIGN(4K) { __BSS_BASE__ = .; *(.bss) /* Reserving 16KiB for the stack. A __STACK_TOP__ is not really -- 2.39.5