// loader.c: boot mechanism agnostic, bootboot-compliant loader #include #include // minimal set of string routines, copied from KarlOS void *memset(void *ptr, int value, size_t num) { __asm__ ("rep stosb" : "+D"(ptr), "+c"(num) : "a"(value) : "memory"); return ptr; } void *memcpy(void *restrict dest, const void *restrict src, size_t num) { __asm__ ("rep movsb" : "+D"(dest), "+S"(src), "+c"(num) : : "memory"); return dest; } int memcmp(const void *ptr, const void *ptr2, size_t num) { unsigned char *d = (unsigned char *)ptr; unsigned char *b = (unsigned char *)ptr2; for (size_t i = 0; i < num; i++) { if (d[i] != b[i]) { return (d[i] - b[i]); } } return 0; } size_t strlen(const char *s) { size_t len = 0; while (*s != '\0') { s++; len++; } return len; } // Helpers from bztsrc's bootboot codebase /** * convert ascii octal number to binary number */ int octbin(unsigned char *str,int size) { int s=0; unsigned char *c=str; while(size-->0){ s*=8; s+=*c-'0'; c++; } return s; } /** * convert ascii hex number to binary number */ int hexbin(unsigned char *str, int size) { int v=0; while(size-->0){ v <<= 4; if(*str>='0' && *str<='9') v += (int)((unsigned char)(*str)-'0'); else if(*str >= 'A' && *str <= 'F') v += (int)((unsigned char)(*str)-'A'+10); str++; } return v; } typedef struct { uint8_t *ptr; uint64_t size; } file_t; #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 typedef struct { unsigned char e_ident[16]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; uint64_t e_entry; uint64_t e_phoff; uint64_t e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } Elf64_Ehdr; typedef struct { uint32_t p_type; uint32_t p_flags; uint64_t p_offset; uint64_t p_vaddr; uint64_t p_paddr; uint64_t p_filesz; uint64_t p_memsz; uint64_t p_align; } Elf64_Phdr; 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(); }