diff --git a/OLVASSEL.md b/OLVASSEL.md index 6736c18..ffd9939 100644 --- a/OLVASSEL.md +++ b/OLVASSEL.md @@ -16,7 +16,7 @@ Előre lefordított binárisok mellékelve, egyből használhatók. 4. *mykernel* egy példa BOOTBOOT [kompatíbilis kernel](https://gitlab.com/bztsrc/bootboot/tree/master/mykernel) C-ben írva, ami vonalakat húz meg színes dobozokat rajzol -Vedd figyelembe, hogy a referencia implementációk nem támogatják a teljes 2-es protokollt, +Vedd figyelembe, hogy a referencia implementációk nem támogatják a teljes 2-es protokollt (kivéve az UEFI változatot), csak statikus memórialeképezéseket kezelnek, ami az 1-es protokoll szintnek felel meg. Gyors kipróbáláshoz találsz bootolható képfájlokat az [images](https://gitlab.com/bztsrc/bootboot/tree/master/images) mappában. @@ -24,11 +24,11 @@ Gyors kipróbáláshoz találsz bootolható képfájlokat az [images](https://gi BOOTBOOT Protokoll ================== -Célközönség ------------ +Lényege +------- -A protokoll definiálja, hogyan kell betölteni ELF64 vagy PE32+ futtathatókat egy induló ramlemezről tisztán -64 bites módban, mindenféle konfiguráció vagy akár a ramlemezkép formátumának ismerete nélkül. +A protokoll definiálja, hogyan kell betölteni ELF64 vagy PE32+ futtathatókat egy induló memórialemezről tisztán +64 bites módban, mindenféle konfiguráció vagy akár a memórialemezkép formátumának ismerete nélkül. A [BIOS](https://gitlab.com/bztsrc/bootboot/tree/master/x86_64-bios)-t támogató gépeken ugyanaz a betöltő működik Multiboottal, láncbetöltéssel MBR, VBR (GPT hibrid indítás) és CDROM indító szektorból, vagy BIOS bővítő ROM-ból @@ -40,13 +40,13 @@ A [Raspberry Pi 3+](https://gitlab.com/bztsrc/bootboot/tree/master/aarch64-rpi) tölti be kernel8.img néven az SD kártya első partíciójáról. A különbség más betöltő protokollokhoz képest a rugalmasság és a hordozhatóság; a tisztán 64 bit támogatás; és hogy -a BOOTBOOT a kernel-t a ramlemezképből tölti be. Ez ideális hobbi OS-ek és mikrokernelek számára. Ez biztosítja, hogy -a kerneled felbontható több fájlra, mégis megadja azt az előnyt, hogy egyszerre tölti be mind, mintha egy monolitikus +a BOOTBOOT a kernel-t a memórialemezképből tölti be. Ez ideális hobbi OS-ek és mikrokernelek számára. Ez biztosítja, hogy +a kerneled felbontható több fájlra, mégis megadja azt az előnyt, hogy egyszerre tölti be mindet, mintha egy monolitikus kernel lenne. Ráadásul mindehhez a saját fájl rendszeredet is használhatod. Megjegyzés: a BOOTBOOT nem egy boot menedzser, hanem egy boot protokoll. Ha interaktív indítómenüt szeretnél, akkor azt a BOOTBOOT kompatíbilis betöltő *elé* kell integrálnod. Például a GRUB lánctöltheti a boot.bin-t (vagy Multiboot -"kernel"-ként a bootboot.bin-t és modulként a ramlemezt) vagy a bootboot.efi hozzáadható az UEFI Boot menedzser menüjéhez. +"kernel"-ként a bootboot.bin-t és modulként a memórialemezt) vagy a bootboot.efi hozzáadható az UEFI Boot menedzser menüjéhez. Licensz ------- diff --git a/README.md b/README.md index 8c40d08..ff5e249 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ I provide pre-compiled images ready for use. 4. *mykernel* an example BOOTBOOT [compatible kernel](https://gitlab.com/bztsrc/bootboot/tree/master/mykernel) in C which draws lines and boxes -Please note that the reference implementations do not support the full protocol at level 2, +Please note that the reference implementations do not support the full protocol at level 2 (except the UEFI version), they only handle static mappings which makes them level 1 loaders. For quick test, you can find example bootable disk [images](https://gitlab.com/bztsrc/bootboot/tree/master/images) too. diff --git a/bootboot.efi b/bootboot.efi index c53ada8..3dfe376 100755 Binary files a/bootboot.efi and b/bootboot.efi differ diff --git a/bootboot.rom b/bootboot.rom index db5ca6d..1878c2f 100644 Binary files a/bootboot.rom and b/bootboot.rom differ diff --git a/x86_64-efi/bootboot.c b/x86_64-efi/bootboot.c index 9d99a3f..3fc487d 100644 --- a/x86_64-efi/bootboot.c +++ b/x86_64-efi/bootboot.c @@ -60,6 +60,8 @@ #define ELFDATA2LSB 1 /* 2's complement, little endian */ #define PT_LOAD 1 /* Loadable program segment */ #define EM_X86_64 62 /* AMD x86-64 architecture */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ typedef struct { @@ -91,6 +93,30 @@ typedef struct UINT64 p_align; /* Segment alignment */ } Elf64_Phdr; +typedef struct +{ + UINT32 sh_name; /* Section name (string tbl index) */ + UINT32 sh_type; /* Section type */ + UINT64 sh_flags; /* Section flags */ + UINT64 sh_addr; /* Section virtual addr at execution */ + UINT64 sh_offset; /* Section file offset */ + UINT64 sh_size; /* Section size in bytes */ + UINT32 sh_link; /* Link to another section */ + UINT32 sh_info; /* Additional section information */ + UINT64 sh_addralign; /* Section alignment */ + UINT64 sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +typedef struct +{ + UINT32 st_name; /* Symbol name (string tbl index) */ + UINT8 st_info; /* Symbol type and binding */ + UINT8 st_other; /* Symbol visibility */ + UINT16 st_shndx; /* Section index */ + UINT64 st_value; /* Symbol value */ + UINT64 st_size; /* Symbol size */ +} Elf64_Sym; + /*** PE32+ defines and structs ***/ #define MZ_MAGIC 0x5a4d /* "MZ" */ #define PE_MAGIC 0x00004550 /* "PE\0\0" */ @@ -109,7 +135,7 @@ typedef struct { UINT16 sections; /* number of sections */ UINT32 timestamp; /* time_t */ UINT32 sym_table; /* symbol table offset */ - UINT32 symbols; /* number of symbols */ + INT32 numsym; /* number of symbols */ UINT16 opt_hdr_size; /* size of optional header */ UINT16 flags; /* flags */ UINT16 file_type; /* file type, PE32PLUS magic */ @@ -118,10 +144,20 @@ typedef struct { UINT32 text_size; /* size of text section(s) */ UINT32 data_size; /* size of data section(s) */ UINT32 bss_size; /* size of bss section(s) */ - INT32 entry_point; /* file offset of entry point */ - INT32 code_base; /* relative code addr in ram */ + INT32 entry_point; /* file offset of entry point */ + INT32 code_base; /* relative code addr in ram */ } pe_hdr; +typedef struct { + UINT32 iszero; /* if this is not zero, then iszero+nameoffs gives UTF-8 string */ + UINT32 nameoffs; + INT32 value; /* value of the symbol */ + UINT16 section; /* section it belongs to */ + UINT16 type; /* symbol type */ + UINT8 storclass; /* storage class */ + UINT8 auxsyms; /* number of pe_sym records following */ +} pe_sym; + /*** EFI defines and structs ***/ struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; struct EFI_FILE_PROTOCOL; @@ -268,6 +304,9 @@ file_t core; // kernel file descriptor BOOTBOOT *bootboot; // the BOOTBOOT structure UINT64 *paging; // paging table for MMU UINT64 entrypoint; // kernel entry point +UINT64 fb_addr = 0xfffffffffc000000; // frame buffer virtual address +UINT64 bb_addr = 0xffffffffffe00000; // bootboot struct virtual address +UINT64 env_addr= 0xffffffffffe01000; // environment string virtual address EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; EFI_FILE_HANDLE RootDir; EFI_FILE_PROTOCOL *Root; @@ -1152,7 +1191,7 @@ LoadCore() DBG(L" * Parsing ELF64 @%lx\n",core.ptr); Elf64_Phdr *phdr=(Elf64_Phdr *)((UINT8 *)ehdr+ehdr->e_phoff); for(i=0;ie_phnum;i++){ - if(phdr->p_type==PT_LOAD && phdr->p_vaddr>>48==0xffff) { + if(phdr->p_type==PT_LOAD && (phdr->p_vaddr >> 30) == 0x3FFFFFFFF) { // hack to keep symtab and strtab for shared libraries core.size = phdr->p_filesz + (ehdr->e_type==3?0x4000:0); ptr = (UINT8*)ehdr + phdr->p_offset; @@ -1162,18 +1201,48 @@ LoadCore() } phdr=(Elf64_Phdr *)((UINT8 *)phdr+ehdr->e_phentsize); } + if(ehdr->e_shoff > 0) { + Elf64_Shdr *shdr=(Elf64_Shdr *)((UINT8 *)ehdr + ehdr->e_shoff); + Elf64_Sym *sym = NULL, *s; + char *strtable = NULL; + UINT32 strsz = 0, syment = 0; + for(i = 0; i < ehdr->e_shnum; i++){ + if(shdr->sh_type == SHT_SYMTAB) { sym=(Elf64_Sym *)((UINT8*)ehdr+shdr->sh_offset); syment=shdr->sh_entsize; } + if(shdr->sh_type == SHT_STRTAB) { strtable = (char *)ehdr + shdr->sh_offset; strsz = shdr->sh_size; } + shdr = (Elf64_Shdr *)((UINT8 *)shdr + ehdr->e_shentsize); + } + if(strtable && strsz > 0 && sym && syment > 0) + for(s = sym, i = 0; i<(strtable-(char*)sym)/syment && s->st_name < strsz; i++, s++) { + if(!CompareMem(strtable + s->st_name, "bootboot", 9)) bb_addr = s->st_value; + if(!CompareMem(strtable + s->st_name, "environment", 12)) env_addr = s->st_value; + if(!CompareMem(strtable + s->st_name, "fb", 3)) fb_addr = s->st_value; + } + } } else if(((mz_hdr*)(core.ptr))->magic==MZ_MAGIC && ((mz_hdr*)(core.ptr))->peaddr<65536 && pehdr->magic == PE_MAGIC && pehdr->machine == IMAGE_FILE_MACHINE_AMD64 && pehdr->file_type == PE_OPT_MAGIC_PE32PLUS && - (INT64)pehdr->code_base>>48==0xffff) { - //Parse PE32+ + (pehdr->code_base & 0xC0000000)) { + // Parse PE32+ DBG(L" * Parsing PE32+ @%lx\n",core.ptr); core.size = (pehdr->entry_point-pehdr->code_base) + pehdr->text_size + pehdr->data_size; ptr = core.ptr; bss = pehdr->bss_size; entrypoint = (INT64)pehdr->entry_point; + if(pehdr->sym_table > 0 && pehdr->numsym > 0) { + pe_sym *s; + char *strtable = (char *)pehdr + pehdr->sym_table + pehdr->numsym * 18 + 4, *name; + for(i = 0; i < pehdr->numsym; i++) { + s = (pe_sym*)((UINT8 *)pehdr + pehdr->sym_table + i * 18); + name = !s->iszero ? (char*)&s->iszero : strtable + s->nameoffs; + if(!CompareMem(name, "bootboot", 9)) bb_addr = (INT64)s->value; + if(!CompareMem(name, "environment", 12)) env_addr = (INT64)s->value; + if(!CompareMem(name, "fb", 3)) fb_addr = (INT64)s->value; + i += s->auxsyms; + } + } } - if(ptr==NULL || core.size<2 || entrypoint==0) - return report(EFI_LOAD_ERROR,L"Kernel is not a valid executable"); + if(ptr==NULL || core.size<2 || entrypoint==0 || (bb_addr>>30)!=0x3FFFFFFFF || (env_addr>>30)!=0x3FFFFFFFF || + (fb_addr>>30)!=0x3FFFFFFFF || (fb_addr & ~(1024*1024*2-1))) + return report(EFI_LOAD_ERROR,L"Kernel is not a valid executable"); // create core segment uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, (core.size + bss + PAGESIZE-1)/PAGESIZE, (EFI_PHYSICAL_ADDRESS*)&core.ptr); @@ -1183,6 +1252,9 @@ LoadCore() if(bss>0) ZeroMem((void*)core.ptr + core.size, bss); core.size += bss; + DBG(L" * fb @%lx\n", fb_addr); + DBG(L" * bootboot @%lx\n", bb_addr); + DBG(L" * environment @%lx\n", env_addr); DBG(L" * Entry point @%lx, text @%lx %d bytes\n",entrypoint, core.ptr, core.size); core.size = ((core.size+PAGESIZE-1)/PAGESIZE)*PAGESIZE; return EFI_SUCCESS; @@ -1541,7 +1613,7 @@ gzerr: return report(EFI_COMPROMISED_DATA,L"Unable to uncompress"); return report(status, L"GOP failed, no framebuffer"); // collect information on system - bootboot->protocol=PROTOCOL_STATIC | LOADER_UEFI; + bootboot->protocol=PROTOCOL_DYNAMIC | LOADER_UEFI; bootboot->size=128; bootboot->numcores=1; CopyMem((void *)&(bootboot->initrd_ptr),&initrd.ptr,8);