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