blob: 8eda4c77b168b376b89775ba6a03f94de4231a7c [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
4#include <commonlib/endian.h>
5#include <getopt.h>
6#include <stdlib.h>
7#include <time.h>
8
9#include "common.h"
10
11/*
12 * BPDT is Boot Partition Descriptor Table. It is located at the start of a
13 * logical boot partition(LBP). It stores information about the critical
14 * sub-partitions present within the LBP.
15 *
16 * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
17 * critical sub-partitions and contains information about the non-critical
18 * sub-partitions present within the LBP.
19 *
20 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
21 * table.
22 */
23#define BPDT_SIGNATURE (0x000055AA)
24
Jeremy Compostella31e21882019-12-09 17:02:45 -070025#define LBP1 (0)
26#define LBP2 (1)
27
Furquan Shaikh233f1b62016-05-19 16:12:16 -070028/* Parameters passed in by caller. */
29static struct param {
30 const char *file_name;
Jeremy Compostella31e21882019-12-09 17:02:45 -070031 size_t logical_boot_partition;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070032 const char *subpart_name;
33 const char *image_name;
34 bool dir_ops;
35 const char *dentry_name;
36} param;
37
38struct bpdt_header {
39 /*
40 * This is used to identify start of BPDT. It should always be
41 * BPDT_SIGNATURE.
42 */
43 uint32_t signature;
44 /* Count of BPDT entries present. */
45 uint16_t descriptor_count;
46 /* Version - Currently supported = 1. */
47 uint16_t bpdt_version;
48 /* Unused - Should be 0. */
49 uint32_t xor_redundant_block;
50 /* Version of IFWI build. */
51 uint32_t ifwi_version;
52 /* Version of FIT tool used to create IFWI. */
53 uint64_t fit_tool_version;
Stefan Reinauer6a001132017-07-13 02:20:27 +020054} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070055#define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
56
57struct bpdt_entry {
58 /* Type of sub-partition. */
59 uint16_t type;
60 /* Attributes of sub-partition. */
61 uint16_t flags;
62 /* Offset of sub-partition from beginning of LBP. */
63 uint32_t offset;
64 /* Size in bytes of sub-partition. */
65 uint32_t size;
Stefan Reinauer6a001132017-07-13 02:20:27 +020066} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070067#define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
68
69struct bpdt {
70 struct bpdt_header h;
71 /* In practice, this could be an array of 0 to n entries. */
72 struct bpdt_entry e[0];
Stefan Reinauer6a001132017-07-13 02:20:27 +020073} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -070074
Werner Zeh310580e2016-06-24 13:03:38 +020075static inline size_t get_bpdt_size(struct bpdt_header *h)
Furquan Shaikh233f1b62016-05-19 16:12:16 -070076{
77 return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
78}
79
80/* Minimum size in bytes allocated to BPDT in IFWI. */
81#define BPDT_MIN_SIZE (512)
82
83/* Header to define directory header for sub-partition. */
84struct subpart_dir_header {
85 /* Should be SUBPART_DIR_MARKER. */
86 uint32_t marker;
87 /* Number of directory entries in the sub-partition. */
88 uint32_t num_entries;
89 /* Currenty supported - 1. */
90 uint8_t header_version;
91 /* Currenty supported - 1. */
92 uint8_t entry_version;
93 /* Length of directory header in bytes. */
94 uint8_t header_length;
95 /*
Furquan Shaikhe51c20b2016-06-15 08:01:10 -070096 * 2s complement of 8-bit sum from first byte of header to last byte of
97 * last directory entry.
Furquan Shaikh233f1b62016-05-19 16:12:16 -070098 */
99 uint8_t checksum;
100 /* ASCII short name of sub-partition. */
101 uint8_t name[4];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200102} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700103#define SUBPART_DIR_HEADER_SIZE \
104 (sizeof(struct subpart_dir_header))
105#define SUBPART_DIR_MARKER 0x44504324
106#define SUBPART_DIR_HEADER_VERSION_SUPPORTED 1
107#define SUBPART_DIR_ENTRY_VERSION_SUPPORTED 1
108
109/* Structure for each directory entry for sub-partition. */
110struct subpart_dir_entry {
111 /* Name of directory entry - Not guaranteed to be NULL-terminated. */
112 uint8_t name[12];
113 /* Offset of entry from beginning of sub-partition. */
114 uint32_t offset;
115 /* Length in bytes of sub-directory entry. */
116 uint32_t length;
117 /* Must be zero. */
118 uint32_t rsvd;
Stefan Reinauer6a001132017-07-13 02:20:27 +0200119} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700120#define SUBPART_DIR_ENTRY_SIZE \
121 (sizeof(struct subpart_dir_entry))
122
123struct subpart_dir {
124 struct subpart_dir_header h;
125 /* In practice, this could be an array of 0 to n entries. */
126 struct subpart_dir_entry e[0];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200127} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700128
129static inline size_t subpart_dir_size(struct subpart_dir_header *h)
130{
131 return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
132}
133
134struct manifest_header {
135 uint32_t header_type;
136 uint32_t header_length;
137 uint32_t header_version;
138 uint32_t flags;
139 uint32_t vendor;
140 uint32_t date;
141 uint32_t size;
142 uint32_t id;
143 uint32_t rsvd;
144 uint64_t version;
145 uint32_t svn;
146 uint64_t rsvd1;
147 uint8_t rsvd2[64];
148 uint32_t modulus_size;
149 uint32_t exponent_size;
150 uint8_t public_key[256];
151 uint32_t exponent;
152 uint8_t signature[256];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200153} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700154
155#define DWORD_SIZE 4
156#define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
157#define MANIFEST_ID_MAGIC (0x324e4d24)
158
159struct module {
160 uint8_t name[12];
161 uint8_t type;
162 uint8_t hash_alg;
163 uint16_t hash_size;
164 uint32_t metadata_size;
165 uint8_t metadata_hash[32];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200166} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700167
168#define MODULE_SIZE (sizeof(struct module))
169
170struct signed_pkg_info_ext {
171 uint32_t ext_type;
172 uint32_t ext_length;
173 uint8_t name[4];
174 uint32_t vcn;
175 uint8_t bitmap[16];
176 uint32_t svn;
177 uint8_t rsvd[16];
Stefan Reinauer6a001132017-07-13 02:20:27 +0200178} __packed;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700179
180#define SIGNED_PKG_INFO_EXT_TYPE 0x15
181#define SIGNED_PKG_INFO_EXT_SIZE \
182 (sizeof(struct signed_pkg_info_ext))
183
184/*
185 * Attributes for various IFWI sub-partitions.
186 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
187 * BPDT.
188 * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
189 * CONTAINS_DIR = Sub-Partition contains directory.
190 * AUTO_GENERATED = Sub-Partition is generated by the tool.
191 * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
192 * an entry for it with size 0 and offset 0.
193 */
194enum subpart_attributes {
195 LIES_WITHIN_BPDT_4K = (1 << 0),
196 NON_CRITICAL_SUBPART = (1 << 1),
197 CONTAINS_DIR = (1 << 2),
198 AUTO_GENERATED = (1 << 3),
199 MANDATORY_BPDT_ENTRY = (1 << 4),
200};
201
202/* Type value for various IFWI sub-partitions. */
203enum bpdt_entry_type {
204 SMIP_TYPE = 0,
205 CSE_RBE_TYPE = 1,
206 CSE_BUP_TYPE = 2,
207 UCODE_TYPE = 3,
208 IBB_TYPE = 4,
209 S_BPDT_TYPE = 5,
210 OBB_TYPE = 6,
211 CSE_MAIN_TYPE = 7,
212 ISH_TYPE = 8,
213 CSE_IDLM_TYPE = 9,
214 IFP_OVERRIDE_TYPE = 10,
215 DEBUG_TOKENS_TYPE = 11,
216 UFS_PHY_TYPE = 12,
217 UFS_GPP_TYPE = 13,
218 PMC_TYPE = 14,
219 IUNIT_TYPE = 15,
220 NVM_CONFIG_TYPE = 16,
221 UEP_TYPE = 17,
222 UFS_RATE_B_TYPE = 18,
223 MAX_SUBPARTS = 19,
224};
225
226/*
227 * There are two order requirements for an IFWI image:
228 * 1. Order in which the sub-partitions lie within the BPDT entries.
229 * 2. Order in which the sub-partitions lie within the image.
230 *
231 * header_order defines #1 i.e. the order in which the sub-partitions should
232 * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
233 * sub-partitions appear in the IFWI image. pack_order controls the offset and
234 * thus sub-partitions would have increasing offsets as we loop over pack_order.
235 */
236const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700237 /* Order of the following entries is mandatory. */
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700238 CSE_IDLM_TYPE,
239 IFP_OVERRIDE_TYPE,
240 S_BPDT_TYPE,
241 CSE_RBE_TYPE,
242 UFS_PHY_TYPE,
243 UFS_GPP_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700244 /* Order of the following entries is recommended. */
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700245 UEP_TYPE,
246 NVM_CONFIG_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700247 UFS_RATE_B_TYPE,
248 IBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700249 SMIP_TYPE,
250 PMC_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700251 CSE_BUP_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700252 UCODE_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700253 DEBUG_TOKENS_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700254 IUNIT_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700255 CSE_MAIN_TYPE,
256 ISH_TYPE,
257 OBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700258};
259
260const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700261 /* Order of the following entries is mandatory. */
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700262 UFS_GPP_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700263 UFS_PHY_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700264 IFP_OVERRIDE_TYPE,
265 UEP_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700266 NVM_CONFIG_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700267 UFS_RATE_B_TYPE,
268 /* Order of the following entries is recommended. */
269 IBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700270 SMIP_TYPE,
271 CSE_RBE_TYPE,
272 PMC_TYPE,
273 CSE_BUP_TYPE,
274 UCODE_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700275 CSE_IDLM_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700276 DEBUG_TOKENS_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700277 S_BPDT_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700278 IUNIT_TYPE,
Furquan Shaikhfe42b112016-06-10 11:05:16 -0700279 CSE_MAIN_TYPE,
280 ISH_TYPE,
281 OBB_TYPE,
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700282};
283
284/* Utility functions. */
285enum ifwi_ret {
286 COMMAND_ERR = -1,
287 NO_ACTION_REQUIRED = 0,
288 REPACK_REQUIRED = 1,
289};
290
291struct dir_ops {
292 enum ifwi_ret (*dir_add)(int);
293};
294
295static enum ifwi_ret ibbp_dir_add(int);
296
297const struct subpart_info {
298 const char *name;
299 const char *readable_name;
300 uint32_t attr;
301 struct dir_ops dir_ops;
302} subparts[MAX_SUBPARTS] = {
303 /* OEM SMIP */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700304 [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700305 /* CSE RBE */
306 [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700307 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700308 /* CSE BUP */
309 [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700310 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700311 /* uCode */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700312 [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700313 /* IBB */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700314 [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700315 /* S-BPDT */
316 [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700317 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700318 /* OBB */
319 [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700320 NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700321 /* CSE Main */
322 [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700323 NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700324 /* ISH */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700325 [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700326 /* CSE IDLM */
327 [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700328 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700329 /* IFP Override */
330 [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
331 LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700332 {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700333 /* Debug Tokens */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700334 [DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700335 /* UFS Phy Configuration */
336 [UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700337 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700338 /* UFS GPP LUN ID */
339 [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700340 MANDATORY_BPDT_ENTRY, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700341 /* PMC */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700342 [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700343 /* IUNIT */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700344 [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700345 /* NVM Config */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700346 [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700347 /* UEP */
348 [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700349 {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700350 /* UFS Rate B Config */
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700351 [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700352};
353
354struct ifwi_image {
355 /* Data read from input file. */
356 struct buffer input_buff;
357
358 /* BPDT header and entries. */
359 struct buffer bpdt;
360 size_t input_ifwi_start_offset;
361 size_t input_ifwi_end_offset;
362
363 /* Subpartition content. */
364 struct buffer subpart_buf[MAX_SUBPARTS];
365} ifwi_image;
366
367static void alloc_buffer(struct buffer *b, size_t s, const char *n)
368{
369 if (buffer_create(b, s, n) == 0)
370 return;
371
372 ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
373 exit(-1);
374}
375
376/*
377 * Read header/entry members in little-endian format.
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100378 * Returns the offset up to which the read was performed.
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700379*/
380static size_t read_member(void *src, size_t offset, size_t size_bytes,
381 void *dst)
382{
383 switch (size_bytes) {
384 case 1:
385 *(uint8_t *)dst = read_at_le8(src, offset);
386 break;
387 case 2:
388 *(uint16_t *)dst = read_at_le16(src, offset);
389 break;
390 case 4:
391 *(uint32_t *)dst = read_at_le32(src, offset);
392 break;
393 case 8:
394 *(uint64_t *)dst = read_at_le64(src, offset);
395 break;
396 default:
397 ERROR("Read size not supported %zd\n", size_bytes);
398 exit(-1);
399 }
400
401 return (offset + size_bytes);
402}
403
404/*
405 * Convert to little endian format.
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100406 * Returns the offset up to which the fixup was performed.
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700407 */
408static size_t fix_member(void *data, size_t offset, size_t size_bytes)
409{
410 uint8_t *src = (uint8_t *)data + offset;
411
412 switch (size_bytes) {
413 case 1:
414 write_at_le8(data, *(uint8_t *)src, offset);
415 break;
416 case 2:
417 write_at_le16(data, *(uint16_t *)src, offset);
418 break;
419 case 4:
420 write_at_le32(data, *(uint32_t *)src, offset);
421 break;
422 case 8:
423 write_at_le64(data, *(uint64_t *)src, offset);
424 break;
425 default:
426 ERROR("Write size not supported %zd\n", size_bytes);
427 exit(-1);
428 }
429 return (offset + size_bytes);
430}
431
432
433static void print_subpart_dir(struct subpart_dir *s)
434{
435 if (verbose == 0)
436 return;
437
438 size_t i;
439
440 printf("%-25s 0x%-23.8x\n", "Marker", s->h.marker);
441 printf("%-25s %-25d\n", "Num entries", s->h.num_entries);
442 printf("%-25s %-25d\n", "Header Version", s->h.header_version);
443 printf("%-25s %-25d\n", "Entry Version", s->h.entry_version);
444 printf("%-25s 0x%-23x\n", "Header Length", s->h.header_length);
445 printf("%-25s 0x%-23x\n", "Checksum", s->h.checksum);
446 printf("%-25s ", "Name");
447 for (i = 0; i < sizeof(s->h.name); i++)
448 printf("%c", s->h.name[i]);
449
450 printf("\n");
451
452 printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
453 "Length", "Rsvd");
454
455 printf("=============================================================="
456 "===========================================================\n");
457
458 for (i = 0; i < s->h.num_entries; i++) {
459 printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i+1,
460 s->e[i].name, s->e[i].offset, s->e[i].length,
461 s->e[i].rsvd);
462 }
463
464 printf("=============================================================="
465 "===========================================================\n");
466}
467
468static void bpdt_print_header(struct bpdt_header *h, const char *name)
469{
470 if (verbose == 0)
471 return;
472
473 printf("%-25s %-25s\n", "Header", name);
474 printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
475 printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
476 printf("%-25s %-25d\n", "BPDT Version", h->bpdt_version);
477 printf("%-25s 0x%-23x\n", "XOR checksum", h->xor_redundant_block);
478 printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700479 printf("%-25s 0x%-23llx\n", "FIT Tool Version",
480 (long long)h->fit_tool_version);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700481}
482
483static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
484 const char *name)
485{
486 if (verbose == 0)
487 return;
488
489 printf("%s entries\n", name);
490
491 printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
492 "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
493 "File Offset");
494
495 printf("=============================================================="
496 "=============================================================="
497 "=============================================================="
498 "===============\n");
499
500
501 size_t i;
502 for (i = 0; i < count; i++) {
503 printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx"
504 "\n", i+1, subparts[e[i].type].name,
505 subparts[e[i].type].readable_name, e[i].type, e[i].flags,
506 e[i].offset, e[i].size,
507 e[i].offset + ifwi_image.input_ifwi_start_offset);
508 }
509
510 printf("=============================================================="
511 "=============================================================="
512 "=============================================================="
513 "===============\n");
514
515}
516
517static void bpdt_validate_header(struct bpdt_header *h, const char *name)
518{
Furquan Shaikh55d2e532016-05-31 11:02:47 -0700519 assert(h->signature == BPDT_SIGNATURE);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700520
521 if (h->bpdt_version != 1) {
522 ERROR("Invalid header : %s\n", name);
523 exit(-1);
524 }
525
526 DEBUG("Validated header : %s\n", name);
527}
528
529static void bpdt_read_header(void *data, struct bpdt_header *h,
530 const char *name)
531{
532 size_t offset = 0;
533
534 offset = read_member(data, offset, sizeof(h->signature), &h->signature);
535 offset = read_member(data, offset, sizeof(h->descriptor_count),
536 &h->descriptor_count);
537 offset = read_member(data, offset, sizeof(h->bpdt_version),
538 &h->bpdt_version);
539 offset = read_member(data, offset, sizeof(h->xor_redundant_block),
540 &h->xor_redundant_block);
541 offset = read_member(data, offset, sizeof(h->ifwi_version),
542 &h->ifwi_version);
Paul Menzeldeb9b032017-03-08 10:51:52 +0100543 read_member(data, offset, sizeof(h->fit_tool_version),
544 &h->fit_tool_version);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700545
546 bpdt_validate_header(h, name);
547 bpdt_print_header(h, name);
548}
549
550static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
551{
552 size_t i, offset = 0;
553 struct bpdt_entry *e = &bpdt->e[0];
554 size_t count = bpdt->h.descriptor_count;
555
556 for (i = 0; i < count; i++) {
557 offset = read_member(data, offset, sizeof(e[i].type),
558 &e[i].type);
559 offset = read_member(data, offset, sizeof(e[i].flags),
560 &e[i].flags);
561 offset = read_member(data, offset, sizeof(e[i].offset),
562 &e[i].offset);
563 offset = read_member(data, offset, sizeof(e[i].size),
564 &e[i].size);
565 }
566
567 bpdt_print_entries(e, count, name);
568}
569
570/*
571 * Given type of sub-partition, identify BPDT entry for it.
572 * Sub-Partition could lie either within BPDT or S-BPDT.
573 */
574static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
575 size_t count, int type)
576{
577 size_t i;
578 for (i = 0; i < count; i++) {
579 if (e[i].type == type)
580 break;
581 }
582
583 if (i == count)
584 return NULL;
585
586 return &e[i];
587}
588
589static struct bpdt_entry *find_entry_by_type(int type)
590{
591 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
592 if (b == NULL)
593 return NULL;
594
595 struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
596 b->h.descriptor_count,
597 type);
598
599 if (curr)
600 return curr;
601
602 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
603 if (b == NULL)
604 return NULL;
605
606 return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
607}
608
609/*
610 * Find sub-partition type given its name. If the name does not exist, returns
611 * -1.
612 */
613static int find_type_by_name(const char *name)
614{
615 int i;
616
617 for (i = 0; i < MAX_SUBPARTS; i++) {
618 if ((strlen(subparts[i].name) == strlen(name)) &&
619 (!strcmp(subparts[i].name, name)))
620 break;
621 }
622
623 if (i == MAX_SUBPARTS) {
624 ERROR("Invalid sub-partition name %s.\n", name);
625 return -1;
626 }
627
628 return i;
629}
630
631/*
632 * Read the content of a sub-partition from input file and store it in
633 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
634 *
635 * Returns the maximum offset occupied by the sub-partitions.
636 */
637static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
638 size_t count)
639{
640 size_t i, type;
641 struct buffer *buf;
642 size_t max_offset = 0;
643
644 for (i = 0; i < count; i++) {
645 type = e[i].type;
646
647 if (type >= MAX_SUBPARTS) {
648 ERROR("Invalid sub-partition type %zd.\n", type);
649 exit(-1);
650 }
651
652 if (buffer_size(&ifwi_image.subpart_buf[type])) {
653 ERROR("Multiple sub-partitions of type %zd(%s).\n",
654 type, subparts[type].name);
655 exit(-1);
656 }
657
658 if (e[i].size == 0) {
659 INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
660 subparts[type].name);
661 continue;
662 }
663
664 assert((e[i].offset + e[i].size) <= size);
665
666 /*
667 * Sub-partitions in IFWI image are not in the same order as
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100668 * in BPDT entries. BPDT entries are in header_order whereas
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700669 * sub-partition offsets in the image are in pack_order.
670 */
671 if ((e[i].offset + e[i].size) > max_offset)
672 max_offset = e[i].offset + e[i].size;
673
674 /*
675 * S-BPDT sub-partition contains information about all the
676 * non-critical sub-partitions. Thus, size of S-BPDT
677 * sub-partition equals size of S-BPDT plus size of all the
678 * non-critical sub-partitions. Thus, reading whole of S-BPDT
679 * here would be redundant as the non-critical partitions are
680 * read and allocated buffers separately. Also, S-BPDT requires
681 * special handling for reading header and entries.
682 */
683 if (type == S_BPDT_TYPE)
684 continue;
685
686 buf = &ifwi_image.subpart_buf[type];
687
688 alloc_buffer(buf, e[i].size, subparts[type].name);
689 memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
690 e[i].size);
691 }
692
693 assert(max_offset);
694 return max_offset;
695}
696
697/*
698 * Allocate buffer for bpdt header, entries and all sub-partition content.
699 * Returns offset in data where BPDT ends.
700 */
701static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
702 struct buffer *b, const char *name)
703{
704 struct bpdt_header bpdt_header;
705 assert((offset + BPDT_HEADER_SIZE) < size);
706 bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
707
708 /* Buffer to read BPDT header and entries. */
Werner Zeh310580e2016-06-24 13:03:38 +0200709 alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700710
711 struct bpdt *bpdt = buffer_get(b);
712 memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
713
714 /*
715 * If no entries are present, maximum offset occupied is (offset +
716 * BPDT_HEADER_SIZE).
717 */
718 if (bpdt->h.descriptor_count == 0)
719 return (offset + BPDT_HEADER_SIZE);
720
721 /* Read all entries. */
Werner Zeh310580e2016-06-24 13:03:38 +0200722 assert((offset + get_bpdt_size(&bpdt->h)) < size);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700723 bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
724 name);
725
726 /* Read all sub-partition content in subpart_buf. */
727 return read_subpart_buf(data, size, &bpdt->e[0],
728 bpdt->h.descriptor_count);
729}
730
731static void parse_sbpdt(void *data, size_t size)
732{
733 struct bpdt_entry *s;
734 s = find_entry_by_type(S_BPDT_TYPE);
735 if (!s)
736 return;
737
738 assert(size > s->offset);
739
740 alloc_bpdt_buffer(data, size, s->offset,
741 &ifwi_image.subpart_buf[S_BPDT_TYPE],
742 "S-BPDT");
743}
744
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700745static uint8_t calc_checksum(struct subpart_dir *s)
746{
747 size_t size = subpart_dir_size(&s->h);
748 uint8_t *data = (uint8_t *)s;
749 uint8_t checksum = 0;
750 size_t i;
751
752 uint8_t old_checksum = s->h.checksum;
753 s->h.checksum = 0;
754
755 for (i = 0; i < size; i++)
756 checksum += data[i];
757
758 s->h.checksum = old_checksum;
759
760 /* 2s complement */
761 return -checksum;
762}
763
764static void validate_subpart_dir(struct subpart_dir *s, const char *name,
765 bool checksum_check)
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700766{
767 if ((s->h.marker != SUBPART_DIR_MARKER) ||
768 (s->h.header_version != SUBPART_DIR_HEADER_VERSION_SUPPORTED) ||
769 (s->h.entry_version != SUBPART_DIR_ENTRY_VERSION_SUPPORTED) ||
770 (s->h.header_length != SUBPART_DIR_HEADER_SIZE)) {
771 ERROR("Invalid subpart_dir for %s.\n", name);
772 exit(-1);
773 }
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700774
775 if (checksum_check == false)
776 return;
777
778 uint8_t checksum = calc_checksum(s);
779
780 if (checksum != s->h.checksum)
781 ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
782 name, checksum, s->h.checksum);
783}
784
785static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
786 const char *name)
787{
788 validate_subpart_dir(s, name, 0);
789}
790
791static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
792 const char *name)
793{
794 validate_subpart_dir(s, name, 1);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700795}
796
797static void parse_subpart_dir(struct buffer *subpart_dir_buf,
798 struct buffer *input_buf, const char *name)
799{
800 struct subpart_dir_header hdr;
801 size_t offset = 0;
802 uint8_t *data = buffer_get(input_buf);
803 size_t size = buffer_size(input_buf);
804
805 /* Read Subpart_Dir header. */
806 assert(size >= SUBPART_DIR_HEADER_SIZE);
807 offset = read_member(data, offset, sizeof(hdr.marker), &hdr.marker);
808 offset = read_member(data, offset, sizeof(hdr.num_entries),
809 &hdr.num_entries);
810 offset = read_member(data, offset, sizeof(hdr.header_version),
811 &hdr.header_version);
812 offset = read_member(data, offset, sizeof(hdr.entry_version),
813 &hdr.entry_version);
814 offset = read_member(data, offset, sizeof(hdr.header_length),
815 &hdr.header_length);
816 offset = read_member(data, offset, sizeof(hdr.checksum), &hdr.checksum);
817 memcpy(hdr.name, data + offset, sizeof(hdr.name));
818 offset += sizeof(hdr.name);
819
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700820 validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700821
822 assert(size > subpart_dir_size(&hdr));
823 alloc_buffer(subpart_dir_buf, subpart_dir_size(&hdr), "Subpart Dir");
824 memcpy(buffer_get(subpart_dir_buf), &hdr, SUBPART_DIR_HEADER_SIZE);
825
826 /* Read Subpart Dir entries. */
827 struct subpart_dir *subpart_dir = buffer_get(subpart_dir_buf);
828 struct subpart_dir_entry *e = &subpart_dir->e[0];
829 uint32_t i;
830 for (i = 0; i < hdr.num_entries; i++) {
831 memcpy(e[i].name, data + offset, sizeof(e[i].name));
832 offset += sizeof(e[i].name);
833 offset = read_member(data, offset, sizeof(e[i].offset),
834 &e[i].offset);
835 offset = read_member(data, offset, sizeof(e[i].length),
836 &e[i].length);
837 offset = read_member(data, offset, sizeof(e[i].rsvd),
838 &e[i].rsvd);
839 }
840
Furquan Shaikhe51c20b2016-06-15 08:01:10 -0700841 validate_subpart_dir_with_checksum(subpart_dir, name);
842
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700843 print_subpart_dir(subpart_dir);
844}
845
Jeremy Compostella31e21882019-12-09 17:02:45 -0700846/* Parse the bpdt entries to compute the size of the BPDT */
847static size_t bpdt_size(void *data)
848{
849 struct bpdt *b = (struct bpdt *)data;
850 size_t i, size = 0;
851
852 for (i = 0; i < b->h.descriptor_count; i++)
853 size = MAX(size, b->e[i].offset + b->e[i].size);
854
855 return size;
856}
857
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700858/* Parse input image file to identify different sub-partitions. */
859static int ifwi_parse(void)
860{
861 DEBUG("Parsing IFWI image...\n");
862 const char *image_name = param.image_name;
863
864 /* Read input file. */
865 struct buffer *buff = &ifwi_image.input_buff;
866 if (buffer_from_file(buff, image_name)) {
867 ERROR("Failed to read input file %s.\n", image_name);
868 return -1;
869 }
870
871 INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
872
873 /* Look for BPDT signature at 4K intervals. */
Jeremy Compostella31e21882019-12-09 17:02:45 -0700874 size_t offset = 0, lbp = LBP1;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700875 void *data = buffer_get(buff);
876
877 while (offset < buffer_size(buff)) {
Jeremy Compostella31e21882019-12-09 17:02:45 -0700878 if (read_at_le32(data, offset) == BPDT_SIGNATURE) {
879 if (lbp == param.logical_boot_partition)
880 break;
881 offset += bpdt_size((uint8_t *)data + offset);
882 lbp++;
883 } else
884 offset += 4 * KiB;
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700885 }
886
887 if (offset >= buffer_size(buff)) {
Jeremy Compostella31e21882019-12-09 17:02:45 -0700888 ERROR("Image does not contain BPDT for LBP=%zd!!\n",
889 param.logical_boot_partition);
Furquan Shaikh233f1b62016-05-19 16:12:16 -0700890 return -1;
891 }
892
893 ifwi_image.input_ifwi_start_offset = offset;
894 INFO("BPDT starts at offset 0x%zx.\n", offset);
895
896 data = (uint8_t *)data + offset;
897 size_t ifwi_size = buffer_size(buff) - offset;
898
899 /* Read BPDT and sub-partitions. */
900 uintptr_t end_offset;
901 end_offset = ifwi_image.input_ifwi_start_offset +
902 alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
903
904 /* Parse S-BPDT, if any. */
905 parse_sbpdt(data, ifwi_size);
906
907 /*
908 * Store end offset of IFWI. Required for copying any trailing non-IFWI
909 * part of the image.
910 * ASSUMPTION: IFWI image always ends on a 4K boundary.
911 */
912 ifwi_image.input_ifwi_end_offset = ALIGN(end_offset, 4 * KiB);
913 DEBUG("Parsing done.\n");
914
915 return 0;
916}
917
918/*
919 * This function is used by repack to count the number of BPDT and S-BPDT
920 * entries that are present. It frees the current buffers used by the entries
921 * and allocates fresh buffers that can be used for repacking. Returns BPDT
922 * entries which are empty and need to be filled in.
923 */
924static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
925{
926 size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
927 assert(size >= bpdt_size);
928
929 /*
930 * If buffer does not have the required size, allocate a fresh buffer.
931 */
932 if (buffer_size(b) != size) {
933 struct buffer temp;
934 alloc_buffer(&temp, size, b->name);
935 memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
936 buffer_delete(b);
937 *b = temp;
938 }
939
940 struct bpdt *bpdt = buffer_get(b);
941 uint8_t *ptr = (uint8_t *)&bpdt->e[0];
942 size_t entries_size = BPDT_ENTRY_SIZE * count;
943
944 /* Zero out BPDT entries. */
945 memset(ptr, 0, entries_size);
946 /* Fill any pad-space with FF. */
947 memset(ptr + entries_size, 0xFF, size - bpdt_size);
948
949 bpdt->h.descriptor_count = count;
950}
951
952static void bpdt_reset(void)
953{
954 size_t i;
955 size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
956
957 /* Count number of BPDT and S-BPDT entries. */
958 for (i = 0; i < MAX_SUBPARTS; i++) {
959 if (buffer_size(&ifwi_image.subpart_buf[i]) == 0) {
960 if (subparts[i].attr & MANDATORY_BPDT_ENTRY) {
961 bpdt_count++;
962 dummy_bpdt_count++;
963 }
964 continue;
965 }
966
967 if (subparts[i].attr & NON_CRITICAL_SUBPART)
968 sbpdt_count++;
969 else
970 bpdt_count++;
971 }
972
973 DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
974 dummy_bpdt_count, sbpdt_count);
975
976 /* Update BPDT if required. */
977 size_t bpdt_size = MAX(BPDT_MIN_SIZE,
978 BPDT_HEADER_SIZE + bpdt_count * BPDT_ENTRY_SIZE);
979 __bpdt_reset(&ifwi_image.bpdt, bpdt_count, bpdt_size);
980
981 /* Update S-BPDT if required. */
982 bpdt_size = ALIGN(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
983 4 * KiB);
984 __bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
985 bpdt_size);
986}
987
988/* Initialize BPDT entries in header order. */
989static void bpdt_entries_init_header_order(void)
990{
991 int i, type;
992 size_t size;
993
994 struct bpdt *bpdt, *sbpdt, *curr;
995 size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
996
997 bpdt = buffer_get(&ifwi_image.bpdt);
998 sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
999
1000 for (i = 0; i < MAX_SUBPARTS; i++) {
1001 type = bpdt_header_order[i];
1002 size = buffer_size(&ifwi_image.subpart_buf[type]);
1003
1004 if ((size == 0) && !(subparts[type].attr &
1005 MANDATORY_BPDT_ENTRY))
1006 continue;
1007
1008 if (subparts[type].attr & NON_CRITICAL_SUBPART) {
1009 curr = sbpdt;
1010 count_ptr = &sbpdt_curr;
1011 } else {
1012 curr = bpdt;
1013 count_ptr = &bpdt_curr;
1014 }
1015
1016 assert(*count_ptr < curr->h.descriptor_count);
1017 curr->e[*count_ptr].type = type;
1018 curr->e[*count_ptr].flags = 0;
1019 curr->e[*count_ptr].offset = 0;
1020 curr->e[*count_ptr].size = size;
1021
1022 (*count_ptr)++;
1023 }
1024}
1025
1026static void pad_buffer(struct buffer *b, size_t size)
1027{
1028 size_t buff_size = buffer_size(b);
1029
1030 assert(buff_size <= size);
1031
1032 if (buff_size == size)
1033 return;
1034
1035 struct buffer temp;
1036 alloc_buffer(&temp, size, b->name);
1037 uint8_t *data = buffer_get(&temp);
1038
1039 memcpy(data, buffer_get(b), buff_size);
1040 memset(data + buff_size, 0xFF, size - buff_size);
1041
1042 *b = temp;
1043}
1044
1045/* Initialize offsets of entries using pack order. */
1046static void bpdt_entries_init_pack_order(void)
1047{
1048 int i, type;
1049 struct bpdt_entry *curr;
1050 size_t curr_offset, curr_end;
1051
1052 curr_offset = MAX(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
1053
1054 /*
1055 * There are two types of sub-partitions that need to be handled here:
1056 * 1. Sub-partitions that lie within the same 4K as BPDT
1057 * 2. Sub-partitions that lie outside the 4K of BPDT
1058 *
1059 * For sub-partitions of type # 1, there is no requirement on the start
1060 * or end of the sub-partition. They need to be packed in without any
1061 * holes left in between. If there is any empty space left after the end
1062 * of the last sub-partition in 4K of BPDT, then that space needs to be
1063 * padded with FF bytes, but the size of the last sub-partition remains
1064 * unchanged.
1065 *
1066 * For sub-partitions of type # 2, both the start and end should be a
1067 * multiple of 4K. If not, then it needs to be padded with FF bytes and
1068 * size adjusted such that the sub-partition ends on 4K boundary.
1069 */
1070
1071 /* #1 Sub-partitions that lie within same 4K as BPDT. */
1072 struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1073
1074 for (i = 0; i < MAX_SUBPARTS; i++) {
1075 type = bpdt_pack_order[i];
1076 curr = find_entry_by_type(type);
1077
1078 if ((curr == NULL) || (curr->size == 0))
1079 continue;
1080
1081 if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1082 continue;
1083
1084 curr->offset = curr_offset;
1085 curr_offset = curr->offset + curr->size;
1086 last_bpdt_buff = &ifwi_image.subpart_buf[type];
1087 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, "
1088 "curr->size=0x%x, buff_size=0x%zx\n", type, curr_offset,
1089 curr->offset, curr->size,
1090 buffer_size(&ifwi_image.subpart_buf[type]));
1091 }
1092
1093 /* Pad ff bytes if there is any empty space left in BPDT 4K. */
1094 curr_end = ALIGN(curr_offset, 4 * KiB);
1095 pad_buffer(last_bpdt_buff,
1096 buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
1097 curr_offset = curr_end;
1098
1099 /* #2 Sub-partitions that lie outside of BPDT 4K. */
1100 for (i = 0; i < MAX_SUBPARTS; i++) {
1101 type = bpdt_pack_order[i];
1102 curr = find_entry_by_type(type);
1103
1104 if ((curr == NULL) || (curr->size == 0))
1105 continue;
1106
1107 if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1108 continue;
1109
1110 assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1111 curr->offset = curr_offset;
1112 curr_end = ALIGN(curr->offset + curr->size, 4 * KiB);
1113 curr->size = curr_end - curr->offset;
1114
1115 pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1116
1117 curr_offset = curr_end;
1118 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, "
1119 "curr->size=0x%x, buff_size=0x%zx\n", type, curr_offset,
1120 curr->offset, curr->size,
1121 buffer_size(&ifwi_image.subpart_buf[type]));
1122 }
1123
1124 /*
1125 * Update size of S-BPDT to include size of all non-critical
1126 * sub-partitions.
1127 *
1128 * Assumption: S-BPDT always lies at the end of IFWI image.
1129 */
1130 curr = find_entry_by_type(S_BPDT_TYPE);
1131 assert(curr);
1132
1133 assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1134 curr->size = curr_offset - curr->offset;
1135}
1136
1137/* Convert all members of BPDT to little-endian format. */
1138static void bpdt_fixup_write_buffer(struct buffer *buf)
1139{
1140 struct bpdt *s = buffer_get(buf);
1141
1142 struct bpdt_header *h = &s->h;
1143 struct bpdt_entry *e = &s->e[0];
1144
1145 size_t count = h->descriptor_count;
1146
1147 size_t offset = 0;
1148
1149 offset = fix_member(&h->signature, offset, sizeof(h->signature));
1150 offset = fix_member(&h->descriptor_count, offset,
1151 sizeof(h->descriptor_count));
1152 offset = fix_member(&h->bpdt_version, offset, sizeof(h->bpdt_version));
1153 offset = fix_member(&h->xor_redundant_block, offset,
1154 sizeof(h->xor_redundant_block));
1155 offset = fix_member(&h->ifwi_version, offset, sizeof(h->ifwi_version));
1156 offset = fix_member(&h->fit_tool_version, offset,
1157 sizeof(h->fit_tool_version));
1158
1159 uint32_t i;
1160 for (i = 0; i < count; i++) {
1161 offset = fix_member(&e[i].type, offset, sizeof(e[i].type));
1162 offset = fix_member(&e[i].flags, offset, sizeof(e[i].flags));
1163 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1164 offset = fix_member(&e[i].size, offset, sizeof(e[i].size));
1165 }
1166}
1167
1168/* Write BPDT to output buffer after fixup. */
1169static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1170{
1171 bpdt_fixup_write_buffer(src);
1172 memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1173}
1174
1175/*
1176 * Follows these steps to re-create image:
1177 * 1. Write any non-IFWI prefix.
1178 * 2. Write out BPDT header and entries.
1179 * 3. Write sub-partition buffers to respective offsets.
1180 * 4. Write any non-IFWI suffix.
1181 *
1182 * While performing the above steps, make sure that any empty holes are filled
1183 * with FF.
1184 */
1185static void ifwi_write(const char *image_name)
1186{
1187 struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1188 assert(s);
1189
1190 size_t ifwi_start, ifwi_end, file_end;
1191
1192 ifwi_start = ifwi_image.input_ifwi_start_offset;
1193 ifwi_end = ifwi_start + ALIGN(s->offset + s->size, 4 * KiB);
1194 file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
1195 ifwi_image.input_ifwi_end_offset);
1196
1197 struct buffer b;
1198
1199 alloc_buffer(&b, file_end, "Final-IFWI");
1200
1201 uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1202 uint8_t *output_data = buffer_get(&b);
1203
1204 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1205 ifwi_end, file_end);
1206
1207 /* Copy non-IFWI prefix, if any. */
1208 memcpy(output_data, input_data, ifwi_start);
1209
1210 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1211
1212 struct buffer ifwi;
1213 buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1214 uint8_t *ifwi_data = buffer_get(&ifwi);
1215
1216 /* Copy sub-partitions using pack_order. */
1217 struct bpdt_entry *curr;
1218 struct buffer *subpart_buf;
1219 int i, type;
1220 for (i = 0; i < MAX_SUBPARTS; i++) {
1221 type = bpdt_pack_order[i];
1222
1223 if (type == S_BPDT_TYPE)
1224 continue;
1225
1226 curr = find_entry_by_type(type);
1227
1228 if ((curr == NULL) || (curr->size == 0))
1229 continue;
1230
1231 subpart_buf = &ifwi_image.subpart_buf[type];
1232
1233 DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, "
1234 "write_size=0x%zx\n", curr->offset, curr->size, type,
1235 buffer_size(subpart_buf));
1236
1237 assert((curr->offset + buffer_size(subpart_buf)) <=
1238 buffer_size(&ifwi));
1239
1240 memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1241 buffer_size(subpart_buf));
1242 }
1243
1244 /* Copy non-IFWI suffix, if any. */
1245 if (ifwi_end != file_end) {
1246 memcpy(output_data + ifwi_end,
1247 input_data + ifwi_image.input_ifwi_end_offset,
1248 file_end - ifwi_end);
1249 DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1250 ifwi_end, file_end - ifwi_end);
1251 }
1252
1253 /*
1254 * Convert BPDT to little-endian format and write it to output buffer.
1255 * S-BPDT is written first and then BPDT.
1256 */
1257 bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1258 bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1259
1260 if (buffer_write_file(&b, image_name)) {
1261 ERROR("File write error\n");
1262 exit(-1);
1263 }
1264
1265 buffer_delete(&b);
1266 printf("Image written successfully to %s.\n", image_name);
1267}
1268
1269/*
1270 * Calculate size and offset of each sub-partition again since it might have
1271 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1272 * entries and write back the new IFWI image to file.
1273 */
1274static void ifwi_repack(void)
1275{
1276 bpdt_reset();
1277 bpdt_entries_init_header_order();
1278 bpdt_entries_init_pack_order();
1279
1280 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1281 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1282
1283 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1284 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1285
1286 DEBUG("Repack done.. writing image.\n");
1287 ifwi_write(param.image_name);
1288}
1289
1290static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1291 size_t count, const char *name)
1292{
1293 memset(hdr, 0, sizeof(*hdr));
1294
1295 hdr->marker = SUBPART_DIR_MARKER;
1296 hdr->num_entries = count;
1297 hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED;
1298 hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED;
1299 hdr->header_length = SUBPART_DIR_HEADER_SIZE;
1300 memcpy(hdr->name, name, sizeof(hdr->name));
1301}
1302
1303static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1304 struct buffer *b, size_t offset)
1305{
1306 memset(e, 0, sizeof(*e));
1307
1308 assert(strlen(b->name) <= sizeof(e->name));
1309 strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
1310 e->offset = offset;
1311 e->length = buffer_size(b);
1312
1313 return (offset + buffer_size(b));
1314}
1315
1316static void init_manifest_header(struct manifest_header *hdr, size_t size)
1317{
1318 memset(hdr, 0, sizeof(*hdr));
1319
1320 hdr->header_type = 0x4;
1321 assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0);
1322 hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE;
1323 hdr->header_version = 0x10000;
1324 hdr->vendor = 0x8086;
1325
1326 struct tm *local_time;
1327 time_t curr_time;
1328 char buffer[11];
1329
1330 curr_time = time(NULL);
1331 local_time = localtime(&curr_time);
1332 strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time);
1333 hdr->date = strtoul(buffer, NULL, 16);
1334
1335 assert((size % DWORD_SIZE) == 0);
1336 hdr->size = size / DWORD_SIZE;
1337 hdr->id = MANIFEST_ID_MAGIC;
1338}
1339
1340static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1341 size_t count, const char *name)
1342{
1343 memset(ext, 0, sizeof(*ext));
1344
1345 ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE;
1346 ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE;
1347 memcpy(ext->name, name, sizeof(ext->name));
1348}
1349
1350static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1351{
1352 struct subpart_dir *s = buffer_get(buf);
1353 struct subpart_dir_header *h = &s->h;
1354 struct subpart_dir_entry *e = &s->e[0];
1355
1356 size_t count = h->num_entries;
1357 size_t offset = 0;
1358
1359 offset = fix_member(&h->marker, offset, sizeof(h->marker));
1360 offset = fix_member(&h->num_entries, offset, sizeof(h->num_entries));
1361 offset = fix_member(&h->header_version, offset,
1362 sizeof(h->header_version));
1363 offset = fix_member(&h->entry_version, offset,
1364 sizeof(h->entry_version));
1365 offset = fix_member(&h->header_length, offset,
1366 sizeof(h->header_length));
1367 offset = fix_member(&h->checksum, offset, sizeof(h->checksum));
1368 offset += sizeof(h->name);
1369
1370 uint32_t i;
1371 for (i = 0; i < count; i++) {
1372 offset += sizeof(e[i].name);
1373 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1374 offset = fix_member(&e[i].length, offset, sizeof(e[i].length));
1375 offset = fix_member(&e[i].rsvd, offset, sizeof(e[i].rsvd));
1376 }
1377}
1378
1379static void create_subpart(struct buffer *dst, struct buffer *info[],
1380 size_t count, const char *name)
1381{
1382 struct buffer subpart_dir_buff;
1383 size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1384
1385 alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1386
1387 struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1388 struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1389
1390 init_subpart_dir_header(h, count, name);
1391
1392 size_t curr_offset = size;
1393 size_t i;
1394
1395 for (i = 0; i < count; i++) {
1396 curr_offset = init_subpart_dir_entry(&e[i], info[i],
1397 curr_offset);
1398 }
1399
1400 alloc_buffer(dst, curr_offset, name);
1401 uint8_t *data = buffer_get(dst);
1402
1403 for (i = 0; i < count; i++) {
1404 memcpy(data + e[i].offset, buffer_get(info[i]),
1405 buffer_size(info[i]));
1406 }
1407
Furquan Shaikhe51c20b2016-06-15 08:01:10 -07001408 h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001409
1410 struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1411
1412 print_subpart_dir(dir);
1413
1414 subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1415 memcpy(data, dir, buffer_size(&subpart_dir_buff));
1416
1417 buffer_delete(&subpart_dir_buff);
1418}
1419
1420static enum ifwi_ret ibbp_dir_add(int type)
1421{
1422#define DUMMY_IBB_SIZE (4 * KiB)
1423
Furquan Shaikh55d2e532016-05-31 11:02:47 -07001424 assert(type == IBB_TYPE);
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001425
1426 /*
1427 * Entry # 1 - IBBP.man
1428 * Contains manifest header and signed pkg info extension.
1429 */
1430 struct buffer manifest;
1431 size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1432 alloc_buffer(&manifest, size, "IBBP.man");
1433
1434 struct manifest_header *man_hdr = buffer_get(&manifest);
1435 init_manifest_header(man_hdr, size);
1436
1437 struct signed_pkg_info_ext *ext;
1438 ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1439
1440 init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1441
1442 /* Entry # 2 - IBBL */
1443 struct buffer ibbl;
1444 if (buffer_from_file(&ibbl, param.file_name))
1445 return COMMAND_ERR;
1446
1447 /* Entry # 3 - IBB */
1448 struct buffer ibb;
1449 alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1450 memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1451
1452 /* Create subpartition. */
1453 struct buffer *info[] = {
1454 &manifest, &ibbl, &ibb,
1455 };
1456 create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1457 ARRAY_SIZE(info), subparts[type].name);
1458
1459 return REPACK_REQUIRED;
1460}
1461
1462static enum ifwi_ret ifwi_raw_add(int type)
1463{
1464 if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1465 return COMMAND_ERR;
1466
1467 printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1468 type, param.file_name);
1469 return REPACK_REQUIRED;
1470}
1471
1472static enum ifwi_ret ifwi_dir_add(int type)
1473{
1474 if (!(subparts[type].attr & CONTAINS_DIR) ||
1475 (subparts[type].dir_ops.dir_add == NULL)) {
1476 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1477 subparts[type].name, type);
1478 return COMMAND_ERR;
1479 }
1480
1481 if (!param.dentry_name) {
1482 ERROR("%s: -e option required\n", __func__);
1483 return COMMAND_ERR;
1484 }
1485
1486 enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
1487 if (ret != COMMAND_ERR)
1488 printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1489 param.subpart_name, type, param.dentry_name,
1490 param.file_name);
1491 else
1492 ERROR("Sub-partition dir operation failed.\n");
1493
1494 return ret;
1495}
1496
1497static enum ifwi_ret ifwi_add(void)
1498{
1499 if (!param.file_name) {
1500 ERROR("%s: -f option required\n", __func__);
1501 return COMMAND_ERR;
1502 }
1503
1504 if (!param.subpart_name) {
1505 ERROR("%s: -n option required\n", __func__);
1506 return COMMAND_ERR;
1507 }
1508
1509 int type = find_type_by_name(param.subpart_name);
1510 if (type == -1)
1511 return COMMAND_ERR;
1512
1513 const struct subpart_info *curr_subpart = &subparts[type];
1514
1515 if (curr_subpart->attr & AUTO_GENERATED) {
1516 ERROR("Cannot add auto-generated sub-partitions.\n");
1517 return COMMAND_ERR;
1518 }
1519
1520 if (buffer_size(&ifwi_image.subpart_buf[type])) {
1521 ERROR("Image already contains sub-partition %s(%d).\n",
1522 param.subpart_name, type);
1523 return COMMAND_ERR;
1524 }
1525
1526 if (param.dir_ops)
1527 return ifwi_dir_add(type);
1528
1529 return ifwi_raw_add(type);
1530}
1531
1532static enum ifwi_ret ifwi_delete(void)
1533{
1534 if (!param.subpart_name) {
1535 ERROR("%s: -n option required\n", __func__);
1536 return COMMAND_ERR;
1537 }
1538
1539 int type = find_type_by_name(param.subpart_name);
1540 if (type == -1)
1541 return COMMAND_ERR;
1542
1543 const struct subpart_info *curr_subpart = &subparts[type];
1544
1545 if (curr_subpart->attr & AUTO_GENERATED) {
1546 ERROR("Cannot delete auto-generated sub-partitions.\n");
1547 return COMMAND_ERR;
1548 }
1549
1550 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1551 printf("Image does not contain sub-partition %s(%d).\n",
1552 param.subpart_name, type);
1553 return NO_ACTION_REQUIRED;
1554 }
1555
1556 buffer_delete(&ifwi_image.subpart_buf[type]);
1557 printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1558 return REPACK_REQUIRED;
1559}
1560
1561static enum ifwi_ret ifwi_dir_extract(int type)
1562{
1563 if (!(subparts[type].attr & CONTAINS_DIR)) {
1564 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1565 subparts[type].name, type);
1566 return COMMAND_ERR;
1567 }
1568
1569 if (!param.dentry_name) {
1570 ERROR("%s: -e option required.\n", __func__);
1571 return COMMAND_ERR;
1572 }
1573
1574 struct buffer subpart_dir_buff;
1575 parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1576 subparts[type].name);
1577
1578 uint32_t i;
1579 struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1580
1581 for (i = 0; i < s->h.num_entries; i++) {
1582 if (!strncmp((char *)s->e[i].name, param.dentry_name,
1583 sizeof(s->e[i].name)))
1584 break;
1585 }
1586
1587 if (i == s->h.num_entries) {
1588 ERROR("Entry %s not found in subpartition for %s.\n",
1589 param.dentry_name, param.subpart_name);
1590 exit(-1);
1591 }
1592
1593 struct buffer dst;
1594
1595 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
1596 s->e[i].length);
1597 buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
1598 s->e[i].length);
1599
1600 if (buffer_write_file(&dst, param.file_name))
1601 return COMMAND_ERR;
1602
1603 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1604 param.subpart_name, type, param.dentry_name, param.file_name);
1605
1606 return NO_ACTION_REQUIRED;
1607}
1608
1609static enum ifwi_ret ifwi_raw_extract(int type)
1610{
1611 if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1612 return COMMAND_ERR;
1613
1614 printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1615 param.file_name);
1616
1617 return NO_ACTION_REQUIRED;
1618}
1619
1620static enum ifwi_ret ifwi_extract(void)
1621{
1622 if (!param.file_name) {
1623 ERROR("%s: -f option required\n", __func__);
1624 return COMMAND_ERR;
1625 }
1626
1627 if (!param.subpart_name) {
1628 ERROR("%s: -n option required\n", __func__);
1629 return COMMAND_ERR;
1630 }
1631
1632 int type = find_type_by_name(param.subpart_name);
1633 if (type == -1)
1634 return COMMAND_ERR;
1635
1636 if (type == S_BPDT_TYPE) {
1637 INFO("Tool does not support raw extract for %s\n",
1638 param.subpart_name);
1639 return NO_ACTION_REQUIRED;
1640 }
1641
1642 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1643 ERROR("Image does not contain sub-partition %s(%d).\n",
1644 param.subpart_name, type);
1645 return COMMAND_ERR;
1646 }
1647
1648 INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1649 if (param.dir_ops)
1650 return ifwi_dir_extract(type);
1651
1652 return ifwi_raw_extract(type);
1653}
1654
1655static enum ifwi_ret ifwi_print(void)
1656{
1657 verbose += 2;
1658
1659 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1660
1661 bpdt_print_header(&b->h, "BPDT");
1662 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1663
1664 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1665 bpdt_print_header(&b->h, "S-BPDT");
1666 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1667
1668 if (param.dir_ops == 0) {
1669 verbose -= 2;
1670 return NO_ACTION_REQUIRED;
1671 }
1672
1673 int i;
1674 struct buffer subpart_dir_buf;
1675 for (i = 0; i < MAX_SUBPARTS ; i++) {
1676 if (!(subparts[i].attr & CONTAINS_DIR) ||
1677 (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
1678 continue;
1679
1680 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1681 subparts[i].name);
1682 buffer_delete(&subpart_dir_buf);
1683 }
1684
1685 verbose -= 2;
1686
1687 return NO_ACTION_REQUIRED;
1688}
1689
1690static enum ifwi_ret ifwi_raw_replace(int type)
1691{
1692 buffer_delete(&ifwi_image.subpart_buf[type]);
1693 return ifwi_raw_add(type);
1694}
1695
1696static enum ifwi_ret ifwi_dir_replace(int type)
1697{
1698 if (!(subparts[type].attr & CONTAINS_DIR)) {
1699 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1700 subparts[type].name, type);
1701 return COMMAND_ERR;
1702 }
1703
1704 if (!param.dentry_name) {
1705 ERROR("%s: -e option required.\n", __func__);
1706 return COMMAND_ERR;
1707 }
1708
1709 struct buffer subpart_dir_buf;
1710 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
1711 subparts[type].name);
1712
1713 uint32_t i;
1714 struct subpart_dir *s = buffer_get(&subpart_dir_buf);
1715
1716 for (i = 0; i < s->h.num_entries; i++) {
1717 if (!strcmp((char *)s->e[i].name, param.dentry_name))
1718 break;
1719 }
1720
1721 if (i == s->h.num_entries) {
1722 ERROR("Entry %s not found in subpartition for %s.\n",
1723 param.dentry_name, param.subpart_name);
1724 exit(-1);
1725 }
1726
1727 struct buffer b;
1728 if (buffer_from_file(&b, param.file_name)) {
1729 ERROR("Failed to read %s\n", param.file_name);
1730 exit(-1);
1731 }
1732
1733 struct buffer dst;
Rolf Evers-Fischereb8b7d62016-06-13 13:51:41 +02001734 size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
1735 buffer_size(&b) - s->e[i].length;
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001736 size_t subpart_start = s->e[i].offset;
1737 size_t subpart_end = s->e[i].offset + s->e[i].length;
1738
1739 alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
1740
1741 uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]);
1742 uint8_t *dst_data = buffer_get(&dst);
1743 size_t curr_offset = 0;
1744
1745 /* Copy data before the sub-partition entry. */
1746 memcpy(dst_data + curr_offset, src_data, subpart_start);
1747 curr_offset += subpart_start;
1748
1749 /* Copy sub-partition entry. */
1750 memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
1751 curr_offset += buffer_size(&b);
1752
1753 /* Copy remaining data. */
1754 memcpy(dst_data + curr_offset, src_data + subpart_end,
1755 buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
1756
1757 /* Update sub-partition buffer. */
1758 int offset = s->e[i].offset;
1759 buffer_delete(&ifwi_image.subpart_buf[type]);
1760 ifwi_image.subpart_buf[type] = dst;
1761
1762 /* Update length of entry in the subpartition. */
1763 s->e[i].length = buffer_size(&b);
1764 buffer_delete(&b);
1765
1766 /* Adjust offsets of affected entries in subpartition. */
1767 offset = s->e[i].offset - offset;
1768 for (; i < s->h.num_entries; i++) {
1769 s->e[i].offset += offset;
1770 }
1771
Furquan Shaikhe51c20b2016-06-15 08:01:10 -07001772 /* Re-calculate checksum. */
1773 s->h.checksum = calc_checksum(s);
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001774
1775 /* Convert members to litte-endian. */
1776 subpart_dir_fixup_write_buffer(&subpart_dir_buf);
1777
1778 memcpy(dst_data, buffer_get(&subpart_dir_buf),
1779 buffer_size(&subpart_dir_buf));
1780
1781 buffer_delete(&subpart_dir_buf);
1782
1783 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
1784 param.subpart_name, type, param.dentry_name, param.file_name);
1785
1786 return REPACK_REQUIRED;
1787}
1788
1789static enum ifwi_ret ifwi_replace(void)
1790{
1791 if (!param.file_name) {
1792 ERROR("%s: -f option required\n", __func__);
1793 return COMMAND_ERR;
1794 }
1795
1796 if (!param.subpart_name) {
1797 ERROR("%s: -n option required\n", __func__);
1798 return COMMAND_ERR;
1799 }
1800
1801 int type = find_type_by_name(param.subpart_name);
1802 if (type == -1)
1803 return COMMAND_ERR;
1804
1805 const struct subpart_info *curr_subpart = &subparts[type];
1806
1807 if (curr_subpart->attr & AUTO_GENERATED) {
1808 ERROR("Cannot replace auto-generated sub-partitions.\n");
1809 return COMMAND_ERR;
1810 }
1811
1812 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1813 ERROR("Image does not contain sub-partition %s(%d).\n",
1814 param.subpart_name, type);
1815 return COMMAND_ERR;
1816 }
1817
1818 if (param.dir_ops)
1819 return ifwi_dir_replace(type);
1820
1821 return ifwi_raw_replace(type);
1822}
1823
1824static enum ifwi_ret ifwi_create(void)
1825{
1826 /*
1827 * Create peels off any non-IFWI content present in the input buffer and
1828 * creates output file with only the IFWI present.
1829 */
1830
1831 if (!param.file_name) {
1832 ERROR("%s: -f option required\n", __func__);
1833 return COMMAND_ERR;
1834 }
1835
1836 /* Peel off any non-IFWI prefix. */
1837 buffer_seek(&ifwi_image.input_buff,
1838 ifwi_image.input_ifwi_start_offset);
1839 /* Peel off any non-IFWI suffix. */
1840 buffer_set_size(&ifwi_image.input_buff,
1841 ifwi_image.input_ifwi_end_offset -
1842 ifwi_image.input_ifwi_start_offset);
1843
1844 /*
1845 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
1846 */
1847 ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
1848 ifwi_image.input_ifwi_start_offset = 0;
1849
1850 param.image_name = param.file_name;
1851
1852 return REPACK_REQUIRED;
1853}
1854
1855struct command {
1856 const char *name;
1857 const char *optstring;
1858 enum ifwi_ret (*function)(void);
1859};
1860
1861static const struct command commands[] = {
Jeremy Compostella31e21882019-12-09 17:02:45 -07001862 {"add", "f:n:e:dsvh?", ifwi_add},
1863 {"create", "f:svh?", ifwi_create},
1864 {"delete", "f:n:svh?", ifwi_delete},
1865 {"extract", "f:n:e:dsvh?", ifwi_extract},
1866 {"print", "dsh?", ifwi_print},
1867 {"replace", "f:n:e:dsvh?", ifwi_replace},
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001868};
1869
1870static struct option long_options[] = {
1871 {"subpart_dentry", required_argument, 0, 'e'},
1872 {"file", required_argument, 0, 'f'},
1873 {"help", required_argument, 0, 'h'},
1874 {"name", required_argument, 0, 'n'},
1875 {"dir_ops", no_argument, 0, 'd'},
1876 {"verbose", no_argument, 0, 'v'},
Jeremy Compostella31e21882019-12-09 17:02:45 -07001877 {"second_lbp", no_argument, 0, 's'},
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001878 {NULL, 0, 0, 0 }
1879};
1880
1881static void usage(const char *name)
1882{
1883 printf("ifwitool: Utility for IFWI manipulation\n\n"
1884 "USAGE:\n"
1885 " %s [-h]\n"
1886 " %s FILE COMMAND [PARAMETERS]\n\n"
1887 "COMMANDs:\n"
Jeremy Compostella31e21882019-12-09 17:02:45 -07001888 " add -f FILE -n NAME [-d -e ENTRY] [-s]\n"
1889 " create -f FILE [-s]\n"
1890 " delete -n NAME [-s]\n"
1891 " extract -f FILE -n NAME [-d -e ENTRY] [-s]\n"
1892 " print [-d] [-s]\n"
1893 " replace -f FILE -n NAME [-d -e ENTRY] [-s]\n"
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001894 "OPTIONs:\n"
1895 " -f FILE : File to read/write/create/extract\n"
Jeremy Compostella31e21882019-12-09 17:02:45 -07001896 " -s : Use the second Logical Boot Partition\n"
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001897 " -d : Perform directory operation\n"
1898 " -e ENTRY: Name of directory entry to operate on\n"
1899 " -v : Verbose level\n"
1900 " -h : Help message\n"
1901 " -n NAME : Name of sub-partition to operate on\n",
1902 name, name
1903 );
1904
1905 printf("\nNAME should be one of:\n");
1906 int i;
1907 for (i = 0; i < MAX_SUBPARTS; i++)
1908 printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
1909 printf("\n");
1910}
1911
1912int main(int argc, char **argv)
1913{
1914 if (argc < 3) {
1915 usage(argv[0]);
1916 return 1;
1917 }
1918
1919 param.image_name = argv[1];
Jeremy Compostella31e21882019-12-09 17:02:45 -07001920 param.logical_boot_partition = LBP1;
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001921 char *cmd = argv[2];
1922 optind += 2;
1923
1924 uint32_t i;
1925
1926 for (i = 0; i < ARRAY_SIZE(commands); i++) {
1927 if (strcmp(cmd, commands[i].name) != 0)
1928 continue;
1929
1930 int c;
1931
1932 while (1) {
1933 int option_index;
1934
1935 c = getopt_long(argc, argv, commands[i].optstring,
1936 long_options, &option_index);
1937
1938 if (c == -1)
1939 break;
1940
1941 /* Filter out illegal long options. */
1942 if (strchr(commands[i].optstring, c) == NULL) {
1943 ERROR("%s: invalid option -- '%c'\n", argv[0],
1944 c);
1945 c = '?';
1946 }
1947
Furquan Shaikh55d2e532016-05-31 11:02:47 -07001948 switch (c) {
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001949 case 'n':
1950 param.subpart_name = optarg;
1951 break;
Jeremy Compostella31e21882019-12-09 17:02:45 -07001952 case 's':
1953 param.logical_boot_partition = LBP2;
1954 break;
Furquan Shaikh233f1b62016-05-19 16:12:16 -07001955 case 'f':
1956 param.file_name = optarg;
1957 break;
1958 case 'd':
1959 param.dir_ops = 1;
1960 break;
1961 case 'e':
1962 param.dentry_name = optarg;
1963 break;
1964 case 'v':
1965 verbose++;
1966 break;
1967 case 'h':
1968 case '?':
1969 usage(argv[0]);
1970 return 1;
1971 default:
1972 break;
1973 }
1974 }
1975
1976 if (ifwi_parse()) {
1977 ERROR("%s: ifwi parsing failed\n", argv[0]);
1978 return 1;
1979 }
1980
1981 enum ifwi_ret ret = commands[i].function();
1982
1983 if (ret == COMMAND_ERR) {
1984 ERROR("%s: failed execution\n", argv[0]);
1985 return 1;
1986 }
1987
1988 if (ret == REPACK_REQUIRED)
1989 ifwi_repack();
1990
1991 return 0;
1992 }
1993
1994 ERROR("%s: invalid command\n", argv[0]);
1995 return 1;
1996}