123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /*
- * aarch64-rpi/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.
- *
- */
- /**
- * 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 ");
- DBG(kernel);
- DBG("\n");
- //decrypt initrd
- if(*((uint32_t*)(initrd_p+708))!=0 && (initrd_p[519]&0xF0)!=0) {
- puts("BOOTBOOT-PANIC: Unsupported cipher\n");
- return ret;
- }
- while(*((uint32_t*)(initrd_p+520))!=0) {
- puts(" * Passphrase? ");
- l=ReadLine(passphrase,sizeof(passphrase));
- if(!l) {
- puts("\n");
- return ret;
- }
- if(*((uint32_t*)(initrd_p+520))!=crc32_calc((char*)passphrase,l)) {
- puts("\rBOOTBOOT-ERROR: Bad passphrase\n");
- continue;
- }
- puts("\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;i<ss;i++) {
- if(i%32==0) {
- SHA256_Init(&ctx);
- SHA256_Update(&ctx,&chk,32);
- SHA256_Update(&ctx,&j,4);
- SHA256_Final(chk,&ctx);
- }
- initrd_p[k++]^=chk[i%32]^iv[i%32];
- }
- }
- memset(initrd_p+680,0,32); *((uint32_t*)(initrd_p+520)) = 0;
- *((uint32_t*)(initrd_p+1020))=crc32_calc((char *)initrd_p+512,508);
- puts(" \r");
- }
- // Get the inode
- char *s,*e;
- s=e=kernel;
- i=0;
- again:
- while(*e!='/'&&*e!=0){e++;}
- if(*e=='/'){e++;}
- if(!memcmp(in,"FSIN",4)){
- //is it inlined?
- if(!memcmp(initrd_p[520]&1? in + 2048 : in + 1024,"FSDR",4)){
- ent=(initrd_p[520]&1? in + 2048 : in + 1024);
- } else if(!memcmp(initrd_p+*((uint64_t*)(in+448))*ss,"FSDR",4)){
- // go, get the sector pointed
- ent=(initrd_p+*((uint64_t*)(in+448))*ss);
- } else {
- return ret;
- }
- //skip header
- unsigned char *hdr=ent; ent+=128;
- //iterate on directory entries
- int j=*((uint64_t*)(hdr+16));
- while(j-->0){
- 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;
- }
- /**
- * 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 ");
- DBG(kernel);
- DBG("\n");
- 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 ");
- DBG(kernel);
- DBG("\n");
- k=strlen((unsigned char*)kernel);
- // hpodc archive
- while(!memcmp(ptr,"070707",6)){
- int ns=oct2bin(ptr+8*6+11,6);
- int fs=oct2bin(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=hex2bin(ptr+8*6+6,8);
- int ns=hex2bin(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 ");
- DBG(kernel);
- DBG("\n");
- k=strlen((unsigned char*)kernel);
- while(!memcmp(ptr+257,"ustar",5)){
- int fs=oct2bin(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.");
- DBG(ver?"10":"0");
- DBG(kernel);
- DBG("\n");
- k=strlen((unsigned char*)kernel);
- // iterate on index until we reach the end or Volume Identifier
- while(ptr<end && ptr[0]!=0x01){
- ptr+=64;
- // file entry?
- if(ptr[0]!=0x12)
- continue;
- // filename match?
- if(!memcmp(ptr+(ver?0x23:0x22),kernel,k+1)){
- ret.size=*((uint64_t*)&ptr[ver?0x1B:0x1A]); // file_length
- ret.ptr=initrd_p + *((uint64_t*)&ptr[ver?0x0B:0x0A]) * bs; // base + start_block * blocksize
- break;
- }
- }
- return ret;
- }
- /**
- * James Molloy's initrd (for some reason it's popular among hobby OS developers)
- * http://www.jamesmolloy.co.uk/tutorial_html
- */
- file_t jamesm_initrd(unsigned char *initrd_p, char *kernel)
- {
- unsigned char *ptr=initrd_p+4;
- int i,k,nf=*((int*)initrd_p);
- file_t ret = { NULL, 0 };
- // no real magic, so we assume initrd contains at least one file...
- if(initrd_p==NULL || kernel==NULL || initrd_p[2]!=0 || initrd_p[3]!=0 || initrd_p[4]!=0xBF)
- return ret;
- DBG(" * JamesM ");
- DBG(kernel);
- DBG("\n");
- k=strlen((unsigned char*)kernel);
- for(i=0;i<nf && ptr[0]==0xBF;i++) {
- if(!memcmp(ptr+1,kernel,k+1)){
- ret.ptr=*((uint32_t*)(ptr+65)) + initrd_p;
- ret.size=*((uint32_t*)(ptr+69));
- }
- ptr+=73;
- }
- return ret;
- }
- /**
- * EchFS
- * http://github.com/echfs/echfs
- */
- file_t ech_initrd(unsigned char *initrd_p, char *kernel)
- {
- uint64_t parent = 0xffffffffffffffffUL, n;
- unsigned char *ptr;
- char *end, *fn;
- int k = 0;
- file_t ret = { NULL, 0 };
- if(initrd_p==NULL || kernel==NULL || memcmp(initrd_p+4,"_ECH_FS_",8))
- return ret;
- DBG(" * EchFS ");
- DBG(kernel);
- DBG("\n");
- memcpy(&k, initrd_p + 28, 4);
- memcpy(&n, initrd_p + 12, 8);
- ptr = initrd_p + (((n * 8 + k - 1) / k) + 16) * k;
- for(end = fn = kernel; *end && *end != '/'; end++);
- while(*((uint64_t*)ptr)) {
- if(*((uint64_t*)ptr) == parent && !memcmp(ptr + 9, fn, end - fn) && !ptr[9 + end - fn]) {
- parent = *((uint64_t*)(ptr + 240));
- if(!*end) {
- ret.size=*((uint64_t*)(ptr + 248));
- ret.ptr=(uint8_t*)(initrd_p + parent * k);
- break;
- }
- end++;
- for(fn = end; *end && *end != '/'; end++);
- }
- ptr += 256;
- }
- return ret;
- }
- /**
- * Static file system drivers registry
- */
- file_t (*fsdrivers[]) (unsigned char *, char *) = {
- fsz_initrd,
- mfs_initrd,
- cpio_initrd,
- tar_initrd,
- sfs_initrd,
- jamesm_initrd,
- ech_initrd,
- NULL
- };
|