From: Duje Mihanović Date: Mon, 27 Jun 2022 19:29:50 +0000 (+0200) Subject: Merge branch 'elf' into mm X-Git-Url: http://git.dujemihanovic.xyz/%7B%7B%20%24.Site.BaseURL%20%7D%7Dposts/index.xml?a=commitdiff_plain;h=5eb69417259dd239d1d7b69724b7e2bccb7d146e;hp=38ad80c9e06f8b906b6d6d27d529eb0a848d666f;p=nameless-os.git Merge branch 'elf' into mm --- diff --git a/.gitignore b/.gitignore index 9fc5bb7..505290e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -toolchain/ -boot.img -boot/x86/boot **/*.o **/*.bin **/*.elf diff --git a/Makefile b/Makefile index bff97e5..f254d0c 100644 --- 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 diff --git a/boot/x86/Makefile b/boot/x86/Makefile index 1de8199..e75e8dc 100644 --- a/boot/x86/Makefile +++ b/boot/x86/Makefile @@ -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 diff --git a/boot/x86/stage3/a20.s b/boot/x86/stage3/a20.s index 8748dde..392e83d 100644 --- a/boot/x86/stage3/a20.s +++ b/boot/x86/stage3/a20.s @@ -1,3 +1,6 @@ +bits 16 +section .text + %macro in_wait 0 push ax %%loop: diff --git a/boot/x86/stage3/e820.s b/boot/x86/stage3/e820.s index 247b361..2d1780b 100644 --- a/boot/x86/stage3/e820.s +++ b/boot/x86/stage3/e820.s @@ -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 index 0000000..d3d215f --- /dev/null +++ b/boot/x86/stage3/elf.c @@ -0,0 +1,78 @@ +/* Code for parsing ELF binaries (the kernel) */ + +#include +#include +#include + +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; iph_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 index 0000000..9692633 --- /dev/null +++ b/boot/x86/stage3/elf.h @@ -0,0 +1,60 @@ +#ifndef BOOT_X86_ELF_H +#define BOOT_X86_ELF_H + +#include + +/* 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 diff --git a/boot/x86/stage3/gdt.s b/boot/x86/stage3/gdt.s index d81bb64..843df7b 100644 --- a/boot/x86/stage3/gdt.s +++ b/boot/x86/stage3/gdt.s @@ -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 diff --git a/boot/x86/stage3/loader.s b/boot/x86/stage3/loader.s index 747905d..bd2fb9b 100644 --- a/boot/x86/stage3/loader.s +++ b/boot/x86/stage3/loader.s @@ -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 index 0000000..5a0e5f7 --- /dev/null +++ b/boot/x86/stage3/paging.c @@ -0,0 +1,67 @@ +/* Code for enabling paging */ + +#include +#include + +/* 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 +#include + +/* 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(); + } +} diff --git a/boot/x86/stage3/print.s b/boot/x86/stage3/print.s index 73b34d5..edc7107 100644 --- a/boot/x86/stage3/print.s +++ b/boot/x86/stage3/print.s @@ -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 index 0000000..1accdc0 --- /dev/null +++ b/boot/x86/stage3/stage3.ld @@ -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__ = .); + } +} diff --git a/boot/x86/stage3/unreal.s b/boot/x86/stage3/unreal.s index cdd361b..1fbe1f9 100644 --- a/boot/x86/stage3/unreal.s +++ b/boot/x86/stage3/unreal.s @@ -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 index 0000000..aded520 --- /dev/null +++ b/kernel/arch/x86/halt.s @@ -0,0 +1,9 @@ +; x86-specific routine for halting + +bits 32 +global halt + +halt: + cli + hlt + jmp $-1 diff --git a/kernel/arch/x86/irq/sample_handler.c b/kernel/arch/x86/irq/sample_handler.c index 0ba0222..5b0e2d4 100644 --- a/kernel/arch/x86/irq/sample_handler.c +++ b/kernel/arch/x86/irq/sample_handler.c @@ -3,6 +3,7 @@ #include #include #include +#include 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"); } diff --git a/kernel/arch/x86/tty/tty.c b/kernel/arch/x86/tty/tty.c index 2110a7d..c55cdd4 100644 --- a/kernel/arch/x86/tty/tty.c +++ b/kernel/arch/x86/tty/tty.c @@ -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; +} diff --git a/kernel/entry.s b/kernel/entry.s index 5ef71bb..d6490a1 100644 --- a/kernel/entry.s +++ b/kernel/entry.s @@ -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/include/arch/x86/io.h b/kernel/include/arch/x86/io.h similarity index 100% rename from include/arch/x86/io.h rename to kernel/include/arch/x86/io.h diff --git a/include/arch/x86/irq/i8259a.h b/kernel/include/arch/x86/irq/i8259a.h similarity index 100% rename from include/arch/x86/irq/i8259a.h rename to kernel/include/arch/x86/irq/i8259a.h diff --git a/include/arch/x86/irq/idt.h b/kernel/include/arch/x86/irq/idt.h similarity index 100% rename from include/arch/x86/irq/idt.h rename to kernel/include/arch/x86/irq/idt.h diff --git a/kernel/include/arch/x86/mm/paging.h b/kernel/include/arch/x86/mm/paging.h new file mode 100644 index 0000000..a4bdf22 --- /dev/null +++ b/kernel/include/arch/x86/mm/paging.h @@ -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 index 0000000..f481e0c --- /dev/null +++ b/kernel/include/panic.h @@ -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 diff --git a/include/arch/x86/tty.h b/kernel/include/tty.h similarity index 91% rename from include/arch/x86/tty.h rename to kernel/include/tty.h index 3ddd6b5..3e1aab0 100644 --- a/include/arch/x86/tty.h +++ b/kernel/include/tty.h @@ -1,5 +1,5 @@ -#ifndef X86_TTY_H -#define X86_TTY_H +#ifndef TTY_H +#define TTY_H #include @@ -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 diff --git a/kernel/linker.ld b/kernel/linker.ld index a730075..a6fb8e4 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -1,5 +1,4 @@ ENTRY(_start) -OUTPUT_FORMAT(binary) SECTIONS { diff --git a/nameless2disk b/nameless2disk index 28b3427..ddd8960 100755 --- a/nameless2disk +++ b/nameless2disk @@ -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