genfv.c 26 KB

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