From fcdea29944cdde05df1d7df29c4dea8b446e3555 Mon Sep 17 00:00:00 2001 From: Thomas Oltmann Date: Mon, 7 Jul 2025 02:38:36 +0200 Subject: [PATCH] Imported a bunch of C code from KarlOS + bootboot --- Makefile | 2 +- fs.h | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lboot.S | 11 +- loader.c | 123 +++++++++++++++++++ 4 files changed, 489 insertions(+), 5 deletions(-) create mode 100644 fs.h diff --git a/Makefile b/Makefile index a600284..e689cd0 100644 --- a/Makefile +++ b/Makefile @@ -19,5 +19,5 @@ boot.elf: lboot.o loader.o fernlader.ld lboot.o: lboot.S $(CC) $(CFLAGS) -c -o $@ $(@:.o=.S) -loader.o: loader.c +loader.o: loader.c bootboot.h fs.h $(CC) $(CFLAGS) -m64 -Os -c -o $@ $(@:.o=.c) diff --git a/fs.h b/fs.h new file mode 100644 index 0000000..a93d2d7 --- /dev/null +++ b/fs.h @@ -0,0 +1,358 @@ +/* + * x86_64-cb/fs.h + * + * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the BOOTBOOT Protocol package. + * @brief Filesystem drivers for initial ramdisk. + * + */ + +#define DBG(...) do {} while (0) + +#if 0 +/** + * FS/Z initrd (OS/Z's native file system) + */ +file_t fsz_initrd(unsigned char *initrd_p, char *kernel) +{ + file_t ret = { NULL, 0 }; + if(initrd_p==NULL || memcmp(initrd_p + 512,"FS/Z",4) || kernel==NULL){ + return ret; + } + unsigned char passphrase[256],chk[32],iv[32]; + unsigned int i,j,k,l,ss=1<<(initrd_p[518]+11); + unsigned char *ent, *in=(initrd_p+*((uint64_t*)(initrd_p+560))*ss); + SHA256_CTX ctx; + DBG(" * FS/Z %s\n",kernel); + //decrypt initrd + if(*((uint32_t*)(initrd_p+520))!=0 && (initrd_p[519]&&0xF0)!=0) { + printf("BOOTBOOT-PANIC: Unsupported cipher\n"); + return ret; + } + while(*((uint32_t*)(initrd_p+520))!=0) { + printf(" * Passphrase? "); + l=ReadLine(passphrase,sizeof(passphrase)); + if(!l) { + printf("\n"); + return ret; + } + if(*((uint32_t*)(initrd_p+520))!=crc32_calc((char*)passphrase,l)) { + printf("\rBOOTBOOT-ERROR: Bad passphrase\n"); + continue; + } + printf("\r * Decrypting...\r"); + SHA256_Init(&ctx); + SHA256_Update(&ctx,passphrase,l); + SHA256_Update(&ctx,initrd_p+512,6); + SHA256_Final(chk,&ctx); + for(i=0;i<32;i++) initrd_p[i+680]^=chk[i]; + SHA256_Init(&ctx); + SHA256_Update(&ctx,initrd_p+680,32); + SHA256_Final(iv,&ctx); + // FSZ_SB_EALG_SHACBC + for(k=ss,j=1;j<*((uint32_t*)(initrd_p+528));j++) { + memcpy(chk,iv,32); + for(i=0;i0){ + if(!memcmp(ent + 16,s,e-s)) { + if(*e==0) { + i=*((uint64_t*)(ent+0)); + break; + } else { + s=e; + in=(initrd_p+*((uint64_t*)(ent+0))*ss); + goto again; + } + } + ent+=128; + } + } else { + i=0; + } + if(i!=0) { + // fid -> inode ptr -> data ptr + unsigned char *in=(initrd_p+i*ss); + if(!memcmp(in,"FSIN",4)){ + ret.size=*((uint64_t*)(in+464)); + if(*((uint64_t*)(in+448)) == i) { + if(!(in[488]&31)) { + // inline data + ret.ptr=(uint8_t*)(initrd_p+i*ss+(initrd_p[520]&1? 2048 : 1024)); + } else { + // sector directory or list inlined + ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p[520]&1? in + 2048 : in + 1024))*ss); + } + } else + if(*((uint64_t*)(in+448))) { + switch((in[488]&15) + (in[488]&16 ? 1 : 0)) { + case 0: // direct data + ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(in+448)) * ss); + break; + case 1: // sector directory or list (only one level supported here, and no holes in files) + ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p + *((uint64_t*)(in+448))*ss)) * ss); + break; + } + } else ret.size=0; + } + } + return ret; +} +#endif + +/** + * Minix3 file system + * directories only checked for their first block, and kernel must be defragmented + */ +file_t mfs_initrd(unsigned char *initrd_p, char *kernel) +{ + uint32_t o, bs, ino_tbl; + uint8_t *ino, *d; + char *s = kernel, *e; + file_t ret = { NULL, 0 }; + if(initrd_p[1048] != 'Z' || initrd_p[1049] != 'M') return ret; + DBG(" * MFS %s\n",kernel); + bs = *((uint16_t*)(initrd_p + 1052)); + ino_tbl = (2 + *((uint16_t*)(initrd_p + 1030)) + *((uint16_t*)(initrd_p + 1032))) * bs; + ino = initrd_p + ino_tbl; +again: + for(e = s; *e && *e != '/'; e++); + d = initrd_p + *((uint32_t*)(ino + 24)) * bs; + for(o = 0; o < *((uint32_t*)(ino + 8)) && o < bs; o += 64, d += 64) { + if(*((uint32_t*)d) && !memcmp(s, d + 4, e - s) && !d[e - s]) { + ino = initrd_p + ino_tbl + (*((uint32_t*)d) - 1) * 64; + d = initrd_p + *((uint32_t*)(ino + 24)) * bs; + if(!*e) { ret.ptr = d; ret.size = *((uint32_t*)(ino + 8)); return ret; } + s = e + 1; goto again; + } + } + return ret; +} + +/** + * cpio archive + */ +file_t cpio_initrd(unsigned char *initrd_p, char *kernel) +{ + unsigned char *ptr=initrd_p; + int k; + file_t ret = { NULL, 0 }; + if(initrd_p==NULL || kernel==NULL || + (memcmp(initrd_p,"070701",6) && memcmp(initrd_p,"070702",6) && memcmp(initrd_p,"070707",6))) + return ret; + DBG(" * cpio %s\n",kernel); + k=strlen(kernel); + // hpodc archive + while(!memcmp(ptr,"070707",6)){ + int ns=octbin(ptr+8*6+11,6); + int fs=octbin(ptr+8*6+11+6,11); + if(!memcmp(ptr+9*6+2*11,kernel,k+1) || + (ptr[9*6+2*11] == '.' && ptr[9*6+2*11+1] == '/' && !memcmp(ptr+9*6+2*11+2,kernel,k+1))) { + ret.size=fs; + ret.ptr=(uint8_t*)(ptr+9*6+2*11+ns); + return ret; + } + ptr+=(76+ns+fs); + } + // newc and crc archive + while(!memcmp(ptr,"07070",5)){ + int fs=hexbin(ptr+8*6+6,8); + int ns=hexbin(ptr+8*11+6,8); + if(!memcmp(ptr+110,kernel,k+1) || (ptr[110] == '.' && ptr[111] == '/' && !memcmp(ptr+112,kernel,k+1))) { + ret.size=fs; + ret.ptr=(uint8_t*)(ptr+((110+ns+3)/4)*4); + return ret; + } + ptr+=((110+ns+3)/4)*4 + ((fs+3)/4)*4; + } + return ret; +} + +/** + * ustar tarball archive + */ +file_t tar_initrd(unsigned char *initrd_p, char *kernel) +{ + unsigned char *ptr=initrd_p; + int k; + file_t ret = { NULL, 0 }; + if(initrd_p==NULL || kernel==NULL || memcmp(initrd_p+257,"ustar",5)) + return ret; + DBG(" * tar %s\n",kernel); + k=strlen(kernel); + while(!memcmp(ptr+257,"ustar",5)){ + int fs=octbin(ptr+0x7c,11); + if(!memcmp(ptr,kernel,k+1) || (ptr[0] == '.' && ptr[1] == '/' && !memcmp(ptr+2,kernel,k+1))) { + ret.size=fs; + ret.ptr=(uint8_t*)(ptr+512); + return ret; + } + ptr+=(((fs+511)/512)+1)*512; + } + return ret; +} + +/** + * Simple File System + */ +file_t sfs_initrd(unsigned char *initrd_p, char *kernel) +{ + unsigned char *ptr, *end; + int k,bs,ver; + file_t ret = { NULL, 0 }; + if(initrd_p==NULL || kernel==NULL || (memcmp(initrd_p+0x1AC,"SFS",3) && memcmp(initrd_p+0x1A6,"SFS",3))) + return ret; + // 1.0 Brendan's version, 1.10 BenLunt's version + ver=!memcmp(initrd_p+0x1A6,"SFS",3)?10:0; + bs=1<<(7+(uint8_t)initrd_p[ver?0x1B6:0x1BC]); + end=initrd_p + *((uint64_t *)&initrd_p[ver?0x1AA:0x1B0]) * bs; // base + total_number_of_blocks * blocksize + // get index area + ptr=end - *((uint64_t *)&initrd_p[ver?0x19E:0x1A4]); // end - size of index area + // got a Starting Marker Entry? + if(ptr[0]!=2) + return ret; + DBG(" * SFS 1.%s %s\n", ver?"10":"0",kernel); + k=strlen(kernel); + // iterate on index until we reach the end or Volume Identifier + while(ptr +#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" + +// 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]; + 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; + void loader_main(void) {