]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Add C code for enabling paging in bootloader
authorDuje Mihanović <duje.mihanovic@skole.hr>
Tue, 21 Jun 2022 13:30:41 +0000 (15:30 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Wed, 22 Jun 2022 16:03:18 +0000 (18:03 +0200)
Also compile the bootloader as ELF as well for easier debugging.

Makefile
boot/x86/Makefile
boot/x86/stage3/loader.s
boot/x86/stage3/paging.c [new file with mode: 0644]
boot/x86/stage3/paging.s [deleted file]
kernel/entry.s

index bff97e5db3072b6832148e6e3cf900c098d2d30f..2eedce2495997d6df2e6aa35a3d82f0a4ed74313 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ CFLAGS = -g -fgnu89-inline -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GI
 
 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
+BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN boot/x86/stage3/loader.elf
 
 default: kernel/kernel.elf bootloader
 
@@ -21,7 +21,8 @@ run: all
 
 boot/x86/mbr: boot/x86/mbr.s
 boot/x86/vbr-fat32: boot/x86/vbr-fat32.s boot/x86/fat32/*.s 
-boot/x86/stage3/LOADER.BIN: boot/x86/stage3/*.s boot/x86/fat32/*.s
+boot/x86/stage3/LOADER.BIN: boot/x86/stage3/*.s boot/x86/stage3/*.c boot/x86/fat32/*.s
+boot/x86/stage3/loader.elf: boot/x86/stage3/*.s boot/x86/stage3/*.c boot/x86/fat32/*.s
 $(BOOTLOADER_OBJ):
        $(MAKE) -C boot/x86
 
index 0e5ac00e050076b8f09aaa7ccc74eeb6ab313691..202d83993072d373a60b39d6f57d6b9805579be1 100644 (file)
@@ -1,9 +1,10 @@
-default: mbr vbr-fat32 stage3/LOADER.BIN
+default: mbr vbr-fat32 stage3/LOADER.BIN stage3/loader.elf
 
+CFLAGS=-g -ffreestanding
 LD=i686-elf-gcc
-LDFLAGS=-T stage3/stage3.ld -nostdlib
+LDFLAGS=-T stage3/stage3.ld -nostdlib -g
 
-STAGE3_OBJ=stage3/loader.o
+STAGE3_OBJ=stage3/loader.o stage3/paging.o
 
 mbr: mbr.s
        $(AS) $(ASFLAGS) -w-zeroing -o $@ $<
@@ -11,8 +12,11 @@ mbr: mbr.s
 vbr-fat32: vbr-fat32.s fat32/*.s
        $(AS) $(ASFLAGS) -o $@ $<
 
+stage3/loader.elf: $(STAGE3_OBJ)
+       $(CC) $(LDFLAGS) -o $@ $^ -Wl,--oformat=elf32-i386
+
 stage3/LOADER.BIN: $(STAGE3_OBJ)
-       $(LD) $(LDFLAGS) -o $@ $<
+       $(CC) $(LDFLAGS) -o $@ $^
 
 stage3/loader.o: stage3/loader.s stage3/*.s
        $(AS) $(ASFLAGS) -f elf -g dwarf2 -DGIT_REVISION=\"$(GIT_REV)\" -o $@ $<
index cdecbaac1b45f56740737cb355b28fefb6151863..9ed71021c5d42b291033df366f9231f3b8522b44 100644 (file)
@@ -1,6 +1,10 @@
 bits 16
 cpu 686
 
+extern enable_paging
+extern map_range
+extern set_up_page_directory
+
 section .text
 %include "../fat32/fat32-structs.s"
 
@@ -69,6 +73,11 @@ _start:
        print kernel_loaded
        
        call get_e820_map
+       mov ebx, ecx
+       mov eax, 24
+       mul ecx
+       add eax, 20
+       sub sp, ax
 
        cli
        lgdt [gdt]
@@ -168,13 +177,43 @@ in_protected:
        mov fs, ax
        mov gs, ax
 
-       call load_paging_structs
+       push dword 0
+       push 0xc0003000
+       push 0xc0000000
+       push 0x103000
+       push 0x100000
+       call map_range
+       cmp eax, 0
+       jne .error
+       add esp, 20
+       push dword 2
+       push 0xc0009000
+       push 0xc0003000
+       push 0x109000
+       push 0x103000
+       call map_range
+       cmp eax, 0
+       jne .error
+       add esp, 20
+       push dword 2
+       push 0x100000
+       push dword 0
+       push 0x100000
+       push dword 0
+       call map_range
+       cmp eax, 0
+       jne .error
+       add esp, 20
+
+       call set_up_page_directory
        call enable_paging
 
-       jmp 0x8:0xc0000000
+       jmp 0xc0000000
        nop
-
-%include "paging.s"
+.error:
+       mov dword [0xb8000], 0xcf28cf3a
+       hlt
+       jmp $-1
 
 section .rodata
 
diff --git a/boot/x86/stage3/paging.c b/boot/x86/stage3/paging.c
new file mode 100644 (file)
index 0000000..0482ded
--- /dev/null
@@ -0,0 +1,70 @@
+/* Code for enabling paging */
+
+#include <stdint.h>
+
+#define ADDRESS_NOT_ALIGNED 1
+#define INVL_ADDRESS 2
+#define ADDRESS_ALREADY_MAPPED 3
+#define ADDRESS_RANGE_MISMATCHED 4
+
+static uint32_t page_directory[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
+static uint32_t page_table_firstmb[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
+static uint32_t page_table_kernel[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
+
+void enable_paging()
+{
+       int cr3;
+       asm ("mov %0, %%cr3": : "a" (page_directory));
+       asm ("mov %%cr0, %0": "=a" (cr3));
+       cr3 |= 0x80000000;
+       asm ("mov %0, %%cr0": : "a" (cr3));
+}
+
+int map_address(void *physical, void *virtual, int flags)
+{
+       if ((uint32_t) physical & 0xfff || (uint32_t) virtual & 0xfff)
+               return ADDRESS_NOT_ALIGNED;
+
+       uint32_t pdir_index = (uint32_t) virtual >> 22;
+       if (pdir_index != 0 && pdir_index != 0x300)
+               return INVL_ADDRESS;
+
+       uint32_t ptbl_index = ((uint32_t) virtual >> 12) & 0x3ff;
+       switch (pdir_index) {
+       case 0:
+               if (page_table_firstmb[ptbl_index] & 1 == 1)
+                       return ADDRESS_ALREADY_MAPPED;
+               page_table_firstmb[ptbl_index] = ((uint32_t) physical & ~0xfff) | (flags & 0xfff) | 1;
+               break;
+       case 0x300:
+               if (page_table_kernel[ptbl_index] & 1 == 1)
+                       return ADDRESS_ALREADY_MAPPED;
+               page_table_kernel[ptbl_index] = ((uint32_t) physical & ~0xfff) | (flags & 0xfff) | 1;
+       }
+
+       return 0;
+}
+
+int map_range(void *phys_start, void *phys_end, void *virt_start, void *virt_end, int flags)
+{
+       if ((uint32_t) phys_start & 0xfff || (uint32_t) phys_end & 0xfff ||
+                       (uint32_t) virt_start & 0xfff || (uint32_t) virt_end & 0xfff)
+               return ADDRESS_NOT_ALIGNED;
+
+       if ((uint32_t) phys_end - (uint32_t) phys_start != (uint32_t) virt_end - (uint32_t) virt_start)
+               return ADDRESS_RANGE_MISMATCHED;
+
+       int loops = ((uint32_t) phys_end - (uint32_t) phys_start) / 4096;
+       for (int i=0; i<loops; i++) {
+               int ret = map_address(phys_start + i*4096, virt_start + i*4096, flags);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+void set_up_page_directory()
+{
+       page_directory[0] = (uint32_t) page_table_firstmb | 3;
+       page_directory[0x300] = (uint32_t) page_table_kernel | 3;
+}
diff --git a/boot/x86/stage3/paging.s b/boot/x86/stage3/paging.s
deleted file mode 100644 (file)
index 004da84..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-; 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
index 5ef71bb84d95dc517fa994c60b4b7a8f12e5aad0..c38ac764d8eb68e74f8f97413881d3b69ec0273a 100644 (file)
@@ -6,7 +6,7 @@ global _start
 _start:
        mov ebp, __STACK_BOTTOM__
        mov esp, ebp
-       push ecx
+       push ebx
        push edi
        call kmain
        hlt