blob: 453d85c44b2acc03232a1caf0009f2eff18e6aae [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifwitool, CLI utility for IFWI manipulation */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Furquan Shaikh233f1b62016-05-19 16:12:16 -07003
Elyes Haouas898176a2022-10-14 10:01:05 +02004#include <commonlib/bsd/helpers.h>
Furquan Shaikh233f1b62016-05-19 16:12:16 -07005#include <commonlib/endian.h>
6#include <getopt.h>
7#include <stdlib.h>
8#include <time.h>
9
10#include "common.h"
11
12/*
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.
16 *
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.
20 *
21 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
22 * table.
23 */
24#define BPDT_SIGNATURE (0x000055AA)
25
Jeremy Compostella31e21882019-12-09 17:02:45 -070026#define LBP1 (0)
27#define LBP2 (1)
28
Furquan Shaikh233f1b62016-05-19 16:12:16 -070029/* Parameters passed in by caller. */
30static struct param {
31 const char *file_name;
Jeremy Compostella31e21882019-12-09 17:02:45 -070032 size_t logical_boot_partition;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070033 const char *subpart_name;
34 const char *image_name;
35 bool dir_ops;
36 const char *dentry_name;
37} param;
38
39struct bpdt_header {
40 /*
41 * This is used to identify start of BPDT. It should always be
42 * BPDT_SIGNATURE.
43 */
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;
Stefan Reinauer6a001132017-07-13 02:20:27 +020055} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070056#define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
57
58struct 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;
Stefan Reinauer6a001132017-07-13 02:20:27 +020067} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070068#define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
69
70struct bpdt {
71 struct bpdt_header h;
72 /* In practice, this could be an array of 0 to n entries. */
Elyes Haouasfc2f3042023-07-30 13:06:10 +020073 struct bpdt_entry e[];
Stefan Reinauer6a001132017-07-13 02:20:27 +020074} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070075
Werner Zeh310580e2016-06-24 13:03:38 +020076static inline size_t get_bpdt_size(struct bpdt_header *h)
Furquan Shaikh233f1b62016-05-19 16:12:16 -070077{
78 return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
79}
80
81/* Minimum size in bytes allocated to BPDT in IFWI. */
82#define BPDT_MIN_SIZE (512)
83
84/* Header to define directory header for sub-partition. */
85struct 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;
96 /*
Furquan Shaikhe51c20b2016-06-15 08:01:10 -070097 * 2s complement of 8-bit sum from first byte of header to last byte of
98 * last directory entry.
Furquan Shaikh233f1b62016-05-19 16:12:16 -070099 */
100 uint8_t checksum;
101 /* ASCII short name of sub-partition. */
102 uint8_t name[4];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200103} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700104#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
109
110/* Structure for each directory entry for sub-partition. */
111struct 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;
Stefan Reinauer6a001132017-07-13 02:20:27 +0200120} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700121#define SUBPART_DIR_ENTRY_SIZE \
122 (sizeof(struct subpart_dir_entry))
123
124struct subpart_dir {
125 struct subpart_dir_header h;
126 /* In practice, this could be an array of 0 to n entries. */
Elyes Haouasfc2f3042023-07-30 13:06:10 +0200127 struct subpart_dir_entry e[];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200128} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700129
130static inline size_t subpart_dir_size(struct subpart_dir_header *h)
131{
132 return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
133}
134
135struct 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];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200154} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700155
156#define DWORD_SIZE 4
157#define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
158#define MANIFEST_ID_MAGIC (0x324e4d24)
159
160struct 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];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200167} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700168
169#define MODULE_SIZE (sizeof(struct module))
170
171struct 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];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200179} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700180
181#define SIGNED_PKG_INFO_EXT_TYPE 0x15
182#define SIGNED_PKG_INFO_EXT_SIZE \
183 (sizeof(struct signed_pkg_info_ext))
184
185/*
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.
194 */
195enum 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),
201};
202
203/* Type value for various IFWI sub-partitions. */
204enum 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,
225};
226
227/*
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.
231 *
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.
236 */
237const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700238 /* Order of the following entries is mandatory. */
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700239 CSE_IDLM_TYPE,
240 IFP_OVERRIDE_TYPE,
241 S_BPDT_TYPE,
242 CSE_RBE_TYPE,
243 UFS_PHY_TYPE,
244 UFS_GPP_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700245 /* Order of the following entries is recommended. */
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700246 UEP_TYPE,
247 NVM_CONFIG_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700248 UFS_RATE_B_TYPE,
249 IBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700250 SMIP_TYPE,
251 PMC_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700252 CSE_BUP_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700253 UCODE_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700254 DEBUG_TOKENS_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700255 IUNIT_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700256 CSE_MAIN_TYPE,
257 ISH_TYPE,
258 OBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700259};
260
261const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700262 /* Order of the following entries is mandatory. */
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700263 UFS_GPP_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700264 UFS_PHY_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700265 IFP_OVERRIDE_TYPE,
266 UEP_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700267 NVM_CONFIG_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700268 UFS_RATE_B_TYPE,
269 /* Order of the following entries is recommended. */
270 IBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700271 SMIP_TYPE,
272 CSE_RBE_TYPE,
273 PMC_TYPE,
274 CSE_BUP_TYPE,
275 UCODE_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700276 CSE_IDLM_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700277 DEBUG_TOKENS_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700278 S_BPDT_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700279 IUNIT_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700280 CSE_MAIN_TYPE,
281 ISH_TYPE,
282 OBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700283};
284
285/* Utility functions. */
286enum ifwi_ret {
287 COMMAND_ERR = -1,
288 NO_ACTION_REQUIRED = 0,
289 REPACK_REQUIRED = 1,
290};
291
292struct dir_ops {
293 enum ifwi_ret (*dir_add)(int);
294};
295
296static enum ifwi_ret ibbp_dir_add(int);
297
298const 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 */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700305 [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700306 /* CSE RBE */
307 [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700308 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700309 /* CSE BUP */
310 [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700311 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700312 /* uCode */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700313 [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700314 /* IBB */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700315 [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700316 /* S-BPDT */
317 [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700318 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700319 /* OBB */
320 [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700321 NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700322 /* CSE Main */
323 [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700324 NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700325 /* ISH */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700326 [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700327 /* CSE IDLM */
328 [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700329 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700330 /* IFP Override */
331 [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
332 LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700333 {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700334 /* Debug Tokens */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700335 [DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700336 /* UFS Phy Configuration */
337 [UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700338 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700339 /* UFS GPP LUN ID */
340 [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700341 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700342 /* PMC */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700343 [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700344 /* IUNIT */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700345 [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700346 /* NVM Config */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700347 [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700348 /* UEP */
349 [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700350 {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700351 /* UFS Rate B Config */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700352 [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700353};
354
355struct ifwi_image {
356 /* Data read from input file. */
357 struct buffer input_buff;
358
359 /* BPDT header and entries. */
360 struct buffer bpdt;
361 size_t input_ifwi_start_offset;
362 size_t input_ifwi_end_offset;
363
364 /* Subpartition content. */
365 struct buffer subpart_buf[MAX_SUBPARTS];
366} ifwi_image;
367
368static void alloc_buffer(struct buffer *b, size_t s, const char *n)
369{
370 if (buffer_create(b, s, n) == 0)
371 return;
372
373 ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
374 exit(-1);
375}
376
377/*
378 * Read header/entry members in little-endian format.
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100379 * Returns the offset up to which the read was performed.
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700380*/
381static size_t read_member(void *src, size_t offset, size_t size_bytes,
382 void *dst)
383{
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);
400 }
401
402 return (offset + size_bytes);
403}
404
405/*
406 * Convert to little endian format.
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100407 * Returns the offset up to which the fixup was performed.
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700408 */
409static size_t fix_member(void *data, size_t offset, size_t size_bytes)
410{
411 uint8_t *src = (uint8_t *)data + offset;
412
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);
429 }
430 return (offset + size_bytes);
431}
432
433
434static void print_subpart_dir(struct subpart_dir *s)
435{
436 if (verbose == 0)
437 return;
438
439 size_t i;
440
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]);
450
451 printf("\n");
452
453 printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
454 "Length", "Rsvd");
455
456 printf("=============================================================="
457 "===========================================================\n");
458
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);
463 }
464
465 printf("=============================================================="
466 "===========================================================\n");
467}
468
469static void bpdt_print_header(struct bpdt_header *h, const char *name)
470{
471 if (verbose == 0)
472 return;
473
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);
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700480 printf("%-25s 0x%-23llx\n", "FIT Tool Version",
481 (long long)h->fit_tool_version);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700482}
483
484static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
485 const char *name)
486{
487 if (verbose == 0)
488 return;
489
490 printf("%s entries\n", name);
491
492 printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
493 "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
494 "File Offset");
495
496 printf("=============================================================="
497 "=============================================================="
498 "=============================================================="
499 "===============\n");
500
501
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);
509 }
510
511 printf("=============================================================="
512 "=============================================================="
513 "=============================================================="
514 "===============\n");
515
516}
517
518static void bpdt_validate_header(struct bpdt_header *h, const char *name)
519{
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700520 assert(h->signature == BPDT_SIGNATURE);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700521
522 if (h->bpdt_version != 1) {
523 ERROR("Invalid header : %s\n", name);
524 exit(-1);
525 }
526
527 DEBUG("Validated header : %s\n", name);
528}
529
530static void bpdt_read_header(void *data, struct bpdt_header *h,
531 const char *name)
532{
533 size_t offset = 0;
534
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);
Paul Menzeldeb9b032017-03-08 10:51:52 +0100544 read_member(data, offset, sizeof(h->fit_tool_version),
545 &h->fit_tool_version);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700546
547 bpdt_validate_header(h, name);
548 bpdt_print_header(h, name);
549}
550
551static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
552{
553 size_t i, offset = 0;
554 struct bpdt_entry *e = &bpdt->e[0];
555 size_t count = bpdt->h.descriptor_count;
556
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);
566 }
567
568 bpdt_print_entries(e, count, name);
569}
570
571/*
572 * Given type of sub-partition, identify BPDT entry for it.
573 * Sub-Partition could lie either within BPDT or S-BPDT.
574 */
575static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
576 size_t count, int type)
577{
578 size_t i;
579 for (i = 0; i < count; i++) {
580 if (e[i].type == type)
581 break;
582 }
583
584 if (i == count)
585 return NULL;
586
587 return &e[i];
588}
589
590static struct bpdt_entry *find_entry_by_type(int type)
591{
592 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
593 if (b == NULL)
594 return NULL;
595
596 struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
597 b->h.descriptor_count,
598 type);
599
600 if (curr)
601 return curr;
602
603 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
604 if (b == NULL)
605 return NULL;
606
607 return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
608}
609
610/*
611 * Find sub-partition type given its name. If the name does not exist, returns
612 * -1.
613 */
614static int find_type_by_name(const char *name)
615{
616 int i;
617
618 for (i = 0; i < MAX_SUBPARTS; i++) {
619 if ((strlen(subparts[i].name) == strlen(name)) &&
620 (!strcmp(subparts[i].name, name)))
621 break;
622 }
623
624 if (i == MAX_SUBPARTS) {
625 ERROR("Invalid sub-partition name %s.\n", name);
626 return -1;
627 }
628
629 return i;
630}
631
632/*
633 * Read the content of a sub-partition from input file and store it in
634 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
635 *
636 * Returns the maximum offset occupied by the sub-partitions.
637 */
638static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
639 size_t count)
640{
641 size_t i, type;
642 struct buffer *buf;
643 size_t max_offset = 0;
644
645 for (i = 0; i < count; i++) {
646 type = e[i].type;
647
648 if (type >= MAX_SUBPARTS) {
649 ERROR("Invalid sub-partition type %zd.\n", type);
650 exit(-1);
651 }
652
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);
657 }
658
659 if (e[i].size == 0) {
660 INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
661 subparts[type].name);
662 continue;
663 }
664
665 assert((e[i].offset + e[i].size) <= size);
666
667 /*
668 * Sub-partitions in IFWI image are not in the same order as
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100669 * in BPDT entries. BPDT entries are in header_order whereas
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700670 * sub-partition offsets in the image are in pack_order.
671 */
672 if ((e[i].offset + e[i].size) > max_offset)
673 max_offset = e[i].offset + e[i].size;
674
675 /*
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.
683 */
684 if (type == S_BPDT_TYPE)
685 continue;
686
687 buf = &ifwi_image.subpart_buf[type];
688
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);
692 }
693
694 assert(max_offset);
695 return max_offset;
696}
697
698/*
699 * Allocate buffer for bpdt header, entries and all sub-partition content.
700 * Returns offset in data where BPDT ends.
701 */
702static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
703 struct buffer *b, const char *name)
704{
705 struct bpdt_header bpdt_header;
706 assert((offset + BPDT_HEADER_SIZE) < size);
707 bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
708
709 /* Buffer to read BPDT header and entries. */
Werner Zeh310580e2016-06-24 13:03:38 +0200710 alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700711
712 struct bpdt *bpdt = buffer_get(b);
713 memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
714
715 /*
716 * If no entries are present, maximum offset occupied is (offset +
717 * BPDT_HEADER_SIZE).
718 */
719 if (bpdt->h.descriptor_count == 0)
720 return (offset + BPDT_HEADER_SIZE);
721
722 /* Read all entries. */
Werner Zeh310580e2016-06-24 13:03:38 +0200723 assert((offset + get_bpdt_size(&bpdt->h)) < size);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700724 bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
725 name);
726
727 /* Read all sub-partition content in subpart_buf. */
728 return read_subpart_buf(data, size, &bpdt->e[0],
729 bpdt->h.descriptor_count);
730}
731
732static void parse_sbpdt(void *data, size_t size)
733{
734 struct bpdt_entry *s;
735 s = find_entry_by_type(S_BPDT_TYPE);
736 if (!s)
737 return;
738
739 assert(size > s->offset);
740
741 alloc_bpdt_buffer(data, size, s->offset,
742 &ifwi_image.subpart_buf[S_BPDT_TYPE],
743 "S-BPDT");
744}
745
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700746static uint8_t calc_checksum(struct subpart_dir *s)
747{
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;
752
753 uint8_t old_checksum = s->h.checksum;
754 s->h.checksum = 0;
755
756 for (i = 0; i < size; i++)
757 checksum += data[i];
758
759 s->h.checksum = old_checksum;
760
761 /* 2s complement */
762 return -checksum;
763}
764
765static void validate_subpart_dir(struct subpart_dir *s, const char *name,
766 bool checksum_check)
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700767{
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);
774 }
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700775
776 if (checksum_check == false)
777 return;
778
779 uint8_t checksum = calc_checksum(s);
780
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);
784}
785
786static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
787 const char *name)
788{
789 validate_subpart_dir(s, name, 0);
790}
791
792static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
793 const char *name)
794{
795 validate_subpart_dir(s, name, 1);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700796}
797
798static void parse_subpart_dir(struct buffer *subpart_dir_buf,
799 struct buffer *input_buf, const char *name)
800{
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);
805
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);
820
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700821 validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700822
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);
826
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);
840 }
841
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700842 validate_subpart_dir_with_checksum(subpart_dir, name);
843
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700844 print_subpart_dir(subpart_dir);
845}
846
Jeremy Compostella31e21882019-12-09 17:02:45 -0700847/* Parse the bpdt entries to compute the size of the BPDT */
848static size_t bpdt_size(void *data)
849{
850 struct bpdt *b = (struct bpdt *)data;
851 size_t i, size = 0;
852
853 for (i = 0; i < b->h.descriptor_count; i++)
854 size = MAX(size, b->e[i].offset + b->e[i].size);
855
856 return size;
857}
858
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700859/* Parse input image file to identify different sub-partitions. */
860static int ifwi_parse(void)
861{
862 DEBUG("Parsing IFWI image...\n");
863 const char *image_name = param.image_name;
864
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;
870 }
871
872 INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
873
874 /* Look for BPDT signature at 4K intervals. */
Jeremy Compostella31e21882019-12-09 17:02:45 -0700875 size_t offset = 0, lbp = LBP1;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700876 void *data = buffer_get(buff);
877
878 while (offset < buffer_size(buff)) {
Jeremy Compostella31e21882019-12-09 17:02:45 -0700879 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;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700886 }
887
888 if (offset >= buffer_size(buff)) {
Jeremy Compostella31e21882019-12-09 17:02:45 -0700889 ERROR("Image does not contain BPDT for LBP=%zd!!\n",
890 param.logical_boot_partition);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700891 return -1;
892 }
893
894 ifwi_image.input_ifwi_start_offset = offset;
895 INFO("BPDT starts at offset 0x%zx.\n", offset);
896
897 data = (uint8_t *)data + offset;
898 size_t ifwi_size = buffer_size(buff) - offset;
899
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");
904
905 /* Parse S-BPDT, if any. */
906 parse_sbpdt(data, ifwi_size);
907
908 /*
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.
912 */
Elyes Haouas898176a2022-10-14 10:01:05 +0200913 ifwi_image.input_ifwi_end_offset = ALIGN_UP(end_offset, 4 * KiB);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700914 DEBUG("Parsing done.\n");
915
916 return 0;
917}
918
919/*
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.
924 */
925static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
926{
927 size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
928 assert(size >= bpdt_size);
929
930 /*
931 * If buffer does not have the required size, allocate a fresh buffer.
932 */
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;
939 }
940
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;
944
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);
949
950 bpdt->h.descriptor_count = count;
951}
952
953static void bpdt_reset(void)
954{
955 size_t i;
956 size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
957
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++;
964 }
965 continue;
966 }
967
968 if (subparts[i].attr & NON_CRITICAL_SUBPART)
969 sbpdt_count++;
970 else
971 bpdt_count++;
972 }
973
974 DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
975 dummy_bpdt_count, sbpdt_count);
976
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);
981
982 /* Update S-BPDT if required. */
Elyes Haouas898176a2022-10-14 10:01:05 +0200983 bpdt_size = ALIGN_UP(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700984 4 * KiB);
985 __bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
986 bpdt_size);
987}
988
989/* Initialize BPDT entries in header order. */
990static void bpdt_entries_init_header_order(void)
991{
992 int i, type;
993 size_t size;
994
995 struct bpdt *bpdt, *sbpdt, *curr;
996 size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
997
998 bpdt = buffer_get(&ifwi_image.bpdt);
999 sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1000
1001 for (i = 0; i < MAX_SUBPARTS; i++) {
1002 type = bpdt_header_order[i];
1003 size = buffer_size(&ifwi_image.subpart_buf[type]);
1004
1005 if ((size == 0) && !(subparts[type].attr &
1006 MANDATORY_BPDT_ENTRY))
1007 continue;
1008
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;
1015 }
1016
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;
1022
1023 (*count_ptr)++;
1024 }
1025}
1026
1027static void pad_buffer(struct buffer *b, size_t size)
1028{
1029 size_t buff_size = buffer_size(b);
1030
1031 assert(buff_size <= size);
1032
1033 if (buff_size == size)
1034 return;
1035
1036 struct buffer temp;
1037 alloc_buffer(&temp, size, b->name);
1038 uint8_t *data = buffer_get(&temp);
1039
1040 memcpy(data, buffer_get(b), buff_size);
1041 memset(data + buff_size, 0xFF, size - buff_size);
1042
1043 *b = temp;
1044}
1045
1046/* Initialize offsets of entries using pack order. */
1047static void bpdt_entries_init_pack_order(void)
1048{
1049 int i, type;
1050 struct bpdt_entry *curr;
1051 size_t curr_offset, curr_end;
1052
1053 curr_offset = MAX(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
1054
1055 /*
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
1059 *
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.
1066 *
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.
1070 */
1071
1072 /* #1 Sub-partitions that lie within same 4K as BPDT. */
1073 struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1074
1075 for (i = 0; i < MAX_SUBPARTS; i++) {
1076 type = bpdt_pack_order[i];
1077 curr = find_entry_by_type(type);
1078
1079 if ((curr == NULL) || (curr->size == 0))
1080 continue;
1081
1082 if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1083 continue;
1084
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]));
1092 }
1093
1094 /* Pad ff bytes if there is any empty space left in BPDT 4K. */
Elyes Haouas898176a2022-10-14 10:01:05 +02001095 curr_end = ALIGN_UP(curr_offset, 4 * KiB);
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001096 pad_buffer(last_bpdt_buff,
1097 buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
1098 curr_offset = curr_end;
1099
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);
1104
1105 if ((curr == NULL) || (curr->size == 0))
1106 continue;
1107
1108 if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1109 continue;
1110
Elyes Haouas898176a2022-10-14 10:01:05 +02001111 assert(curr_offset == ALIGN_UP(curr_offset, 4 * KiB));
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001112 curr->offset = curr_offset;
Elyes Haouas898176a2022-10-14 10:01:05 +02001113 curr_end = ALIGN_UP(curr->offset + curr->size, 4 * KiB);
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001114 curr->size = curr_end - curr->offset;
1115
1116 pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1117
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]));
1123 }
1124
1125 /*
1126 * Update size of S-BPDT to include size of all non-critical
1127 * sub-partitions.
1128 *
1129 * Assumption: S-BPDT always lies at the end of IFWI image.
1130 */
1131 curr = find_entry_by_type(S_BPDT_TYPE);
1132 assert(curr);
1133
Elyes Haouas898176a2022-10-14 10:01:05 +02001134 assert(curr_offset == ALIGN_UP(curr_offset, 4 * KiB));
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001135 curr->size = curr_offset - curr->offset;
1136}
1137
1138/* Convert all members of BPDT to little-endian format. */
1139static void bpdt_fixup_write_buffer(struct buffer *buf)
1140{
1141 struct bpdt *s = buffer_get(buf);
1142
1143 struct bpdt_header *h = &s->h;
1144 struct bpdt_entry *e = &s->e[0];
1145
1146 size_t count = h->descriptor_count;
1147
1148 size_t offset = 0;
1149
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));
1159
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));
1166 }
1167}
1168
1169/* Write BPDT to output buffer after fixup. */
1170static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1171{
1172 bpdt_fixup_write_buffer(src);
1173 memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1174}
1175
1176/*
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.
1182 *
1183 * While performing the above steps, make sure that any empty holes are filled
1184 * with FF.
1185 */
1186static void ifwi_write(const char *image_name)
1187{
1188 struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1189 assert(s);
1190
1191 size_t ifwi_start, ifwi_end, file_end;
1192
1193 ifwi_start = ifwi_image.input_ifwi_start_offset;
Elyes Haouas898176a2022-10-14 10:01:05 +02001194 ifwi_end = ifwi_start + ALIGN_UP(s->offset + s->size, 4 * KiB);
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001195 file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
1196 ifwi_image.input_ifwi_end_offset);
1197
1198 struct buffer b;
1199
1200 alloc_buffer(&b, file_end, "Final-IFWI");
1201
1202 uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1203 uint8_t *output_data = buffer_get(&b);
1204
1205 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1206 ifwi_end, file_end);
1207
1208 /* Copy non-IFWI prefix, if any. */
1209 memcpy(output_data, input_data, ifwi_start);
1210
1211 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1212
1213 struct buffer ifwi;
1214 buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1215 uint8_t *ifwi_data = buffer_get(&ifwi);
1216
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];
1223
1224 if (type == S_BPDT_TYPE)
1225 continue;
1226
1227 curr = find_entry_by_type(type);
1228
1229 if ((curr == NULL) || (curr->size == 0))
1230 continue;
1231
1232 subpart_buf = &ifwi_image.subpart_buf[type];
1233
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));
1237
1238 assert((curr->offset + buffer_size(subpart_buf)) <=
1239 buffer_size(&ifwi));
1240
1241 memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1242 buffer_size(subpart_buf));
1243 }
1244
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);
1252 }
1253
1254 /*
1255 * Convert BPDT to little-endian format and write it to output buffer.
1256 * S-BPDT is written first and then BPDT.
1257 */
1258 bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1259 bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1260
1261 if (buffer_write_file(&b, image_name)) {
1262 ERROR("File write error\n");
1263 exit(-1);
1264 }
1265
1266 buffer_delete(&b);
1267 printf("Image written successfully to %s.\n", image_name);
1268}
1269
1270/*
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.
1274 */
1275static void ifwi_repack(void)
1276{
1277 bpdt_reset();
1278 bpdt_entries_init_header_order();
1279 bpdt_entries_init_pack_order();
1280
1281 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1282 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1283
1284 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1285 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1286
1287 DEBUG("Repack done.. writing image.\n");
1288 ifwi_write(param.image_name);
1289}
1290
1291static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1292 size_t count, const char *name)
1293{
1294 memset(hdr, 0, sizeof(*hdr));
1295
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));
1302}
1303
1304static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1305 struct buffer *b, size_t offset)
1306{
1307 memset(e, 0, sizeof(*e));
1308
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);
1313
1314 return (offset + buffer_size(b));
1315}
1316
1317static void init_manifest_header(struct manifest_header *hdr, size_t size)
1318{
1319 memset(hdr, 0, sizeof(*hdr));
1320
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;
1326
1327 struct tm *local_time;
1328 time_t curr_time;
1329 char buffer[11];
1330
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);
1335
1336 assert((size % DWORD_SIZE) == 0);
1337 hdr->size = size / DWORD_SIZE;
1338 hdr->id = MANIFEST_ID_MAGIC;
1339}
1340
1341static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1342 size_t count, const char *name)
1343{
1344 memset(ext, 0, sizeof(*ext));
1345
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));
1349}
1350
1351static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1352{
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];
1356
1357 size_t count = h->num_entries;
1358 size_t offset = 0;
1359
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);
1370
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));
1377 }
1378}
1379
1380static void create_subpart(struct buffer *dst, struct buffer *info[],
1381 size_t count, const char *name)
1382{
1383 struct buffer subpart_dir_buff;
1384 size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1385
1386 alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1387
1388 struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1389 struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1390
1391 init_subpart_dir_header(h, count, name);
1392
1393 size_t curr_offset = size;
1394 size_t i;
1395
1396 for (i = 0; i < count; i++) {
1397 curr_offset = init_subpart_dir_entry(&e[i], info[i],
1398 curr_offset);
1399 }
1400
1401 alloc_buffer(dst, curr_offset, name);
1402 uint8_t *data = buffer_get(dst);
1403
1404 for (i = 0; i < count; i++) {
1405 memcpy(data + e[i].offset, buffer_get(info[i]),
1406 buffer_size(info[i]));
1407 }
1408
Furquan Shaikhe51c20b2016-06-15 08:01:10 -07001409 h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001410
1411 struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1412
1413 print_subpart_dir(dir);
1414
1415 subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1416 memcpy(data, dir, buffer_size(&subpart_dir_buff));
1417
1418 buffer_delete(&subpart_dir_buff);
1419}
1420
1421static enum ifwi_ret ibbp_dir_add(int type)
1422{
1423#define DUMMY_IBB_SIZE (4 * KiB)
1424
Furquan Shaikh55d2e532016-05-31 11:02:47 -07001425 assert(type == IBB_TYPE);
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001426
1427 /*
1428 * Entry # 1 - IBBP.man
1429 * Contains manifest header and signed pkg info extension.
1430 */
1431 struct buffer manifest;
1432 size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1433 alloc_buffer(&manifest, size, "IBBP.man");
1434
1435 struct manifest_header *man_hdr = buffer_get(&manifest);
1436 init_manifest_header(man_hdr, size);
1437
1438 struct signed_pkg_info_ext *ext;
1439 ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1440
1441 init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1442
1443 /* Entry # 2 - IBBL */
1444 struct buffer ibbl;
1445 if (buffer_from_file(&ibbl, param.file_name))
1446 return COMMAND_ERR;
1447
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);
1452
1453 /* Create subpartition. */
1454 struct buffer *info[] = {
1455 &manifest, &ibbl, &ibb,
1456 };
1457 create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1458 ARRAY_SIZE(info), subparts[type].name);
1459
1460 return REPACK_REQUIRED;
1461}
1462
1463static enum ifwi_ret ifwi_raw_add(int type)
1464{
1465 if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1466 return COMMAND_ERR;
1467
1468 printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1469 type, param.file_name);
1470 return REPACK_REQUIRED;
1471}
1472
1473static enum ifwi_ret ifwi_dir_add(int type)
1474{
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;
1480 }
1481
1482 if (!param.dentry_name) {
1483 ERROR("%s: -e option required\n", __func__);
1484 return COMMAND_ERR;
1485 }
1486
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");
1494
1495 return ret;
1496}
1497
1498static enum ifwi_ret ifwi_add(void)
1499{
1500 if (!param.file_name) {
1501 ERROR("%s: -f option required\n", __func__);
1502 return COMMAND_ERR;
1503 }
1504
1505 if (!param.subpart_name) {
1506 ERROR("%s: -n option required\n", __func__);
1507 return COMMAND_ERR;
1508 }
1509
1510 int type = find_type_by_name(param.subpart_name);
1511 if (type == -1)
1512 return COMMAND_ERR;
1513
1514 const struct subpart_info *curr_subpart = &subparts[type];
1515
1516 if (curr_subpart->attr & AUTO_GENERATED) {
1517 ERROR("Cannot add auto-generated sub-partitions.\n");
1518 return COMMAND_ERR;
1519 }
1520
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;
1525 }
1526
1527 if (param.dir_ops)
1528 return ifwi_dir_add(type);
1529
1530 return ifwi_raw_add(type);
1531}
1532
1533static enum ifwi_ret ifwi_delete(void)
1534{
1535 if (!param.subpart_name) {
1536 ERROR("%s: -n option required\n", __func__);
1537 return COMMAND_ERR;
1538 }
1539
1540 int type = find_type_by_name(param.subpart_name);
1541 if (type == -1)
1542 return COMMAND_ERR;
1543
1544 const struct subpart_info *curr_subpart = &subparts[type];
1545
1546 if (curr_subpart->attr & AUTO_GENERATED) {
1547 ERROR("Cannot delete auto-generated sub-partitions.\n");
1548 return COMMAND_ERR;
1549 }
1550
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;
1555 }
1556
1557 buffer_delete(&ifwi_image.subpart_buf[type]);
1558 printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1559 return REPACK_REQUIRED;
1560}
1561
1562static enum ifwi_ret ifwi_dir_extract(int type)
1563{
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;
1568 }
1569
1570 if (!param.dentry_name) {
1571 ERROR("%s: -e option required.\n", __func__);
1572 return COMMAND_ERR;
1573 }
1574
1575 struct buffer subpart_dir_buff;
1576 parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1577 subparts[type].name);
1578
1579 uint32_t i;
1580 struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1581
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;
1586 }
1587
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);
1592 }
1593
1594 struct buffer dst;
1595
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);
1600
1601 if (buffer_write_file(&dst, param.file_name))
1602 return COMMAND_ERR;
1603
1604 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1605 param.subpart_name, type, param.dentry_name, param.file_name);
1606
1607 return NO_ACTION_REQUIRED;
1608}
1609
1610static enum ifwi_ret ifwi_raw_extract(int type)
1611{
1612 if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1613 return COMMAND_ERR;
1614
1615 printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1616 param.file_name);
1617
1618 return NO_ACTION_REQUIRED;
1619}
1620
1621static enum ifwi_ret ifwi_extract(void)
1622{
1623 if (!param.file_name) {
1624 ERROR("%s: -f option required\n", __func__);
1625 return COMMAND_ERR;
1626 }
1627
1628 if (!param.subpart_name) {
1629 ERROR("%s: -n option required\n", __func__);
1630 return COMMAND_ERR;
1631 }
1632
1633 int type = find_type_by_name(param.subpart_name);
1634 if (type == -1)
1635 return COMMAND_ERR;
1636
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;
1641 }
1642
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;
1647 }
1648
1649 INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1650 if (param.dir_ops)
1651 return ifwi_dir_extract(type);
1652
1653 return ifwi_raw_extract(type);
1654}
1655
1656static enum ifwi_ret ifwi_print(void)
1657{
1658 verbose += 2;
1659
1660 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1661
1662 bpdt_print_header(&b->h, "BPDT");
1663 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1664
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");
1668
1669 if (param.dir_ops == 0) {
1670 verbose -= 2;
1671 return NO_ACTION_REQUIRED;
1672 }
1673
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;
1680
1681 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1682 subparts[i].name);
1683 buffer_delete(&subpart_dir_buf);
1684 }
1685
1686 verbose -= 2;
1687
1688 return NO_ACTION_REQUIRED;
1689}
1690
1691static enum ifwi_ret ifwi_raw_replace(int type)
1692{
1693 buffer_delete(&ifwi_image.subpart_buf[type]);
1694 return ifwi_raw_add(type);
1695}
1696
1697static enum ifwi_ret ifwi_dir_replace(int type)
1698{
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;
1703 }
1704
1705 if (!param.dentry_name) {
1706 ERROR("%s: -e option required.\n", __func__);
1707 return COMMAND_ERR;
1708 }
1709
1710 struct buffer subpart_dir_buf;
1711 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
1712 subparts[type].name);
1713
1714 uint32_t i;
1715 struct subpart_dir *s = buffer_get(&subpart_dir_buf);
1716
1717 for (i = 0; i < s->h.num_entries; i++) {
1718 if (!strcmp((char *)s->e[i].name, param.dentry_name))
1719 break;
1720 }
1721
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);
1726 }
1727
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);
1732 }
1733
1734 struct buffer dst;
Rolf Evers-Fischereb8b7d62016-06-13 13:51:41 +02001735 size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
1736 buffer_size(&b) - s->e[i].length;
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001737 size_t subpart_start = s->e[i].offset;
1738 size_t subpart_end = s->e[i].offset + s->e[i].length;
1739
1740 alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
1741
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;
1745
1746 /* Copy data before the sub-partition entry. */
1747 memcpy(dst_data + curr_offset, src_data, subpart_start);
1748 curr_offset += subpart_start;
1749
1750 /* Copy sub-partition entry. */
1751 memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
1752 curr_offset += buffer_size(&b);
1753
1754 /* Copy remaining data. */
1755 memcpy(dst_data + curr_offset, src_data + subpart_end,
1756 buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
1757
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;
1762
1763 /* Update length of entry in the subpartition. */
1764 s->e[i].length = buffer_size(&b);
1765 buffer_delete(&b);
1766
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;
1771 }
1772
Furquan Shaikhe51c20b2016-06-15 08:01:10 -07001773 /* Re-calculate checksum. */
1774 s->h.checksum = calc_checksum(s);
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001775
1776 /* Convert members to litte-endian. */
1777 subpart_dir_fixup_write_buffer(&subpart_dir_buf);
1778
1779 memcpy(dst_data, buffer_get(&subpart_dir_buf),
1780 buffer_size(&subpart_dir_buf));
1781
1782 buffer_delete(&subpart_dir_buf);
1783
1784 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
1785 param.subpart_name, type, param.dentry_name, param.file_name);
1786
1787 return REPACK_REQUIRED;
1788}
1789
1790static enum ifwi_ret ifwi_replace(void)
1791{
1792 if (!param.file_name) {
1793 ERROR("%s: -f option required\n", __func__);
1794 return COMMAND_ERR;
1795 }
1796
1797 if (!param.subpart_name) {
1798 ERROR("%s: -n option required\n", __func__);
1799 return COMMAND_ERR;
1800 }
1801
1802 int type = find_type_by_name(param.subpart_name);
1803 if (type == -1)
1804 return COMMAND_ERR;
1805
1806 const struct subpart_info *curr_subpart = &subparts[type];
1807
1808 if (curr_subpart->attr & AUTO_GENERATED) {
1809 ERROR("Cannot replace auto-generated sub-partitions.\n");
1810 return COMMAND_ERR;
1811 }
1812
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;
1817 }
1818
1819 if (param.dir_ops)
1820 return ifwi_dir_replace(type);
1821
1822 return ifwi_raw_replace(type);
1823}
1824
1825static enum ifwi_ret ifwi_create(void)
1826{
1827 /*
1828 * Create peels off any non-IFWI content present in the input buffer and
1829 * creates output file with only the IFWI present.
1830 */
1831
1832 if (!param.file_name) {
1833 ERROR("%s: -f option required\n", __func__);
1834 return COMMAND_ERR;
1835 }
1836
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);
1844
1845 /*
1846 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
1847 */
1848 ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
1849 ifwi_image.input_ifwi_start_offset = 0;
1850
1851 param.image_name = param.file_name;
1852
1853 return REPACK_REQUIRED;
1854}
1855
1856struct command {
1857 const char *name;
1858 const char *optstring;
1859 enum ifwi_ret (*function)(void);
1860};
1861
1862static const struct command commands[] = {
Jeremy Compostella31e21882019-12-09 17:02:45 -07001863 {"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},
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001869};
1870
1871static 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'},
Jeremy Compostella31e21882019-12-09 17:02:45 -07001878 {"second_lbp", no_argument, 0, 's'},
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001879 {NULL, 0, 0, 0 }
1880};
1881
1882static void usage(const char *name)
1883{
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"
Jeremy Compostella31e21882019-12-09 17:02:45 -07001889 " 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"
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001895 "OPTIONs:\n"
1896 " -f FILE : File to read/write/create/extract\n"
Jeremy Compostella31e21882019-12-09 17:02:45 -07001897 " -s : Use the second Logical Boot Partition\n"
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001898 " -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
1904 );
1905
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");
1911}
1912
1913int main(int argc, char **argv)
1914{
1915 if (argc < 3) {
1916 usage(argv[0]);
1917 return 1;
1918 }
1919
1920 param.image_name = argv[1];
Jeremy Compostella31e21882019-12-09 17:02:45 -07001921 param.logical_boot_partition = LBP1;
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001922 char *cmd = argv[2];
1923 optind += 2;
1924
1925 uint32_t i;
1926
1927 for (i = 0; i < ARRAY_SIZE(commands); i++) {
1928 if (strcmp(cmd, commands[i].name) != 0)
1929 continue;
1930
1931 int c;
1932
1933 while (1) {
1934 int option_index;
1935
1936 c = getopt_long(argc, argv, commands[i].optstring,
1937 long_options, &option_index);
1938
1939 if (c == -1)
1940 break;
1941
1942 /* Filter out illegal long options. */
1943 if (strchr(commands[i].optstring, c) == NULL) {
1944 ERROR("%s: invalid option -- '%c'\n", argv[0],
1945 c);
1946 c = '?';
1947 }
1948
Furquan Shaikh55d2e532016-05-31 11:02:47 -07001949 switch (c) {
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001950 case 'n':
1951 param.subpart_name = optarg;
1952 break;
Jeremy Compostella31e21882019-12-09 17:02:45 -07001953 case 's':
1954 param.logical_boot_partition = LBP2;
1955 break;
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001956 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;
1974 }
1975 }
1976
1977 if (ifwi_parse()) {
1978 ERROR("%s: ifwi parsing failed\n", argv[0]);
1979 return 1;
1980 }
1981
1982 enum ifwi_ret ret = commands[i].function();
1983
1984 if (ret == COMMAND_ERR) {
1985 ERROR("%s: failed execution\n", argv[0]);
1986 return 1;
1987 }
1988
1989 if (ret == REPACK_REQUIRED)
1990 ifwi_repack();
1991
1992 return 0;
1993 }
1994
1995 ERROR("%s: invalid command\n", argv[0]);
1996 return 1;
1997}