efidsk.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /*
  2. * utils/efidsk.c
  3. *
  4. * Copyright (C) 2022 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * This file is part of the POSIX-UEFI package.
  27. * @brief small tool to create a disk image with EFI System Partition
  28. *
  29. */
  30. #include <stdint.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <dirent.h>
  35. #include <sys/stat.h>
  36. #include <time.h>
  37. typedef struct {
  38. uint32_t Data1;
  39. uint16_t Data2;
  40. uint16_t Data3;
  41. uint8_t Data4[8];
  42. } __attribute__((packed)) guid_t;
  43. guid_t dguid, pguid;
  44. /**
  45. * Print usage
  46. */
  47. void usage(char *cmd)
  48. {
  49. printf("POSIX-UEFI utils - efidsk by bztsrc@gitlab MIT\r\n\r\n");
  50. printf("%s [-p|-c] [-s <size>] indir outfile\r\n\r\n", cmd);
  51. printf(" -p save only the partition image without GPT\r\n");
  52. printf(" -c save EFI CDROM (ISO9660 El Torito no emulation boot catalog)\r\n");
  53. printf(" -s <size> set the size of partition in megabytes (defaults to 33M)\r\n");
  54. printf(" indir use the contents of this directory\r\n");
  55. printf(" outfile output image file name\r\n");
  56. exit(1);
  57. }
  58. #define SECTOR_PER_CLUSTER 1
  59. #define FIRST_PARTITION 2048
  60. struct tm *fat_ts;
  61. int fs_len = 0, skipbytes = 0, fat_nextcluster, fat_bpc, fat_spf, fat_lfncnt, fat_numclu = 67584;
  62. unsigned char *fs_base = NULL;
  63. unsigned char *fat_rootdir, *fat_data, fat_lfn[769];
  64. uint32_t *fat_fat32_1, *fat_fat32_2;
  65. /**
  66. * Add a new cluster
  67. */
  68. unsigned char *fat_newclu(int parent)
  69. {
  70. int clu;
  71. while(parent != fat_nextcluster && fat_fat32_1[parent] && fat_fat32_1[parent] != 0xFFFFFFF)
  72. parent = fat_fat32_1[parent];
  73. fat_fat32_1[parent] = fat_fat32_2[parent] = fat_nextcluster;
  74. fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = 0xFFFFFFF;
  75. clu = fat_nextcluster++;
  76. if(fat_nextcluster >= fat_numclu) { fprintf(stderr,"efidsk: not enough space on partition\r\n"); exit(1); }
  77. return fat_data + clu * fat_bpc;
  78. }
  79. /**
  80. * Read in file name
  81. */
  82. unsigned char *fat_readlfn(unsigned char *dir, int *clu, int *size, int parent)
  83. {
  84. uint16_t uc2[256], *u;
  85. unsigned char *s, *d;
  86. int i = 0, n;
  87. memset(fat_lfn, 0, sizeof(fat_lfn));
  88. if(!dir[0]) return dir;
  89. while(dir[0] == '.') dir += 32;
  90. fat_lfncnt++;
  91. if(parent != 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) {
  92. parent = fat_fat32_1[parent];
  93. if(!parent || parent == 0xFFFFFFF) return NULL;
  94. dir = fat_data + parent * fat_bpc;
  95. }
  96. if(dir[0xB] != 0xF) {
  97. for(s = dir, d = fat_lfn, i = 0; *s && *s != ' ' && i < 8; i++)
  98. *d++ = *s++;
  99. if(dir[8] && dir[8] != ' ') {
  100. *d++ = '.';
  101. for(s = dir + 8; *s != ' ' && i < 3; i++)
  102. *d++ = *s++;
  103. }
  104. } else {
  105. memset(uc2, 0, sizeof(uc2));
  106. n = dir[0] & 0x3F;
  107. u = uc2 + (n - 1) * 13;
  108. while(n--) {
  109. for(i = 0; i < 5; i++)
  110. u[i] = dir[i*2+2] << 8 | dir[i*2+1];
  111. for(i = 0; i < 6; i++)
  112. u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE];
  113. u[11] = dir[0x1D] << 8 | dir[0x1C];
  114. u[12] = dir[0x1F] << 8 | dir[0x1E];
  115. u -= 13;
  116. dir += 32;
  117. if(!((uint64_t)(dir - fs_base) & (fat_bpc - 1))) {
  118. parent = fat_fat32_1[parent];
  119. if(!parent || parent == 0xFFFFFFF) return NULL;
  120. dir = fat_data + parent * fat_bpc;
  121. }
  122. }
  123. for(d = fat_lfn, u = uc2; *u; u++)
  124. if(*u < 0x80) {
  125. *d++ = *u;
  126. } else if(*u < 0x800) {
  127. *d++ = ((*u>>6)&0x1F)|0xC0;
  128. *d++ = (*u&0x3F)|0x80;
  129. } else {
  130. *d++ = ((*u>>12)&0x0F)|0xE0;
  131. *d++ = ((*u>>6)&0x3F)|0x80;
  132. *d++ = (*u&0x3F)|0x80;
  133. }
  134. }
  135. *clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A];
  136. *size = (dir[0x1F] << 24) | (dir[0x1E] << 16) | (dir[0x1D] << 8) | dir[0x1C];
  137. return dir + 32;
  138. }
  139. /**
  140. * Write file name
  141. */
  142. unsigned char *fat_writelfn(unsigned char *dir, char *name, int type, int size, int parent, int clu)
  143. {
  144. uint16_t uc2[256], *u;
  145. unsigned char *s, c = 0, sfn[12];
  146. int i, n;
  147. if(name[0] == '.') {
  148. memset(dir, ' ', 11);
  149. memcpy(dir, name, strlen(name));
  150. } else {
  151. memset(uc2, 0, sizeof(uc2));
  152. for(n = 0, u = uc2, s = (unsigned char*)name; *s; n++, u++) {
  153. if((*s & 128) != 0) {
  154. if((*s & 32) == 0) { *u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s += 2; } else
  155. if((*s & 16) == 0) { *u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 3; }
  156. else { fprintf(stderr,"efidsk: unable to encode file name '%s'\r\n", name); exit(1); }
  157. } else
  158. *u = *s++;
  159. }
  160. /* don't convert "Microsoft" to "MICROS~1 ", that's patented... */
  161. sprintf((char*)sfn, "~%07xLFN", fat_lfncnt++);
  162. for(i = 0; i < 11; i++)
  163. c = (((c & 1) << 7) | ((c & 0xfe) >> 1)) + sfn[i];
  164. n = (n + 12) / 13;
  165. u = uc2 + (n - 1) * 13;
  166. i = 0x40;
  167. while(n--) {
  168. if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1)))
  169. dir = fat_newclu(parent);
  170. dir[0] = i | (n + 1);
  171. dir[11] = 0xF;
  172. dir[0xD] = c;
  173. memcpy(dir + 1, (unsigned char*)u, 10);
  174. memcpy(dir + 14, (unsigned char*)u + 10, 12);
  175. memcpy(dir + 28, (unsigned char*)u + 22, 4);
  176. i = 0;
  177. u -= 13;
  178. dir += 32;
  179. }
  180. if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1)))
  181. dir = fat_newclu(parent);
  182. memcpy(dir, sfn, 11);
  183. }
  184. if(type) {
  185. dir[0xB] = 0x10;
  186. } else {
  187. dir[0x1C] = size & 0xFF; dir[0x1D] = (size >> 8) & 0xFF;
  188. dir[0x1E] = (size >> 16) & 0xFF; dir[0x1F] = (size >> 24) & 0xFF;
  189. }
  190. if(!clu) clu = size > 0 || type ? fat_nextcluster : 0;
  191. if(clu < 3) clu = 0;
  192. dir[0x1A] = clu & 0xFF; dir[0x1B] = (clu >> 8) & 0xFF;
  193. dir[0x14] = (clu >> 16) & 0xFF; dir[0x15] = (clu >> 24) & 0xFF;
  194. i = (fat_ts->tm_hour << 11) | (fat_ts->tm_min << 5) | (fat_ts->tm_sec/2);
  195. dir[0xE] = dir[0x16] = i & 0xFF; dir[0xF] = dir[0x17] = (i >> 8) & 0xFF;
  196. i = ((fat_ts->tm_year+1900-1980) << 9) | ((fat_ts->tm_mon+1) << 5) | (fat_ts->tm_mday);
  197. return dir + 32;
  198. }
  199. /**
  200. * Create a fat file system
  201. */
  202. void fat_open(int start)
  203. {
  204. int i;
  205. if(fat_numclu < 67584) { fprintf(stderr,"efidsk: not enough clusters\r\n"); exit(1); }
  206. /* "format" the partition to FAT32 */
  207. fs_len = fat_numclu * 512 * SECTOR_PER_CLUSTER;
  208. fs_base = realloc(fs_base, fs_len);
  209. if(!fs_base) { fprintf(stderr,"efidsk: unable to allocate memory\r\n"); exit(1); }
  210. memset(fs_base, 0, fs_len);
  211. memcpy(fs_base + 3, "MSWIN4.1", 8);
  212. fs_base[0xC] = 2; fs_base[0x10] = 2; fs_base[0x15] = 0xF8; fs_base[0x1FE] = 0x55; fs_base[0x1FF] = 0xAA;
  213. fs_base[0x18] = 0x20; fs_base[0x1A] = 0x40;
  214. memcpy(fs_base + 0x1C, &start, 4);
  215. memcpy(fs_base + 0x20, &fat_numclu, 4);
  216. fat_spf = (fat_numclu*4) / 512;
  217. fs_base[0xD] = SECTOR_PER_CLUSTER; fs_base[0xE] = 8;
  218. fs_base[0x24] = fat_spf & 0xFF; fs_base[0x25] = (fat_spf >> 8) & 0xFF;
  219. fs_base[0x26] = (fat_spf >> 16) & 0xFF; fs_base[0x27] = (fat_spf >> 24) & 0xFF;
  220. fs_base[0x2C] = 2; fs_base[0x30] = 1; fs_base[0x32] = 6; fs_base[0x40] = 0x80; fs_base[0x42] = 0x29;
  221. memcpy(fs_base + 0x43, &pguid, 4);
  222. memcpy(fs_base + 0x47, "EFI System FAT32 ", 19);
  223. memcpy(fs_base + 0x200, "RRaA", 4); memcpy(fs_base + 0x3E4, "rrAa", 4);
  224. for(i = 0; i < 8; i++) fs_base[0x3E8 + i] = 0xFF;
  225. fs_base[0x3FE] = 0x55; fs_base[0x3FF] = 0xAA;
  226. fat_bpc = fs_base[0xD] * 512;
  227. fat_rootdir = fs_base + (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512;
  228. fat_data = fat_rootdir - 2*fat_bpc;
  229. fat_fat32_1 = (uint32_t*)(&fs_base[fs_base[0xE] * 512]);
  230. fat_fat32_2 = (uint32_t*)(&fs_base[(fs_base[0xE]+fat_spf) * 512]);
  231. fat_fat32_1[0] = fat_fat32_2[0] = fat_fat32_1[2] = fat_fat32_2[2] = 0x0FFFFFF8;
  232. fat_fat32_1[1] = fat_fat32_2[1] = 0x0FFFFFFF;
  233. fat_nextcluster = 3;
  234. }
  235. /**
  236. * Add a file to the file system
  237. */
  238. void fat_add(struct stat *st, char *name, unsigned char *content, int size)
  239. {
  240. int parent = 2, clu, i, j;
  241. unsigned char *dir = fat_rootdir;
  242. char *end, *fn = strrchr(name, '/');
  243. if(!fn) fn = name; else fn++;
  244. if(!strcmp(fn, ".") || !strcmp(fn, "..")) return;
  245. if(!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) return;
  246. fat_ts = gmtime(&st->st_mtime);
  247. fn = name;
  248. end = strchr(name, '/');
  249. if(!end) end = name + strlen(name);
  250. fat_lfncnt = 1;
  251. do {
  252. dir = fat_readlfn(dir, &clu, &j, parent);
  253. if(!dir) return;
  254. if(!memcmp(fat_lfn, fn, end - fn) && !fat_lfn[end - fn]) {
  255. fat_lfncnt = 1;
  256. parent = clu;
  257. dir = fat_data + parent * fat_bpc + 64;
  258. fn = end + 1;
  259. end = *end ? strchr(fn, '/') : NULL;
  260. if(!end) { end = fn + strlen(fn); break; }
  261. }
  262. } while(dir[0]);
  263. dir = fat_writelfn(dir, fn, S_ISDIR(st->st_mode), size, parent, 0);
  264. if(S_ISDIR(st->st_mode)) {
  265. dir = fat_newclu(fat_nextcluster);
  266. dir = fat_writelfn(dir, ".", 1, 0, 2, fat_nextcluster - 1);
  267. dir = fat_writelfn(dir, "..", 1, 0, 2, parent);
  268. } else if(content && size > 0) {
  269. if(fat_nextcluster * fat_bpc + size >= fs_len) {
  270. fprintf(stderr,"efidsk: not enough space on partition\r\n");
  271. exit(1);
  272. }
  273. memcpy(fat_data + fat_nextcluster * fat_bpc, content, size);
  274. for(i = 0; i < ((size + fat_bpc-1) & ~(fat_bpc-1)); i += fat_bpc, fat_nextcluster++) {
  275. fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = fat_nextcluster+1;
  276. }
  277. fat_fat32_1[fat_nextcluster-1] = fat_fat32_2[fat_nextcluster-1] = 0xFFFFFFF;
  278. }
  279. }
  280. /**
  281. * Close the file system
  282. */
  283. void fat_close()
  284. {
  285. int i;
  286. if(!fs_base || fs_len < 512) return;
  287. fat_nextcluster -= 2;
  288. i = ((fs_len - (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512)/fat_bpc) - fat_nextcluster;
  289. fs_base[0x3E8] = i & 0xFF; fs_base[0x3E9] = (i >> 8) & 0xFF;
  290. fs_base[0x3EA] = (i >> 16) & 0xFF; fs_base[0x3EB] = (i >> 24) & 0xFF;
  291. fs_base[0x3EC] = fat_nextcluster & 0xFF; fs_base[0x3ED] = (fat_nextcluster >> 8) & 0xFF;
  292. fs_base[0x3EE] = (fat_nextcluster >> 16) & 0xFF; fs_base[0x3EF] = (fat_nextcluster >> 24) & 0xFF;
  293. /* copy backup boot sectors */
  294. memcpy(fs_base + (fs_base[0x32]*512), fs_base, 1024);
  295. }
  296. /**
  297. * Read a file entirely into memory
  298. */
  299. long int read_size;
  300. unsigned char* readfileall(char *file)
  301. {
  302. unsigned char *data=NULL;
  303. FILE *f;
  304. read_size = 0;
  305. if(!file || !*file) return NULL;
  306. f = fopen(file,"r");
  307. if(f) {
  308. fseek(f, 0L, SEEK_END);
  309. read_size = (long int)ftell(f);
  310. fseek(f, 0L, SEEK_SET);
  311. data = (unsigned char*)malloc(read_size + 1);
  312. if(!data) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); }
  313. memset(data, 0, read_size + 1);
  314. fread(data, read_size, 1, f);
  315. data[read_size] = 0;
  316. fclose(f);
  317. }
  318. return data;
  319. }
  320. /**
  321. * Recursively parse a directory
  322. */
  323. void parsedir(char *directory, int parent)
  324. {
  325. DIR *dir;
  326. struct dirent *ent;
  327. char full[8192];
  328. unsigned char *tmp;
  329. struct stat st;
  330. if(!parent && !skipbytes) skipbytes = strlen(directory) + 1;
  331. if ((dir = opendir(directory)) != NULL) {
  332. while ((ent = readdir(dir)) != NULL) {
  333. if(!parent && (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))) continue;
  334. full[0] = 0;
  335. strncat(full, directory, sizeof(full)-1);
  336. strncat(full, "/", sizeof(full)-1);
  337. strncat(full, ent->d_name, sizeof(full)-1);
  338. if(stat(full, &st)) continue;
  339. read_size = 0;
  340. if(S_ISDIR(st.st_mode)) {
  341. fat_add(&st, full + skipbytes, NULL, 0);
  342. if(strcmp(ent->d_name, ".") && strcmp(ent->d_name, ".."))
  343. parsedir(full, parent+1);
  344. } else
  345. if(S_ISREG(st.st_mode)) {
  346. tmp = readfileall(full);
  347. fat_add(&st, full + skipbytes, tmp, read_size);
  348. if(tmp) free(tmp);
  349. }
  350. }
  351. closedir(dir);
  352. }
  353. }
  354. /**
  355. * CRC calculation with precalculated lookup table
  356. */
  357. uint32_t crc32_lookup[256]={
  358. 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,
  359. 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
  360. 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
  361. 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
  362. 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
  363. 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
  364. 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
  365. 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
  366. 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
  367. 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
  368. 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,
  369. 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
  370. 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,
  371. 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
  372. 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
  373. 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
  374. 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
  375. 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
  376. 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
  377. 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
  378. 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
  379. 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
  380. 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,
  381. 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
  382. 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
  383. 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
  384. 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,
  385. 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
  386. 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
  387. uint32_t crc32_calc(unsigned char *start,int length)
  388. {
  389. uint32_t crc32_val=0xffffffff;
  390. while(length--) crc32_val=(crc32_val>>8)^crc32_lookup[(crc32_val&0xff)^(unsigned char)*start++];
  391. crc32_val^=0xffffffff;
  392. return crc32_val;
  393. }
  394. /**
  395. * Write out GUID Partitioning Table
  396. */
  397. void setint(int val, unsigned char *ptr) { memcpy(ptr,&val,4); }
  398. void writegpt(FILE *f)
  399. {
  400. guid_t efiguid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA,0x4B,0x00,0xA0,0xC9,0x3E,0xC9,0x3B} };
  401. int i;
  402. unsigned char *gpt = malloc(FIRST_PARTITION * 512), gpt2[512], *p;
  403. char *name;
  404. if(!gpt) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); }
  405. memset(gpt, 0, FIRST_PARTITION * 512);
  406. gpt[0x1FE]=0x55; gpt[0x1FF]=0xAA;
  407. memcpy(gpt+0x1B8, &dguid.Data1, 4); /* WinNT disk id */
  408. /* MBR, EFI System Partition / boot partition. */
  409. gpt[0x1C0-2]=0x80; /* bootable flag */
  410. setint(FIRST_PARTITION+1,gpt+0x1C0); /* start CHS */
  411. gpt[0x1C0+2]=0xC; /* type, LBA FAT32 (0xC) */
  412. setint(fs_len/512,gpt+0x1C0+4); /* end CHS */
  413. setint(FIRST_PARTITION,gpt+0x1C0+6); /* start LBA */
  414. setint(fs_len/512,gpt+0x1C0+10); /* number of sectors */
  415. /* MBR, protective GPT entry */
  416. setint(1,gpt+0x1D0); /* start CHS */
  417. gpt[0x1D0+2]=0xEE; /* type */
  418. setint(FIRST_PARTITION+1,gpt+0x1D0+4); /* end CHS */
  419. setint(1,gpt+0x1D0+6); /* start LBA */
  420. setint(FIRST_PARTITION,gpt+0x1D0+10); /* number of sectors */
  421. /* GPT header */
  422. p = gpt + 512;
  423. memcpy(p,"EFI PART",8); /* magic */
  424. setint(1,p+10); /* revision */
  425. setint(92,p+12); /* size */
  426. setint(1,p+24); /* primary LBA */
  427. setint(2*FIRST_PARTITION+fat_numclu-2,p+32);/* secondary LBA */
  428. setint(FIRST_PARTITION,p+40); /* first usable LBA */
  429. setint(FIRST_PARTITION+fat_numclu,p+48); /* last usable LBA */
  430. memcpy(p+56,&dguid,sizeof(guid_t)); /* disk UUID */
  431. setint(2,p+72); /* partitioning table LBA */
  432. setint((FIRST_PARTITION-2)*512/128,p+80); /* number of entries */
  433. setint(128,p+84); /* size of one entry */
  434. p += 512;
  435. /* GPT, EFI System Partition (ESP) */
  436. memcpy(p, &efiguid, sizeof(guid_t)); /* entry type */
  437. memcpy(p+16, &pguid, sizeof(guid_t)); /* partition UUID */
  438. setint(FIRST_PARTITION,p+32); /* start LBA */
  439. setint(FIRST_PARTITION+fat_numclu-1,p+40); /* end LBA */
  440. name = "EFI System Partition"; /* name */
  441. for(i = 0; name[i]; i++) p[56+i*2] = name[i];
  442. p += 128;
  443. /* calculate checksums */
  444. setint(crc32_calc(gpt+1024,((gpt[512+81]<<8)|gpt[512+80])*128),gpt+512+88);
  445. setint(crc32_calc(gpt+512,92),gpt+512+16);
  446. memcpy(gpt2, gpt+512, 512);
  447. setint(1,gpt2+32); /* secondary lba */
  448. setint(2*FIRST_PARTITION+fat_numclu-2,gpt2+24); /* primary lba */
  449. setint(FIRST_PARTITION+fat_numclu,gpt2+72); /* partition lba */
  450. setint(0,gpt2+16); /* calculate with zero */
  451. setint(crc32_calc(gpt2,92),gpt2+16);
  452. fwrite(gpt, 1, FIRST_PARTITION * 512, f);
  453. fwrite(fs_base, 1, fs_len, f);
  454. fwrite(gpt + 1024, 1, (FIRST_PARTITION - 2) * 512, f);
  455. fwrite(gpt2, 1, 512, f);
  456. free(gpt);
  457. }
  458. /**
  459. * Write out ISO9660 El Torito "no emulation" Boot Catalog
  460. */
  461. 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]; }
  462. void writeetbc(FILE *f)
  463. {
  464. int i;
  465. time_t t;
  466. char isodate[128];
  467. unsigned char *gpt = malloc(FIRST_PARTITION * 512), *iso;
  468. if(!gpt) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); }
  469. memset(gpt, 0, FIRST_PARTITION * 512);
  470. t = time(NULL);
  471. fat_ts = gmtime(&t);
  472. sprintf((char*)&isodate, "%04d%02d%02d%02d%02d%02d00",
  473. fat_ts->tm_year+1900,fat_ts->tm_mon+1,fat_ts->tm_mday,fat_ts->tm_hour,fat_ts->tm_min,fat_ts->tm_sec);
  474. iso = gpt + 16*2048;
  475. /* 16th sector: Primary Volume Descriptor */
  476. iso[0]=1; /* Header ID */
  477. memcpy(&iso[1], "CD001", 5);
  478. iso[6]=1; /* version */
  479. for(i=8;i<72;i++) iso[i]=' ';
  480. memcpy(&iso[40], "EFI CDROM", 9); /* Volume Identifier */
  481. setinte((FIRST_PARTITION*512+fs_len+2047)/2048, &iso[80]);
  482. iso[120]=iso[123]=1; /* Volume Set Size */
  483. iso[124]=iso[127]=1; /* Volume Sequence Number */
  484. iso[129]=iso[130]=8; /* logical blocksize (0x800) */
  485. iso[156]=0x22; /* root directory recordsize */
  486. setinte(20, &iso[158]); /* root directory LBA */
  487. setinte(2048, &iso[166]); /* root directory size */
  488. iso[174]=fat_ts->tm_year; /* root directory create date */
  489. iso[175]=fat_ts->tm_mon+1;
  490. iso[176]=fat_ts->tm_mday;
  491. iso[177]=fat_ts->tm_hour;
  492. iso[178]=fat_ts->tm_min;
  493. iso[179]=fat_ts->tm_sec;
  494. iso[180]=0; /* timezone UTC (GMT) */
  495. iso[181]=2; /* root directory flags (0=hidden,1=directory) */
  496. iso[184]=1; /* root directory number */
  497. iso[188]=1; /* root directory filename length */
  498. for(i=190;i<813;i++) iso[i]=' '; /* Volume data */
  499. memcpy(&iso[318], "POSIX-UEFI <HTTPS://GITLAB.COM/BZTSRC/POSIX-UEFI>", 49);
  500. memcpy(&iso[446], "EFIDSK", 6);
  501. memcpy(&iso[574], "POSIX-UEFI", 11);
  502. for(i=702;i<813;i++) iso[i]=' '; /* file descriptors */
  503. memcpy(&iso[813], &isodate, 16); /* volume create date */
  504. memcpy(&iso[830], &isodate, 16); /* volume modify date */
  505. for(i=847;i<863;i++) iso[i]='0'; /* volume expiration date */
  506. for(i=864;i<880;i++) iso[i]='0'; /* volume shown date */
  507. iso[881]=1; /* filestructure version */
  508. for(i=883;i<1395;i++) iso[i]=' '; /* file descriptors */
  509. /* 17th sector: Boot Record Descriptor */
  510. iso[2048]=0; /* Header ID */
  511. memcpy(&iso[2049], "CD001", 5);
  512. iso[2054]=1; /* version */
  513. memcpy(&iso[2055], "EL TORITO SPECIFICATION", 23);
  514. setinte(19, &iso[2048+71]); /* Boot Catalog LBA */
  515. /* 18th sector: Volume Descritor Terminator */
  516. iso[4096]=0xFF; /* Header ID */
  517. memcpy(&iso[4097], "CD001", 5);
  518. iso[4102]=1; /* version */
  519. /* 19th sector: Boot Catalog */
  520. /* --- UEFI, Validation Entry + Initial/Default Entry + Final --- */
  521. iso[6144]=0x91; /* Header ID, Validation Entry, Final */
  522. iso[6145]=0xEF; /* Platform EFI */
  523. iso[6176]=0x88; /* Bootable, Initial/Default Entry */
  524. iso[6182]=1; /* Sector Count */
  525. setint(FIRST_PARTITION/4, &iso[6184]); /* ESP Start LBA */
  526. /* 20th sector: Root Directory */
  527. /* . */
  528. iso[8192]=0x21 + 1; /* recordsize */
  529. setinte(20, &iso[8194]); /* LBA */
  530. setinte(2048, &iso[8202]); /* size */
  531. iso[8210]=fat_ts->tm_year; /* date */
  532. iso[8211]=fat_ts->tm_mon+1;
  533. iso[8212]=fat_ts->tm_mday;
  534. iso[8213]=fat_ts->tm_hour;
  535. iso[8214]=fat_ts->tm_min;
  536. iso[8215]=fat_ts->tm_sec;
  537. iso[8216]=0; /* timezone UTC (GMT) */
  538. iso[8217]=2; /* flags (0=hidden,1=directory) */
  539. iso[8220]=1; /* serial */
  540. iso[8224]=1; /* filename length */
  541. iso[8225]=0; /* filename '.' */
  542. /* .. */
  543. iso[8226]=0x21 + 1; /* recordsize */
  544. setinte(20, &iso[8228]); /* LBA */
  545. setinte(2048, &iso[8236]); /* size */
  546. iso[8244]=fat_ts->tm_year; /* date */
  547. iso[8245]=fat_ts->tm_mon+1;
  548. iso[8246]=fat_ts->tm_mday;
  549. iso[8247]=fat_ts->tm_hour;
  550. iso[8248]=fat_ts->tm_min;
  551. iso[8249]=fat_ts->tm_sec;
  552. iso[8250]=0; /* timezone UTC (GMT) */
  553. iso[8251]=2; /* flags (0=hidden,1=directory) */
  554. iso[8254]=1; /* serial */
  555. iso[8258]=1; /* filename length */
  556. iso[8259]='\001'; /* filename '..' */
  557. fwrite(gpt, 1, FIRST_PARTITION * 512, f);
  558. fwrite(fs_base, 1, fs_len, f);
  559. free(gpt);
  560. }
  561. /**
  562. * Main function
  563. */
  564. int main(int argc, char **argv)
  565. {
  566. FILE *f;
  567. int i, part = 0, cdrom = 0;
  568. char *in = NULL, *out = NULL;
  569. /* get random GUIDs */
  570. srand(time(NULL));
  571. i = rand(); memcpy(&((uint8_t*)&dguid)[0], &i, 4);
  572. i = rand(); memcpy(&((uint8_t*)&dguid)[4], &i, 4);
  573. i = rand(); memcpy(&((uint8_t*)&dguid)[8], &i, 4);
  574. i = rand(); memcpy(&((uint8_t*)&dguid)[12], &i, 4);
  575. i = rand(); memcpy(&((uint8_t*)&pguid)[0], &i, 4);
  576. i = rand(); memcpy(&((uint8_t*)&pguid)[4], &i, 4);
  577. i = rand(); memcpy(&((uint8_t*)&pguid)[8], &i, 4);
  578. i = rand(); memcpy(&((uint8_t*)&pguid)[12], &i, 4);
  579. /* parse command line */
  580. for(i = 1; i < argc && argv[i]; i++)
  581. if(argv[i][0] == '-') {
  582. switch(argv[i][1]) {
  583. case 'p': part++; break;
  584. case 'c': cdrom++; break;
  585. case 's': fat_numclu = atoi(argv[++i]) * 2048; break;
  586. default: usage(argv[0]); break;
  587. }
  588. } else
  589. if(!in) in = argv[i]; else
  590. if(!out) out = argv[i]; else
  591. usage(argv[0]);
  592. if(!out) usage(argv[0]);
  593. /* generate file system image */
  594. remove(out);
  595. fat_open(part ? 0 : FIRST_PARTITION);
  596. parsedir(in, 0);
  597. fat_close();
  598. /* write out image */
  599. if(fs_base) {
  600. f = fopen(out, "wb");
  601. if(!f) {
  602. fprintf(stderr, "efidsk: unable to write '%s'\r\n", out);
  603. return 2;
  604. }
  605. if(!part) {
  606. if(!cdrom)
  607. writegpt(f);
  608. else
  609. writeetbc(f);
  610. } else
  611. fwrite(fs_base, 1, fs_len, f);
  612. fclose(f);
  613. free(fs_base);
  614. }
  615. return 0;
  616. }