diff --git a/lboot.S b/lboot.S index af17760..21d1c53 100644 --- a/lboot.S +++ b/lboot.S @@ -102,8 +102,12 @@ init_com1: com1_write 1, 0x00 // clear interrupts com1_write 3, 0x07 // 8 bit data + 1 parity bit ret - // enable_a20: Allow use of 'high' memory -enable_a20: // TODO more thorough implementation + // enable_a20: Allow use of 'high' (>1Mb) memory +enable_a20: // Of all the ways to toggle A20, we only try the Fast A20 Gate. + // This is known to cause problems on some ancient systems, + // but as our bootloader exclusively runs on 64-bit machines, + // we should not run into any of those systems. + // Modern machines apparently don't even have the A20 line anymore. inb $0x92, %al or $2, %al outb %al, $0x92 @@ -129,7 +133,7 @@ _urunreal: pop %ds ret // get_map: Retrieve memory map using e820 BIOS function -get_map: mov %ds, %ax +get_map: mov %ds, %ax mov %ax, %es mov $memmap, %di xor %ebx, %ebx diff --git a/loader.c b/loader.c index 60b8038..58b72ca 100644 --- a/loader.c +++ b/loader.c @@ -1,3 +1,5 @@ +// loader.c: boot mechanism agnostic, bootboot-compliant loader + #include #include @@ -85,16 +87,20 @@ typedef struct { #include "bootboot.h" #include "fs.h" +#define KILO(x) ((intptr_t)(x) * 1024) +#define MEG(x) (KILO(x) * 1024) +#define PAGES(x) ((intptr_t)(x) * 0x1000) + +#define ADDR_FRAMEBUFFER MEG(-64) +#define ADDR_MMIO MEG(-128) +#define ADDR_BOOTBOOT MEG(-2) +#define ADDR_ENVIRONMENT (MEG(-2) + PAGES(1)) +#define ADDR_LOAD (MEG(-2) + PAGES(2)) + // ELF64 -#define EI_NIDENT 16 -#define EI_MAG0 0x7F -#define EI_MAG1 'E' -#define EI_MAG2 'L' -#define EI_MAG3 'F' - typedef struct { - unsigned char e_ident[EI_NIDENT]; + unsigned char e_ident[16]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; @@ -121,8 +127,69 @@ typedef struct { uint64_t p_align; } Elf64_Phdr; -void -loader_main(void) +static void +panic(void) { for (;;) {} } + +static int +load_elf(file_t file, uintptr_t *entry) +{ + if (file.size < sizeof (Elf64_Ehdr)) { + return -1; + } + + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)file.ptr; + if (memcmp(ehdr->e_ident, "\177ELF\2\1\1", 7) != 0) { + return -1; + } + + if (ehdr->e_type != 2) { + return -1; + } + + if (ehdr->e_phentsize < sizeof (Elf64_Phdr)) { + return -1; + } + if (file.size < ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum) { + return -1; + } + + for (uint16_t p = 0; p < ehdr->e_phnum; p++) { + Elf64_Phdr *phdr = (Elf64_Phdr *)(file.ptr + ehdr->e_phoff + ehdr->e_phentsize * p); + if (phdr->p_type == 1) { // PT_LOAD + if (file.size < phdr->p_offset + phdr->p_filesz) { + return -1; + } + memcpy((void *)ADDR_LOAD, file.ptr + phdr->p_offset, phdr->p_filesz); + if (phdr->p_filesz < phdr->p_memsz) { + memset((void *)(ADDR_LOAD + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz); + } + } + } + + *entry = ehdr->e_entry; + + return 0; +} + +void +loader_main(void) +{ + uint64_t entry = 0; + file_t elf = { 0, 0 }; + if (load_elf(elf, &entry) < 0) { + panic(); + } + + uint64_t stack = 0; + + __asm__ __volatile__ ( + "mov\t%1, %rbp\n\t" + "mov\t%rbp, %rsp\n\t" + "call\t*%0" + : : "r"(entry), "r"(stack) : "memory"); + + panic(); +}