1
0
Fork 0
mirror of https://gitlab.com/bztsrc/bootboot.git synced 2023-02-13 20:54:32 -05:00
bztsrc--bootboot/images/mkimg.c
2020-03-16 11:39:41 +01:00

433 lines
18 KiB
C

/*
* images/mkimg.c
*
* Copyright (C) 2017 - 2020 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 Small tool to create disk or cdrom images with BOOTBOOT
*
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
long int read_size;
/**
* Read file into memory
*/
unsigned char* readfileall(char *file)
{
unsigned char *data=NULL;
FILE *f;
read_size=0;
f=fopen(file,"r");
if(f){
fseek(f,0L,SEEK_END);
read_size=ftell(f);
fseek(f,0L,SEEK_SET);
data=(unsigned char*)malloc(read_size+1);
if(data==NULL) { fprintf(stderr,"mkimg: Unable to allocate %ld memory\n",read_size+1); exit(1); }
memset(data,0,read_size+1);
fread(data,read_size,1,f);
fclose(f);
}
return data;
}
/**
* Set integers in byte arrays
*/
int getint(unsigned char *ptr) { return (unsigned char)ptr[0]+(unsigned char)ptr[1]*256+(unsigned char)ptr[2]*256*256+ptr[3]*256*256*256; }
void setint(int val, unsigned char *ptr) { memcpy(ptr,&val,4); }
void setinte(int val, unsigned char *ptr) { char *v=(char*)&val; memcpy(ptr,&val,4); ptr[4]=v[3]; ptr[5]=v[2]; ptr[6]=v[1]; ptr[7]=v[0]; }
/**
* CRC-stuff
*/
unsigned int crc32_lookup[256]={
0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,0x0edb8832,
0x79dcb8a4,0xe0d5e91e,0x97d2d988,0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,0x1db71064,0x6ab020f2,
0xf3b97148,0x84be41de,0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,0x136c9856,0x646ba8c0,0xfd62f97a,
0x8a65c9ec,0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,
0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,0x32d86ce3,
0x45df5c75,0xdcd60dcf,0xabd13d59,0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,0x21b4f4b5,0x56b3c423,
0xcfba9599,0xb8bda50f,0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,0x2f6f7c87,0x58684c11,0xc1611dab,
0xb6662d3d,0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,0x6b6b51f4,
0x1c6c6162,0x856530d8,0xf262004e,0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,0x65b0d9c6,0x12b7e950,
0x8bbeb8ea,0xfcb9887c,0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,0x4db26158,0x3ab551ce,0xa3bc0074,
0xd4bb30e2,0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,
0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,0x5768b525,
0x206f85b3,0xb966d409,0xce61e49f,0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,0x59b33d17,0x2eb40d81,
0xb7bd5c3b,0xc0ba6cad,0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,0xead54739,0x9dd277af,0x04db2615,
0x73dc1683,0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,0xfed41b76,
0x89d32be0,0x10da7a5a,0x67dd4acc,0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,0xd6d6a3e8,0xa1d1937e,
0x38d8c2c4,0x4fdff252,0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,0xd80d2bda,0xaf0a1b4c,0x36034af6,
0x41047a60,0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,
0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,0xc2d7ffa7,
0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,0x9c0906a9,0xeb0e363f,
0x72076785,0x05005713,0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,0x92d28e9b,0xe5d5be0d,0x7cdcefb7,
0x0bdbdf21,0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,0xa00ae278,
0xd70dd2ee,0x4e048354,0x3903b3c2,0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,0xaed16a4a,0xd9d65adc,
0x40df0b66,0x37d83bf0,0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,0xbdbdf21c,0xcabac28a,0x53b39330,
0x24b4a3a6,0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,
0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d};
unsigned int crc32a_calc(char *start, int length)
{
unsigned int crc32_val=0xffffffff;
while(length--) crc32_val=(crc32_val>>8)^crc32_lookup[(crc32_val&0xff)^(unsigned char)*start++];
crc32_val^=0xffffffff;
return crc32_val;
}
/**
* Create a ROM image of the initrd
*/
void initrdrom()
{
int i, size;
unsigned char *fs, *buf, c=0;
FILE *f;
fs=readfileall("initrd.bin"); size=((read_size+32+511)/512)*512;
if(fs==NULL) { fprintf(stderr,"mkimg: unable to load initrd.bin\n"); exit(2); }
buf=(unsigned char*)malloc(size+1);
/* Option ROM header */
buf[0]=0x55; buf[1]=0xAA; buf[2]=(read_size+32+511)/512;
/* asm "xor ax,ax; retf" */
buf[3]=0x31; buf[4]=0xC0; buf[5]=0xCB;
/* identifier, size and data */
memcpy(buf+8,"INITRD",6);
memcpy(buf+16,&read_size,4);
memcpy(buf+32,fs,read_size);
/* checksum */
for(i=0;i<size;i++) c+=buf[i];
buf[6]=(unsigned char)((int)(256-c));
/* write out */
f=fopen("initrd.rom","wb");
if(!f) { fprintf(stderr,"mkimg: unable to write initrd.rom\n"); exit(3); }
fwrite(buf,size,1,f);
fclose(f);
}
/**
* Create a hybrid disk image from partition image with initrd in it
*/
int createdisk(int disksize, char *diskname)
{
unsigned long int i,j=0,gs=63*512,es,bbs=0;
unsigned long int uuid[4]={0x12345678,0x12345678,0x12345678,0x12345678};
unsigned char *esp, *gpt, *iso, *p, *loader;
time_t t=time(NULL);
struct tm *ts=gmtime(&t);
char isodate[17];
FILE *f;
esp=readfileall("bootpart.bin"); es=read_size;
gpt=malloc(gs+512);
memset(gpt,0,gs+512);
iso=malloc(32768);
memset(iso,0,32768);
if(disksize<64*1024*1024) disksize = 64*1024*1024;
/* make the UUID unique */
uuid[0] ^= (unsigned long int)t;
/* MBR / VBR stage 1 loader */
loader=readfileall("../boot.bin");
if(loader==NULL) {
loader=malloc(512);
memset(loader,0,512);
} else {
memset(loader+0x1B8,0,0x1FE - 0x1B8);
}
/* search for stage2 loader (FS0:\BOOTBOOT\LOADER) */
if(es>0) {
for(i=0;i<es-512;i+=512) {
if((unsigned char)esp[i+0]==0x55 &&
(unsigned char)esp[i+1]==0xAA &&
(unsigned char)esp[i+3]==0xE9 &&
(unsigned char)esp[i+8]=='B' &&
(unsigned char)esp[i+12]=='B') {
bbs=((i+65536)/512);
break;
}
}
}
/* save stage2 address into stage1 */
if(bbs>0) {
setint(bbs,loader+0x1B0);
/* WinNT disk id */
setint(uuid[0],loader+0x1B8);
} else {
fprintf(stderr,"mkimg: FS0:\\BOOTBOOT\\LOADER not found\n");
memset(loader, 0, 512);
}
/* magic */
loader[0x1FE]=0x55; loader[0x1FF]=0xAA;
/* copy stage1 loader into VBR too */
if(loader[0]!=0 && es>0) {
/* skip BPB */
memcpy(esp, loader, 11);
memcpy(esp+0x5A, loader+0x5A, 512-0x5A);
}
/* generate PMBR partitioning table */
j=0x1C0;
if(es>0) {
/* MBR, EFI System Partition */
loader[j-2]=0x80; /* bootable flag */
setint(129,loader+j); /* start CHS */
loader[j+2]=esp[0x39]=='1' ? 0xE : 0xC; /* type, LBA FAT16 (0xE) or FAT32 (0xC) */
setint(((gs+es)/512)+2,loader+j+4); /* end CHS */
setint(128,loader+j+6); /* start LBA */
setint(((es)/512),loader+j+10); /* number of sectors */
j+=16;
}
/* MBR, GPT entry */
setint(1,loader+j); /* start CHS */
loader[j+2]=0xEE; /* type */
setint((gs/512)+1,loader+j+4); /* end CHS */
setint(1,loader+j+6); /* start LBA */
setint((gs/512),loader+j+10); /* number of sectors */
j+=16;
/* GPT header */
memset(gpt,0,gs);
memcpy(gpt,"EFI PART",8); /* magic */
setint(1,gpt+10); /* revision */
setint(92,gpt+12); /* size */
setint(1,gpt+24); /* primary LBA */
setint(disksize/512-1,gpt+32); /* secondary LBA */
setint((gs/512)+1,gpt+40); /* first usable LBA */
setint((disksize/512)-1,gpt+48); /* last usable LBA */
setint(uuid[0],gpt+56); /* disk UUID */
setint(uuid[1],gpt+60);
setint(uuid[2],gpt+64);
setint(uuid[3],gpt+68);
setint(2,gpt+72); /* partitioning table LBA */
setint(es?1:0,gpt+80); /* number of entries */
setint(128,gpt+84); /* size of one entry */
p=gpt+512;
/* GPT, EFI System Partition (ESP, /boot) */
if(es>0) {
setint(0x0C12A7328,p); /* entry type */
setint(0x011D2F81F,p+4);
setint(0x0A0004BBA,p+8);
setint(0x03BC93EC9,p+12);
setint(uuid[0]+1,p+16); /* partition UUID */
setint(uuid[1],p+20);
setint(uuid[2],p+24);
setint(uuid[3],p+28);
setint(128,p+32); /* start LBA */
setint(((es)/512)+127,p+40); /* end LBA */
memcpy(p+64,L"EFI System Partition",42); /* name */
p+=128;
}
/* calculate checksums */
/* partitioning table */
i=(int)(gpt[80]*gpt[84]);
setint(crc32a_calc((char*)gpt+512,i),gpt+88);
/* header */
i=getint(gpt+12); /* size of header */
setint(0,gpt+16); /* calculate as zero */
setint(crc32a_calc((char*)gpt,i),gpt+16);
/* ISO9660 cdrom image part */
if(bbs%4!=0) {
fprintf(stderr,"mkimg: %s\n","Stage2 is not 2048 byte sector aligned");
exit(3);
}
sprintf((char*)&isodate, "%04d%02d%02d%02d%02d%02d00",
ts->tm_year+1900,ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
/* 16th sector: Primary Volume Descriptor */
iso[0]=1; /* Header ID */
memcpy(&iso[1], "CD001", 5);
iso[6]=1; /* version */
for(i=8;i<72;i++) iso[i]=' ';
memcpy(&iso[40], "BOOTBOOT_CD", 11); /* Volume Identifier */
setinte((65536+es+2047)/2048, &iso[80]);
iso[120]=iso[123]=1; /* Volume Set Size */
iso[124]=iso[127]=1; /* Volume Sequence Number */
iso[129]=iso[130]=8; /* logical blocksize (0x800) */
iso[156]=0x22; /* root directory recordsize */
setinte(20, &iso[158]); /* root directory LBA */
setinte(2048, &iso[166]); /* root directory size */
iso[174]=ts->tm_year; /* root directory create date */
iso[175]=ts->tm_mon+1;
iso[176]=ts->tm_mday;
iso[177]=ts->tm_hour;
iso[178]=ts->tm_min;
iso[179]=ts->tm_sec;
iso[180]=0; /* timezone UTC (GMT) */
iso[181]=2; /* root directory flags (0=hidden,1=directory) */
iso[184]=1; /* root directory number */
iso[188]=1; /* root directory filename length */
for(i=190;i<813;i++) iso[i]=' '; /* Volume data */
memcpy(&iso[318], "BOOTBOOT <HTTPS://GITLAB.COM/BZTSRC/BOOTBOOT>", 45);
memcpy(&iso[446], "BOOTBOOT MKIMG", 14);
memcpy(&iso[574], "BOOTBOOT CD", 11);
for(i=702;i<813;i++) iso[i]=' '; /* file descriptors */
memcpy(&iso[813], &isodate, 16); /* volume create date */
memcpy(&iso[830], &isodate, 16); /* volume modify date */
for(i=847;i<863;i++) iso[i]='0'; /* volume expiration date */
for(i=864;i<880;i++) iso[i]='0'; /* volume shown date */
iso[881]=1; /* filestructure version */
for(i=883;i<1395;i++) iso[i]=' '; /* file descriptors */
/* 17th sector: Boot Record Descriptor */
iso[2048]=0; /* Header ID */
memcpy(&iso[2049], "CD001", 5);
iso[2054]=1; /* version */
memcpy(&iso[2055], "EL TORITO SPECIFICATION", 23);
setinte(19, &iso[2048+71]); /* Boot Catalog LBA */
/* 18th sector: Volume Descritor Terminator */
iso[4096]=0xFF; /* Header ID */
memcpy(&iso[4097], "CD001", 5);
iso[4102]=1; /* version */
/* 19th sector: Boot Catalog */
/* --- BIOS, Validation Entry + Initial/Default Entry --- */
iso[6144]=1; /* Header ID, Validation Entry */
iso[6145]=0; /* Platform 80x86 */
iso[6172]=0xaa; /* magic bytes */
iso[6173]=0x55;
iso[6174]=0x55;
iso[6175]=0xaa;
iso[6176]=0x88; /* Bootable, Initial/Default Entry */
iso[6182]=4; /* Sector Count */
setint(128/4, &iso[6184]); /* Boot Record LBA */
/* --- UEFI, Final Section Header Entry + Section Entry --- */
iso[6208]=0x91; /* Header ID, Final Section Header Entry */
iso[6209]=0xEF; /* Platform EFI */
iso[6210]=1; /* Number of entries */
iso[6240]=0x88; /* Bootable, Section Entry */
setint(128/4, &iso[6248]); /* ESP Start LBA */
/* 20th sector: Root Directory */
/* . */
iso[8192]=0x22; /* recordsize */
setinte(20, &iso[8194]); /* LBA */
setinte(2048, &iso[8202]); /* size */
iso[8210]=ts->tm_year; /* date */
iso[8211]=ts->tm_mon+1;
iso[8212]=ts->tm_mday;
iso[8213]=ts->tm_hour;
iso[8214]=ts->tm_min;
iso[8215]=ts->tm_sec;
iso[8216]=0; /* timezone UTC (GMT) */
iso[8217]=2; /* flags (0=hidden,1=directory) */
iso[8220]=1; /* serial */
iso[8224]=1; /* filename length */
/* .. */
iso[8226]=0x22; /* recordsize */
setinte(20, &iso[8228]); /* LBA */
setinte(2048, &iso[8236]); /* size */
iso[8244]=ts->tm_year; /* date */
iso[8245]=ts->tm_mon+1;
iso[8246]=ts->tm_mday;
iso[8247]=ts->tm_hour;
iso[8248]=ts->tm_min;
iso[8249]=ts->tm_sec;
iso[8250]=0; /* timezone UTC (GMT) */
iso[8251]=2; /* flags (0=hidden,1=directory) */
iso[8254]=1; /* serial */
iso[8258]=2; /* filename length */
/* README.TXT */
iso[8260]=0x22+12; /* recordsize */
setinte(21, &iso[8262]); /* LBA */
setinte(130, &iso[8270]); /* size */
iso[8278]=ts->tm_year; /* date */
iso[8279]=ts->tm_mon+1;
iso[8280]=ts->tm_mday;
iso[8281]=ts->tm_hour;
iso[8282]=ts->tm_min;
iso[8283]=ts->tm_sec;
iso[8284]=0; /* timezone UTC (GMT) */
iso[8285]=0; /* flags (0=hidden,1=directory) */
iso[8288]=1; /* serial */
iso[8292]=12; /* filename length */
memcpy(&iso[8293], "README.TXT;1", 12);
/* 21th sector: contents of README.TXT */
memcpy(&iso[10240], "BOOTBOOT Live Image\r\n\r\nBootable as\r\n"
" - CDROM (El Torito, UEFI)\r\n"
" - USB stick (BIOS, Multiboot, UEFI)\r\n"
" - SD card (Raspberry Pi 3+)", 130);
f=fopen(diskname,"wb");
if(!f) {
fprintf(stderr,"mkimg: unable to write %s\n",diskname);
exit(2);
}
/* (P)MBR */
fwrite(loader,512,1,f);
/* GPT header + entries */
fwrite(gpt,gs,1,f);
/* ISO9660 descriptors */
fwrite(iso,32768,1,f);
/* Partitions */
if(es>0)
fwrite(esp,es,1,f);
fseek(f,disksize-gs,SEEK_SET);
/* GPT entries again */
fwrite(gpt+512,gs-512,1,f);
/* GPT secondary header */
i=getint(gpt+32);
setint(getint(gpt+24),gpt+32); /* secondary lba */
setint(i,gpt+24); /* primary lba */
setint((i*512-gs)/512+1,gpt+72); /* partition lba */
i=getint(gpt+12); /* size of header */
setint(0,gpt+16); /* calculate with zero */
setint(crc32a_calc((char*)gpt,i),gpt+16);
fwrite(gpt,512,1,f);
fclose(f);
return 1;
}
/**
* Main entry point
*/
int main(int argc, char **argv)
{
if(argc < 2 || argv[1]==NULL || !strcmp(argv[1],"help") || (strcmp(argv[1], "rom") && argc < 3)) {
printf( "BOOTBOOT mkimg utility - bztsrc@gitlab\n\nUsage:\n"
" ./mkimg <disk image size in megabytes> <disk image name>\n"
" ./mkimg rom\n\n"
"Creates a hybrid disk / cdrom image from bootpart.bin, or initrd.rom from initrd.bin.\n");
exit(0);
}
if(!strcmp(argv[1], "rom"))
initrdrom();
else
createdisk(atoi(argv[1])*1024*1024, argv[2]);
return 0;
}