mkuboot.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. mkuboot.c
  5. Abstract:
  6. This module implements the utility to create U-Boot images.
  7. Author:
  8. Chris Stevens 2-Jul-2015
  9. Environment:
  10. User
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #define RTL_API
  16. #define KERNEL_API
  17. #include <minoca/lib/types.h>
  18. #include <minoca/lib/status.h>
  19. #include <minoca/lib/rtl.h>
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <getopt.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <time.h>
  26. #include <string.h>
  27. #include <fcntl.h>
  28. #include "uefifw.h"
  29. #include "uboot.h"
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. #define MKUBOOT_VERSION_MAJOR 1
  34. #define MKUBOOT_VERSION_MINOR 0
  35. #define MKUBOOT_USAGE \
  36. "Usage: mkuboot [-c] [-a arch] [-f format] [-e entry_point] " \
  37. "[-l load_address] -o image file\n" \
  38. "Mkuboot creates a bootable U-Boot image based off of the given file.\n" \
  39. "Options are:\n" \
  40. " -a, --arch=arch -- Specify the architecture of the image file. \n" \
  41. " Valid values are arm and x86.\n" \
  42. " -c, --create -- Create the output even if it already exists.\n" \
  43. " -e, --entry=entry_point -- Specify the hexidecimal value of the data\n" \
  44. " file's entry point.\n" \
  45. " -f, --format=format -- Specify the output format. Valid values \n" \
  46. " are fit and legacy. Legacy is the default.\n" \
  47. " -l, --load=address -- Specify the hexidecimal load address for \n" \
  48. " data file.\n" \
  49. " -o, --output=image -- Specify the output image name.\n" \
  50. " -v, --verbose -- Output more information.\n" \
  51. " file -- Specify the image to use for creating the U-Boot image.\n" \
  52. " --help -- Print this help text and exit.\n" \
  53. " --version -- Print the application version information and exit.\n\n" \
  54. #define MKUBOOT_OPTIONS_STRING "a:ce:f:l:o:vhV"
  55. #define MKUBOOT_OPTION_VERBOSE 0x00000001
  56. #define MKUBOOT_OPTION_CREATE_ALWAYS 0x00000002
  57. #define MKUBOOT_ARCHITECTURE_ARM 1
  58. #define MKUBOOT_ARCHITECTURE_X86 2
  59. //
  60. // Define the default description to use for the FIT image.
  61. //
  62. #define MKUBOOT_DEFAULT_FIT_DESCRIPTION "Minoca U-Boot Firmware Image."
  63. #define MKUBOOT_DEFAULT_FIT_DEVICE_TREE_DESCRIPTION "Empty Device Tree."
  64. //
  65. // Define the default kernel, device tree, and configuration names.
  66. //
  67. #define MKUBOOT_DEFAULT_FIT_KERNEL_NAME "kernel@1"
  68. #define MKUBOOT_DEFAULT_FIT_DEVICE_TREE_NAME "fdt@1"
  69. #define MKUBOOT_DEFAULT_FIT_CONFIGURATION_NAME "config@1"
  70. //
  71. // Define the alignment for a U-Boot fit image. Empirically, it is smaller than
  72. // 4K, but be on the safe side.
  73. //
  74. #define MKUBOOT_FIT_ALIGNMENT 4096
  75. //
  76. // ------------------------------------------------------ Data Type Definitions
  77. //
  78. typedef enum _MKUBOOT_PROPERTY {
  79. MkUBootPropertyDescription,
  80. MkUBootPropertyTimestamp,
  81. MkUBootPropertyData,
  82. MkUBootPropertyType,
  83. MkUBootPropertyArchitecture,
  84. MkUBootPropertyOs,
  85. MkUBootPropertyCompression,
  86. MkUBootPropertyLoadAddress,
  87. MkUBootPropertyEntryPoint,
  88. MkUBootPropertyDefault,
  89. MkUBootPropertyKernel,
  90. MkUBootPropertyCount
  91. } MKUBOOT_PROPERTY, *PMKUBOOT_PROPERTY;
  92. typedef enum _MKUBOOT_FORMAT {
  93. MkUBootFormatInvalid,
  94. MkUBootFormatLegacy,
  95. MkUBootFormatFit
  96. } MKUBOOT_FORMAT, *PMKUBOOT_FORMAT;
  97. /*++
  98. Structure Description:
  99. This structure defines the context used by mkuboot while creating an image.
  100. Members:
  101. InputFileName - Stores a null-terminated path to the input file.
  102. OutputFileName - Store a null-terminated path to the output file.
  103. InputFileBuffer - Stores a pointer to the input files contents.
  104. InputFileSize - Stores the size of the input file, in bytes.
  105. OutputFile - Stores a pointer to the opened output file stream.
  106. Options - Stores a bitmask of options. See MKUBOOT_OPTION_* for definitions.
  107. Architecture - Stores the architecture of the input file.
  108. LoadAddress - Stores the data load address to store in the U-Boot image.
  109. EntryPoint - Stores the data entry point to store in the U-Boot image.
  110. --*/
  111. typedef struct _MKUBOOT_CONTEXT {
  112. CHAR8 *InputFileName;
  113. CHAR8 *OutputFileName;
  114. void *InputFileBuffer;
  115. UINT32 InputFileSize;
  116. FILE *OutputFile;
  117. UINT32 Options;
  118. UINT32 Architecture;
  119. UINT32 LoadAddress;
  120. UINT32 EntryPoint;
  121. } MKUBOOT_CONTEXT, *PMKUBOOT_CONTEXT;
  122. /*++
  123. Structure Description:
  124. This structure defines the set of information needed to convert a U-Boot
  125. property type to it's name and string name offset.
  126. Members:
  127. Property - Stores the property type value.
  128. Name - Stores a null-terminated string representing the name of the
  129. property.
  130. Offset - Stores the property's offset into the dictionary.
  131. --*/
  132. typedef struct _MKUBOOT_PROPERTY_ENTRY {
  133. MKUBOOT_PROPERTY Property;
  134. CHAR8 *Name;
  135. UINT32 Offset;
  136. } MKUBOOT_PROPERTY_ENTRY, *PMKUBOOT_PROPERTY_ENTRY;
  137. //
  138. // ----------------------------------------------- Internal Function Prototypes
  139. //
  140. int
  141. MupOpenFiles (
  142. PMKUBOOT_CONTEXT Context
  143. );
  144. void
  145. MupCloseFiles (
  146. PMKUBOOT_CONTEXT Context
  147. );
  148. int
  149. MupCreateLegacyImage (
  150. PMKUBOOT_CONTEXT Context
  151. );
  152. int
  153. MupCreateFitImage (
  154. PMKUBOOT_CONTEXT Context
  155. );
  156. int
  157. MupCreateStringsDictionary (
  158. void **Strings,
  159. UINT32 *StringsSize
  160. );
  161. void
  162. MupDestroyStringsDictionary (
  163. void *Strings
  164. );
  165. int
  166. MupWriteFitStructures (
  167. PMKUBOOT_CONTEXT Context
  168. );
  169. int
  170. MupWriteNodeStart (
  171. PMKUBOOT_CONTEXT Context,
  172. CHAR8 *Name
  173. );
  174. int
  175. MupWriteProperty (
  176. PMKUBOOT_CONTEXT Context,
  177. MKUBOOT_PROPERTY Property,
  178. void *Data,
  179. UINT32 DataSize
  180. );
  181. //
  182. // -------------------------------------------------------------------- Globals
  183. //
  184. struct option MkUBootLongOptions[] = {
  185. {"address", required_argument, 0, 'a'},
  186. {"create", no_argument, 0, 'c'},
  187. {"entry", required_argument, 0, 'e'},
  188. {"format", required_argument, 0, 'f'},
  189. {"output", required_argument, 0, 'o'},
  190. {"help", no_argument, 0, 'h'},
  191. {"version", no_argument, 0, 'V'},
  192. {"verbose", no_argument, 0, 'v'},
  193. {NULL, 0, 0, 0},
  194. };
  195. //
  196. // Store the set of property entries whose names need to be written to the
  197. // strings dictionary.
  198. //
  199. MKUBOOT_PROPERTY_ENTRY MkUBootProperties[MkUBootPropertyCount] = {
  200. {MkUBootPropertyDescription, UBOOT_FIT_PROPERTY_DESCRIPTION, 0},
  201. {MkUBootPropertyTimestamp, UBOOT_FIT_PROPERTY_TIMESTAMP, 0},
  202. {MkUBootPropertyData, UBOOT_FIT_PROPERTY_DATA, 0},
  203. {MkUBootPropertyType, UBOOT_FIT_PROPERTY_TYPE, 0},
  204. {MkUBootPropertyArchitecture, UBOOT_FIT_PROPERTY_ARCHITECTURE, 0},
  205. {MkUBootPropertyOs, UBOOT_FIT_PROPERTY_OS, 0},
  206. {MkUBootPropertyCompression, UBOOT_FIT_PROPERTY_COMPRESSION, 0},
  207. {MkUBootPropertyLoadAddress, UBOOT_FIT_PROPERTY_LOAD_ADDRESS, 0},
  208. {MkUBootPropertyEntryPoint, UBOOT_FIT_PROPERTY_ENTRY_POINT, 0},
  209. {MkUBootPropertyDefault, UBOOT_FIT_PROPERTY_DEFAULT, 0},
  210. {MkUBootPropertyKernel, UBOOT_FIT_PROPERTY_KERNEL, 0},
  211. };
  212. //
  213. // ------------------------------------------------------------------ Functions
  214. //
  215. int
  216. main (
  217. int ArgumentCount,
  218. CHAR8 **Arguments
  219. )
  220. /*++
  221. Routine Description:
  222. This routine is the main entry point for the program. It collects the
  223. options passed to it, and creates the output UBoot image.
  224. Arguments:
  225. ArgumentCount - Supplies the number of command line arguments the program
  226. was invoked with.
  227. Arguments - Supplies a tokenized array of command line arguments.
  228. Return Value:
  229. Returns an integer exit code. 0 for success, nonzero otherwise.
  230. --*/
  231. {
  232. CHAR8 *AfterScan;
  233. CHAR8 *Argument;
  234. int ArgumentIndex;
  235. MKUBOOT_CONTEXT Context;
  236. MKUBOOT_FORMAT Format;
  237. int Option;
  238. int Result;
  239. srand(time(NULL));
  240. RtlZeroMemory(&Context, sizeof(MKUBOOT_CONTEXT));
  241. Format = MkUBootFormatLegacy;
  242. Context.Architecture = MKUBOOT_ARCHITECTURE_X86;
  243. //
  244. // Process the command line options
  245. //
  246. while (TRUE) {
  247. Option = getopt_long(ArgumentCount,
  248. Arguments,
  249. MKUBOOT_OPTIONS_STRING,
  250. MkUBootLongOptions,
  251. NULL);
  252. if (Option == -1) {
  253. break;
  254. }
  255. if ((Option == '?') || (Option == ':')) {
  256. Result = 1;
  257. goto MainEnd;
  258. }
  259. switch (Option) {
  260. case 'a':
  261. Argument = optarg;
  262. if (strcasecmp(Argument, "arm") == 0) {
  263. Context.Architecture = MKUBOOT_ARCHITECTURE_ARM;
  264. } else if (strcasecmp(Argument, "x86") == 0) {
  265. Context.Architecture = MKUBOOT_ARCHITECTURE_X86;
  266. } else {
  267. fprintf(stderr,
  268. "mkuboot: Invalid architecture '%s'.\n",
  269. Argument);
  270. Result = 1;
  271. goto MainEnd;
  272. }
  273. break;
  274. case 'c':
  275. Context.Options |= MKUBOOT_OPTION_CREATE_ALWAYS;
  276. break;
  277. case 'e':
  278. Argument = optarg;
  279. errno = 0;
  280. Context.EntryPoint = (UINT32)strtoul(Argument, &AfterScan, 16);
  281. if ((Context.EntryPoint == 0) && (errno != 0)) {
  282. fprintf(stderr, "mkuboot: Invalid entry point '%s'.\n",
  283. Argument);
  284. Result = 1;
  285. goto MainEnd;
  286. }
  287. break;
  288. case 'f':
  289. Argument = optarg;
  290. if (strcasecmp(Argument, "legacy") == 0) {
  291. Format = MkUBootFormatLegacy;
  292. } else if (strcasecmp(Argument, "fit") == 0) {
  293. Format = MkUBootFormatFit;
  294. } else {
  295. fprintf(stderr,
  296. "mkuboot: Invalid disk format '%s'.\n",
  297. Argument);
  298. Result = 1;
  299. goto MainEnd;
  300. }
  301. break;
  302. case 'l':
  303. Argument = optarg;
  304. errno = 0;
  305. Context.LoadAddress = (UINT32)strtoul(Argument, &AfterScan, 16);
  306. if ((Context.LoadAddress == 0) && (errno != 0)) {
  307. fprintf(stderr, "mkuboot: Invalid load address '%s'.\n",
  308. Argument);
  309. Result = 1;
  310. goto MainEnd;
  311. }
  312. break;
  313. case 'o':
  314. Context.OutputFileName = optarg;
  315. break;
  316. case 'v':
  317. Context.Options |= MKUBOOT_OPTION_VERBOSE;
  318. break;
  319. case 'V':
  320. printf("mkuboot version %d.%d.\n",
  321. MKUBOOT_VERSION_MAJOR,
  322. MKUBOOT_VERSION_MINOR);
  323. return 1;
  324. case 'h':
  325. printf(MKUBOOT_USAGE);
  326. return 1;
  327. default:
  328. assert(FALSE);
  329. Result = 1;
  330. goto MainEnd;
  331. }
  332. }
  333. //
  334. // Make sure an output image file was specified.
  335. //
  336. if (Context.OutputFileName == NULL) {
  337. fprintf(stderr,
  338. "mkuboot: An output image must be specified with -o.\n");
  339. Result = 1;
  340. goto MainEnd;
  341. }
  342. //
  343. // The last remaining argument should be the file to convert into the
  344. // U-Boot image.
  345. //
  346. ArgumentIndex = optind;
  347. if ((ArgumentIndex > ArgumentCount) ||
  348. (ArgumentCount - ArgumentIndex) != 1) {
  349. fprintf(stderr, "mkuboot: An input file must be specified.\n");
  350. Result = 1;
  351. goto MainEnd;
  352. }
  353. Context.InputFileName = Arguments[ArgumentIndex];
  354. //
  355. // Open the input and output files now stored in the context.
  356. //
  357. Result = MupOpenFiles(&Context);
  358. if (Result != 0) {
  359. goto MainEnd;
  360. }
  361. //
  362. // Create the U-Boot image based on the requested format type.
  363. //
  364. switch (Format) {
  365. case MkUBootFormatLegacy:
  366. Result = MupCreateLegacyImage(&Context);
  367. if (Result != 0) {
  368. fprintf(stderr, "mkuboot: Failed to create image.\n");
  369. Result = 1;
  370. goto MainEnd;
  371. }
  372. break;
  373. case MkUBootFormatFit:
  374. Result = MupCreateFitImage(&Context);
  375. if (Result != 0) {
  376. fprintf(stderr, "mkuboot: Failed to create image.\n");
  377. Result = 1;
  378. goto MainEnd;
  379. }
  380. break;
  381. default:
  382. fprintf(stderr, "Unknown image format.\n");
  383. Result = 1;
  384. goto MainEnd;
  385. }
  386. Result = 0;
  387. MainEnd:
  388. MupCloseFiles(&Context);
  389. return Result;
  390. }
  391. //
  392. // --------------------------------------------------------- Internal Functions
  393. //
  394. int
  395. MupOpenFiles (
  396. PMKUBOOT_CONTEXT Context
  397. )
  398. /*++
  399. Routine Description:
  400. This routine opens the input and output files in the given context.
  401. Arguments:
  402. Context - Supplies a pointer to the make U-Boot context.
  403. Return Value:
  404. Returns 0 on success. Non-zero on failure.
  405. --*/
  406. {
  407. size_t BytesRead;
  408. FILE *InputFile;
  409. UINT8 *InputFileBuffer;
  410. UINT32 InputFileSize;
  411. CHAR8 *OpenMode;
  412. FILE *OutputFile;
  413. int Result;
  414. InputFile = NULL;
  415. InputFileBuffer = NULL;
  416. OutputFile = NULL;
  417. Result = 0;
  418. //
  419. // Open the input file to get its size.
  420. //
  421. InputFile = fopen(Context->InputFileName, "rb");
  422. if (InputFile == NULL) {
  423. fprintf(stderr,
  424. "mkuboot: Unable to open input file \"%s\" for read: %s.\n",
  425. Context->InputFileName,
  426. strerror(errno));
  427. Result = 1;
  428. goto OpenFilesEnd;
  429. }
  430. //
  431. // Get the size of the input file image and allocate a buffer to hold it.
  432. //
  433. fseek(InputFile, 0, SEEK_END);
  434. InputFileSize = (UINT32)ftell(InputFile);
  435. fseek(InputFile, 0, SEEK_SET);
  436. InputFileBuffer = malloc(InputFileSize);
  437. if (InputFileBuffer == NULL) {
  438. fprintf(stderr,
  439. "mkuboot: Failed to allocate memory for input file \"%s\".",
  440. Context->InputFileName);
  441. Result = 1;
  442. goto OpenFilesEnd;
  443. }
  444. //
  445. // Read the input file.
  446. //
  447. BytesRead = fread(InputFileBuffer, 1, InputFileSize, InputFile);
  448. if (BytesRead != InputFileSize) {
  449. fprintf(stderr,
  450. "mkuboot: Unable to read \"%s\". Read %ld bytes, expected "
  451. "%ld.\n",
  452. Context->InputFileName,
  453. BytesRead,
  454. InputFileSize);
  455. Result = 1;
  456. goto OpenFilesEnd;
  457. }
  458. //
  459. // Open the output file for write.
  460. //
  461. OpenMode = "rb+";
  462. if ((Context->Options & MKUBOOT_OPTION_CREATE_ALWAYS) != 0) {
  463. OpenMode = "wb+";
  464. }
  465. OutputFile = fopen(Context->OutputFileName, OpenMode);
  466. if (OutputFile == NULL) {
  467. fprintf(stderr,
  468. "mkuboot: Unable to open output file \"%s\" for write: %s.\n",
  469. Context->OutputFileName,
  470. strerror(errno));
  471. Result = 1;
  472. goto OpenFilesEnd;
  473. }
  474. //
  475. // Update the context with the collected data.
  476. //
  477. Context->InputFileBuffer = InputFileBuffer;
  478. Context->InputFileSize = InputFileSize;
  479. Context->OutputFile = OutputFile;
  480. OpenFilesEnd:
  481. if (Result != 0) {
  482. if (InputFileBuffer != NULL) {
  483. free(InputFileBuffer);
  484. }
  485. if (OutputFile != NULL) {
  486. fclose(OutputFile);
  487. }
  488. }
  489. if (InputFile != NULL) {
  490. fclose(InputFile);
  491. }
  492. return Result;
  493. }
  494. void
  495. MupCloseFiles (
  496. PMKUBOOT_CONTEXT Context
  497. )
  498. /*++
  499. Routine Description:
  500. This routine closes the input and output files in the given context.
  501. Arguments:
  502. Context - Supplies a pointer to the make U-Boot context.
  503. Return Value:
  504. None.
  505. --*/
  506. {
  507. if (Context->OutputFile != NULL) {
  508. fclose(Context->OutputFile);
  509. Context->OutputFile = NULL;
  510. }
  511. if (Context->InputFileBuffer != NULL) {
  512. free(Context->InputFileBuffer);
  513. Context->InputFileBuffer = NULL;
  514. }
  515. Context->InputFileSize = 0;
  516. return;
  517. }
  518. int
  519. MupCreateLegacyImage (
  520. PMKUBOOT_CONTEXT Context
  521. )
  522. /*++
  523. Routine Description:
  524. This routine creates a legacy U-Boot image out of the given input file and
  525. writes it to the output file.
  526. Arguments:
  527. Context - Supplies a pointer to the U-Boot image creation context.
  528. Return Value:
  529. Returns 0 on success. Non-zero on failure.
  530. --*/
  531. {
  532. size_t BytesWritten;
  533. int Result;
  534. UBOOT_HEADER UBootHeader;
  535. Result = 0;
  536. //
  537. // Fill out the U-Boot header.
  538. //
  539. RtlZeroMemory(&UBootHeader, sizeof(UBOOT_HEADER));
  540. UBootHeader.Magic = RtlByteSwapUlong(UBOOT_MAGIC);
  541. UBootHeader.CreationTimestamp = RtlByteSwapUlong(time(NULL));
  542. UBootHeader.DataSize = RtlByteSwapUlong(Context->InputFileSize);
  543. UBootHeader.DataLoadAddress = RtlByteSwapUlong(Context->LoadAddress);
  544. UBootHeader.EntryPoint = RtlByteSwapUlong(Context->EntryPoint);
  545. UBootHeader.DataCrc32 = RtlComputeCrc32(0,
  546. Context->InputFileBuffer,
  547. Context->InputFileSize);
  548. UBootHeader.DataCrc32 = RtlByteSwapUlong(UBootHeader.DataCrc32);
  549. UBootHeader.OperatingSystem = UBOOT_OS_LINUX;
  550. UBootHeader.Architecture = UBOOT_ARCHITECTURE_ARM;
  551. UBootHeader.ImageType = UBOOT_IMAGE_KERNEL;
  552. UBootHeader.CompressionType = UBOOT_COMPRESSION_NONE;
  553. RtlStringCopy((PSTR)&UBootHeader.ImageName,
  554. Context->InputFileName,
  555. UBOOT_MAX_NAME);
  556. UBootHeader.HeaderCrc32 = RtlComputeCrc32(0,
  557. &UBootHeader,
  558. sizeof(UBOOT_HEADER));
  559. UBootHeader.HeaderCrc32 = RtlByteSwapUlong(UBootHeader.HeaderCrc32);
  560. //
  561. // Write out the U-Boot header.
  562. //
  563. BytesWritten = fwrite(&UBootHeader,
  564. 1,
  565. sizeof(UBOOT_HEADER),
  566. Context->OutputFile);
  567. if (BytesWritten != sizeof(UBOOT_HEADER)) {
  568. fprintf(stderr,
  569. "mkuboot: Needed to write %d byte U-Boot header, wrote %d "
  570. "bytes.\n",
  571. sizeof(UBOOT_HEADER),
  572. BytesWritten);
  573. Result = 1;
  574. goto CreateLegacyImageEnd;
  575. }
  576. //
  577. // Write the input file to the data section of the output file.
  578. //
  579. BytesWritten = fwrite(Context->InputFileBuffer,
  580. 1,
  581. Context->InputFileSize,
  582. Context->OutputFile);
  583. if (BytesWritten != Context->InputFileSize) {
  584. Result = 1;
  585. goto CreateLegacyImageEnd;
  586. }
  587. CreateLegacyImageEnd:
  588. return Result;
  589. }
  590. int
  591. MupCreateFitImage (
  592. PMKUBOOT_CONTEXT Context
  593. )
  594. /*++
  595. Routine Description:
  596. This routine creates a FIT U-Boot image out of the given input file and
  597. writes it to the output file.
  598. Arguments:
  599. Context - Supplies a pointer to the U-Boot image creation context.
  600. Return Value:
  601. Returns 0 on success. Non-zero on failure.
  602. --*/
  603. {
  604. size_t BytesWritten;
  605. UBOOT_FIT_MEMORY_RESERVE_MAP MemoryReserveMap;
  606. UINT32 MemoryReserveMapOffset;
  607. long Offset;
  608. int Result;
  609. void *Strings;
  610. UINT32 StringsOffset;
  611. UINT32 StringsSize;
  612. UINT32 StructuresOffset;
  613. UINT32 StructuresSize;
  614. UINT32 TotalSize;
  615. UBOOT_FIT_HEADER UBootFitHeader;
  616. Result = 0;
  617. Strings = NULL;
  618. //
  619. // Create the strings dictionary. This initialized the global properties
  620. // array so that it holds the correct string offsets for each property's
  621. // string.
  622. //
  623. Result = MupCreateStringsDictionary(&Strings, &StringsSize);
  624. if (Result != 0) {
  625. fprintf(stderr, "mkuboot: Failed to create strings dictionary.\n");
  626. goto CreateFitImageEnd;
  627. }
  628. //
  629. // Reserve space in the image for the U-Boot FIT header.
  630. //
  631. BytesWritten = 0;
  632. while (BytesWritten < sizeof(UBOOT_FIT_HEADER)) {
  633. fputc('\0', Context->OutputFile);
  634. BytesWritten += 1;
  635. }
  636. //
  637. // Write out the reserve memory map.
  638. //
  639. Offset = ftell(Context->OutputFile);
  640. if (Offset < 0) {
  641. fprintf(stderr, "mkuboot: Failed to seek.\n");
  642. Result = 1;
  643. goto CreateFitImageEnd;
  644. }
  645. MemoryReserveMapOffset = (UINT32)Offset;
  646. MemoryReserveMap.BaseAddress = 0;
  647. MemoryReserveMap.Size = 0;
  648. BytesWritten = fwrite(&MemoryReserveMap,
  649. 1,
  650. sizeof(UBOOT_FIT_MEMORY_RESERVE_MAP),
  651. Context->OutputFile);
  652. if (BytesWritten != sizeof(UBOOT_FIT_MEMORY_RESERVE_MAP)) {
  653. fprintf(stderr, "mkuboot: Failed to write reserve memory map.\n");
  654. Result = 1;
  655. goto CreateFitImageEnd;
  656. }
  657. //
  658. // Write the structure data out to the file.
  659. //
  660. Offset = ftell(Context->OutputFile);
  661. if (Offset < 0) {
  662. fprintf(stderr, "mkuboot: Failed to seek.\n");
  663. Result = 1;
  664. goto CreateFitImageEnd;
  665. }
  666. StructuresOffset = (UINT32)Offset;
  667. Result = MupWriteFitStructures(Context);
  668. if (Result != 0) {
  669. fprintf(stderr, "mkuboot: Failed to write FIT structures.\n");
  670. goto CreateFitImageEnd;
  671. }
  672. Offset = ftell(Context->OutputFile);
  673. if (Offset < 0) {
  674. fprintf(stderr, "mkuboot: Failed to seek.\n");
  675. Result = 1;
  676. goto CreateFitImageEnd;
  677. }
  678. StringsOffset = (UINT32)Offset;
  679. StructuresSize = StringsOffset - StructuresOffset;
  680. //
  681. // Write the strings out to the file.
  682. //
  683. BytesWritten = fwrite(Strings, 1, StringsSize, Context->OutputFile);
  684. if (BytesWritten != StringsSize) {
  685. fprintf(stderr,
  686. "mkuboot: Failed to write FIT strings. Write %ld bytes, "
  687. "expected %ld.\n",
  688. BytesWritten,
  689. StringsSize);
  690. Result = 1;
  691. goto CreateFitImageEnd;
  692. }
  693. Offset = ftell(Context->OutputFile);
  694. if (Offset < 0) {
  695. fprintf(stderr, "mkuboot: Failed to seek.\n");
  696. Result = 1;
  697. goto CreateFitImageEnd;
  698. }
  699. TotalSize = (UINT32)Offset;
  700. //
  701. // Align the total size up to the alignment value.
  702. //
  703. while ((TotalSize & (MKUBOOT_FIT_ALIGNMENT - 1)) != 0) {
  704. fputc('\0', Context->OutputFile);
  705. TotalSize += 1;
  706. }
  707. //
  708. // Fill out the U-Boot FIT header.
  709. //
  710. RtlZeroMemory(&UBootFitHeader, sizeof(UBOOT_FIT_HEADER));
  711. UBootFitHeader.Magic = RtlByteSwapUlong(UBOOT_FIT_MAGIC);
  712. UBootFitHeader.TotalSize = RtlByteSwapUlong(TotalSize);
  713. UBootFitHeader.StructuresOffset = RtlByteSwapUlong(StructuresOffset);
  714. UBootFitHeader.StringsOffset = RtlByteSwapUlong(StringsOffset);
  715. UBootFitHeader.MemoryReserveMapOffset =
  716. RtlByteSwapUlong(MemoryReserveMapOffset);
  717. UBootFitHeader.Version = RtlByteSwapUlong(UBOOT_FIT_VERSION);
  718. UBootFitHeader.LastCompatibleVersion =
  719. RtlByteSwapUlong(UBOOT_FIT_LAST_COMPATIBLE_VERSION);
  720. UBootFitHeader.BootCpuId = 0;
  721. UBootFitHeader.StringsSize = RtlByteSwapUlong(StringsSize);
  722. UBootFitHeader.StructuresSize = RtlByteSwapUlong(StructuresSize);
  723. //
  724. // Write out the U-Boot FIT header back at the beginning of the file.
  725. //
  726. Result = fseek(Context->OutputFile, 0, SEEK_SET);
  727. if (Result != 0) {
  728. Result = 1;
  729. goto CreateFitImageEnd;
  730. }
  731. BytesWritten = fwrite(&UBootFitHeader,
  732. 1,
  733. sizeof(UBOOT_FIT_HEADER),
  734. Context->OutputFile);
  735. if (BytesWritten != sizeof(UBOOT_FIT_HEADER)) {
  736. fprintf(stderr,
  737. "mkuboot: Needed to write %d byte U-Boot FIT header, wrote %d "
  738. "bytes.\n",
  739. sizeof(UBOOT_FIT_HEADER),
  740. BytesWritten);
  741. Result = 1;
  742. goto CreateFitImageEnd;
  743. }
  744. CreateFitImageEnd:
  745. if (Strings != NULL) {
  746. MupDestroyStringsDictionary(Strings);
  747. }
  748. return Result;
  749. }
  750. int
  751. MupCreateStringsDictionary (
  752. void **Strings,
  753. UINT32 *StringsSize
  754. )
  755. /*++
  756. Routine Description:
  757. This routine creates the strings dictionary for a U-Boot FIT image.
  758. Arguments:
  759. Strings - Supplies a pointer that receives the string dictionary.
  760. StringsSize - Supplies a pointer that receives the total size of the string
  761. dictionary, in bytes.
  762. Return Value:
  763. None.
  764. --*/
  765. {
  766. void *Buffer;
  767. int Index;
  768. size_t Length;
  769. UINT32 Offset;
  770. PMKUBOOT_PROPERTY_ENTRY PropertyEntry;
  771. int Result;
  772. UINT32 Size;
  773. //
  774. // Calculate the total size of the dictionary. For now, only the property
  775. // strings are included.
  776. //
  777. Size = 0;
  778. for (Index = 0; Index < MkUBootPropertyCount; Index += 1) {
  779. PropertyEntry = &(MkUBootProperties[Index]);
  780. Length = RtlStringLength(PropertyEntry->Name) + 1;
  781. Size += Length;
  782. }
  783. Buffer = malloc(Size);
  784. if (Buffer == NULL) {
  785. Result = 1;
  786. goto CreateStringsDictionaryEnd;
  787. }
  788. //
  789. // Copy the strings, including null terminators, into the buffer. While
  790. // doing so, fill in the offsets for the properties.
  791. //
  792. Offset = 0;
  793. for (Index = 0; Index < MkUBootPropertyCount; Index += 1) {
  794. PropertyEntry = &(MkUBootProperties[Index]);
  795. PropertyEntry->Offset = Offset;
  796. Length = RtlStringLength(PropertyEntry->Name) + 1;
  797. RtlCopyMemory(Buffer + Offset, PropertyEntry->Name, Length);
  798. Offset += Length;
  799. }
  800. Result = 0;
  801. CreateStringsDictionaryEnd:
  802. if (Result != 0) {
  803. if (Buffer != NULL) {
  804. free(Buffer);
  805. Buffer = NULL;
  806. }
  807. Size = 0;
  808. }
  809. *Strings = Buffer;
  810. *StringsSize = Size;
  811. return Result;
  812. }
  813. void
  814. MupDestroyStringsDictionary (
  815. void *Strings
  816. )
  817. /*++
  818. Routine Description:
  819. This routine destroys the given strings dictionary.
  820. Arguments:
  821. Strings - Supplies a pointer to the string dictionary to destroy.
  822. Return Value:
  823. None.
  824. --*/
  825. {
  826. free(Strings);
  827. return;
  828. }
  829. int
  830. MupWriteFitStructures (
  831. PMKUBOOT_CONTEXT Context
  832. )
  833. /*++
  834. Routine Description:
  835. This routine writes all of the structures out a U-Boot FIT image. From the
  836. context it writes the input file as the one an only kernel for the default
  837. configuration. It also creates an empty flat device tree required by U-Boot.
  838. Arguments:
  839. Context - Supplies a pointer to the make U-Boot context.
  840. Return Value:
  841. Returns 0 on success. Non-zero on failure.
  842. --*/
  843. {
  844. UINT32 Address;
  845. size_t BytesWritten;
  846. UINT32 EndNodeTag;
  847. UINT32 EndTag;
  848. size_t Length;
  849. int Result;
  850. CHAR8 *String;
  851. UINT32 Timestamp;
  852. EndTag = RtlByteSwapUlong(UBOOT_FIT_TAG_END);
  853. EndNodeTag = RtlByteSwapUlong(UBOOT_FIT_TAG_NODE_END);
  854. //
  855. // Write the root node.
  856. //
  857. Result = MupWriteNodeStart(Context, UBOOT_FIT_NODE_ROOT);
  858. if (Result != 0) {
  859. goto FitWriteStructuresEnd;
  860. }
  861. //
  862. // Write the root's timestamp.
  863. //
  864. Timestamp = RtlByteSwapUlong(time(NULL));
  865. Result = MupWriteProperty(Context,
  866. MkUBootPropertyTimestamp,
  867. &Timestamp,
  868. sizeof(UINT32));
  869. if (Result != 0) {
  870. goto FitWriteStructuresEnd;
  871. }
  872. //
  873. // Write the root description property.
  874. //
  875. Length = strlen(MKUBOOT_DEFAULT_FIT_DESCRIPTION) + 1;
  876. Result = MupWriteProperty(Context,
  877. MkUBootPropertyDescription,
  878. MKUBOOT_DEFAULT_FIT_DESCRIPTION,
  879. Length);
  880. if (Result != 0) {
  881. goto FitWriteStructuresEnd;
  882. }
  883. //
  884. // Write the images node.
  885. //
  886. Result = MupWriteNodeStart(Context, UBOOT_FIT_NODE_IMAGES);
  887. if (Result != 0) {
  888. goto FitWriteStructuresEnd;
  889. }
  890. //
  891. // Write the kernel node, including the data, type, os type, compression,
  892. // load address, and entry point.
  893. //
  894. Result = MupWriteNodeStart(Context, MKUBOOT_DEFAULT_FIT_KERNEL_NAME);
  895. if (Result != 0) {
  896. goto FitWriteStructuresEnd;
  897. }
  898. Result = MupWriteProperty(Context,
  899. MkUBootPropertyData,
  900. Context->InputFileBuffer,
  901. Context->InputFileSize);
  902. if (Result != 0) {
  903. goto FitWriteStructuresEnd;
  904. }
  905. if (Context->LoadAddress != 0) {
  906. String = UBOOT_IMAGE_STRING_KERNEL;
  907. } else {
  908. String = UBOOT_IMAGE_STRING_KERNEL_NO_LOAD;
  909. }
  910. Length = strlen(String) + 1;
  911. Result = MupWriteProperty(Context, MkUBootPropertyType, String, Length);
  912. if (Result != 0) {
  913. goto FitWriteStructuresEnd;
  914. }
  915. switch (Context->Architecture) {
  916. case MKUBOOT_ARCHITECTURE_ARM:
  917. String = UBOOT_ARCHITECTURE_STRING_ARM;
  918. break;
  919. case MKUBOOT_ARCHITECTURE_X86:
  920. String = UBOOT_ARCHITECTURE_STRING_X86;
  921. break;
  922. default:
  923. fprintf(stderr, "mkuboot: Invalid architecture.\n");
  924. Result = 1;
  925. goto FitWriteStructuresEnd;
  926. }
  927. Length = strlen(String) + 1;
  928. Result = MupWriteProperty(Context,
  929. MkUBootPropertyArchitecture,
  930. String,
  931. Length);
  932. if (Result != 0) {
  933. goto FitWriteStructuresEnd;
  934. }
  935. Length = strlen(UBOOT_OS_STRING_LINUX) + 1;
  936. Result = MupWriteProperty(Context,
  937. MkUBootPropertyOs,
  938. UBOOT_OS_STRING_LINUX,
  939. Length);
  940. if (Result != 0) {
  941. goto FitWriteStructuresEnd;
  942. }
  943. Length = strlen(UBOOT_COMPRESSION_STRING_NONE) + 1;
  944. Result = MupWriteProperty(Context,
  945. MkUBootPropertyCompression,
  946. UBOOT_COMPRESSION_STRING_NONE,
  947. Length);
  948. if (Result != 0) {
  949. goto FitWriteStructuresEnd;
  950. }
  951. Address = RtlByteSwapUlong(Context->LoadAddress);
  952. Result = MupWriteProperty(Context,
  953. MkUBootPropertyLoadAddress,
  954. &Address,
  955. sizeof(UINT32));
  956. if (Result != 0) {
  957. goto FitWriteStructuresEnd;
  958. }
  959. Address = RtlByteSwapUlong(Context->EntryPoint);
  960. Result = MupWriteProperty(Context,
  961. MkUBootPropertyEntryPoint,
  962. &Address,
  963. sizeof(UINT32));
  964. if (Result != 0) {
  965. goto FitWriteStructuresEnd;
  966. }
  967. //
  968. // Write the kernel's node end tag.
  969. //
  970. BytesWritten = fwrite(&EndNodeTag, 1, sizeof(UINT32), Context->OutputFile);
  971. if (BytesWritten != sizeof(UINT32)) {
  972. Result = 1;
  973. goto FitWriteStructuresEnd;
  974. }
  975. //
  976. // Write the Flat Device Tree's node, including a description, empty data
  977. // set, and a type property.
  978. //
  979. Result = MupWriteNodeStart(Context, MKUBOOT_DEFAULT_FIT_DEVICE_TREE_NAME);
  980. if (Result != 0) {
  981. goto FitWriteStructuresEnd;
  982. }
  983. Length = strlen(MKUBOOT_DEFAULT_FIT_DEVICE_TREE_DESCRIPTION) + 1;
  984. Result = MupWriteProperty(Context,
  985. MkUBootPropertyDescription,
  986. MKUBOOT_DEFAULT_FIT_DEVICE_TREE_DESCRIPTION,
  987. Length);
  988. if (Result != 0) {
  989. goto FitWriteStructuresEnd;
  990. }
  991. Result = MupWriteProperty(Context, MkUBootPropertyData, NULL, 0);
  992. if (Result != 0) {
  993. goto FitWriteStructuresEnd;
  994. }
  995. Length = strlen(UBOOT_IMAGE_STRING_FLAT_DEVICE_TREE) + 1;
  996. Result = MupWriteProperty(Context,
  997. MkUBootPropertyType,
  998. UBOOT_IMAGE_STRING_FLAT_DEVICE_TREE,
  999. Length);
  1000. if (Result != 0) {
  1001. goto FitWriteStructuresEnd;
  1002. }
  1003. //
  1004. // Write the device tree's node end tag, and the image node's end tag.
  1005. //
  1006. BytesWritten = fwrite(&EndNodeTag, 1, sizeof(UINT32), Context->OutputFile);
  1007. if (BytesWritten != sizeof(UINT32)) {
  1008. Result = 1;
  1009. goto FitWriteStructuresEnd;
  1010. }
  1011. BytesWritten = fwrite(&EndNodeTag, 1, sizeof(UINT32), Context->OutputFile);
  1012. if (BytesWritten != sizeof(UINT32)) {
  1013. Result = 1;
  1014. goto FitWriteStructuresEnd;
  1015. }
  1016. //
  1017. // Write the configurations node.
  1018. //
  1019. Result = MupWriteNodeStart(Context, UBOOT_FIT_NODE_CONFIGURATIONS);
  1020. if (Result != 0) {
  1021. goto FitWriteStructuresEnd;
  1022. }
  1023. //
  1024. // Write the default configuration property.
  1025. //
  1026. Length = strlen(MKUBOOT_DEFAULT_FIT_CONFIGURATION_NAME) + 1;
  1027. Result = MupWriteProperty(Context,
  1028. MkUBootPropertyDefault,
  1029. MKUBOOT_DEFAULT_FIT_CONFIGURATION_NAME,
  1030. Length);
  1031. if (Result != 0) {
  1032. goto FitWriteStructuresEnd;
  1033. }
  1034. //
  1035. // Create the default configuration's node.
  1036. //
  1037. Result = MupWriteNodeStart(Context, MKUBOOT_DEFAULT_FIT_CONFIGURATION_NAME);
  1038. if (Result != 0) {
  1039. goto FitWriteStructuresEnd;
  1040. }
  1041. Length = strlen(MKUBOOT_DEFAULT_FIT_KERNEL_NAME) + 1;
  1042. Result = MupWriteProperty(Context,
  1043. MkUBootPropertyKernel,
  1044. MKUBOOT_DEFAULT_FIT_KERNEL_NAME,
  1045. Length);
  1046. if (Result != 0) {
  1047. goto FitWriteStructuresEnd;
  1048. }
  1049. //
  1050. // End both the default configuration node and the configuration node.
  1051. //
  1052. BytesWritten = fwrite(&EndNodeTag, 1, sizeof(UINT32), Context->OutputFile);
  1053. if (BytesWritten != sizeof(UINT32)) {
  1054. Result = 1;
  1055. goto FitWriteStructuresEnd;
  1056. }
  1057. BytesWritten = fwrite(&EndNodeTag, 1, sizeof(UINT32), Context->OutputFile);
  1058. if (BytesWritten != sizeof(UINT32)) {
  1059. Result = 1;
  1060. goto FitWriteStructuresEnd;
  1061. }
  1062. //
  1063. // Write the final node end tag for the root and the end tag.
  1064. //
  1065. BytesWritten = fwrite(&EndNodeTag, 1, sizeof(UINT32), Context->OutputFile);
  1066. if (BytesWritten != sizeof(UINT32)) {
  1067. Result = 1;
  1068. goto FitWriteStructuresEnd;
  1069. }
  1070. BytesWritten = fwrite(&EndTag, 1, sizeof(UINT32), Context->OutputFile);
  1071. if (BytesWritten != sizeof(UINT32)) {
  1072. Result = 1;
  1073. goto FitWriteStructuresEnd;
  1074. }
  1075. FitWriteStructuresEnd:
  1076. return Result;
  1077. }
  1078. int
  1079. MupWriteNodeStart (
  1080. PMKUBOOT_CONTEXT Context,
  1081. CHAR8 *Name
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. This routine writes a FIT image start node with the given name to the
  1086. context's output file.
  1087. Arguments:
  1088. Context - Supplies a pointer to the make U-Boot context.
  1089. Name - Supplies the name of the node.
  1090. Return Value:
  1091. Returns 0 on success. Non-zero on failure.
  1092. --*/
  1093. {
  1094. size_t BytesWritten;
  1095. size_t NameLength;
  1096. PUBOOT_FIT_NODE Node;
  1097. UINT32 NodeSize;
  1098. int Result;
  1099. NameLength = strlen(Name) + 1;
  1100. NodeSize = sizeof(UBOOT_FIT_NODE) + NameLength;
  1101. NodeSize = ALIGN_VALUE(NodeSize, UBOOT_FIT_TAG_ALIGNMENT);
  1102. Node = malloc(NodeSize);
  1103. if (Node == NULL) {
  1104. Result = 1;
  1105. goto WriteNodeStartEnd;
  1106. }
  1107. RtlZeroMemory(Node, NodeSize);
  1108. Node->Tag = RtlByteSwapUlong(UBOOT_FIT_TAG_NODE_START);
  1109. RtlCopyMemory((Node + 1), Name, NameLength);
  1110. BytesWritten = fwrite(Node, 1, NodeSize, Context->OutputFile);
  1111. if (BytesWritten != NodeSize) {
  1112. Result = 1;
  1113. goto WriteNodeStartEnd;
  1114. }
  1115. Result = 0;
  1116. WriteNodeStartEnd:
  1117. if (Node != NULL) {
  1118. free(Node);
  1119. }
  1120. return Result;
  1121. }
  1122. int
  1123. MupWriteProperty (
  1124. PMKUBOOT_CONTEXT Context,
  1125. MKUBOOT_PROPERTY Property,
  1126. void *Data,
  1127. UINT32 DataSize
  1128. )
  1129. /*++
  1130. Routine Description:
  1131. This routine writes a FIT property tag to the context's output file using
  1132. the given data.
  1133. Arguments:
  1134. Context - Supplies a pointer to the make U-Boot context.
  1135. Property - Supplies the property to be written.
  1136. Data - Supplies a pointer to the data to write for the property.
  1137. DataSize - Supplies the size of the data to write.
  1138. Return Value:
  1139. Returns 0 on success. Non-zero on failure.
  1140. --*/
  1141. {
  1142. size_t BytesWritten;
  1143. PUBOOT_FIT_PROPERTY FitProperty;
  1144. UINT32 FitPropertySize;
  1145. int Result;
  1146. UINT32 StringOffset;
  1147. FitPropertySize = sizeof(UBOOT_FIT_PROPERTY) + DataSize;
  1148. FitPropertySize = ALIGN_VALUE(FitPropertySize, UBOOT_FIT_TAG_ALIGNMENT);
  1149. FitProperty = malloc(FitPropertySize);
  1150. if (FitProperty == NULL) {
  1151. Result = 1;
  1152. goto WritePropertyEnd;
  1153. }
  1154. RtlZeroMemory(FitProperty, FitPropertySize);
  1155. FitProperty->Tag = RtlByteSwapUlong(UBOOT_FIT_TAG_PROPERTY);
  1156. FitProperty->Size = RtlByteSwapUlong(DataSize);
  1157. StringOffset = RtlByteSwapUlong(MkUBootProperties[Property].Offset);
  1158. FitProperty->StringOffset = StringOffset;
  1159. if (DataSize != 0) {
  1160. RtlCopyMemory((FitProperty + 1), Data, DataSize);
  1161. }
  1162. BytesWritten = fwrite(FitProperty, 1, FitPropertySize, Context->OutputFile);
  1163. if (BytesWritten != FitPropertySize) {
  1164. Result = 1;
  1165. goto WritePropertyEnd;
  1166. }
  1167. Result = 0;
  1168. WritePropertyEnd:
  1169. if (FitProperty != NULL) {
  1170. free(FitProperty);
  1171. }
  1172. return Result;
  1173. }