]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Merge branch 'elf' into mm
authorDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 27 Jun 2022 19:29:50 +0000 (21:29 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 27 Jun 2022 19:29:50 +0000 (21:29 +0200)
27 files changed:
.gitignore
Makefile
boot/x86/Makefile
boot/x86/stage3/a20.s
boot/x86/stage3/e820.s
boot/x86/stage3/elf.c [new file with mode: 0644]
boot/x86/stage3/elf.h [new file with mode: 0644]
boot/x86/stage3/gdt.s
boot/x86/stage3/loader.s
boot/x86/stage3/paging.c [new file with mode: 0644]
boot/x86/stage3/paging.h [new file with mode: 0644]
boot/x86/stage3/prekernel.c [new file with mode: 0644]
boot/x86/stage3/print.s
boot/x86/stage3/stage3.ld [new file with mode: 0644]
boot/x86/stage3/unreal.s
kernel/arch/x86/halt.s [new file with mode: 0644]
kernel/arch/x86/irq/sample_handler.c
kernel/arch/x86/tty/tty.c
kernel/entry.s
kernel/include/arch/x86/io.h [moved from include/arch/x86/io.h with 100% similarity]
kernel/include/arch/x86/irq/i8259a.h [moved from include/arch/x86/irq/i8259a.h with 100% similarity]
kernel/include/arch/x86/irq/idt.h [moved from include/arch/x86/irq/idt.h with 100% similarity]
kernel/include/arch/x86/mm/paging.h [new file with mode: 0644]
kernel/include/panic.h [new file with mode: 0644]
kernel/include/tty.h [moved from include/arch/x86/tty.h with 91% similarity]
kernel/linker.ld
nameless2disk

index 9fc5bb791de04c0037818d3ffd4aa4f55db8b732..505290e343ff63ed7a90f33cc3aed7a0d612bd91 100644 (file)
@@ -1,6 +1,3 @@
-toolchain/
-boot.img
-boot/x86/boot
 **/*.o
 **/*.bin
 **/*.elf
index bff97e5db3072b6832148e6e3cf900c098d2d30f..f254d0c8ed42952a44a7d1cd42ad6c699b727b63 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,15 @@
 export AS = yasm
+ASFLAGS = -g dwarf2 -f elf
 export CC = i686-elf-gcc
 QEMU = qemu-system-i386 -monitor stdio
 
 export GIT_REV = $(shell git describe --long HEAD)
 
-CFLAGS = -g -fgnu89-inline -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
+CFLAGS = -g -fgnu89-inline -Ikernel/include -Ikernel/include/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/kernel.o
+KERNEL_OBJ = kernel/entry.o kernel/arch/x86/halt.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
 
@@ -19,38 +20,36 @@ bootloader: $(BOOTLOADER_OBJ)
 run: all
        $(QEMU) boot/x86/disk.img
 
+debug: all
+       $(QEMU) -s -S boot/x86/disk.img
+
 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/stage3.ld
+boot/x86/stage3/loader.elf: boot/x86/stage3/*.s boot/x86/stage3/*.c boot/x86/fat32/*.s boot/x86/stage3/stage3.ld
 $(BOOTLOADER_OBJ):
        $(MAKE) -C boot/x86
 
-boot/x86/disk.img: boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN boot/x86/disk.dump kernel/kernel.bin
+boot/x86/disk.img: boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN boot/x86/disk.dump kernel/kernel.elf
        truncate -s1G boot/x86/disk.img
        sfdisk boot/x86/disk.img < boot/x86/disk.dump
        mkfs.fat -F 32 --offset 2048 boot/x86/disk.img
        dd if=boot/x86/mbr of=boot/x86/disk.img bs=440 count=1 conv=notrunc
        dd if=boot/x86/vbr-fat32 of=boot/x86/disk.img bs=1 skip=90 seek=1048666 conv=notrunc
        mcopy -i boot/x86/disk.img@@1M boot/x86/stage3/LOADER.BIN ::.
-       mcopy -i boot/x86/disk.img@@1M kernel/kernel.bin ::./KERNEL.BIN
-
-kernel/kernel.bin: ${KERNEL_OBJ} kernel/linker.ld
-       $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ}
-
-kernel/entry.o: kernel/entry.s
-       $(AS) -f elf $< -o $@
+       mcopy -i boot/x86/disk.img@@1M kernel/kernel.elf ::./KERNEL.ELF
 
 kernel/arch/x86/irq/sample_handler.o: kernel/arch/x86/irq/sample_handler.c
        $(CC) $(CFLAGS) -mgeneral-regs-only -c $< -o $@
 
-kernel/kernel.elf: kernel/kernel.bin
-       $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ} -Wl,--oformat=elf32-i386
+kernel/kernel.elf: $(KERNEL_OBJ)
+       $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ} -lgcc
        i686-elf-objcopy --only-keep-debug kernel/kernel.elf kernel/kernel.dbg
        i686-elf-objcopy --add-gnu-debuglink=kernel/kernel.dbg kernel/kernel.elf
        i686-elf-strip --strip-unneeded kernel/kernel.elf
 
 clean:
-       -rm kernel/kernel.{bin,dbg,elf} ${KERNEL_OBJ}
+       -rm kernel/kernel.{dbg,elf} ${KERNEL_OBJ}
        cd boot/x86 && $(MAKE) clean
 
-.PHONY: default all clean run bootloader
+.PHONY: default all clean run debug bootloader
index 1de8199c99b304f2de447804485c5f1b14867932..e75e8dc23573c664b7cbeb8de2ab66ae69720b39 100644 (file)
@@ -1,4 +1,10 @@
-default: mbr vbr-fat32 stage3/LOADER.BIN
+default: mbr vbr-fat32 stage3/LOADER.BIN stage3/loader.elf
+
+CFLAGS=-g -ffreestanding -Istage3
+LD=i686-elf-gcc
+LDFLAGS=-T stage3/stage3.ld -ffreestanding -nostdlib -g
+
+STAGE3_OBJ=stage3/loader.o stage3/paging.o stage3/elf.o stage3/prekernel.o
 
 mbr: mbr.s
        $(AS) $(ASFLAGS) -w-zeroing -o $@ $<
@@ -6,10 +12,16 @@ mbr: mbr.s
 vbr-fat32: vbr-fat32.s fat32/*.s
        $(AS) $(ASFLAGS) -o $@ $<
 
-stage3/LOADER.BIN: stage3/loader.s stage3/*.s
-       $(AS) $(ASFLAGS) -DGIT_REVISION=\"$(GIT_REV)\" -o $@ $<
+stage3/loader.elf: $(STAGE3_OBJ)
+       $(CC) $(LDFLAGS) -o $@ $^ -lgcc -Wl,--oformat=elf32-i386
+
+stage3/LOADER.BIN: $(STAGE3_OBJ)
+       $(CC) $(LDFLAGS) -o $@ $^ -lgcc
+
+stage3/loader.o: stage3/loader.s stage3/*.s
+       $(AS) $(ASFLAGS) -f elf -g dwarf2 -DGIT_REVISION=\"$(GIT_REV)\" -o $@ $<
 
 clean:
-       -rm mbr vbr-fat32 stage3/LOADER.BIN disk.img
+       -rm mbr vbr-fat32 stage3/LOADER.BIN stage3/loader.elf $(STAGE3_OBJ) disk.img
 
 .PHONY : default clean
index 8748dde580673653b15db546ade7739a1db13ac3..392e83de920c1fac19e06c301979ceb618348824 100644 (file)
@@ -1,3 +1,6 @@
+bits 16
+section .text
+
 %macro in_wait 0
        push ax
 %%loop:
index 247b3614cf83dcb8a754759ec4edd345e5193e0f..2d1780bfb48ac6f23e917971150612560dc1b3e1 100644 (file)
@@ -1,6 +1,7 @@
 ; Code for getting the BIOS E820 memory map
 
 bits 16
+section .text
 
 ; Return: ECX - number of entries, DI - pointer to map
 get_e820_map:
@@ -61,5 +62,6 @@ get_e820_map:
                hlt
                jmp $-1
 
+section .rodata
 no_e820: db "BIOS does not support E820, cannot proceed!", 0xd, 0xa, 0
 e820_unexpected: db "Unexpected value in EAX after getting map entry: expected SMAP, got ", 0
diff --git a/boot/x86/stage3/elf.c b/boot/x86/stage3/elf.c
new file mode 100644 (file)
index 0000000..d3d215f
--- /dev/null
@@ -0,0 +1,78 @@
+/* Code for parsing ELF binaries (the kernel) */
+
+#include <elf.h>
+#include <paging.h>
+#include <stdint.h>
+
+int check_elf_header(struct elf_header *header)
+{
+       if (header->magic != ELF_MAGIC)
+               return ELF_HEADER_INVALID;
+       if (header->bits != ELF_32BIT)
+               return MISMATCHED_SYSTEM;
+       if (header->endianness != ELF_LITTLE_ENDIAN)
+               return MISMATCHED_SYSTEM;
+       if (header->header_ver != 1)
+               return ELF_HEADER_INVALID;
+       if (header->os_abi != ELF_SYSV_ABI)
+               return MISMATCHED_SYSTEM;
+       if (header->type != ELF_TYPE_EXECUTABLE)
+               return NOT_EXECUTABLE;
+       if (header->machine != ELF_X86_ISA)
+               return MISMATCHED_SYSTEM;
+       if (header->elf_ver != 1)
+               return ELF_HEADER_INVALID;
+
+       return 0;
+}
+
+int setup_elf_executable(struct elf_header *header)
+{
+       /* Check the header. */
+       int header_valid = check_elf_header(header);
+       if (header_valid)
+               return header_valid;
+
+       /* Get the program header. The casting is necessary because without it
+        * the code will add some multiple of the program header offset rather
+        * than the actual offset. */
+       struct program_header *prog_hdr = (struct program_header *) ((uint32_t) header+header->program_hdr);
+       for (int i=0; i<header->ph_entry_count; i++) {
+               /* We're only interested in loadable segments. */
+               if (prog_hdr[i].seg_type != ELF_PT_LOAD)
+                       continue;
+
+               /* Calculate the memory range. */
+               void *phys_start, *phys_end, *virt_end;
+               int flags;
+               phys_start = (void *) header + prog_hdr[i].file_offset;
+               if (prog_hdr[i].memsz & 0xfff) { /* Align if needed. */
+                       phys_end = phys_start+((prog_hdr[i].memsz+0x1000) & ~0xfff);
+                       virt_end = prog_hdr[i].vaddr+((prog_hdr[i].memsz+0x1000) & ~0xfff);
+               }
+               else {
+                       phys_end = phys_start+prog_hdr[i].memsz;
+                       virt_end = prog_hdr[i].vaddr+prog_hdr[i].memsz;
+               }
+
+               flags = prog_hdr[i].flags & ELF_FLAG_WRITABLE;
+
+               /* Map the range. */
+               int ret = map_range(phys_start, phys_end, prog_hdr[i].vaddr, virt_end, flags);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int execute_elf(struct elf_header *header, void *arg1, int arg2)
+{
+       /* Check the header and map all needed memory ranges. */
+       int ret = setup_elf_executable(header);
+       if (ret)
+               return ret;
+
+       /* Execute the kernel. */
+       header->entry(arg1, arg2);
+}
diff --git a/boot/x86/stage3/elf.h b/boot/x86/stage3/elf.h
new file mode 100644 (file)
index 0000000..9692633
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef BOOT_X86_ELF_H
+#define BOOT_X86_ELF_H
+
+#include <stdint.h>
+
+/* Some constants we will test against. */
+#define ELF_MAGIC 0x464c457f
+#define ELF_32BIT 0x1
+#define ELF_LITTLE_ENDIAN 0x1
+#define ELF_SYSV_ABI 0x0
+#define ELF_TYPE_EXECUTABLE 0x2
+#define ELF_X86_ISA 0x3
+
+#define ELF_PT_LOAD 0x1
+
+#define ELF_FLAG_EXECUTABLE 0x1
+#define ELF_FLAG_WRITABLE 0x2
+#define ELF_FLAG_READABLE 0x4
+
+/* Return error codes for the functions. */
+#define ELF_HEADER_INVALID 5
+#define MISMATCHED_SYSTEM 6
+#define NOT_EXECUTABLE 7
+
+struct elf_header {
+       uint32_t magic;
+       uint8_t bits;
+       uint8_t endianness;
+       uint8_t header_ver; /* always 1 */
+       uint8_t os_abi;
+       uint8_t padding[8];
+       uint16_t type;
+       uint16_t machine;
+       uint32_t elf_ver; /* always 1 */
+       void (*entry)(void *, int);
+       uint32_t program_hdr; /* offset into file */
+       uint32_t section_hdr;
+       uint32_t flags;
+       uint16_t hdr_size;
+       uint16_t ph_entry_size;
+       uint16_t ph_entry_count;
+       uint16_t sh_entry_size;
+       uint16_t sh_entry_count;
+       uint16_t sh_name_index;
+};
+
+struct program_header {
+       uint32_t seg_type;
+       uint32_t file_offset;
+       void *vaddr;
+       uint32_t undefined;
+       uint32_t filesz;
+       uint32_t memsz;
+       uint32_t flags;
+       uint32_t align;
+};
+
+extern int execute_elf(struct elf_header *header, void *arg1, int arg2);
+
+#endif
index d81bb64ecd34e90a144bab77c73f8afa7dba3f84..843df7bbdd259d040d8e8b442433b77e9090f758 100644 (file)
@@ -1,4 +1,7 @@
 ; Initial GDT for kernel, which wants a flat code and data descriptor
+
+section .rodata
+
 gdt:
        dw .end-.start-1
        dd .start
index 747905d704ef8bc0ae3c50921d996c3bc5ac000e..bd2fb9b912fa31d65b95f25dbc093e0264527f21 100644 (file)
@@ -1,7 +1,9 @@
 bits 16
 cpu 686
-org 0x1800
 
+extern run_kernel
+
+section .text
 %include "../fat32/fat32-structs.s"
 
 %macro print 1
@@ -11,7 +13,11 @@ org 0x1800
        pop si
 %endmacro
 
+extern __STACK_BOTTOM__
+
+global _start
 _start:
+       mov sp, __STACK_BOTTOM__
        mov [BOOT_DRIVE], dl
        call enable_unreal
        print begin
@@ -55,9 +61,11 @@ _start:
        pop si
        pop cx
        print kernel_found
+       mov eax, [es:di+dir_entry.filesize]
+       mov [KERNEL_SIZE], eax
        mov ax, [es:di+dir_entry.firstclushi]
        shl eax, 16
-       mov ax, [es:di+(dir_entry.firstcluslo)]
+       mov ax, [es:di+dir_entry.firstcluslo]
        call print_dword
        mov edi, 0x100000
        print kernel_loading
@@ -65,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]
@@ -147,7 +160,6 @@ memcpy:
        pop esi
        ret
 
-
 %include "unreal.s"
 %include "a20.s"
 %include "../fat32/fat32.s"
@@ -155,8 +167,9 @@ memcpy:
 %include "print.s"
 %include "e820.s"
 
-in_protected:
 bits 32
+section .text
+in_protected:
        mov ax, 0x10
        mov ds, ax
        mov es, ax
@@ -164,13 +177,18 @@ bits 32
        mov fs, ax
        mov gs, ax
 
-       call load_paging_structs
-       call enable_paging
+       push dword [KERNEL_SIZE]
+       push 0x100000
+       push ebx
+       push edi
+       call run_kernel
+
+section .bss
+KERNEL_SIZE: resd 1
 
-       jmp 0x8:0xc0000000
-       nop
+section .rodata
 
-kernel_name: db "KERNEL  BIN"
+kernel_name: db "KERNEL  ELF"
 begin: db "Nameless Bootloader revision ", GIT_REVISION, 0xd, 0xa, 0
 a20_enabled: db "A20 has been enabled", 0xd, 0xa, "Searching for kernel...", 0xd, 0xa, 0
 a20_fail: db "Failed to enable A20, giving up!", 0xd, 0xa, 0
@@ -178,7 +196,7 @@ crit_err: db "A critical error occurred, dumping registers now: ", 0xd, 0xa, 0
 kernel_found: db "Found kernel at cluster ", 0
 kernel_loading: db 0xd, 0xa, "Loading kernel...", 0xd, 0xa, 0
 kernel_loaded: db "Kernel successfully loaded.", 0xd, 0xa, "Setting up kernel environment and running kernel...", 0xd, 0xa, 0
-missing_kernel: db "Could not find KERNEL.BIN", 0xd, 0xa, 0
+missing_kernel: db "Could not find KERNEL.ELF", 0xd, 0xa, 0
 eax_s: db "EAX: ", 0
 ebx_s: db "EBX: ", 0
 ecx_s: db "ECX: ", 0
diff --git a/boot/x86/stage3/paging.c b/boot/x86/stage3/paging.c
new file mode 100644 (file)
index 0000000..5a0e5f7
--- /dev/null
@@ -0,0 +1,67 @@
+/* Code for enabling paging */
+
+#include <stdint.h>
+#include <paging.h>
+
+/* Preallocated page tables. */
+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.h b/boot/x86/stage3/paging.h
new file mode 100644 (file)
index 0000000..487943e
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef BOOT_X86_PAGING_H
+#define BOOT_X86_PAGING_H
+
+#define ADDRESS_NOT_ALIGNED 1
+#define INVL_ADDRESS 2
+#define ADDRESS_ALREADY_MAPPED 3
+#define ADDRESS_RANGE_MISMATCHED 4
+
+extern int map_range(void *phys_start, void *phys_end, void *virt_start, void *virt_end, int flags);
+extern void set_up_page_directory();
+extern void enable_paging();
+
+#endif
diff --git a/boot/x86/stage3/prekernel.c b/boot/x86/stage3/prekernel.c
new file mode 100644 (file)
index 0000000..280c350
--- /dev/null
@@ -0,0 +1,62 @@
+#include <elf.h>
+#include <paging.h>
+
+/* This bit of code will be run right after the segment registers have been set
+ * up for protected mode. */
+
+const char *error_messages[] = {
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "KERNEL.ELF is not a valid ELF file!",
+       "KERNEL.ELF is a non-x86 or userspace executable!",
+       "KERNEL.ELF is not an executable ELF file!"
+};
+
+void printerr(const char *error)
+{
+       char *message = (char *) error;
+       for (int i=0;;i++) {
+               char temp = *message;
+               if (!temp) return;
+               *(char *) (0xb8000+i*2) = temp;
+               *(char *) (0xb8000+1+i*2) = 0xcf;
+               message++;
+       }
+}
+
+void halt()
+{
+loop:
+       asm("hlt":);
+       goto loop;
+}
+
+void run_kernel(void *e820_map, unsigned int e820_map_size, struct elf_header *kernel, unsigned int kernel_size)
+{
+       /* Before trying to parse our kernel ELF, let's set up paging. */
+       unsigned int bootloader_mem_size = 0x100000 + kernel_size;
+
+       /* Align the size to a 4K boundary. */
+       if (bootloader_mem_size & 0xfff) {
+               bootloader_mem_size += 0x1000;
+               bootloader_mem_size &= ~0xfff;
+       }
+
+       /* Map the bootloader memory. */
+       int ret = map_range(0, (void *) bootloader_mem_size, 0, (void *) bootloader_mem_size, 2);
+       if (ret) {
+               printerr(error_messages[ret-1]);
+               halt();
+       }
+       set_up_page_directory();
+       enable_paging();
+
+       /* Parse and run the kernel ELF. */
+       ret = execute_elf(kernel, e820_map, e820_map_size);
+       if (ret) {
+               printerr(error_messages[ret-1]);
+               halt();
+       }
+}
index 73b34d5adb8f5cf4fb5215e051202a40278b296d..edc71077c3a2312ab1b7284cb3e4353349e36f31 100644 (file)
@@ -1,5 +1,8 @@
 ; Routines for printing
 
+bits 16
+section .text
+
 print_str:
        push ax
        push bx
diff --git a/boot/x86/stage3/stage3.ld b/boot/x86/stage3/stage3.ld
new file mode 100644 (file)
index 0000000..1accdc0
--- /dev/null
@@ -0,0 +1,17 @@
+ENTRY(_start)
+OUTPUT_FORMAT(binary)
+
+SECTIONS {
+       . = 0x1800;
+       .text : {
+               stage3/loader.o(.text)
+               *(.text)
+       }
+       .rodata : { *(.rodata) }
+       .data : { *(.data) }
+       .bss : {
+               *(.bss)
+               . += 1K;
+               PROVIDE(__STACK_BOTTOM__ = .);
+       }
+}
index cdd361bbdd85ccf6ca83f2039d52494fc9362cda..1fbe1f909cf0953f26037dcb57df79362d7ad31a 100644 (file)
@@ -1,5 +1,8 @@
 ; Routine for enabling unreal mode, which allows using 32-bit offsets in real mode
 
+bits 16
+section .text
+
 enable_unreal:
        cli
        push eax
@@ -25,6 +28,8 @@ enable_unreal:
        sti
        ret
 
+section .rodata
+
 ; GDT with 1 flat data segment descriptor
 gdt_info:
        dw gdt_end-gdt_start-1
diff --git a/kernel/arch/x86/halt.s b/kernel/arch/x86/halt.s
new file mode 100644 (file)
index 0000000..aded520
--- /dev/null
@@ -0,0 +1,9 @@
+; x86-specific routine for halting
+
+bits 32
+global halt
+
+halt:
+       cli
+       hlt
+       jmp $-1
index 0ba022287400813058340d07504939dcc347e508..5b0e2d470217a767c0b02ddc295d4586e7e6fb84 100644 (file)
@@ -3,6 +3,7 @@
 #include <io.h>
 #include <stdint.h>
 #include <mm/paging.h>
+#include <panic.h>
 
 typedef uint32_t uword_t;
 
@@ -36,7 +37,7 @@ void pf_handler(struct fault_frame *frame)
        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);
+       kprint("A page fault occurred!\n", VGA_COLOR_BRIGHT_RED);
        kprint("Faulting address: ", 0);
        kprintd(address);
        kprint("\n", 0);
@@ -51,18 +52,12 @@ void pf_handler(struct fault_frame *frame)
        if (errcode.id) {
                kprint("Fault occurred while fetching instruction\n", 0);
        }
-       asm("cli");
-halt:
-       asm("hlt");
-       goto halt;
+       PANIC("page fault");
 }
 
 __attribute__((interrupt))
 void double_fault(struct abort_frame *frame)
 {
-       *(volatile uint32_t *) (0xb8000) = 0xcf28cf3a;
-halt:
-       asm volatile ("cli; hlt");
-       goto halt;
+       PANIC("double fault");
 }
 
index 2110a7d003703dc3e0d2f89c483521889e2f33d7..c55cdd41eb8fe0c06afa792a63e9d2c0d767060f 100644 (file)
@@ -175,3 +175,38 @@ void kprintq(uint64_t qword)
        temp = qword & 0xF;
        kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
 }
+
+int kprintdec(uint32_t num, uint8_t color)
+{
+       char buffer[11];
+       int digits = 10;
+       /* TODO: make an actual memset function to use instead of this */
+       for (int i=0; i<11; i++) {
+               buffer[i] = 0;
+       }
+
+       /* put the numbers in the buffer */
+       for (int i=9; i>0 && num>0; i--) {
+               uint8_t currdigit = num%10;
+               buffer[i] = currdigit+'0';
+               num /= 10;
+       }
+
+       /* shift the array as much as needed */
+       while (*buffer == '\0') {
+               digits--;
+               for (int i=0; i<9; i++) {
+                       buffer[i] = buffer[i+1];
+               }
+       }
+
+       /* zero out any leftovers */
+       if (digits < 10) {
+               for (int i=digits; i<10; i++) {
+                       buffer[i] = '\0';
+               }
+       }
+
+       kprint(buffer, color);
+       return digits;
+}
index 5ef71bb84d95dc517fa994c60b4b7a8f12e5aad0..d6490a1159587a81cda63257b3ee3e9028fdaf68 100644 (file)
@@ -2,12 +2,31 @@ bits 32
 extern kmain
 extern __STACK_BOTTOM__
 
+section .text
 global _start
 _start:
+       ; Here, the stack will look like:
+       ; return address, map pointer, map size.
+
+       ; Skip the return address.
+       add esp, 4
+       ; Save the kernel arguments.
+       ; Can this be done without the global variables?
+       pop dword [e820_map]
+       pop dword [e820_map_size]
+       sub esp, 12
+       ; Do the stack switch.
        mov ebp, __STACK_BOTTOM__
        mov esp, ebp
-       push ecx
-       push edi
+       ; Restore the kernel arguments.
+       push dword [e820_map_size]
+       push dword [e820_map]
+       ; Call the actual kernel.
        call kmain
        hlt
        jmp $-1
+
+; Temporarily save arguments here to survive the upcoming stack switch.
+section .bss
+e820_map: resd 1
+e820_map_size: resd 1
diff --git a/kernel/include/arch/x86/mm/paging.h b/kernel/include/arch/x86/mm/paging.h
new file mode 100644 (file)
index 0000000..a4bdf22
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef X86_PAGING_H
+#define X86_PAGING_H
+
+struct page_directory_entry {
+       unsigned p: 1,
+                rw: 1,
+                us: 1,
+                pwt: 1,
+                pcd: 1,
+                a: 1,
+                ignored: 1,
+                ps: 1,
+                ignored2: 4,
+                page_table_addr: 20;
+} __attribute__((packed));
+
+struct page_table_entry {
+       unsigned p: 1,
+                rw: 1,
+                us: 1,
+                pwt: 1,
+                pcd: 1,
+                a: 1,
+                d: 1,
+                pat: 1,
+                g: 1,
+                ignored: 3,
+                page_frame_addr: 20;
+} __attribute__((packed));
+
+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));
+
+#endif
diff --git a/kernel/include/panic.h b/kernel/include/panic.h
new file mode 100644 (file)
index 0000000..f481e0c
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef PANIC_H
+#define PANIC_H
+
+extern void halt();
+
+#define PANIC(msg) \
+       kprint("PANIC (", VGA_COLOR_BRIGHT_RED);\
+       kprint(msg, VGA_COLOR_BRIGHT_RED);\
+       kprint(") in ", VGA_COLOR_BRIGHT_RED);\
+       kprint(__FILE__, VGA_COLOR_BRIGHT_RED);\
+       kprintc(':', VGA_COLOR_BRIGHT_RED);\
+       kprintdec(__LINE__, VGA_COLOR_BRIGHT_RED);\
+       kprintc(':', VGA_COLOR_BRIGHT_RED);\
+       kprint(__func__, VGA_COLOR_BRIGHT_RED);\
+       kprint("()", VGA_COLOR_BRIGHT_RED);\
+       halt();
+
+#endif
similarity index 91%
rename from include/arch/x86/tty.h
rename to kernel/include/tty.h
index 3ddd6b5c81c0dbc607bce4a3993c2f86027c50a4..3e1aab0de8b4858896ee4e352e616841fe6bc4f7 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef X86_TTY_H
-#define X86_TTY_H
+#ifndef TTY_H
+#define TTY_H
 
 #include <stdint.h>
 
@@ -27,4 +27,5 @@ extern void kprintb(const uint8_t byte);
 extern void kprintw(const uint16_t word);
 extern void kprintd(const uint32_t dword);
 extern void kprintq(const uint64_t qword);
+extern int kprintdec(uint32_t num, uint8_t color);
 #endif
index a7300751065656c085993d56b48971614c8637fc..a6fb8e48ed2d2289fde99b19e8bb976ac75d004c 100644 (file)
@@ -1,5 +1,4 @@
 ENTRY(_start)
-OUTPUT_FORMAT(binary)
 
 SECTIONS
 {
index 28b3427ca0063b2dd83fb2402fba23d28111264c..ddd8960718596f83cdd3a98f83d8d85c81cd0e9f 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 # Shell script to install Nameless to a disk.
 
-BINARIES=( boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN kernel/kernel.bin )
+BINARIES=( boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN kernel/kernel.elf )
 
 check_binaries() {
        for i in "${BINARIES[@]}"; do
@@ -72,7 +72,7 @@ install_blkdev() {
                exit 1
        fi
        cp boot/x86/stage3/LOADER.BIN $mountpoint/LOADER.BIN
-       cp kernel/kernel.bin $mountpoint/KERNEL.BIN
+       cp kernel/kernel.elf $mountpoint/KERNEL.ELF
        if ! [ $? -eq 0 ]; then
                echo An error occurred!
                exit 1