genfv.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. genfv.c
  9. Abstract:
  10. This module implements the UEFI build tool for creating an FFS firmware
  11. volume out of one or more FFS files.
  12. Author:
  13. Evan Green 7-Mar-2014
  14. Environment:
  15. Build
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <getopt.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/stat.h>
  27. #include <unistd.h>
  28. #include "uefifw.h"
  29. #include "efiffs.h"
  30. #include "fwvol.h"
  31. //
  32. // ---------------------------------------------------------------- Definitions
  33. //
  34. #define GENFV_VERSION_MAJOR 1
  35. #define GENFV_VERSION_MINOR 0
  36. #define GENFV_USAGE \
  37. "Usage: GenFv [options] [files...]\n" \
  38. "The GenFv utility takes one or more FFS files produced by the GenFFS " \
  39. "utility and combines them into a single FFS firmware volume.\nValid " \
  40. "option are:\n" \
  41. " -a, --attributes=value -- Specify the firmware volume attributes.\n" \
  42. " -b, --block-size=size -- Specify the block size. If not supplied, 512 " \
  43. "is assumed.\n" \
  44. " -c, --block-count=count -- Specify the number of blocks in the \n" \
  45. " volume. If not supplied, the volume will be sized to fit the \n" \
  46. " files it contains.\n" \
  47. " -o, --output=File -- Specify the output image name.\n" \
  48. " -v, --verbose -- Print extra information.\n" \
  49. " --help -- Print this help and exit.\n" \
  50. " --version -- Print version information and exit.\n" \
  51. #define GENFV_OPTIONS_STRING "b:c:o:v"
  52. //
  53. // Set this flag to print additional information.
  54. //
  55. #define GENFV_OPTION_VERBOSE 0x00000001
  56. //
  57. // Set this flag if a large file was seen.
  58. //
  59. #define GENFV_OPTION_LARGE_FILE 0x00000002
  60. #define GENFV_DEFAULT_BLOCK_SIZE 512
  61. #define GENFV_DEFAULT_ATTRIBUTES \
  62. (EFI_FVB_READ_STATUS | EFI_FVB2_ALIGNMENT_8 | \
  63. EFI_FVB_MEMORY_MAPPED | EFI_FVB2_WEAK_ALIGNMENT)
  64. #define GENFV_DEFAULT_OUTPUT_NAME "fwvol"
  65. //
  66. // ------------------------------------------------------ Data Type Definitions
  67. //
  68. /*++
  69. Structure Description:
  70. This structure defines the application context information for the GenFV
  71. utility.
  72. Members:
  73. Flags - Stores a bitfield of flags. See GENFV_OPTION_* definition.
  74. OutputName - Stores the name of the output image.
  75. BlockSize - Stores the block size of the device.
  76. BlockCount - Stores the number of blocks in the device.
  77. Attributes - Stores the firmware volume attributes.
  78. FileCount - Stores the number of input files.
  79. Files - Stores the array of input files.
  80. MaxAlignment - Stores the highest alignment value seen.
  81. --*/
  82. typedef struct _GENFV_CONTEXT {
  83. UINT32 Flags;
  84. CHAR8 *OutputName;
  85. UINT32 BlockSize;
  86. UINT64 BlockCount;
  87. UINT32 Attributes;
  88. UINTN FileCount;
  89. CHAR8 **Files;
  90. UINT32 MaxAlignment;
  91. } GENFV_CONTEXT, *PGENFV_CONTEXT;
  92. //
  93. // ----------------------------------------------- Internal Function Prototypes
  94. //
  95. int
  96. GenfvCreateVolume (
  97. PGENFV_CONTEXT Context
  98. );
  99. int
  100. GenfvAddFile (
  101. PGENFV_CONTEXT Context,
  102. VOID *Buffer,
  103. UINTN BufferSize,
  104. UINTN *Offset,
  105. UINTN FileIndex
  106. );
  107. int
  108. GenfvAddPadFile (
  109. PGENFV_CONTEXT Context,
  110. VOID *Buffer,
  111. UINTN BufferSize,
  112. UINTN *Offset,
  113. UINTN NewOffset
  114. );
  115. int
  116. GenfvGetFileSize (
  117. CHAR8 *File,
  118. UINT64 *Size
  119. );
  120. UINT8
  121. GenfvCalculateChecksum8 (
  122. UINT8 *Buffer,
  123. UINTN Size
  124. );
  125. UINT16
  126. GenfvCalculateChecksum16 (
  127. UINT16 *Buffer,
  128. UINTN Size
  129. );
  130. UINT32
  131. GenfvReadAlignment (
  132. EFI_FFS_FILE_HEADER *Header
  133. );
  134. BOOLEAN
  135. GenfvCompareGuids (
  136. EFI_GUID *FirstGuid,
  137. EFI_GUID *SecondGuid
  138. );
  139. //
  140. // -------------------------------------------------------------------- Globals
  141. //
  142. struct option GenfvLongOptions[] = {
  143. {"attributes", required_argument, 0, 'a'},
  144. {"block-size", required_argument, 0, 'b'},
  145. {"block-count", required_argument, 0, 'c'},
  146. {"output", required_argument, 0, 'o'},
  147. {"verbose", no_argument, 0, 'v'},
  148. {"help", no_argument, 0, 'h'},
  149. {"version", no_argument, 0, 'V'},
  150. {NULL, 0, 0, 0},
  151. };
  152. EFI_GUID GenfvFfsVolumeTopGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
  153. EFI_GUID GenfvFfsFileSystem2Guid = EFI_FIRMWARE_FILE_SYSTEM2_GUID;
  154. EFI_GUID GenfvFfsFileSystem3Guid = EFI_FIRMWARE_FILE_SYSTEM2_GUID;
  155. //
  156. // ------------------------------------------------------------------ Functions
  157. //
  158. int
  159. main (
  160. int ArgumentCount,
  161. CHAR8 **Arguments
  162. )
  163. /*++
  164. Routine Description:
  165. This routine is the main entry point into the GenFV utility, which creates
  166. a firmware volume from FFS files.
  167. Arguments:
  168. ArgumentCount - Supplies the number of command line parameters.
  169. Arguments - Supplies the array of pointers to parameter strings.
  170. Return Value:
  171. 0 on success.
  172. Non-zero on failure.
  173. --*/
  174. {
  175. CHAR8 *AfterScan;
  176. int ArgumentIndex;
  177. GENFV_CONTEXT Context;
  178. int Option;
  179. int Status;
  180. memset(&Context, 0, sizeof(GENFV_CONTEXT));
  181. Context.Attributes = GENFV_DEFAULT_ATTRIBUTES;
  182. Context.OutputName = GENFV_DEFAULT_OUTPUT_NAME;
  183. //
  184. // Process the control arguments.
  185. //
  186. while (TRUE) {
  187. Option = getopt_long(ArgumentCount,
  188. Arguments,
  189. GENFV_OPTIONS_STRING,
  190. GenfvLongOptions,
  191. NULL);
  192. if (Option == -1) {
  193. break;
  194. }
  195. if ((Option == '?') || (Option == ':')) {
  196. Status = EINVAL;
  197. goto mainEnd;
  198. }
  199. switch (Option) {
  200. case 'a':
  201. Context.Attributes = strtol(optarg, &AfterScan, 0);
  202. if (AfterScan == optarg) {
  203. fprintf(stderr, "Error: Invalid FV attributes: %s.\n", optarg);
  204. Status = 1;
  205. goto mainEnd;
  206. }
  207. break;
  208. case 'b':
  209. Context.BlockSize = strtoul(optarg, &AfterScan, 0);
  210. if (AfterScan == optarg) {
  211. fprintf(stderr, "Error: Invalid FV block size: %s.\n", optarg);
  212. Status = EINVAL;
  213. goto mainEnd;
  214. }
  215. if ((Context.BlockSize & (Context.BlockSize - 1)) != 0) {
  216. fprintf(stderr, "Error: Block size must be a power of two.\n");
  217. Status = EINVAL;
  218. goto mainEnd;
  219. }
  220. break;
  221. case 'c':
  222. Context.BlockCount = strtoull(optarg, &AfterScan, 0);
  223. if (AfterScan == optarg) {
  224. fprintf(stderr, "Error: Invalid block count: %s.\n", optarg);
  225. Status = EINVAL;
  226. goto mainEnd;
  227. }
  228. break;
  229. case 'o':
  230. Context.OutputName = optarg;
  231. break;
  232. case 'v':
  233. Context.Flags |= GENFV_OPTION_VERBOSE;
  234. break;
  235. case 'V':
  236. printf("GenFv version %d.%d\n",
  237. GENFV_VERSION_MAJOR,
  238. GENFV_VERSION_MINOR);
  239. return 1;
  240. case 'h':
  241. printf(GENFV_USAGE);
  242. return 1;
  243. default:
  244. assert(FALSE);
  245. Status = EINVAL;
  246. goto mainEnd;
  247. }
  248. }
  249. if (Context.BlockSize == 0) {
  250. Context.BlockSize = GENFV_DEFAULT_BLOCK_SIZE;
  251. }
  252. ArgumentIndex = optind;
  253. if (ArgumentIndex > ArgumentCount) {
  254. ArgumentIndex = ArgumentCount;
  255. }
  256. Context.FileCount = ArgumentCount - ArgumentIndex;
  257. Context.Files = &(Arguments[ArgumentIndex]);
  258. Status = GenfvCreateVolume(&Context);
  259. if (Status != 0) {
  260. goto mainEnd;
  261. }
  262. mainEnd:
  263. if (Status != 0) {
  264. fprintf(stderr, "GenFV failed: %s.\n", strerror(Status));
  265. return 1;
  266. }
  267. return 0;
  268. }
  269. //
  270. // --------------------------------------------------------- Internal Functions
  271. //
  272. int
  273. GenfvCreateVolume (
  274. PGENFV_CONTEXT Context
  275. )
  276. /*++
  277. Routine Description:
  278. This routine creates a firmware volume from the given context.
  279. Arguments:
  280. Context - Supplies the application context.
  281. Return Value:
  282. 0 on success.
  283. Non-zero on failure.
  284. --*/
  285. {
  286. UINT32 AlignmentValue;
  287. VOID *Buffer;
  288. UINTN BufferSize;
  289. ssize_t BytesWritten;
  290. UINTN CurrentOffset;
  291. UINTN FileIndex;
  292. EFI_FIRMWARE_VOLUME_HEADER *Header;
  293. UINT32 MaxAlignment;
  294. FILE *Output;
  295. int Status;
  296. Buffer = NULL;
  297. Output = NULL;
  298. assert(Context->BlockSize != 0);
  299. //
  300. // If a block count was specified, use that directly. Otherwise, run
  301. // through once to compute the needed size of the buffer.
  302. //
  303. if (Context->BlockCount != 0) {
  304. CurrentOffset = Context->BlockCount * Context->BlockSize;
  305. } else {
  306. BufferSize = 0;
  307. //
  308. // At the beginning of the volume is the header, plus the block map
  309. // which consists of a single entry and a terminator. The volume header
  310. // already has a single entry in it, so just one more is needed for the
  311. // terminator.
  312. //
  313. CurrentOffset = sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
  314. sizeof(EFI_FV_BLOCK_MAP_ENTRY);
  315. CurrentOffset = ALIGN_VALUE(CurrentOffset, 8);
  316. for (FileIndex = 0; FileIndex < Context->FileCount; FileIndex += 1) {
  317. Status = GenfvAddFile(Context,
  318. Buffer,
  319. BufferSize,
  320. &CurrentOffset,
  321. FileIndex);
  322. if (Status != 0) {
  323. goto CreateVolumeEnd;
  324. }
  325. }
  326. //
  327. // Align up to the block size.
  328. //
  329. CurrentOffset = ALIGN_VALUE(CurrentOffset, Context->BlockSize);
  330. Context->BlockCount = CurrentOffset / Context->BlockSize;
  331. }
  332. BufferSize = CurrentOffset;
  333. //
  334. // Allocate the image buffer.
  335. //
  336. Buffer = malloc(BufferSize);
  337. if (Buffer == NULL) {
  338. fprintf(stderr,
  339. "Error: Failed to allocate image buffer, size 0x%lx.\n",
  340. (long)CurrentOffset);
  341. Status = ENOMEM;
  342. goto CreateVolumeEnd;
  343. }
  344. memset(Buffer, 0, BufferSize);
  345. if (BufferSize <
  346. sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY)) {
  347. fprintf(stderr, "Error: The image is way too tiny.\n");
  348. Status = ERANGE;
  349. goto CreateVolumeEnd;
  350. }
  351. Header = Buffer;
  352. if ((Context->Flags & GENFV_OPTION_LARGE_FILE) != 0) {
  353. memcpy(&(Header->FileSystemGuid),
  354. &GenfvFfsFileSystem3Guid,
  355. sizeof(EFI_GUID));
  356. } else {
  357. memcpy(&(Header->FileSystemGuid),
  358. &GenfvFfsFileSystem2Guid,
  359. sizeof(EFI_GUID));
  360. }
  361. //
  362. // Compute the maximum alignment value.
  363. //
  364. AlignmentValue = 0;
  365. MaxAlignment = Context->MaxAlignment;
  366. while (MaxAlignment > 1) {
  367. AlignmentValue += 1;
  368. MaxAlignment >>= 1;
  369. }
  370. //
  371. // Initialize the firmware volume header.
  372. //
  373. Header->Length = Context->BlockCount * Context->BlockSize;
  374. Header->Signature = EFI_FVH_SIGNATURE;
  375. Header->Attributes = Context->Attributes |
  376. ((AlignmentValue << 16) & 0xFFFF0000);
  377. Header->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
  378. sizeof(EFI_FV_BLOCK_MAP_ENTRY);
  379. Header->ExtHeaderOffset = 0;
  380. Header->Revision = EFI_FVH_REVISION;
  381. Header->BlockMap[0].BlockCount = Context->BlockCount;
  382. Header->BlockMap[0].BlockLength = Context->BlockSize;
  383. Header->BlockMap[1].BlockCount = 0;
  384. Header->BlockMap[1].BlockLength = 0;
  385. Header->Checksum = GenfvCalculateChecksum16((UINT16 *)Header,
  386. Header->HeaderLength);
  387. //
  388. // Add all the files to the image.
  389. //
  390. CurrentOffset = Header->HeaderLength;
  391. for (FileIndex = 0; FileIndex < Context->FileCount; FileIndex += 1) {
  392. Status = GenfvAddFile(Context,
  393. Buffer,
  394. BufferSize,
  395. &CurrentOffset,
  396. FileIndex);
  397. if (Status != 0) {
  398. goto CreateVolumeEnd;
  399. }
  400. }
  401. //
  402. // Create the output file and write out the image.
  403. //
  404. Output = fopen(Context->OutputName, "wb");
  405. if (Output == NULL) {
  406. Status = errno;
  407. fprintf(stderr,
  408. "Error: Failed to open output %s: %s.\n",
  409. Context->OutputName,
  410. strerror(Status));
  411. goto CreateVolumeEnd;
  412. }
  413. BytesWritten = fwrite(Buffer, 1, BufferSize, Output);
  414. if (BytesWritten != BufferSize) {
  415. Status = errno;
  416. if (Status == 0) {
  417. Status = EIO;
  418. }
  419. fprintf(stderr,
  420. "Error: Failed to write %s: %s.\n",
  421. Context->OutputName,
  422. strerror(Status));
  423. goto CreateVolumeEnd;
  424. }
  425. CreateVolumeEnd:
  426. if (Buffer != NULL) {
  427. free(Buffer);
  428. }
  429. if (Output != NULL) {
  430. fclose(Output);
  431. }
  432. return Status;
  433. }
  434. int
  435. GenfvAddFile (
  436. PGENFV_CONTEXT Context,
  437. VOID *Buffer,
  438. UINTN BufferSize,
  439. UINTN *Offset,
  440. UINTN FileIndex
  441. )
  442. /*++
  443. Routine Description:
  444. This routine adds a file to the buffer containing the working firmware
  445. volume image.
  446. Arguments:
  447. Context - Supplies the application context.
  448. Buffer - Supplies an optional pointer to the buffer to add. If NULL, only
  449. the size will be computed.
  450. BufferSize - Supplies the total size of the supplied buffer.
  451. Offset - Supplies a pointer that on input contains the current offset into
  452. the buffer. On output this will be advanced past the portion used by
  453. this file, even if no bufer was supplied.
  454. FileIndex - Supplies the index of the file to add in the context's file
  455. array.
  456. Return Value:
  457. 0 on success.
  458. Non-zero on failure.
  459. --*/
  460. {
  461. UINTN Alignment;
  462. ssize_t BytesRead;
  463. FILE *File;
  464. EFI_FFS_FILE_HEADER *FileHeader;
  465. CHAR8 *FileName;
  466. UINT64 FileSize;
  467. EFI_FFS_FILE_HEADER2 Header;
  468. UINTN HeaderSize;
  469. UINT8 HeaderSum;
  470. UINTN PaddedOffset;
  471. int Status;
  472. UINTN TopFileEnd;
  473. assert(FileIndex < Context->FileCount);
  474. FileName = Context->Files[FileIndex];
  475. File = fopen(FileName, "rb");
  476. if (File == NULL) {
  477. fprintf(stderr,
  478. "Error: Failed to open %s: %s.\n",
  479. FileName,
  480. strerror(errno));
  481. Status = errno;
  482. goto AddFileEnd;
  483. }
  484. Status = GenfvGetFileSize(FileName, &FileSize);
  485. if (Status != 0) {
  486. goto AddFileEnd;
  487. }
  488. HeaderSize = sizeof(EFI_FFS_FILE_HEADER);
  489. if (FileSize > MAX_FFS_SIZE) {
  490. HeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
  491. Context->Flags |= GENFV_OPTION_LARGE_FILE;
  492. }
  493. BytesRead = fread(&Header, 1, HeaderSize, File);
  494. if (BytesRead < HeaderSize) {
  495. fprintf(stderr,
  496. "Error: Only read %ld bytes of %s.\n",
  497. (long)BytesRead,
  498. FileName);
  499. Status = EINVAL;
  500. goto AddFileEnd;
  501. }
  502. //
  503. // Verify the FFS file checksum in case a bozo tried to slip in a non-FFS
  504. // file.
  505. //
  506. Header.State = 0;
  507. HeaderSum = Header.IntegrityCheck.Checksum.Header;
  508. Header.IntegrityCheck.Checksum16 = 0;
  509. if (HeaderSum != GenfvCalculateChecksum8((UINT8 *)&Header, HeaderSize)) {
  510. fprintf(stderr,
  511. "Error: %s does not appear to be a valid FFS file. "
  512. "Did you use GenFFS to create it?\n", FileName);
  513. Status = EINVAL;
  514. goto AddFileEnd;
  515. }
  516. //
  517. // Get the alignment and add a pad file if needed.
  518. //
  519. Alignment = GenfvReadAlignment((EFI_FFS_FILE_HEADER *)&Header);
  520. if (Alignment > Context->MaxAlignment) {
  521. Context->MaxAlignment = Alignment;
  522. }
  523. //
  524. // Things get trickier for a volume top file.
  525. //
  526. if (GenfvCompareGuids(&(Header.Name), &GenfvFfsVolumeTopGuid) != FALSE) {
  527. if (FileIndex != Context->FileCount - 1) {
  528. fprintf(stderr,
  529. "Error: A volume top file (%s) must be the last file.\n",
  530. FileName);
  531. Status = EINVAL;
  532. goto AddFileEnd;
  533. }
  534. //
  535. // The volume top file must align propertly. If there's a block count
  536. // set, then the file start must align.
  537. //
  538. if (Context->BlockCount != 0) {
  539. PaddedOffset = (Context->BlockCount * Context->BlockSize) -
  540. FileSize;
  541. if ((PaddedOffset % Alignment) != 0) {
  542. fprintf(stderr,
  543. "Error: Volume top file is size 0x%llx, which "
  544. "conflicts with its required alignment of 0x%x.\n",
  545. FileSize,
  546. (UINT32)Alignment);
  547. Status = EINVAL;
  548. goto AddFileEnd;
  549. }
  550. //
  551. // If there's no block count set, align this file out to its desired
  552. // alignment, then verify that the file ends on a block boundary.
  553. //
  554. } else {
  555. PaddedOffset = *Offset;
  556. if (((*Offset + HeaderSize) % Alignment) != 0) {
  557. PaddedOffset = (*Offset + HeaderSize +
  558. sizeof(EFI_FFS_FILE_HEADER) + Alignment) &
  559. ~(Alignment - 1);
  560. PaddedOffset -= HeaderSize;
  561. }
  562. TopFileEnd = PaddedOffset + HeaderSize + FileSize;
  563. if ((TopFileEnd % Context->BlockSize) != 0) {
  564. fprintf(stderr,
  565. "Error: Volume top file is size 0x%llx, which "
  566. "conflicts with its required alignment of 0x%x.\n",
  567. FileSize,
  568. (UINT32)Alignment);
  569. Status = EINVAL;
  570. goto AddFileEnd;
  571. }
  572. }
  573. //
  574. // Create a pad file if needed.
  575. //
  576. if (PaddedOffset != *Offset) {
  577. Status = GenfvAddPadFile(Context,
  578. Buffer,
  579. BufferSize,
  580. Offset,
  581. PaddedOffset);
  582. if (Status != 0) {
  583. goto AddFileEnd;
  584. }
  585. }
  586. //
  587. // This is not a volume top file. Pad out to its required alignment
  588. // if necessary.
  589. //
  590. } else {
  591. if (((*Offset + HeaderSize) % Alignment) != 0) {
  592. PaddedOffset = (*Offset + HeaderSize + sizeof(EFI_FFS_FILE_HEADER) +
  593. Alignment) &
  594. ~(Alignment - 1);
  595. PaddedOffset -= HeaderSize;
  596. Status = GenfvAddPadFile(Context,
  597. Buffer,
  598. BufferSize,
  599. Offset,
  600. PaddedOffset);
  601. if (Status != 0) {
  602. goto AddFileEnd;
  603. }
  604. }
  605. }
  606. //
  607. // Read the file in.
  608. //
  609. if (BufferSize != 0) {
  610. if ((Context->Flags & GENFV_OPTION_VERBOSE) != 0) {
  611. printf("Adding file %s at offset %lx, size %llx\n",
  612. FileName,
  613. (long)*Offset,
  614. FileSize);
  615. }
  616. fseek(File, 0, SEEK_SET);
  617. if (*Offset + FileSize > BufferSize) {
  618. Status = ERANGE;
  619. goto AddFileEnd;
  620. }
  621. BytesRead = fread(Buffer + *Offset, 1, FileSize, File);
  622. if (BytesRead != FileSize) {
  623. fprintf(stderr, "Error: Failed to read from %s.\n", FileName);
  624. Status = EIO;
  625. goto AddFileEnd;
  626. }
  627. //
  628. // Flip the state bits if the erase polarity is one.
  629. //
  630. FileHeader = (EFI_FFS_FILE_HEADER *)(Buffer + *Offset);
  631. if ((Context->Attributes & EFI_FVB_ERASE_POLARITY) != 0) {
  632. FileHeader->State = ~(FileHeader->State);
  633. }
  634. }
  635. *Offset += FileSize;
  636. //
  637. // Align up to 8-bytes.
  638. //
  639. *Offset = ALIGN_VALUE(*Offset, 8);
  640. if ((BufferSize != 0) && (*Offset > BufferSize)) {
  641. Status = ERANGE;
  642. goto AddFileEnd;
  643. }
  644. Status = 0;
  645. AddFileEnd:
  646. if (File != NULL) {
  647. fclose(File);
  648. }
  649. return Status;
  650. }
  651. int
  652. GenfvAddPadFile (
  653. PGENFV_CONTEXT Context,
  654. VOID *Buffer,
  655. UINTN BufferSize,
  656. UINTN *Offset,
  657. UINTN NewOffset
  658. )
  659. /*++
  660. Routine Description:
  661. This routine adds a pad file to the image.
  662. Arguments:
  663. Context - Supplies the application context.
  664. Buffer - Supplies an optional pointer to the buffer to add. If NULL, only
  665. the size will be computed.
  666. BufferSize - Supplies the total size of the supplied buffer.
  667. Offset - Supplies a pointer that on input contains the current offset into
  668. the buffer. On output this will be advanced past the portion used by
  669. this file, even if no bufer was supplied.
  670. NewOffset - Supplies the offset the pad file should extend to.
  671. Return Value:
  672. 0 on success.
  673. Non-zero on failure.
  674. --*/
  675. {
  676. UINTN HeaderSize;
  677. EFI_FFS_FILE_HEADER2 *PadFile;
  678. UINTN PadFileSize;
  679. if (BufferSize != 0) {
  680. if (NewOffset > BufferSize) {
  681. return ERANGE;
  682. }
  683. memset(Buffer + *Offset, 0, NewOffset - *Offset);
  684. PadFile = Buffer + *Offset;
  685. PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
  686. PadFile->Attributes = 0;
  687. PadFileSize = (NewOffset - *Offset) - sizeof(EFI_FFS_FILE_HEADER);
  688. if ((Context->Flags & GENFV_OPTION_VERBOSE) != 0) {
  689. printf("Creating pad file at 0x%lx, Size %lx to new offset "
  690. "0x%lx.\n",
  691. *Offset,
  692. PadFileSize,
  693. NewOffset);
  694. }
  695. if (PadFileSize > MAX_FFS_SIZE) {
  696. HeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
  697. PadFileSize = (NewOffset - *Offset) - HeaderSize;
  698. PadFile->ExtendedSize = PadFileSize;
  699. Context->Flags |= GENFV_OPTION_LARGE_FILE;
  700. } else {
  701. HeaderSize = sizeof(EFI_FFS_FILE_HEADER);
  702. PadFile->Size[0] = (UINT8)(PadFileSize & 0xFF);
  703. PadFile->Size[1] = (UINT8)((PadFileSize & 0xFF00) >> 8);
  704. PadFile->Size[2] = (UINT8)((PadFileSize & 0xFF0000) >> 16);
  705. }
  706. PadFile->IntegrityCheck.Checksum.Header =
  707. GenfvCalculateChecksum8((UINT8 *)PadFile, HeaderSize);
  708. PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
  709. PadFile->State = EFI_FILE_HEADER_CONSTRUCTION |
  710. EFI_FILE_HEADER_VALID |
  711. EFI_FILE_DATA_VALID;
  712. if ((Context->Attributes & EFI_FVB_ERASE_POLARITY) != 0) {
  713. PadFile->State = ~(PadFile->State);
  714. }
  715. }
  716. *Offset = NewOffset;
  717. return 0;
  718. }
  719. int
  720. GenfvGetFileSize (
  721. CHAR8 *File,
  722. UINT64 *Size
  723. )
  724. /*++
  725. Routine Description:
  726. This routine returns the size of the given file.
  727. Arguments:
  728. File - Supplies a pointer to a string containing the path to the file to
  729. get the size of.
  730. Size - Supplies a pointer where the size of the file will be returned on
  731. success.
  732. Return Value:
  733. 0 on success.
  734. Non-zero on failure.
  735. --*/
  736. {
  737. int Result;
  738. struct stat Stat;
  739. Result = stat(File, &Stat);
  740. if (Result != 0) {
  741. return Result;
  742. }
  743. *Size = Stat.st_size;
  744. return Result;
  745. }
  746. UINT8
  747. GenfvCalculateChecksum8 (
  748. UINT8 *Buffer,
  749. UINTN Size
  750. )
  751. /*++
  752. Routine Description:
  753. This routine calculates the checksum of the bytes in the given buffer.
  754. Arguments:
  755. Buffer - Supplies a pointer to a buffer containing byte data.
  756. Size - Supplies the size of the buffer.
  757. Return Value:
  758. Returns the 8-bit checksum of each byte in the buffer.
  759. --*/
  760. {
  761. UINTN Index;
  762. UINT8 Sum;
  763. Sum = 0;
  764. for (Index = 0; Index < Size; Index += 1) {
  765. Sum = (UINT8)(Sum + Buffer[Index]);
  766. }
  767. return 0x100 - Sum;
  768. }
  769. UINT16
  770. GenfvCalculateChecksum16 (
  771. UINT16 *Buffer,
  772. UINTN Size
  773. )
  774. /*++
  775. Routine Description:
  776. This routine calculates the 16-bit checksum of the bytes in the given
  777. buffer.
  778. Arguments:
  779. Buffer - Supplies a pointer to a buffer containing byte data.
  780. Size - Supplies the size of the buffer, in bytes.
  781. Return Value:
  782. Returns the 16-bit checksum of the buffer words.
  783. --*/
  784. {
  785. UINTN Index;
  786. UINT16 Sum;
  787. Size = Size / sizeof(UINT16);
  788. Sum = 0;
  789. for (Index = 0; Index < Size; Index += 1) {
  790. Sum = (UINT16)(Sum + Buffer[Index]);
  791. }
  792. return 0x10000 - Sum;
  793. }
  794. UINT32
  795. GenfvReadAlignment (
  796. EFI_FFS_FILE_HEADER *Header
  797. )
  798. /*++
  799. Routine Description:
  800. This routine returns the alignment requirement from a FFS file header.
  801. Arguments:
  802. Header - Supplies a pointer to the header.
  803. Return Value:
  804. Returns the alignment, in bytes.
  805. --*/
  806. {
  807. switch ((Header->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) {
  808. //
  809. // 1 byte alignment.
  810. //
  811. case 0:
  812. return 1 << 0;
  813. //
  814. // 16 byte alignment.
  815. //
  816. case 1:
  817. return 1 << 4;
  818. //
  819. // 128 byte alignment.
  820. //
  821. case 2:
  822. return 1 << 7;
  823. //
  824. // 512 byte alignment.
  825. //
  826. case 3:
  827. return 1 << 9;
  828. //
  829. // 1K byte alignment.
  830. //
  831. case 4:
  832. return 1 << 10;
  833. //
  834. // 4K byte alignment.
  835. //
  836. case 5:
  837. return 1 << 12;
  838. //
  839. // 32K byte alignment.
  840. //
  841. case 6:
  842. return 1 << 15;
  843. default:
  844. break;
  845. }
  846. assert(FALSE);
  847. return 0;
  848. }
  849. BOOLEAN
  850. GenfvCompareGuids (
  851. EFI_GUID *FirstGuid,
  852. EFI_GUID *SecondGuid
  853. )
  854. /*++
  855. Routine Description:
  856. This routine compares two GUIDs.
  857. Arguments:
  858. FirstGuid - Supplies a pointer to the first GUID.
  859. SecondGuid - Supplies a pointer to the second GUID.
  860. Return Value:
  861. TRUE if the GUIDs are equal.
  862. FALSE if the GUIDs are different.
  863. --*/
  864. {
  865. UINT32 *FirstPointer;
  866. UINT32 *SecondPointer;
  867. //
  868. // Compare GUIDs 32 bits at a time.
  869. //
  870. FirstPointer = (UINT32 *)FirstGuid;
  871. SecondPointer = (UINT32 *)SecondGuid;
  872. if ((FirstPointer[0] == SecondPointer[0]) &&
  873. (FirstPointer[1] == SecondPointer[1]) &&
  874. (FirstPointer[2] == SecondPointer[2]) &&
  875. (FirstPointer[3] == SecondPointer[3])) {
  876. return TRUE;
  877. }
  878. return FALSE;
  879. }