Also compile the bootloader as ELF as well for easier debugging.
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
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
-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 $@ $<
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 $@ $<
bits 16
cpu 686
+extern enable_paging
+extern map_range
+extern set_up_page_directory
+
section .text
%include "../fat32/fat32-structs.s"
print kernel_loaded
call get_e820_map
+ mov ebx, ecx
+ mov eax, 24
+ mul ecx
+ add eax, 20
+ sub sp, ax
cli
lgdt [gdt]
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
--- /dev/null
+/* 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;
+}
+++ /dev/null
-; 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
_start:
mov ebp, __STACK_BOTTOM__
mov esp, ebp
- push ecx
+ push ebx
push edi
call kmain
hlt