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