Xeon-SP boards: Factor out OCP VPD `get_cxl_mode()` impl
[coreboot2.git] / util / cbfstool / ifwitool.c
blob453d85c44b2acc03232a1caf0009f2eff18e6aae
1 /* ifwitool, CLI utility for IFWI manipulation */
2 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <commonlib/bsd/helpers.h>
5 #include <commonlib/endian.h>
6 #include <getopt.h>
7 #include <stdlib.h>
8 #include <time.h>
10 #include "common.h"
13 * BPDT is Boot Partition Descriptor Table. It is located at the start of a
14 * logical boot partition(LBP). It stores information about the critical
15 * sub-partitions present within the LBP.
17 * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
18 * critical sub-partitions and contains information about the non-critical
19 * sub-partitions present within the LBP.
21 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
22 * table.
24 #define BPDT_SIGNATURE (0x000055AA)
26 #define LBP1 (0)
27 #define LBP2 (1)
29 /* Parameters passed in by caller. */
30 static struct param {
31 const char *file_name;
32 size_t logical_boot_partition;
33 const char *subpart_name;
34 const char *image_name;
35 bool dir_ops;
36 const char *dentry_name;
37 } param;
39 struct bpdt_header {
41 * This is used to identify start of BPDT. It should always be
42 * BPDT_SIGNATURE.
44 uint32_t signature;
45 /* Count of BPDT entries present. */
46 uint16_t descriptor_count;
47 /* Version - Currently supported = 1. */
48 uint16_t bpdt_version;
49 /* Unused - Should be 0. */
50 uint32_t xor_redundant_block;
51 /* Version of IFWI build. */
52 uint32_t ifwi_version;
53 /* Version of FIT tool used to create IFWI. */
54 uint64_t fit_tool_version;
55 } __packed;
56 #define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
58 struct bpdt_entry {
59 /* Type of sub-partition. */
60 uint16_t type;
61 /* Attributes of sub-partition. */
62 uint16_t flags;
63 /* Offset of sub-partition from beginning of LBP. */
64 uint32_t offset;
65 /* Size in bytes of sub-partition. */
66 uint32_t size;
67 } __packed;
68 #define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
70 struct bpdt {
71 struct bpdt_header h;
72 /* In practice, this could be an array of 0 to n entries. */
73 struct bpdt_entry e[];
74 } __packed;
76 static inline size_t get_bpdt_size(struct bpdt_header *h)
78 return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
81 /* Minimum size in bytes allocated to BPDT in IFWI. */
82 #define BPDT_MIN_SIZE (512)
84 /* Header to define directory header for sub-partition. */
85 struct subpart_dir_header {
86 /* Should be SUBPART_DIR_MARKER. */
87 uint32_t marker;
88 /* Number of directory entries in the sub-partition. */
89 uint32_t num_entries;
90 /* Currenty supported - 1. */
91 uint8_t header_version;
92 /* Currenty supported - 1. */
93 uint8_t entry_version;
94 /* Length of directory header in bytes. */
95 uint8_t header_length;
97 * 2s complement of 8-bit sum from first byte of header to last byte of
98 * last directory entry.
100 uint8_t checksum;
101 /* ASCII short name of sub-partition. */
102 uint8_t name[4];
103 } __packed;
104 #define SUBPART_DIR_HEADER_SIZE \
105 (sizeof(struct subpart_dir_header))
106 #define SUBPART_DIR_MARKER 0x44504324
107 #define SUBPART_DIR_HEADER_VERSION_SUPPORTED 1
108 #define SUBPART_DIR_ENTRY_VERSION_SUPPORTED 1
110 /* Structure for each directory entry for sub-partition. */
111 struct subpart_dir_entry {
112 /* Name of directory entry - Not guaranteed to be NULL-terminated. */
113 uint8_t name[12];
114 /* Offset of entry from beginning of sub-partition. */
115 uint32_t offset;
116 /* Length in bytes of sub-directory entry. */
117 uint32_t length;
118 /* Must be zero. */
119 uint32_t rsvd;
120 } __packed;
121 #define SUBPART_DIR_ENTRY_SIZE \
122 (sizeof(struct subpart_dir_entry))
124 struct subpart_dir {
125 struct subpart_dir_header h;
126 /* In practice, this could be an array of 0 to n entries. */
127 struct subpart_dir_entry e[];
128 } __packed;
130 static inline size_t subpart_dir_size(struct subpart_dir_header *h)
132 return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
135 struct manifest_header {
136 uint32_t header_type;
137 uint32_t header_length;
138 uint32_t header_version;
139 uint32_t flags;
140 uint32_t vendor;
141 uint32_t date;
142 uint32_t size;
143 uint32_t id;
144 uint32_t rsvd;
145 uint64_t version;
146 uint32_t svn;
147 uint64_t rsvd1;
148 uint8_t rsvd2[64];
149 uint32_t modulus_size;
150 uint32_t exponent_size;
151 uint8_t public_key[256];
152 uint32_t exponent;
153 uint8_t signature[256];
154 } __packed;
156 #define DWORD_SIZE 4
157 #define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
158 #define MANIFEST_ID_MAGIC (0x324e4d24)
160 struct module {
161 uint8_t name[12];
162 uint8_t type;
163 uint8_t hash_alg;
164 uint16_t hash_size;
165 uint32_t metadata_size;
166 uint8_t metadata_hash[32];
167 } __packed;
169 #define MODULE_SIZE (sizeof(struct module))
171 struct signed_pkg_info_ext {
172 uint32_t ext_type;
173 uint32_t ext_length;
174 uint8_t name[4];
175 uint32_t vcn;
176 uint8_t bitmap[16];
177 uint32_t svn;
178 uint8_t rsvd[16];
179 } __packed;
181 #define SIGNED_PKG_INFO_EXT_TYPE 0x15
182 #define SIGNED_PKG_INFO_EXT_SIZE \
183 (sizeof(struct signed_pkg_info_ext))
186 * Attributes for various IFWI sub-partitions.
187 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
188 * BPDT.
189 * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
190 * CONTAINS_DIR = Sub-Partition contains directory.
191 * AUTO_GENERATED = Sub-Partition is generated by the tool.
192 * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
193 * an entry for it with size 0 and offset 0.
195 enum subpart_attributes {
196 LIES_WITHIN_BPDT_4K = (1 << 0),
197 NON_CRITICAL_SUBPART = (1 << 1),
198 CONTAINS_DIR = (1 << 2),
199 AUTO_GENERATED = (1 << 3),
200 MANDATORY_BPDT_ENTRY = (1 << 4),
203 /* Type value for various IFWI sub-partitions. */
204 enum bpdt_entry_type {
205 SMIP_TYPE = 0,
206 CSE_RBE_TYPE = 1,
207 CSE_BUP_TYPE = 2,
208 UCODE_TYPE = 3,
209 IBB_TYPE = 4,
210 S_BPDT_TYPE = 5,
211 OBB_TYPE = 6,
212 CSE_MAIN_TYPE = 7,
213 ISH_TYPE = 8,
214 CSE_IDLM_TYPE = 9,
215 IFP_OVERRIDE_TYPE = 10,
216 DEBUG_TOKENS_TYPE = 11,
217 UFS_PHY_TYPE = 12,
218 UFS_GPP_TYPE = 13,
219 PMC_TYPE = 14,
220 IUNIT_TYPE = 15,
221 NVM_CONFIG_TYPE = 16,
222 UEP_TYPE = 17,
223 UFS_RATE_B_TYPE = 18,
224 MAX_SUBPARTS = 19,
228 * There are two order requirements for an IFWI image:
229 * 1. Order in which the sub-partitions lie within the BPDT entries.
230 * 2. Order in which the sub-partitions lie within the image.
232 * header_order defines #1 i.e. the order in which the sub-partitions should
233 * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
234 * sub-partitions appear in the IFWI image. pack_order controls the offset and
235 * thus sub-partitions would have increasing offsets as we loop over pack_order.
237 const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
238 /* Order of the following entries is mandatory. */
239 CSE_IDLM_TYPE,
240 IFP_OVERRIDE_TYPE,
241 S_BPDT_TYPE,
242 CSE_RBE_TYPE,
243 UFS_PHY_TYPE,
244 UFS_GPP_TYPE,
245 /* Order of the following entries is recommended. */
246 UEP_TYPE,
247 NVM_CONFIG_TYPE,
248 UFS_RATE_B_TYPE,
249 IBB_TYPE,
250 SMIP_TYPE,
251 PMC_TYPE,
252 CSE_BUP_TYPE,
253 UCODE_TYPE,
254 DEBUG_TOKENS_TYPE,
255 IUNIT_TYPE,
256 CSE_MAIN_TYPE,
257 ISH_TYPE,
258 OBB_TYPE,
261 const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
262 /* Order of the following entries is mandatory. */
263 UFS_GPP_TYPE,
264 UFS_PHY_TYPE,
265 IFP_OVERRIDE_TYPE,
266 UEP_TYPE,
267 NVM_CONFIG_TYPE,
268 UFS_RATE_B_TYPE,
269 /* Order of the following entries is recommended. */
270 IBB_TYPE,
271 SMIP_TYPE,
272 CSE_RBE_TYPE,
273 PMC_TYPE,
274 CSE_BUP_TYPE,
275 UCODE_TYPE,
276 CSE_IDLM_TYPE,
277 DEBUG_TOKENS_TYPE,
278 S_BPDT_TYPE,
279 IUNIT_TYPE,
280 CSE_MAIN_TYPE,
281 ISH_TYPE,
282 OBB_TYPE,
285 /* Utility functions. */
286 enum ifwi_ret {
287 COMMAND_ERR = -1,
288 NO_ACTION_REQUIRED = 0,
289 REPACK_REQUIRED = 1,
292 struct dir_ops {
293 enum ifwi_ret (*dir_add)(int);
296 static enum ifwi_ret ibbp_dir_add(int);
298 const struct subpart_info {
299 const char *name;
300 const char *readable_name;
301 uint32_t attr;
302 struct dir_ops dir_ops;
303 } subparts[MAX_SUBPARTS] = {
304 /* OEM SMIP */
305 [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
306 /* CSE RBE */
307 [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
308 MANDATORY_BPDT_ENTRY, {NULL} },
309 /* CSE BUP */
310 [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
311 MANDATORY_BPDT_ENTRY, {NULL} },
312 /* uCode */
313 [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
314 /* IBB */
315 [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
316 /* S-BPDT */
317 [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
318 MANDATORY_BPDT_ENTRY, {NULL} },
319 /* OBB */
320 [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
321 NON_CRITICAL_SUBPART, {NULL} },
322 /* CSE Main */
323 [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
324 NON_CRITICAL_SUBPART, {NULL} },
325 /* ISH */
326 [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
327 /* CSE IDLM */
328 [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
329 MANDATORY_BPDT_ENTRY, {NULL} },
330 /* IFP Override */
331 [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
332 LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
333 {NULL} },
334 /* Debug Tokens */
335 [DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
336 /* UFS Phy Configuration */
337 [UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
338 MANDATORY_BPDT_ENTRY, {NULL} },
339 /* UFS GPP LUN ID */
340 [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
341 MANDATORY_BPDT_ENTRY, {NULL} },
342 /* PMC */
343 [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
344 /* IUNIT */
345 [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
346 /* NVM Config */
347 [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
348 /* UEP */
349 [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
350 {NULL} },
351 /* UFS Rate B Config */
352 [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
355 struct ifwi_image {
356 /* Data read from input file. */
357 struct buffer input_buff;
359 /* BPDT header and entries. */
360 struct buffer bpdt;
361 size_t input_ifwi_start_offset;
362 size_t input_ifwi_end_offset;
364 /* Subpartition content. */
365 struct buffer subpart_buf[MAX_SUBPARTS];
366 } ifwi_image;
368 static void alloc_buffer(struct buffer *b, size_t s, const char *n)
370 if (buffer_create(b, s, n) == 0)
371 return;
373 ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
374 exit(-1);
378 * Read header/entry members in little-endian format.
379 * Returns the offset up to which the read was performed.
381 static size_t read_member(void *src, size_t offset, size_t size_bytes,
382 void *dst)
384 switch (size_bytes) {
385 case 1:
386 *(uint8_t *)dst = read_at_le8(src, offset);
387 break;
388 case 2:
389 *(uint16_t *)dst = read_at_le16(src, offset);
390 break;
391 case 4:
392 *(uint32_t *)dst = read_at_le32(src, offset);
393 break;
394 case 8:
395 *(uint64_t *)dst = read_at_le64(src, offset);
396 break;
397 default:
398 ERROR("Read size not supported %zd\n", size_bytes);
399 exit(-1);
402 return (offset + size_bytes);
406 * Convert to little endian format.
407 * Returns the offset up to which the fixup was performed.
409 static size_t fix_member(void *data, size_t offset, size_t size_bytes)
411 uint8_t *src = (uint8_t *)data + offset;
413 switch (size_bytes) {
414 case 1:
415 write_at_le8(data, *(uint8_t *)src, offset);
416 break;
417 case 2:
418 write_at_le16(data, *(uint16_t *)src, offset);
419 break;
420 case 4:
421 write_at_le32(data, *(uint32_t *)src, offset);
422 break;
423 case 8:
424 write_at_le64(data, *(uint64_t *)src, offset);
425 break;
426 default:
427 ERROR("Write size not supported %zd\n", size_bytes);
428 exit(-1);
430 return (offset + size_bytes);
434 static void print_subpart_dir(struct subpart_dir *s)
436 if (verbose == 0)
437 return;
439 size_t i;
441 printf("%-25s 0x%-23.8x\n", "Marker", s->h.marker);
442 printf("%-25s %-25d\n", "Num entries", s->h.num_entries);
443 printf("%-25s %-25d\n", "Header Version", s->h.header_version);
444 printf("%-25s %-25d\n", "Entry Version", s->h.entry_version);
445 printf("%-25s 0x%-23x\n", "Header Length", s->h.header_length);
446 printf("%-25s 0x%-23x\n", "Checksum", s->h.checksum);
447 printf("%-25s ", "Name");
448 for (i = 0; i < sizeof(s->h.name); i++)
449 printf("%c", s->h.name[i]);
451 printf("\n");
453 printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
454 "Length", "Rsvd");
456 printf("=============================================================="
457 "===========================================================\n");
459 for (i = 0; i < s->h.num_entries; i++) {
460 printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i+1,
461 s->e[i].name, s->e[i].offset, s->e[i].length,
462 s->e[i].rsvd);
465 printf("=============================================================="
466 "===========================================================\n");
469 static void bpdt_print_header(struct bpdt_header *h, const char *name)
471 if (verbose == 0)
472 return;
474 printf("%-25s %-25s\n", "Header", name);
475 printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
476 printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
477 printf("%-25s %-25d\n", "BPDT Version", h->bpdt_version);
478 printf("%-25s 0x%-23x\n", "XOR checksum", h->xor_redundant_block);
479 printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
480 printf("%-25s 0x%-23llx\n", "FIT Tool Version",
481 (long long)h->fit_tool_version);
484 static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
485 const char *name)
487 if (verbose == 0)
488 return;
490 printf("%s entries\n", name);
492 printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
493 "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
494 "File Offset");
496 printf("=============================================================="
497 "=============================================================="
498 "=============================================================="
499 "===============\n");
502 size_t i;
503 for (i = 0; i < count; i++) {
504 printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx"
505 "\n", i+1, subparts[e[i].type].name,
506 subparts[e[i].type].readable_name, e[i].type, e[i].flags,
507 e[i].offset, e[i].size,
508 e[i].offset + ifwi_image.input_ifwi_start_offset);
511 printf("=============================================================="
512 "=============================================================="
513 "=============================================================="
514 "===============\n");
518 static void bpdt_validate_header(struct bpdt_header *h, const char *name)
520 assert(h->signature == BPDT_SIGNATURE);
522 if (h->bpdt_version != 1) {
523 ERROR("Invalid header : %s\n", name);
524 exit(-1);
527 DEBUG("Validated header : %s\n", name);
530 static void bpdt_read_header(void *data, struct bpdt_header *h,
531 const char *name)
533 size_t offset = 0;
535 offset = read_member(data, offset, sizeof(h->signature), &h->signature);
536 offset = read_member(data, offset, sizeof(h->descriptor_count),
537 &h->descriptor_count);
538 offset = read_member(data, offset, sizeof(h->bpdt_version),
539 &h->bpdt_version);
540 offset = read_member(data, offset, sizeof(h->xor_redundant_block),
541 &h->xor_redundant_block);
542 offset = read_member(data, offset, sizeof(h->ifwi_version),
543 &h->ifwi_version);
544 read_member(data, offset, sizeof(h->fit_tool_version),
545 &h->fit_tool_version);
547 bpdt_validate_header(h, name);
548 bpdt_print_header(h, name);
551 static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
553 size_t i, offset = 0;
554 struct bpdt_entry *e = &bpdt->e[0];
555 size_t count = bpdt->h.descriptor_count;
557 for (i = 0; i < count; i++) {
558 offset = read_member(data, offset, sizeof(e[i].type),
559 &e[i].type);
560 offset = read_member(data, offset, sizeof(e[i].flags),
561 &e[i].flags);
562 offset = read_member(data, offset, sizeof(e[i].offset),
563 &e[i].offset);
564 offset = read_member(data, offset, sizeof(e[i].size),
565 &e[i].size);
568 bpdt_print_entries(e, count, name);
572 * Given type of sub-partition, identify BPDT entry for it.
573 * Sub-Partition could lie either within BPDT or S-BPDT.
575 static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
576 size_t count, int type)
578 size_t i;
579 for (i = 0; i < count; i++) {
580 if (e[i].type == type)
581 break;
584 if (i == count)
585 return NULL;
587 return &e[i];
590 static struct bpdt_entry *find_entry_by_type(int type)
592 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
593 if (b == NULL)
594 return NULL;
596 struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
597 b->h.descriptor_count,
598 type);
600 if (curr)
601 return curr;
603 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
604 if (b == NULL)
605 return NULL;
607 return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
611 * Find sub-partition type given its name. If the name does not exist, returns
612 * -1.
614 static int find_type_by_name(const char *name)
616 int i;
618 for (i = 0; i < MAX_SUBPARTS; i++) {
619 if ((strlen(subparts[i].name) == strlen(name)) &&
620 (!strcmp(subparts[i].name, name)))
621 break;
624 if (i == MAX_SUBPARTS) {
625 ERROR("Invalid sub-partition name %s.\n", name);
626 return -1;
629 return i;
633 * Read the content of a sub-partition from input file and store it in
634 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
636 * Returns the maximum offset occupied by the sub-partitions.
638 static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
639 size_t count)
641 size_t i, type;
642 struct buffer *buf;
643 size_t max_offset = 0;
645 for (i = 0; i < count; i++) {
646 type = e[i].type;
648 if (type >= MAX_SUBPARTS) {
649 ERROR("Invalid sub-partition type %zd.\n", type);
650 exit(-1);
653 if (buffer_size(&ifwi_image.subpart_buf[type])) {
654 ERROR("Multiple sub-partitions of type %zd(%s).\n",
655 type, subparts[type].name);
656 exit(-1);
659 if (e[i].size == 0) {
660 INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
661 subparts[type].name);
662 continue;
665 assert((e[i].offset + e[i].size) <= size);
668 * Sub-partitions in IFWI image are not in the same order as
669 * in BPDT entries. BPDT entries are in header_order whereas
670 * sub-partition offsets in the image are in pack_order.
672 if ((e[i].offset + e[i].size) > max_offset)
673 max_offset = e[i].offset + e[i].size;
676 * S-BPDT sub-partition contains information about all the
677 * non-critical sub-partitions. Thus, size of S-BPDT
678 * sub-partition equals size of S-BPDT plus size of all the
679 * non-critical sub-partitions. Thus, reading whole of S-BPDT
680 * here would be redundant as the non-critical partitions are
681 * read and allocated buffers separately. Also, S-BPDT requires
682 * special handling for reading header and entries.
684 if (type == S_BPDT_TYPE)
685 continue;
687 buf = &ifwi_image.subpart_buf[type];
689 alloc_buffer(buf, e[i].size, subparts[type].name);
690 memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
691 e[i].size);
694 assert(max_offset);
695 return max_offset;
699 * Allocate buffer for bpdt header, entries and all sub-partition content.
700 * Returns offset in data where BPDT ends.
702 static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
703 struct buffer *b, const char *name)
705 struct bpdt_header bpdt_header;
706 assert((offset + BPDT_HEADER_SIZE) < size);
707 bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
709 /* Buffer to read BPDT header and entries. */
710 alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
712 struct bpdt *bpdt = buffer_get(b);
713 memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
716 * If no entries are present, maximum offset occupied is (offset +
717 * BPDT_HEADER_SIZE).
719 if (bpdt->h.descriptor_count == 0)
720 return (offset + BPDT_HEADER_SIZE);
722 /* Read all entries. */
723 assert((offset + get_bpdt_size(&bpdt->h)) < size);
724 bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
725 name);
727 /* Read all sub-partition content in subpart_buf. */
728 return read_subpart_buf(data, size, &bpdt->e[0],
729 bpdt->h.descriptor_count);
732 static void parse_sbpdt(void *data, size_t size)
734 struct bpdt_entry *s;
735 s = find_entry_by_type(S_BPDT_TYPE);
736 if (!s)
737 return;
739 assert(size > s->offset);
741 alloc_bpdt_buffer(data, size, s->offset,
742 &ifwi_image.subpart_buf[S_BPDT_TYPE],
743 "S-BPDT");
746 static uint8_t calc_checksum(struct subpart_dir *s)
748 size_t size = subpart_dir_size(&s->h);
749 uint8_t *data = (uint8_t *)s;
750 uint8_t checksum = 0;
751 size_t i;
753 uint8_t old_checksum = s->h.checksum;
754 s->h.checksum = 0;
756 for (i = 0; i < size; i++)
757 checksum += data[i];
759 s->h.checksum = old_checksum;
761 /* 2s complement */
762 return -checksum;
765 static void validate_subpart_dir(struct subpart_dir *s, const char *name,
766 bool checksum_check)
768 if ((s->h.marker != SUBPART_DIR_MARKER) ||
769 (s->h.header_version != SUBPART_DIR_HEADER_VERSION_SUPPORTED) ||
770 (s->h.entry_version != SUBPART_DIR_ENTRY_VERSION_SUPPORTED) ||
771 (s->h.header_length != SUBPART_DIR_HEADER_SIZE)) {
772 ERROR("Invalid subpart_dir for %s.\n", name);
773 exit(-1);
776 if (checksum_check == false)
777 return;
779 uint8_t checksum = calc_checksum(s);
781 if (checksum != s->h.checksum)
782 ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
783 name, checksum, s->h.checksum);
786 static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
787 const char *name)
789 validate_subpart_dir(s, name, 0);
792 static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
793 const char *name)
795 validate_subpart_dir(s, name, 1);
798 static void parse_subpart_dir(struct buffer *subpart_dir_buf,
799 struct buffer *input_buf, const char *name)
801 struct subpart_dir_header hdr;
802 size_t offset = 0;
803 uint8_t *data = buffer_get(input_buf);
804 size_t size = buffer_size(input_buf);
806 /* Read Subpart_Dir header. */
807 assert(size >= SUBPART_DIR_HEADER_SIZE);
808 offset = read_member(data, offset, sizeof(hdr.marker), &hdr.marker);
809 offset = read_member(data, offset, sizeof(hdr.num_entries),
810 &hdr.num_entries);
811 offset = read_member(data, offset, sizeof(hdr.header_version),
812 &hdr.header_version);
813 offset = read_member(data, offset, sizeof(hdr.entry_version),
814 &hdr.entry_version);
815 offset = read_member(data, offset, sizeof(hdr.header_length),
816 &hdr.header_length);
817 offset = read_member(data, offset, sizeof(hdr.checksum), &hdr.checksum);
818 memcpy(hdr.name, data + offset, sizeof(hdr.name));
819 offset += sizeof(hdr.name);
821 validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
823 assert(size > subpart_dir_size(&hdr));
824 alloc_buffer(subpart_dir_buf, subpart_dir_size(&hdr), "Subpart Dir");
825 memcpy(buffer_get(subpart_dir_buf), &hdr, SUBPART_DIR_HEADER_SIZE);
827 /* Read Subpart Dir entries. */
828 struct subpart_dir *subpart_dir = buffer_get(subpart_dir_buf);
829 struct subpart_dir_entry *e = &subpart_dir->e[0];
830 uint32_t i;
831 for (i = 0; i < hdr.num_entries; i++) {
832 memcpy(e[i].name, data + offset, sizeof(e[i].name));
833 offset += sizeof(e[i].name);
834 offset = read_member(data, offset, sizeof(e[i].offset),
835 &e[i].offset);
836 offset = read_member(data, offset, sizeof(e[i].length),
837 &e[i].length);
838 offset = read_member(data, offset, sizeof(e[i].rsvd),
839 &e[i].rsvd);
842 validate_subpart_dir_with_checksum(subpart_dir, name);
844 print_subpart_dir(subpart_dir);
847 /* Parse the bpdt entries to compute the size of the BPDT */
848 static size_t bpdt_size(void *data)
850 struct bpdt *b = (struct bpdt *)data;
851 size_t i, size = 0;
853 for (i = 0; i < b->h.descriptor_count; i++)
854 size = MAX(size, b->e[i].offset + b->e[i].size);
856 return size;
859 /* Parse input image file to identify different sub-partitions. */
860 static int ifwi_parse(void)
862 DEBUG("Parsing IFWI image...\n");
863 const char *image_name = param.image_name;
865 /* Read input file. */
866 struct buffer *buff = &ifwi_image.input_buff;
867 if (buffer_from_file(buff, image_name)) {
868 ERROR("Failed to read input file %s.\n", image_name);
869 return -1;
872 INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
874 /* Look for BPDT signature at 4K intervals. */
875 size_t offset = 0, lbp = LBP1;
876 void *data = buffer_get(buff);
878 while (offset < buffer_size(buff)) {
879 if (read_at_le32(data, offset) == BPDT_SIGNATURE) {
880 if (lbp == param.logical_boot_partition)
881 break;
882 offset += bpdt_size((uint8_t *)data + offset);
883 lbp++;
884 } else
885 offset += 4 * KiB;
888 if (offset >= buffer_size(buff)) {
889 ERROR("Image does not contain BPDT for LBP=%zd!!\n",
890 param.logical_boot_partition);
891 return -1;
894 ifwi_image.input_ifwi_start_offset = offset;
895 INFO("BPDT starts at offset 0x%zx.\n", offset);
897 data = (uint8_t *)data + offset;
898 size_t ifwi_size = buffer_size(buff) - offset;
900 /* Read BPDT and sub-partitions. */
901 uintptr_t end_offset;
902 end_offset = ifwi_image.input_ifwi_start_offset +
903 alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
905 /* Parse S-BPDT, if any. */
906 parse_sbpdt(data, ifwi_size);
909 * Store end offset of IFWI. Required for copying any trailing non-IFWI
910 * part of the image.
911 * ASSUMPTION: IFWI image always ends on a 4K boundary.
913 ifwi_image.input_ifwi_end_offset = ALIGN_UP(end_offset, 4 * KiB);
914 DEBUG("Parsing done.\n");
916 return 0;
920 * This function is used by repack to count the number of BPDT and S-BPDT
921 * entries that are present. It frees the current buffers used by the entries
922 * and allocates fresh buffers that can be used for repacking. Returns BPDT
923 * entries which are empty and need to be filled in.
925 static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
927 size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
928 assert(size >= bpdt_size);
931 * If buffer does not have the required size, allocate a fresh buffer.
933 if (buffer_size(b) != size) {
934 struct buffer temp;
935 alloc_buffer(&temp, size, b->name);
936 memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
937 buffer_delete(b);
938 *b = temp;
941 struct bpdt *bpdt = buffer_get(b);
942 uint8_t *ptr = (uint8_t *)&bpdt->e[0];
943 size_t entries_size = BPDT_ENTRY_SIZE * count;
945 /* Zero out BPDT entries. */
946 memset(ptr, 0, entries_size);
947 /* Fill any pad-space with FF. */
948 memset(ptr + entries_size, 0xFF, size - bpdt_size);
950 bpdt->h.descriptor_count = count;
953 static void bpdt_reset(void)
955 size_t i;
956 size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
958 /* Count number of BPDT and S-BPDT entries. */
959 for (i = 0; i < MAX_SUBPARTS; i++) {
960 if (buffer_size(&ifwi_image.subpart_buf[i]) == 0) {
961 if (subparts[i].attr & MANDATORY_BPDT_ENTRY) {
962 bpdt_count++;
963 dummy_bpdt_count++;
965 continue;
968 if (subparts[i].attr & NON_CRITICAL_SUBPART)
969 sbpdt_count++;
970 else
971 bpdt_count++;
974 DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
975 dummy_bpdt_count, sbpdt_count);
977 /* Update BPDT if required. */
978 size_t bpdt_size = MAX(BPDT_MIN_SIZE,
979 BPDT_HEADER_SIZE + bpdt_count * BPDT_ENTRY_SIZE);
980 __bpdt_reset(&ifwi_image.bpdt, bpdt_count, bpdt_size);
982 /* Update S-BPDT if required. */
983 bpdt_size = ALIGN_UP(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
984 4 * KiB);
985 __bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
986 bpdt_size);
989 /* Initialize BPDT entries in header order. */
990 static void bpdt_entries_init_header_order(void)
992 int i, type;
993 size_t size;
995 struct bpdt *bpdt, *sbpdt, *curr;
996 size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
998 bpdt = buffer_get(&ifwi_image.bpdt);
999 sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1001 for (i = 0; i < MAX_SUBPARTS; i++) {
1002 type = bpdt_header_order[i];
1003 size = buffer_size(&ifwi_image.subpart_buf[type]);
1005 if ((size == 0) && !(subparts[type].attr &
1006 MANDATORY_BPDT_ENTRY))
1007 continue;
1009 if (subparts[type].attr & NON_CRITICAL_SUBPART) {
1010 curr = sbpdt;
1011 count_ptr = &sbpdt_curr;
1012 } else {
1013 curr = bpdt;
1014 count_ptr = &bpdt_curr;
1017 assert(*count_ptr < curr->h.descriptor_count);
1018 curr->e[*count_ptr].type = type;
1019 curr->e[*count_ptr].flags = 0;
1020 curr->e[*count_ptr].offset = 0;
1021 curr->e[*count_ptr].size = size;
1023 (*count_ptr)++;
1027 static void pad_buffer(struct buffer *b, size_t size)
1029 size_t buff_size = buffer_size(b);
1031 assert(buff_size <= size);
1033 if (buff_size == size)
1034 return;
1036 struct buffer temp;
1037 alloc_buffer(&temp, size, b->name);
1038 uint8_t *data = buffer_get(&temp);
1040 memcpy(data, buffer_get(b), buff_size);
1041 memset(data + buff_size, 0xFF, size - buff_size);
1043 *b = temp;
1046 /* Initialize offsets of entries using pack order. */
1047 static void bpdt_entries_init_pack_order(void)
1049 int i, type;
1050 struct bpdt_entry *curr;
1051 size_t curr_offset, curr_end;
1053 curr_offset = MAX(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
1056 * There are two types of sub-partitions that need to be handled here:
1057 * 1. Sub-partitions that lie within the same 4K as BPDT
1058 * 2. Sub-partitions that lie outside the 4K of BPDT
1060 * For sub-partitions of type # 1, there is no requirement on the start
1061 * or end of the sub-partition. They need to be packed in without any
1062 * holes left in between. If there is any empty space left after the end
1063 * of the last sub-partition in 4K of BPDT, then that space needs to be
1064 * padded with FF bytes, but the size of the last sub-partition remains
1065 * unchanged.
1067 * For sub-partitions of type # 2, both the start and end should be a
1068 * multiple of 4K. If not, then it needs to be padded with FF bytes and
1069 * size adjusted such that the sub-partition ends on 4K boundary.
1072 /* #1 Sub-partitions that lie within same 4K as BPDT. */
1073 struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1075 for (i = 0; i < MAX_SUBPARTS; i++) {
1076 type = bpdt_pack_order[i];
1077 curr = find_entry_by_type(type);
1079 if ((curr == NULL) || (curr->size == 0))
1080 continue;
1082 if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1083 continue;
1085 curr->offset = curr_offset;
1086 curr_offset = curr->offset + curr->size;
1087 last_bpdt_buff = &ifwi_image.subpart_buf[type];
1088 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, "
1089 "curr->size=0x%x, buff_size=0x%zx\n", type, curr_offset,
1090 curr->offset, curr->size,
1091 buffer_size(&ifwi_image.subpart_buf[type]));
1094 /* Pad ff bytes if there is any empty space left in BPDT 4K. */
1095 curr_end = ALIGN_UP(curr_offset, 4 * KiB);
1096 pad_buffer(last_bpdt_buff,
1097 buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
1098 curr_offset = curr_end;
1100 /* #2 Sub-partitions that lie outside of BPDT 4K. */
1101 for (i = 0; i < MAX_SUBPARTS; i++) {
1102 type = bpdt_pack_order[i];
1103 curr = find_entry_by_type(type);
1105 if ((curr == NULL) || (curr->size == 0))
1106 continue;
1108 if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1109 continue;
1111 assert(curr_offset == ALIGN_UP(curr_offset, 4 * KiB));
1112 curr->offset = curr_offset;
1113 curr_end = ALIGN_UP(curr->offset + curr->size, 4 * KiB);
1114 curr->size = curr_end - curr->offset;
1116 pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1118 curr_offset = curr_end;
1119 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, "
1120 "curr->size=0x%x, buff_size=0x%zx\n", type, curr_offset,
1121 curr->offset, curr->size,
1122 buffer_size(&ifwi_image.subpart_buf[type]));
1126 * Update size of S-BPDT to include size of all non-critical
1127 * sub-partitions.
1129 * Assumption: S-BPDT always lies at the end of IFWI image.
1131 curr = find_entry_by_type(S_BPDT_TYPE);
1132 assert(curr);
1134 assert(curr_offset == ALIGN_UP(curr_offset, 4 * KiB));
1135 curr->size = curr_offset - curr->offset;
1138 /* Convert all members of BPDT to little-endian format. */
1139 static void bpdt_fixup_write_buffer(struct buffer *buf)
1141 struct bpdt *s = buffer_get(buf);
1143 struct bpdt_header *h = &s->h;
1144 struct bpdt_entry *e = &s->e[0];
1146 size_t count = h->descriptor_count;
1148 size_t offset = 0;
1150 offset = fix_member(&h->signature, offset, sizeof(h->signature));
1151 offset = fix_member(&h->descriptor_count, offset,
1152 sizeof(h->descriptor_count));
1153 offset = fix_member(&h->bpdt_version, offset, sizeof(h->bpdt_version));
1154 offset = fix_member(&h->xor_redundant_block, offset,
1155 sizeof(h->xor_redundant_block));
1156 offset = fix_member(&h->ifwi_version, offset, sizeof(h->ifwi_version));
1157 offset = fix_member(&h->fit_tool_version, offset,
1158 sizeof(h->fit_tool_version));
1160 uint32_t i;
1161 for (i = 0; i < count; i++) {
1162 offset = fix_member(&e[i].type, offset, sizeof(e[i].type));
1163 offset = fix_member(&e[i].flags, offset, sizeof(e[i].flags));
1164 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1165 offset = fix_member(&e[i].size, offset, sizeof(e[i].size));
1169 /* Write BPDT to output buffer after fixup. */
1170 static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1172 bpdt_fixup_write_buffer(src);
1173 memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1177 * Follows these steps to re-create image:
1178 * 1. Write any non-IFWI prefix.
1179 * 2. Write out BPDT header and entries.
1180 * 3. Write sub-partition buffers to respective offsets.
1181 * 4. Write any non-IFWI suffix.
1183 * While performing the above steps, make sure that any empty holes are filled
1184 * with FF.
1186 static void ifwi_write(const char *image_name)
1188 struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1189 assert(s);
1191 size_t ifwi_start, ifwi_end, file_end;
1193 ifwi_start = ifwi_image.input_ifwi_start_offset;
1194 ifwi_end = ifwi_start + ALIGN_UP(s->offset + s->size, 4 * KiB);
1195 file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
1196 ifwi_image.input_ifwi_end_offset);
1198 struct buffer b;
1200 alloc_buffer(&b, file_end, "Final-IFWI");
1202 uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1203 uint8_t *output_data = buffer_get(&b);
1205 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1206 ifwi_end, file_end);
1208 /* Copy non-IFWI prefix, if any. */
1209 memcpy(output_data, input_data, ifwi_start);
1211 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1213 struct buffer ifwi;
1214 buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1215 uint8_t *ifwi_data = buffer_get(&ifwi);
1217 /* Copy sub-partitions using pack_order. */
1218 struct bpdt_entry *curr;
1219 struct buffer *subpart_buf;
1220 int i, type;
1221 for (i = 0; i < MAX_SUBPARTS; i++) {
1222 type = bpdt_pack_order[i];
1224 if (type == S_BPDT_TYPE)
1225 continue;
1227 curr = find_entry_by_type(type);
1229 if ((curr == NULL) || (curr->size == 0))
1230 continue;
1232 subpart_buf = &ifwi_image.subpart_buf[type];
1234 DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, "
1235 "write_size=0x%zx\n", curr->offset, curr->size, type,
1236 buffer_size(subpart_buf));
1238 assert((curr->offset + buffer_size(subpart_buf)) <=
1239 buffer_size(&ifwi));
1241 memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1242 buffer_size(subpart_buf));
1245 /* Copy non-IFWI suffix, if any. */
1246 if (ifwi_end != file_end) {
1247 memcpy(output_data + ifwi_end,
1248 input_data + ifwi_image.input_ifwi_end_offset,
1249 file_end - ifwi_end);
1250 DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1251 ifwi_end, file_end - ifwi_end);
1255 * Convert BPDT to little-endian format and write it to output buffer.
1256 * S-BPDT is written first and then BPDT.
1258 bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1259 bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1261 if (buffer_write_file(&b, image_name)) {
1262 ERROR("File write error\n");
1263 exit(-1);
1266 buffer_delete(&b);
1267 printf("Image written successfully to %s.\n", image_name);
1271 * Calculate size and offset of each sub-partition again since it might have
1272 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1273 * entries and write back the new IFWI image to file.
1275 static void ifwi_repack(void)
1277 bpdt_reset();
1278 bpdt_entries_init_header_order();
1279 bpdt_entries_init_pack_order();
1281 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1282 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1284 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1285 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1287 DEBUG("Repack done.. writing image.\n");
1288 ifwi_write(param.image_name);
1291 static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1292 size_t count, const char *name)
1294 memset(hdr, 0, sizeof(*hdr));
1296 hdr->marker = SUBPART_DIR_MARKER;
1297 hdr->num_entries = count;
1298 hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED;
1299 hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED;
1300 hdr->header_length = SUBPART_DIR_HEADER_SIZE;
1301 memcpy(hdr->name, name, sizeof(hdr->name));
1304 static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1305 struct buffer *b, size_t offset)
1307 memset(e, 0, sizeof(*e));
1309 assert(strlen(b->name) <= sizeof(e->name));
1310 strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
1311 e->offset = offset;
1312 e->length = buffer_size(b);
1314 return (offset + buffer_size(b));
1317 static void init_manifest_header(struct manifest_header *hdr, size_t size)
1319 memset(hdr, 0, sizeof(*hdr));
1321 hdr->header_type = 0x4;
1322 assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0);
1323 hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE;
1324 hdr->header_version = 0x10000;
1325 hdr->vendor = 0x8086;
1327 struct tm *local_time;
1328 time_t curr_time;
1329 char buffer[11];
1331 curr_time = time(NULL);
1332 local_time = localtime(&curr_time);
1333 strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time);
1334 hdr->date = strtoul(buffer, NULL, 16);
1336 assert((size % DWORD_SIZE) == 0);
1337 hdr->size = size / DWORD_SIZE;
1338 hdr->id = MANIFEST_ID_MAGIC;
1341 static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1342 size_t count, const char *name)
1344 memset(ext, 0, sizeof(*ext));
1346 ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE;
1347 ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE;
1348 memcpy(ext->name, name, sizeof(ext->name));
1351 static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1353 struct subpart_dir *s = buffer_get(buf);
1354 struct subpart_dir_header *h = &s->h;
1355 struct subpart_dir_entry *e = &s->e[0];
1357 size_t count = h->num_entries;
1358 size_t offset = 0;
1360 offset = fix_member(&h->marker, offset, sizeof(h->marker));
1361 offset = fix_member(&h->num_entries, offset, sizeof(h->num_entries));
1362 offset = fix_member(&h->header_version, offset,
1363 sizeof(h->header_version));
1364 offset = fix_member(&h->entry_version, offset,
1365 sizeof(h->entry_version));
1366 offset = fix_member(&h->header_length, offset,
1367 sizeof(h->header_length));
1368 offset = fix_member(&h->checksum, offset, sizeof(h->checksum));
1369 offset += sizeof(h->name);
1371 uint32_t i;
1372 for (i = 0; i < count; i++) {
1373 offset += sizeof(e[i].name);
1374 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1375 offset = fix_member(&e[i].length, offset, sizeof(e[i].length));
1376 offset = fix_member(&e[i].rsvd, offset, sizeof(e[i].rsvd));
1380 static void create_subpart(struct buffer *dst, struct buffer *info[],
1381 size_t count, const char *name)
1383 struct buffer subpart_dir_buff;
1384 size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1386 alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1388 struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1389 struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1391 init_subpart_dir_header(h, count, name);
1393 size_t curr_offset = size;
1394 size_t i;
1396 for (i = 0; i < count; i++) {
1397 curr_offset = init_subpart_dir_entry(&e[i], info[i],
1398 curr_offset);
1401 alloc_buffer(dst, curr_offset, name);
1402 uint8_t *data = buffer_get(dst);
1404 for (i = 0; i < count; i++) {
1405 memcpy(data + e[i].offset, buffer_get(info[i]),
1406 buffer_size(info[i]));
1409 h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
1411 struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1413 print_subpart_dir(dir);
1415 subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1416 memcpy(data, dir, buffer_size(&subpart_dir_buff));
1418 buffer_delete(&subpart_dir_buff);
1421 static enum ifwi_ret ibbp_dir_add(int type)
1423 #define DUMMY_IBB_SIZE (4 * KiB)
1425 assert(type == IBB_TYPE);
1428 * Entry # 1 - IBBP.man
1429 * Contains manifest header and signed pkg info extension.
1431 struct buffer manifest;
1432 size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1433 alloc_buffer(&manifest, size, "IBBP.man");
1435 struct manifest_header *man_hdr = buffer_get(&manifest);
1436 init_manifest_header(man_hdr, size);
1438 struct signed_pkg_info_ext *ext;
1439 ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1441 init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1443 /* Entry # 2 - IBBL */
1444 struct buffer ibbl;
1445 if (buffer_from_file(&ibbl, param.file_name))
1446 return COMMAND_ERR;
1448 /* Entry # 3 - IBB */
1449 struct buffer ibb;
1450 alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1451 memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1453 /* Create subpartition. */
1454 struct buffer *info[] = {
1455 &manifest, &ibbl, &ibb,
1457 create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1458 ARRAY_SIZE(info), subparts[type].name);
1460 return REPACK_REQUIRED;
1463 static enum ifwi_ret ifwi_raw_add(int type)
1465 if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1466 return COMMAND_ERR;
1468 printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1469 type, param.file_name);
1470 return REPACK_REQUIRED;
1473 static enum ifwi_ret ifwi_dir_add(int type)
1475 if (!(subparts[type].attr & CONTAINS_DIR) ||
1476 (subparts[type].dir_ops.dir_add == NULL)) {
1477 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1478 subparts[type].name, type);
1479 return COMMAND_ERR;
1482 if (!param.dentry_name) {
1483 ERROR("%s: -e option required\n", __func__);
1484 return COMMAND_ERR;
1487 enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
1488 if (ret != COMMAND_ERR)
1489 printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1490 param.subpart_name, type, param.dentry_name,
1491 param.file_name);
1492 else
1493 ERROR("Sub-partition dir operation failed.\n");
1495 return ret;
1498 static enum ifwi_ret ifwi_add(void)
1500 if (!param.file_name) {
1501 ERROR("%s: -f option required\n", __func__);
1502 return COMMAND_ERR;
1505 if (!param.subpart_name) {
1506 ERROR("%s: -n option required\n", __func__);
1507 return COMMAND_ERR;
1510 int type = find_type_by_name(param.subpart_name);
1511 if (type == -1)
1512 return COMMAND_ERR;
1514 const struct subpart_info *curr_subpart = &subparts[type];
1516 if (curr_subpart->attr & AUTO_GENERATED) {
1517 ERROR("Cannot add auto-generated sub-partitions.\n");
1518 return COMMAND_ERR;
1521 if (buffer_size(&ifwi_image.subpart_buf[type])) {
1522 ERROR("Image already contains sub-partition %s(%d).\n",
1523 param.subpart_name, type);
1524 return COMMAND_ERR;
1527 if (param.dir_ops)
1528 return ifwi_dir_add(type);
1530 return ifwi_raw_add(type);
1533 static enum ifwi_ret ifwi_delete(void)
1535 if (!param.subpart_name) {
1536 ERROR("%s: -n option required\n", __func__);
1537 return COMMAND_ERR;
1540 int type = find_type_by_name(param.subpart_name);
1541 if (type == -1)
1542 return COMMAND_ERR;
1544 const struct subpart_info *curr_subpart = &subparts[type];
1546 if (curr_subpart->attr & AUTO_GENERATED) {
1547 ERROR("Cannot delete auto-generated sub-partitions.\n");
1548 return COMMAND_ERR;
1551 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1552 printf("Image does not contain sub-partition %s(%d).\n",
1553 param.subpart_name, type);
1554 return NO_ACTION_REQUIRED;
1557 buffer_delete(&ifwi_image.subpart_buf[type]);
1558 printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1559 return REPACK_REQUIRED;
1562 static enum ifwi_ret ifwi_dir_extract(int type)
1564 if (!(subparts[type].attr & CONTAINS_DIR)) {
1565 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1566 subparts[type].name, type);
1567 return COMMAND_ERR;
1570 if (!param.dentry_name) {
1571 ERROR("%s: -e option required.\n", __func__);
1572 return COMMAND_ERR;
1575 struct buffer subpart_dir_buff;
1576 parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1577 subparts[type].name);
1579 uint32_t i;
1580 struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1582 for (i = 0; i < s->h.num_entries; i++) {
1583 if (!strncmp((char *)s->e[i].name, param.dentry_name,
1584 sizeof(s->e[i].name)))
1585 break;
1588 if (i == s->h.num_entries) {
1589 ERROR("Entry %s not found in subpartition for %s.\n",
1590 param.dentry_name, param.subpart_name);
1591 exit(-1);
1594 struct buffer dst;
1596 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
1597 s->e[i].length);
1598 buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
1599 s->e[i].length);
1601 if (buffer_write_file(&dst, param.file_name))
1602 return COMMAND_ERR;
1604 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1605 param.subpart_name, type, param.dentry_name, param.file_name);
1607 return NO_ACTION_REQUIRED;
1610 static enum ifwi_ret ifwi_raw_extract(int type)
1612 if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1613 return COMMAND_ERR;
1615 printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1616 param.file_name);
1618 return NO_ACTION_REQUIRED;
1621 static enum ifwi_ret ifwi_extract(void)
1623 if (!param.file_name) {
1624 ERROR("%s: -f option required\n", __func__);
1625 return COMMAND_ERR;
1628 if (!param.subpart_name) {
1629 ERROR("%s: -n option required\n", __func__);
1630 return COMMAND_ERR;
1633 int type = find_type_by_name(param.subpart_name);
1634 if (type == -1)
1635 return COMMAND_ERR;
1637 if (type == S_BPDT_TYPE) {
1638 INFO("Tool does not support raw extract for %s\n",
1639 param.subpart_name);
1640 return NO_ACTION_REQUIRED;
1643 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1644 ERROR("Image does not contain sub-partition %s(%d).\n",
1645 param.subpart_name, type);
1646 return COMMAND_ERR;
1649 INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1650 if (param.dir_ops)
1651 return ifwi_dir_extract(type);
1653 return ifwi_raw_extract(type);
1656 static enum ifwi_ret ifwi_print(void)
1658 verbose += 2;
1660 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1662 bpdt_print_header(&b->h, "BPDT");
1663 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1665 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1666 bpdt_print_header(&b->h, "S-BPDT");
1667 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1669 if (param.dir_ops == 0) {
1670 verbose -= 2;
1671 return NO_ACTION_REQUIRED;
1674 int i;
1675 struct buffer subpart_dir_buf;
1676 for (i = 0; i < MAX_SUBPARTS ; i++) {
1677 if (!(subparts[i].attr & CONTAINS_DIR) ||
1678 (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
1679 continue;
1681 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1682 subparts[i].name);
1683 buffer_delete(&subpart_dir_buf);
1686 verbose -= 2;
1688 return NO_ACTION_REQUIRED;
1691 static enum ifwi_ret ifwi_raw_replace(int type)
1693 buffer_delete(&ifwi_image.subpart_buf[type]);
1694 return ifwi_raw_add(type);
1697 static enum ifwi_ret ifwi_dir_replace(int type)
1699 if (!(subparts[type].attr & CONTAINS_DIR)) {
1700 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1701 subparts[type].name, type);
1702 return COMMAND_ERR;
1705 if (!param.dentry_name) {
1706 ERROR("%s: -e option required.\n", __func__);
1707 return COMMAND_ERR;
1710 struct buffer subpart_dir_buf;
1711 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
1712 subparts[type].name);
1714 uint32_t i;
1715 struct subpart_dir *s = buffer_get(&subpart_dir_buf);
1717 for (i = 0; i < s->h.num_entries; i++) {
1718 if (!strcmp((char *)s->e[i].name, param.dentry_name))
1719 break;
1722 if (i == s->h.num_entries) {
1723 ERROR("Entry %s not found in subpartition for %s.\n",
1724 param.dentry_name, param.subpart_name);
1725 exit(-1);
1728 struct buffer b;
1729 if (buffer_from_file(&b, param.file_name)) {
1730 ERROR("Failed to read %s\n", param.file_name);
1731 exit(-1);
1734 struct buffer dst;
1735 size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
1736 buffer_size(&b) - s->e[i].length;
1737 size_t subpart_start = s->e[i].offset;
1738 size_t subpart_end = s->e[i].offset + s->e[i].length;
1740 alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
1742 uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]);
1743 uint8_t *dst_data = buffer_get(&dst);
1744 size_t curr_offset = 0;
1746 /* Copy data before the sub-partition entry. */
1747 memcpy(dst_data + curr_offset, src_data, subpart_start);
1748 curr_offset += subpart_start;
1750 /* Copy sub-partition entry. */
1751 memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
1752 curr_offset += buffer_size(&b);
1754 /* Copy remaining data. */
1755 memcpy(dst_data + curr_offset, src_data + subpart_end,
1756 buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
1758 /* Update sub-partition buffer. */
1759 int offset = s->e[i].offset;
1760 buffer_delete(&ifwi_image.subpart_buf[type]);
1761 ifwi_image.subpart_buf[type] = dst;
1763 /* Update length of entry in the subpartition. */
1764 s->e[i].length = buffer_size(&b);
1765 buffer_delete(&b);
1767 /* Adjust offsets of affected entries in subpartition. */
1768 offset = s->e[i].offset - offset;
1769 for (; i < s->h.num_entries; i++) {
1770 s->e[i].offset += offset;
1773 /* Re-calculate checksum. */
1774 s->h.checksum = calc_checksum(s);
1776 /* Convert members to litte-endian. */
1777 subpart_dir_fixup_write_buffer(&subpart_dir_buf);
1779 memcpy(dst_data, buffer_get(&subpart_dir_buf),
1780 buffer_size(&subpart_dir_buf));
1782 buffer_delete(&subpart_dir_buf);
1784 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
1785 param.subpart_name, type, param.dentry_name, param.file_name);
1787 return REPACK_REQUIRED;
1790 static enum ifwi_ret ifwi_replace(void)
1792 if (!param.file_name) {
1793 ERROR("%s: -f option required\n", __func__);
1794 return COMMAND_ERR;
1797 if (!param.subpart_name) {
1798 ERROR("%s: -n option required\n", __func__);
1799 return COMMAND_ERR;
1802 int type = find_type_by_name(param.subpart_name);
1803 if (type == -1)
1804 return COMMAND_ERR;
1806 const struct subpart_info *curr_subpart = &subparts[type];
1808 if (curr_subpart->attr & AUTO_GENERATED) {
1809 ERROR("Cannot replace auto-generated sub-partitions.\n");
1810 return COMMAND_ERR;
1813 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1814 ERROR("Image does not contain sub-partition %s(%d).\n",
1815 param.subpart_name, type);
1816 return COMMAND_ERR;
1819 if (param.dir_ops)
1820 return ifwi_dir_replace(type);
1822 return ifwi_raw_replace(type);
1825 static enum ifwi_ret ifwi_create(void)
1828 * Create peels off any non-IFWI content present in the input buffer and
1829 * creates output file with only the IFWI present.
1832 if (!param.file_name) {
1833 ERROR("%s: -f option required\n", __func__);
1834 return COMMAND_ERR;
1837 /* Peel off any non-IFWI prefix. */
1838 buffer_seek(&ifwi_image.input_buff,
1839 ifwi_image.input_ifwi_start_offset);
1840 /* Peel off any non-IFWI suffix. */
1841 buffer_set_size(&ifwi_image.input_buff,
1842 ifwi_image.input_ifwi_end_offset -
1843 ifwi_image.input_ifwi_start_offset);
1846 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
1848 ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
1849 ifwi_image.input_ifwi_start_offset = 0;
1851 param.image_name = param.file_name;
1853 return REPACK_REQUIRED;
1856 struct command {
1857 const char *name;
1858 const char *optstring;
1859 enum ifwi_ret (*function)(void);
1862 static const struct command commands[] = {
1863 {"add", "f:n:e:dsvh?", ifwi_add},
1864 {"create", "f:svh?", ifwi_create},
1865 {"delete", "f:n:svh?", ifwi_delete},
1866 {"extract", "f:n:e:dsvh?", ifwi_extract},
1867 {"print", "dsh?", ifwi_print},
1868 {"replace", "f:n:e:dsvh?", ifwi_replace},
1871 static struct option long_options[] = {
1872 {"subpart_dentry", required_argument, 0, 'e'},
1873 {"file", required_argument, 0, 'f'},
1874 {"help", required_argument, 0, 'h'},
1875 {"name", required_argument, 0, 'n'},
1876 {"dir_ops", no_argument, 0, 'd'},
1877 {"verbose", no_argument, 0, 'v'},
1878 {"second_lbp", no_argument, 0, 's'},
1879 {NULL, 0, 0, 0 }
1882 static void usage(const char *name)
1884 printf("ifwitool: Utility for IFWI manipulation\n\n"
1885 "USAGE:\n"
1886 " %s [-h]\n"
1887 " %s FILE COMMAND [PARAMETERS]\n\n"
1888 "COMMANDs:\n"
1889 " add -f FILE -n NAME [-d -e ENTRY] [-s]\n"
1890 " create -f FILE [-s]\n"
1891 " delete -n NAME [-s]\n"
1892 " extract -f FILE -n NAME [-d -e ENTRY] [-s]\n"
1893 " print [-d] [-s]\n"
1894 " replace -f FILE -n NAME [-d -e ENTRY] [-s]\n"
1895 "OPTIONs:\n"
1896 " -f FILE : File to read/write/create/extract\n"
1897 " -s : Use the second Logical Boot Partition\n"
1898 " -d : Perform directory operation\n"
1899 " -e ENTRY: Name of directory entry to operate on\n"
1900 " -v : Verbose level\n"
1901 " -h : Help message\n"
1902 " -n NAME : Name of sub-partition to operate on\n",
1903 name, name
1906 printf("\nNAME should be one of:\n");
1907 int i;
1908 for (i = 0; i < MAX_SUBPARTS; i++)
1909 printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
1910 printf("\n");
1913 int main(int argc, char **argv)
1915 if (argc < 3) {
1916 usage(argv[0]);
1917 return 1;
1920 param.image_name = argv[1];
1921 param.logical_boot_partition = LBP1;
1922 char *cmd = argv[2];
1923 optind += 2;
1925 uint32_t i;
1927 for (i = 0; i < ARRAY_SIZE(commands); i++) {
1928 if (strcmp(cmd, commands[i].name) != 0)
1929 continue;
1931 int c;
1933 while (1) {
1934 int option_index;
1936 c = getopt_long(argc, argv, commands[i].optstring,
1937 long_options, &option_index);
1939 if (c == -1)
1940 break;
1942 /* Filter out illegal long options. */
1943 if (strchr(commands[i].optstring, c) == NULL) {
1944 ERROR("%s: invalid option -- '%c'\n", argv[0],
1946 c = '?';
1949 switch (c) {
1950 case 'n':
1951 param.subpart_name = optarg;
1952 break;
1953 case 's':
1954 param.logical_boot_partition = LBP2;
1955 break;
1956 case 'f':
1957 param.file_name = optarg;
1958 break;
1959 case 'd':
1960 param.dir_ops = 1;
1961 break;
1962 case 'e':
1963 param.dentry_name = optarg;
1964 break;
1965 case 'v':
1966 verbose++;
1967 break;
1968 case 'h':
1969 case '?':
1970 usage(argv[0]);
1971 return 1;
1972 default:
1973 break;
1977 if (ifwi_parse()) {
1978 ERROR("%s: ifwi parsing failed\n", argv[0]);
1979 return 1;
1982 enum ifwi_ret ret = commands[i].function();
1984 if (ret == COMMAND_ERR) {
1985 ERROR("%s: failed execution\n", argv[0]);
1986 return 1;
1989 if (ret == REPACK_REQUIRED)
1990 ifwi_repack();
1992 return 0;
1995 ERROR("%s: invalid command\n", argv[0]);
1996 return 1;