diff --git a/utils/OLVASSEL.md b/utils/OLVASSEL.md index 1457dd1..c097486 100644 --- a/utils/OLVASSEL.md +++ b/utils/OLVASSEL.md @@ -7,3 +7,5 @@ olyan különböző formátumú fájlokká, amiket az UEFI firmware használ. * __efirom__ - ez PCI Option ROM képet készít * __efiffs__ - ez DXE UEFI eszközmeghajtó képet (bővebb infó [ebben a wikiben](https://github.com/pbatard/efifs/wiki/Adding-a-driver-to-a-UEFI-firmware#adding-the-module-to-the-firmware) található arról, hogy kell a firmwarehez adni). + +* __efidsk__ - indítható lemezképet készít EFI Rendszer Partícióval egy könyvtár tartalmából diff --git a/utils/README.md b/utils/README.md index f0eb527..2f65717 100644 --- a/utils/README.md +++ b/utils/README.md @@ -7,3 +7,5 @@ with POSIX-UEFI into different file formats required by the UEFI firmware. * __efirom__ - creates a PCI Option ROM image * __efiffs__ - creates a DXE UEFI driver image (see [this wiki](https://github.com/pbatard/efifs/wiki/Adding-a-driver-to-a-UEFI-firmware#adding-the-module-to-the-firmware) on how to add it to a firmware). + +* __efidsk__ - creates a bootable disk image with EFI System Partition from the contents of a directory diff --git a/utils/efidsk.c b/utils/efidsk.c new file mode 100644 index 0000000..2809503 --- /dev/null +++ b/utils/efidsk.c @@ -0,0 +1,521 @@ +/* + * utils/efidsk.c + * + * Copyright (C) 2022 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 POSIX-UEFI package. + * @brief small tool to create a disk image with EFI System Partition + * + */ + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} __attribute__((packed)) guid_t; +guid_t dguid, pguid; + +/** + * Print usage + */ +void usage(char *cmd) +{ + printf("POSIX-UEFI utils - efidsk by bztsrc@gitlab MIT\r\n\r\n"); + printf("%s [-p] [-s ] indir outfile\r\n\r\n", cmd); + printf(" -p save only the partition image without GPT\r\n"); + printf(" -s set the size of partition in megabytes (defaults to 33M)\r\n"); + printf(" indir use the contents of this directory\r\n"); + printf(" outfile output image file name\r\n"); + exit(1); +} + +#define SECTOR_PER_CLUSTER 1 +#define FIRST_PARTITION 2048 + +struct tm *fat_ts; +int fs_len = 0, skipbytes = 0, fat_nextcluster, fat_bpc, fat_spf, fat_lfncnt, fat_numclu = 67584; +unsigned char *fs_base = NULL; +unsigned char *fat_rootdir, *fat_data, fat_lfn[769]; +uint32_t *fat_fat32_1, *fat_fat32_2; + +/** + * Add a new cluster + */ +unsigned char *fat_newclu(int parent) +{ + int clu; + while(parent != fat_nextcluster && fat_fat32_1[parent] && fat_fat32_1[parent] != 0xFFFFFFF) + parent = fat_fat32_1[parent]; + fat_fat32_1[parent] = fat_fat32_2[parent] = fat_nextcluster; + fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = 0xFFFFFFF; + clu = fat_nextcluster++; + if(fat_nextcluster >= fat_numclu) { fprintf(stderr,"efidsk: not enough space on partition\r\n"); exit(1); } + return fat_data + clu * fat_bpc; +} + +/** + * Read in file name + */ +unsigned char *fat_readlfn(unsigned char *dir, int *clu, int *size, int parent) +{ + uint16_t uc2[256], *u; + unsigned char *s, *d; + int i = 0, n; + memset(fat_lfn, 0, sizeof(fat_lfn)); + if(!dir[0]) return dir; + while(dir[0] == '.') dir += 32; + fat_lfncnt++; + if(parent != 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) { + parent = fat_fat32_1[parent]; + if(!parent || parent == 0xFFFFFFF) return NULL; + dir = fat_data + parent * fat_bpc; + } + if(dir[0xB] != 0xF) { + for(s = dir, d = fat_lfn, i = 0; *s && *s != ' ' && i < 8; i++) + *d++ = *s++; + if(dir[8] && dir[8] != ' ') { + *d++ = '.'; + for(s = dir + 8; *s != ' ' && i < 3; i++) + *d++ = *s++; + } + } else { + memset(uc2, 0, sizeof(uc2)); + n = dir[0] & 0x3F; + u = uc2 + (n - 1) * 13; + while(n--) { + for(i = 0; i < 5; i++) + u[i] = dir[i*2+2] << 8 | dir[i*2+1]; + for(i = 0; i < 6; i++) + u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE]; + u[11] = dir[0x1D] << 8 | dir[0x1C]; + u[12] = dir[0x1F] << 8 | dir[0x1E]; + u -= 13; + dir += 32; + if(!((uint64_t)(dir - fs_base) & (fat_bpc - 1))) { + parent = fat_fat32_1[parent]; + if(!parent || parent == 0xFFFFFFF) return NULL; + dir = fat_data + parent * fat_bpc; + } + } + for(d = fat_lfn, u = uc2; *u; u++) + if(*u < 0x80) { + *d++ = *u; + } else if(*u < 0x800) { + *d++ = ((*u>>6)&0x1F)|0xC0; + *d++ = (*u&0x3F)|0x80; + } else { + *d++ = ((*u>>12)&0x0F)|0xE0; + *d++ = ((*u>>6)&0x3F)|0x80; + *d++ = (*u&0x3F)|0x80; + } + } + *clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A]; + *size = (dir[0x1F] << 24) | (dir[0x1E] << 16) | (dir[0x1D] << 8) | dir[0x1C]; + return dir + 32; +} + +/** + * Write file name + */ +unsigned char *fat_writelfn(unsigned char *dir, char *name, int type, int size, int parent, int clu) +{ + uint16_t uc2[256], *u; + unsigned char *s, c = 0, sfn[12]; + int i, n; + if(name[0] == '.') { + memset(dir, ' ', 11); + memcpy(dir, name, strlen(name)); + } else { + memset(uc2, 0, sizeof(uc2)); + for(n = 0, u = uc2, s = (unsigned char*)name; *s; n++, u++) { + if((*s & 128) != 0) { + if((*s & 32) == 0) { *u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s += 2; } else + if((*s & 16) == 0) { *u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 3; } + else { fprintf(stderr,"efidsk: unable to encode file name '%s'\r\n", name); exit(1); } + } else + *u = *s++; + } + /* don't convert "Microsoft" to "MICROS~1 ", that's patented... */ + sprintf((char*)sfn, "~%07xLFN", fat_lfncnt++); + for(i = 0; i < 11; i++) + c = (((c & 1) << 7) | ((c & 0xfe) >> 1)) + sfn[i]; + n = (n + 12) / 13; + u = uc2 + (n - 1) * 13; + i = 0x40; + while(n--) { + if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) + dir = fat_newclu(parent); + dir[0] = i | (n + 1); + dir[11] = 0xF; + dir[0xD] = c; + memcpy(dir + 1, (unsigned char*)u, 10); + memcpy(dir + 14, (unsigned char*)u + 10, 12); + memcpy(dir + 28, (unsigned char*)u + 22, 4); + i = 0; + u -= 13; + dir += 32; + } + if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) + dir = fat_newclu(parent); + memcpy(dir, sfn, 11); + } + if(type) { + dir[0xB] = 0x10; + } else { + dir[0x1C] = size & 0xFF; dir[0x1D] = (size >> 8) & 0xFF; + dir[0x1E] = (size >> 16) & 0xFF; dir[0x1F] = (size >> 24) & 0xFF; + } + if(!clu) clu = size > 0 || type ? fat_nextcluster : 0; + if(clu < 3) clu = 0; + dir[0x1A] = clu & 0xFF; dir[0x1B] = (clu >> 8) & 0xFF; + dir[0x14] = (clu >> 16) & 0xFF; dir[0x15] = (clu >> 24) & 0xFF; + i = (fat_ts->tm_hour << 11) | (fat_ts->tm_min << 5) | (fat_ts->tm_sec/2); + dir[0xE] = dir[0x16] = i & 0xFF; dir[0xF] = dir[0x17] = (i >> 8) & 0xFF; + i = ((fat_ts->tm_year+1900-1980) << 9) | ((fat_ts->tm_mon+1) << 5) | (fat_ts->tm_mday); + return dir + 32; +} + +/** + * Create a fat file system + */ +void fat_open(int start) +{ + int i; + + if(fat_numclu < 67584) { fprintf(stderr,"efidsk: not enough clusters\r\n"); exit(1); } + /* "format" the partition to FAT32 */ + fs_len = fat_numclu * 512 * SECTOR_PER_CLUSTER; + fs_base = realloc(fs_base, fs_len); + if(!fs_base) { fprintf(stderr,"efidsk: unable to allocate memory\r\n"); exit(1); } + memset(fs_base, 0, fs_len); + memcpy(fs_base + 3, "MSWIN4.1", 8); + fs_base[0xC] = 2; fs_base[0x10] = 2; fs_base[0x15] = 0xF8; fs_base[0x1FE] = 0x55; fs_base[0x1FF] = 0xAA; + fs_base[0x18] = 0x20; fs_base[0x1A] = 0x40; + memcpy(fs_base + 0x1C, &start, 4); + memcpy(fs_base + 0x20, &fat_numclu, 4); + fat_spf = (fat_numclu*4) / 512; + fs_base[0xD] = SECTOR_PER_CLUSTER; fs_base[0xE] = 8; + fs_base[0x24] = fat_spf & 0xFF; fs_base[0x25] = (fat_spf >> 8) & 0xFF; + fs_base[0x26] = (fat_spf >> 16) & 0xFF; fs_base[0x27] = (fat_spf >> 24) & 0xFF; + fs_base[0x2C] = 2; fs_base[0x30] = 1; fs_base[0x32] = 6; fs_base[0x40] = 0x80; fs_base[0x42] = 0x29; + memcpy(fs_base + 0x43, &pguid, 4); + memcpy(fs_base + 0x47, "EFI System FAT32 ", 19); + memcpy(fs_base + 0x200, "RRaA", 4); memcpy(fs_base + 0x3E4, "rrAa", 4); + for(i = 0; i < 8; i++) fs_base[0x3E8 + i] = 0xFF; + fs_base[0x3FE] = 0x55; fs_base[0x3FF] = 0xAA; + fat_bpc = fs_base[0xD] * 512; + fat_rootdir = fs_base + (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512; + fat_data = fat_rootdir - 2*fat_bpc; + fat_fat32_1 = (uint32_t*)(&fs_base[fs_base[0xE] * 512]); + fat_fat32_2 = (uint32_t*)(&fs_base[(fs_base[0xE]+fat_spf) * 512]); + fat_fat32_1[0] = fat_fat32_2[0] = fat_fat32_1[2] = fat_fat32_2[2] = 0x0FFFFFF8; + fat_fat32_1[1] = fat_fat32_2[1] = 0x0FFFFFFF; + fat_nextcluster = 3; +} + +/** + * Add a file to the file system + */ +void fat_add(struct stat *st, char *name, unsigned char *content, int size) +{ + int parent = 2, clu, i, j; + unsigned char *dir = fat_rootdir; + char *end, *fn = strrchr(name, '/'); + if(!fn) fn = name; else fn++; + if(!strcmp(fn, ".") || !strcmp(fn, "..")) return; + if(!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) return; + fat_ts = gmtime(&st->st_mtime); + fn = name; + end = strchr(name, '/'); + if(!end) end = name + strlen(name); + fat_lfncnt = 1; + do { + dir = fat_readlfn(dir, &clu, &j, parent); + if(!dir) return; + if(!memcmp(fat_lfn, fn, end - fn) && !fat_lfn[end - fn]) { + fat_lfncnt = 1; + parent = clu; + dir = fat_data + parent * fat_bpc + 64; + fn = end + 1; + end = *end ? strchr(fn, '/') : NULL; + if(!end) { end = fn + strlen(fn); break; } + } + } while(dir[0]); + dir = fat_writelfn(dir, fn, S_ISDIR(st->st_mode), size, parent, 0); + if(S_ISDIR(st->st_mode)) { + dir = fat_newclu(fat_nextcluster); + dir = fat_writelfn(dir, ".", 1, 0, 2, fat_nextcluster - 1); + dir = fat_writelfn(dir, "..", 1, 0, 2, parent); + } else if(content && size > 0) { + if(fat_nextcluster * fat_bpc + size >= fs_len) { + fprintf(stderr,"efidsk: not enough space on partition\r\n"); + exit(1); + } + memcpy(fat_data + fat_nextcluster * fat_bpc, content, size); + for(i = 0; i < ((size + fat_bpc-1) & ~(fat_bpc-1)); i += fat_bpc, fat_nextcluster++) { + fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = fat_nextcluster+1; + } + fat_fat32_1[fat_nextcluster-1] = fat_fat32_2[fat_nextcluster-1] = 0xFFFFFFF; + } +} + +/** + * Close the file system + */ +void fat_close() +{ + int i; + if(!fs_base || fs_len < 512) return; + fat_nextcluster -= 2; + i = ((fs_len - (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512)/fat_bpc) - fat_nextcluster; + fs_base[0x3E8] = i & 0xFF; fs_base[0x3E9] = (i >> 8) & 0xFF; + fs_base[0x3EA] = (i >> 16) & 0xFF; fs_base[0x3EB] = (i >> 24) & 0xFF; + fs_base[0x3EC] = fat_nextcluster & 0xFF; fs_base[0x3ED] = (fat_nextcluster >> 8) & 0xFF; + fs_base[0x3EE] = (fat_nextcluster >> 16) & 0xFF; fs_base[0x3EF] = (fat_nextcluster >> 24) & 0xFF; + /* copy backup boot sectors */ + memcpy(fs_base + (fs_base[0x32]*512), fs_base, 1024); +} + +/** + * Read a file entirely into memory + */ +long int read_size; +unsigned char* readfileall(char *file) +{ + unsigned char *data=NULL; + FILE *f; + read_size = 0; + if(!file || !*file) return NULL; + f = fopen(file,"r"); + if(f) { + fseek(f, 0L, SEEK_END); + read_size = (long int)ftell(f); + fseek(f, 0L, SEEK_SET); + data = (unsigned char*)malloc(read_size + 1); + if(!data) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); } + memset(data, 0, read_size + 1); + fread(data, read_size, 1, f); + data[read_size] = 0; + fclose(f); + } + return data; +} + +/** + * Recursively parse a directory + */ +void parsedir(char *directory, int parent) +{ + DIR *dir; + struct dirent *ent; + char full[8192]; + unsigned char *tmp; + struct stat st; + + if(!parent && !skipbytes) skipbytes = strlen(directory) + 1; + + if ((dir = opendir(directory)) != NULL) { + while ((ent = readdir(dir)) != NULL) { + if(!parent && (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))) continue; + full[0] = 0; + strncat(full, directory, sizeof(full)-1); + strncat(full, "/", sizeof(full)-1); + strncat(full, ent->d_name, sizeof(full)-1); + if(stat(full, &st)) continue; + read_size = 0; + if(S_ISDIR(st.st_mode)) { + fat_add(&st, full + skipbytes, NULL, 0); + if(strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) + parsedir(full, parent+1); + } else + if(S_ISREG(st.st_mode)) { + tmp = readfileall(full); + fat_add(&st, full + skipbytes, tmp, read_size); + if(tmp) free(tmp); + } + } + closedir(dir); + } +} + +/** + * CRC calculation with precalculated lookup table + */ +uint32_t 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}; +uint32_t crc32_calc(unsigned char *start,int length) +{ + uint32_t crc32_val=0xffffffff; + while(length--) crc32_val=(crc32_val>>8)^crc32_lookup[(crc32_val&0xff)^(unsigned char)*start++]; + crc32_val^=0xffffffff; + return crc32_val; +} + +/** + * Write out GUID Partitioning Table + */ +void setint(int val, unsigned char *ptr) { memcpy(ptr,&val,4); } +void writegpt(FILE *f) +{ + guid_t efiguid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA,0x4B,0x00,0xA0,0xC9,0x3E,0xC9,0x3B} }; + int i; + unsigned char *gpt = malloc(FIRST_PARTITION * 512), gpt2[512], *p; + char *name; + if(!gpt) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); } + memset(gpt, 0, FIRST_PARTITION * 512); + p = gpt + 512; + + /* GPT header */ + memcpy(p,"EFI PART",8); /* magic */ + setint(1,p+10); /* revision */ + setint(92,p+12); /* size */ + setint(1,p+24); /* primary LBA */ + setint(2*FIRST_PARTITION+fat_numclu-2,p+32);/* secondary LBA */ + setint(FIRST_PARTITION,p+40); /* first usable LBA */ + setint(FIRST_PARTITION+fat_numclu,p+48); /* last usable LBA */ + memcpy(p+56,&dguid,sizeof(guid_t)); /* disk UUID */ + setint(2,p+72); /* partitioning table LBA */ + setint((FIRST_PARTITION-2)*512/128,p+80); /* number of entries */ + setint(128,p+84); /* size of one entry */ + p += 512; + + /* GPT, EFI System Partition (ESP) */ + memcpy(p, &efiguid, sizeof(guid_t)); /* entry type */ + memcpy(p+16, &pguid, sizeof(guid_t)); /* partition UUID */ + setint(FIRST_PARTITION,p+32); /* start LBA */ + setint(FIRST_PARTITION+fat_numclu-1,p+40); /* end LBA */ + name = "EFI System Partition"; /* name */ + for(i = 0; name[i]; i++) p[56+i*2] = name[i]; + p += 128; + + /* calculate checksums */ + setint(crc32_calc(gpt+1024,((gpt[512+81]<<8)|gpt[512+80])*128),gpt+512+88); + setint(crc32_calc(gpt+512,92),gpt+512+16); + memcpy(gpt2, gpt+512, 512); + setint(1,gpt2+32); /* secondary lba */ + setint(2*FIRST_PARTITION+fat_numclu-2,gpt2+24); /* primary lba */ + setint(FIRST_PARTITION+fat_numclu,gpt2+72); /* partition lba */ + setint(0,gpt2+16); /* calculate with zero */ + setint(crc32_calc(gpt2,92),gpt2+16); + + fwrite(gpt, 1, FIRST_PARTITION * 512, f); + fwrite(fs_base, 1, fs_len, f); + fwrite(gpt + 1024, 1, (FIRST_PARTITION - 2) * 512, f); + fwrite(gpt2, 1, 512, f); + free(gpt); +} + +/** + * Main function + */ +int main(int argc, char **argv) +{ + FILE *f; + int i, part = 0; + char *in = NULL, *out = NULL; + + /* get random GUIDs */ + srand(time(NULL)); + i = rand(); memcpy(&((uint8_t*)&dguid)[0], &i, 4); + i = rand(); memcpy(&((uint8_t*)&dguid)[4], &i, 4); + i = rand(); memcpy(&((uint8_t*)&dguid)[8], &i, 4); + i = rand(); memcpy(&((uint8_t*)&dguid)[12], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[0], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[4], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[8], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[12], &i, 4); + + /* parse command line */ + for(i = 1; i < argc && argv[i]; i++) + if(argv[i][0] == '-') { + switch(argv[i][1]) { + case 'p': part++; break; + case 's': fat_numclu = atoi(argv[++i]) * 2048; break; + default: usage(argv[0]); break; + } + } else + if(!in) in = argv[i]; else + if(!out) out = argv[i]; else + usage(argv[0]); + if(!out) usage(argv[0]); + + /* generate file system image */ + remove(out); + fat_open(part ? 0 : FIRST_PARTITION); + parsedir(in, 0); + fat_close(); + + /* write out image */ + if(fs_base) { + f = fopen(out, "wb"); + if(!f) { + fprintf(stderr, "efidsk: unable to write '%s'\r\n", out); + return 2; + } + if(!part) + writegpt(f); + else + fwrite(fs_base, 1, fs_len, f); + fclose(f); + free(fs_base); + } + + return 0; +}