diff options
Diffstat (limited to 'util/cbfstool/cse_serger.c')
-rw-r--r-- | util/cbfstool/cse_serger.c | 987 |
1 files changed, 987 insertions, 0 deletions
diff --git a/util/cbfstool/cse_serger.c b/util/cbfstool/cse_serger.c new file mode 100644 index 0000000000..cc49671d19 --- /dev/null +++ b/util/cbfstool/cse_serger.c @@ -0,0 +1,987 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* CSE Serger - Tool for stitching Intel CSE components */ + +#include <errno.h> +#include <getopt.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include "cse_serger.h" + +#define NO_PARTITION_TYPE (-1) + +static struct params { + bool print_sub_parts; + const char *partition_name; + int partition_type; + const char *output_dir; + const char *image_name; + const char *version_str; + const char *input_file; + struct cse_layout_regions layout_regions; +} params; + +static const struct { + const char *version_str; + const struct bpdt_ops *ops; +} bpdt_ops_table[] = { + { "1.6", &bpdt_1_6_ops }, + { "1.7", &bpdt_1_7_ops }, +}; + +static const struct { + enum subpart_hdr_version version; + const struct subpart_hdr_ops *ops; +} subpart_hdr_ops_table[] = { + { SUBPART_HDR_VERSION_1, &subpart_hdr_1_ops }, + { SUBPART_HDR_VERSION_2, &subpart_hdr_2_ops }, +}; + +static const struct { + enum subpart_entry_version version; + const struct subpart_entry_ops *ops; +} subpart_entry_ops_table[] = { + { SUBPART_ENTRY_VERSION_1, &subpart_entry_1_ops }, +}; + +enum bpdt_entry_type { + SMIP = 0, + CSE_RBE = 1, + CSE_BUP = 2, + UCODE = 3, + IBB = 4, + S_BPDT = 5, + OBB = 6, + CSE_MAIN = 7, + ISH = 8, + CSE_IDLM = 9, + IFP_OVERRIDE = 10, + UTOK = 11, + UFS_PHY = 12, + UFS_GPP = 13, + PMC = 14, + IUNIT = 15, + NVM_CFG = 16, + UEP = 17, + OEM_KM = 20, + PAVP = 22, + IOM_FW = 23, + NPHY_FW = 24, + TBT_FW = 25, + ICC = 32, + + MAX_SUBPARTS, +}; + +static struct { + struct buffer input_buff; + + const struct bpdt_ops *bpdt_ops; + const struct subpart_hdr_ops *subpart_hdr_ops; + const struct subpart_entry_ops *subpart_entry_ops; + + bpdt_hdr_ptr bpdt_hdr; + cse_layout_ptr cse_layout; + struct bpdt_entry bpdt_entries[MAX_SUBPARTS]; + struct buffer subpart_buff[MAX_SUBPARTS]; + bool repack; + size_t file_end_offset; +} ifwi; + +#define SUBPART_WITH_ALT(_index, _rname, _name, _aname) \ + [_index] = { _rname, _name, _aname } +#define SUBPART(_index, _rname, _name) \ + SUBPART_WITH_ALT(_index, _rname, _name, "") + +static const struct { + const char *readable_name; + const char *name; + const char *alt_name; +} subparts[] = { + SUBPART(SMIP, "OEM SMIP", "SMIP"), + SUBPART(CSE_RBE, "CSE RBE", "RBEP"), + SUBPART_WITH_ALT(CSE_BUP, "CSE BUP", "FTPR", "MFTP"), + SUBPART(UCODE, "Microcode", "UCOD"), + SUBPART(IBB, "Initial Boot Block", "IBBP"), + SUBPART(S_BPDT, "Secondary BPDT", "SBDT"), + SUBPART(OBB, "OEM Boot Block", "OBBP"), + SUBPART(CSE_MAIN, "CSE Main", "NFTP"), + SUBPART(ISH, "ISH Firmware", "ISHP"), + SUBPART(CSE_IDLM, "CSE IDLM", "DLMP"), + SUBPART(IFP_OVERRIDE, "IFP override", "IFPP"), + SUBPART(UTOK, "Debug tokens", "UTOK"), + SUBPART(UFS_PHY, "UFS Phy", "UFSP"), + SUBPART(UFS_GPP, "UFS GPP", "UFSG"), + SUBPART(PMC, "PMC Firmware", "PMCP"), + SUBPART(IUNIT, "IUNIT Firmware", "IUNP"), + SUBPART(NVM_CFG, "NVM CFG", "NVMC"), + SUBPART(UEP, "UEP", "UEPP"), + SUBPART(OEM_KM, "OEM Key Manifest", "OEMP"), + SUBPART(PAVP, "PAVP", "PAVP"), + SUBPART(IOM_FW, "IOM Firmware", "IOMP"), + SUBPART(NPHY_FW, "NPHY Firmware", "NPHY"), + SUBPART(TBT_FW, "TBT Firmware", "TBTP"), + SUBPART(ICC, "ICC Firmware", "PCHC"), +}; + +static const char *subpart_readable_name(enum bpdt_entry_type type) +{ + return subparts[type].readable_name; +} + +static const char *subpart_name(enum bpdt_entry_type type) +{ + return subparts[type].name; +} + +static const char *subpart_alt_name(enum bpdt_entry_type type) +{ + return subparts[type].alt_name; +} + +static struct buffer *subpart_buff(int type) +{ + return &ifwi.subpart_buff[type]; +} + +static int subpart_get_type_from_name(const char *name) +{ + int i; + + for (i = 0; i < MAX_SUBPARTS; i++) { + if (subpart_name(i) == NULL) + continue; + + if (!strcmp(subpart_name(i), name)) + return i; + + if (!strcmp(subpart_alt_name(i), name)) + return i; + } + + return -1; +} + +void write_member(struct buffer *buff, void *src, size_t size) +{ + void *dst = buffer_get(buff); + + switch (size) { + case 1: + write_le8(dst, *(uint8_t *)src); + break; + case 2: + write_le16(dst, *(uint16_t *)src); + break; + case 4: + write_le32(dst, *(uint32_t *)src); + break; + case 8: + write_le64(dst, *(uint64_t *)src); + break; + default: + memcpy(dst, src, size); + break; + } + + buffer_seek(buff, size); +} + +void read_member(struct buffer *buff, void *dst, size_t size) +{ + const void *src = buffer_get(buff); + + switch (size) { + case 1: + *(uint8_t *)dst = read_le8(src); + break; + case 2: + *(uint16_t *)dst = read_le16(src); + break; + case 4: + *(uint32_t *)dst = read_le32(src); + break; + case 8: + *(uint64_t *)dst = read_le64(src); + break; + default: + memcpy(dst, src, size); + break; + } + + buffer_seek(buff, size); +} + +static const struct bpdt_ops *get_bpdt_ops(const struct buffer *buff) +{ + assert(buff || params.version_str); + + for (size_t i = 0; i < ARRAY_SIZE(bpdt_ops_table); i++) { + if (params.version_str) { + if (!strcmp(params.version_str, bpdt_ops_table[i].version_str)) + return bpdt_ops_table[i].ops; + else + continue; + } + if (bpdt_ops_table[i].ops->match_version(buff)) + return bpdt_ops_table[i].ops; + } + + return NULL; +} + +static const struct subpart_hdr_ops *get_subpart_hdr_ops(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(subpart_hdr_ops_table); i++) { + if (subpart_hdr_ops_table[i].version == ifwi.bpdt_ops->subpart_hdr_version) + return subpart_hdr_ops_table[i].ops; + } + + return NULL; +} + +static const struct subpart_entry_ops *get_subpart_entry_ops(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(subpart_entry_ops_table); i++) { + if (subpart_entry_ops_table[i].version == ifwi.bpdt_ops->subpart_entry_version) + return subpart_entry_ops_table[i].ops; + } + + return NULL; +} + +static int subpart_read(struct buffer *input_buff) +{ + size_t input_size = buffer_size(input_buff); + struct bpdt_entry *e = &ifwi.bpdt_entries[0]; + struct buffer *buff; + + for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++, e++) { + if (e->size == 0) + continue; + + if (e->type >= MAX_SUBPARTS) { + ERROR("Invalid part type(%d)\n", e->type); + return -1; + } + + if (e->offset + e->size > input_size) { + ERROR("Part(%d) exceeds file size. Part offset=0x%x, Part size = 0x%x, File size = 0x%zx\n", + e->type, e->offset, e->size, input_size); + return -1; + } + + buff = subpart_buff(e->type); + if (buffer_size(buff) != 0) { + ERROR("Multiple subparts of same type(%d %s)!\n", + e->type, subpart_name(e->type)); + return -1; + } + + buffer_splice(buff, input_buff, e->offset, e->size); + } + + return 0; +} + +static struct bpdt_entry *find_bpdt_entry(uint32_t type) +{ + struct bpdt_entry *e = &ifwi.bpdt_entries[0]; + + for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++, e++) { + if (e->type == type) + return e; + } + + return NULL; +} + +static struct bpdt_entry *new_bpdt_entry(void) +{ + size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); + if (count == MAX_SUBPARTS) { + ERROR("No space for new BPDT entry!\n"); + return NULL; + } + + ifwi.bpdt_ops->inc_entry_count(ifwi.bpdt_hdr); + + return &ifwi.bpdt_entries[count]; +} + +static void set_file_end_offset(struct buffer *buff) +{ + struct bpdt_entry *e = &ifwi.bpdt_entries[0]; + size_t end_offset; + size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); + + ifwi.file_end_offset = ALIGN_UP(buffer_offset(buff), BUFF_SIZE_ALIGN); + + for (size_t i = 0; i < count; i++, e++) { + end_offset = e->offset + e->size; + if (end_offset > ifwi.file_end_offset) + ifwi.file_end_offset = end_offset; + + } +} + +static void read_bpdt_entries(struct buffer *buff) +{ + struct bpdt_entry *e = &ifwi.bpdt_entries[0]; + size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); + + for (size_t i = 0; i < count; i++, e++) { + READ_MEMBER(buff, e->type); + READ_MEMBER(buff, e->offset); + READ_MEMBER(buff, e->size); + } +} + +static int write_bpdt_entries(struct buffer *buff) +{ + struct bpdt_entry *e = &ifwi.bpdt_entries[0]; + size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); + + if (buffer_size(buff) < count * sizeof(*e)) { + ERROR("Not enough buffer space for bpdt entries!\n"); + return -1; + } + + for (size_t i = 0; i < count; i++, e++) { + WRITE_MEMBER(buff, e->type); + WRITE_MEMBER(buff, e->offset); + WRITE_MEMBER(buff, e->size); + } + + return 0; +} + +static void print_bpdt_entries(void) +{ + const size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); + + if (count == 0) + return; + + const struct bpdt_entry *e = &ifwi.bpdt_entries[0]; + + printf("\n * BPDT entries\n"); + + printf("%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #", + "Partition Name", "Human readable name", "Type", "Offset", "Size"); + + printf("====================================================================" + "====================================================================\n"); + + for (size_t i = 0; i < count; i++) { + printf("%-25zd%-25s%-25s%-25d0x%-23x0x%-23x" + "\n", i+1, subpart_name(e[i].type), subpart_readable_name(e[i].type), + e[i].type, e[i].offset, e[i].size); + } + + printf("====================================================================" + "====================================================================\n"); +} + +static int ifwi_parse(const char *image_name) +{ + struct buffer *input_buff = &ifwi.input_buff; + struct buffer bpdt_buff; + + if (buffer_from_file(input_buff, image_name)) { + ERROR("Failed to read input file %s\n", image_name); + return -1; + } + + buffer_clone(&bpdt_buff, input_buff); + + ifwi.bpdt_ops = get_bpdt_ops(&bpdt_buff); + if (!ifwi.bpdt_ops) { + ERROR("No matching bpdt_ops!\n"); + return -1; + } + + ifwi.bpdt_hdr = ifwi.bpdt_ops->read_hdr(&bpdt_buff); + if (ifwi.bpdt_hdr == NULL) + return -1; + + read_bpdt_entries(&bpdt_buff); + set_file_end_offset(&bpdt_buff); + + if (!ifwi.bpdt_ops->validate_checksum(ifwi.bpdt_hdr, &ifwi.bpdt_entries[0])) { + ERROR("Checksum failed!\n"); + return -1; + } + + ifwi.subpart_hdr_ops = get_subpart_hdr_ops(); + if (ifwi.subpart_hdr_ops == NULL) { + ERROR("No matching subpart_hdr_ops for given BPDT!\n"); + return -1; + } + + ifwi.subpart_entry_ops = get_subpart_entry_ops(); + if (ifwi.subpart_entry_ops == NULL) { + ERROR("No matching subpart_entry_ops for given BPDT!\n"); + return -1; + } + + return subpart_read(&ifwi.input_buff); +} + +static int subpart_write(struct buffer *buff) +{ + struct bpdt_entry *e; + struct buffer *s_buff; + + for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++) { + e = &ifwi.bpdt_entries[i]; + + if (e->size == 0) + continue; + + if (e->offset + e->size > buffer_size(buff)) { + ERROR("Subpart end(0x%x) overflows buffer size(0x%zx)\n", + e->offset + e->size, buffer_size(buff)); + return -1; + } + + s_buff = subpart_buff(e->type); + + if (buffer_size(s_buff) != e->size) { + ERROR("Subpart buffer size does not match BPDT entry size!\n"); + return -1; + } + + memcpy(buffer_get(buff) + e->offset, buffer_get(s_buff), e->size); + } + + return 0; +} + +static int ifwi_repack(void) +{ + if (!ifwi.repack) + return 0; + + struct buffer output_buff; + const size_t size = ifwi.file_end_offset; + struct buffer bpdt_buff; + + if (buffer_create(&output_buff, size, "Output IFWI")) { + ERROR("Unable to allocate output buff!\n"); + return -1; + } + + buffer_clone(&bpdt_buff, &output_buff); + + ifwi.bpdt_ops->update_checksum(ifwi.bpdt_hdr, &ifwi.bpdt_entries[0]); + + if (ifwi.bpdt_ops->write_hdr(&bpdt_buff, ifwi.bpdt_hdr)) + return -1; + + if (write_bpdt_entries(&bpdt_buff)) + return -1; + + subpart_write(&output_buff); + + if (buffer_write_file(&output_buff, params.image_name)) { + ERROR("File write error!\n"); + return -1; + } + + printf("Image written successfully to %s.\n", params.image_name); + return 0; +} + +static bool should_process_partition(int type) +{ + if (params.partition_name) { + const char *name = subpart_name(type); + + if (!name) + return false; + + if (strcmp(params.partition_name, name)) + return false; + } else if (params.partition_type != NO_PARTITION_TYPE) { + if (params.partition_type != type) + return false; + } + + return true; +} + +static int process_entries(int (*fn)(const struct bpdt_entry *e)) +{ + struct bpdt_entry *e = &ifwi.bpdt_entries[0]; + bool found = false; + + for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++, e++) { + if (e->size == 0) + continue; + + if (!should_process_partition(e->type)) + continue; + + if (fn(e)) + return -1; + + found = true; + } + + if (!found && params.partition_name) { + ERROR("Partition %s not found!\n", params.partition_name); + return -1; + } + + if (!found && params.partition_type != NO_PARTITION_TYPE) { + ERROR("Partition type %d not found!\n", params.partition_type); + return -1; + } + + return 0; +} + +static int print_subpart(const struct bpdt_entry *e) +{ + struct buffer buff; + subpart_hdr_ptr hdr; + + printf("\n\n * Subpart entry #%d(%s)\n", e->type, subpart_readable_name(e->type)); + + buffer_clone(&buff, subpart_buff(e->type)); + hdr = ifwi.subpart_hdr_ops->read(&buff); + if (!hdr) { + ERROR("Failed to read subpart header!\n"); + return -1; + } + + ifwi.subpart_hdr_ops->print(hdr); + ifwi.subpart_entry_ops->print(&buff, ifwi.subpart_hdr_ops->get_entry_count(hdr)); + ifwi.subpart_hdr_ops->free(hdr); + + return 0; +} + +static int cmd_print(void) +{ + ifwi.bpdt_ops->print_hdr(ifwi.bpdt_hdr); + print_bpdt_entries(); + + if (!params.print_sub_parts && !params.partition_name && + params.partition_type == NO_PARTITION_TYPE) + return 0; + + return process_entries(print_subpart); +} + +static char *get_file_path(const char *name) +{ + size_t filename_len = strlen(name) + 1; + + /* output_dir name followed by '/' */ + if (params.output_dir) + filename_len += strlen(params.output_dir) + 1; + + char *filepath = malloc(filename_len); + if (!filepath) + return NULL; + + snprintf(filepath, filename_len, "%s%s%s", + params.output_dir ? : "", + params.output_dir ? "/" : "", + name); + + return filepath; +} + +static int write_partition_to_file(const struct bpdt_entry *e) +{ + size_t end_offset = e->offset + e->size - 1; + + if (end_offset > buffer_size(&ifwi.input_buff)) { + ERROR("Offset out of bounds!\n"); + return -1; + } + + const char *name = subpart_name(e->type); + char *filepath = get_file_path(name); + if (!filepath) { + ERROR("Failed to allocate filepath!\n"); + return -1; + } + + printf("Dumping %.4s in %s\n", name, filepath); + + struct buffer buff; + buffer_splice(&buff, &ifwi.input_buff, e->offset, e->size); + buffer_write_file(&buff, filepath); + + free(filepath); + return 0; +} + +static int cmd_dump(void) +{ + struct stat sb; + + if (params.output_dir && (stat(params.output_dir, &sb) == -1)) { + ERROR("Failed to stat %s: %s\n", params.output_dir, strerror(errno)); + return -1; + } + + return process_entries(write_partition_to_file); +} + +static int cmd_print_layout(void) +{ + if (params.version_str == NULL) { + ERROR("No version provided!\n"); + return -1; + } + + const struct bpdt_ops *ops = get_bpdt_ops(NULL); + if (!ops) { + ERROR("No matching bpdt_ops!\n"); + return -1; + } + + struct buffer buff; + if (buffer_from_file(&buff, params.image_name)) { + ERROR("Failed to read input file %s\n", params.image_name); + return -1; + } + + ifwi.cse_layout = ops->read_layout(&buff); + if (!ifwi.cse_layout) { + ERROR("Failed to read CSE layout!\n"); + return -1; + } + + ops->print_layout(ifwi.cse_layout); + + return 0; +} + +static int allocate_buffer(struct buffer *buff, struct buffer *wbuff, const char *str) +{ + if (params.version_str == NULL) { + ERROR("No version provided!\n"); + return -1; + } + + ifwi.bpdt_ops = get_bpdt_ops(NULL); + if (!ifwi.bpdt_ops) + return -1; + + if (buffer_create(buff, BUFF_SIZE_ALIGN, str)) { + ERROR("Buffer creation error!\n"); + return -1; + } + + void *data = buffer_get(buff); + memset(data, 0xff, buffer_size(buff)); + + buffer_clone(wbuff, buff); + + return 0; +} + +static int cmd_create_layout(void) +{ + struct buffer buff, wbuff; + + if (allocate_buffer(&buff, &wbuff, "CSE layout")) + return -1; + + ifwi.cse_layout = ifwi.bpdt_ops->create_layout(¶ms.layout_regions); + if (!ifwi.cse_layout) { + ERROR("Failed to create layout!\n"); + return -1; + } + + if (ifwi.bpdt_ops->write_layout(&wbuff, ifwi.cse_layout)) { + ERROR("Failed to write CSE layout!\n"); + return -1; + } + + buffer_write_file(&buff, params.image_name); + return 0; +} + +static int cmd_create_bpdt(void) +{ + struct buffer buff; + struct buffer wbuff; + + if (allocate_buffer(&buff, &wbuff, "BPDT header")) + return -1; + + ifwi.bpdt_hdr = ifwi.bpdt_ops->create_hdr(); + if (!ifwi.bpdt_hdr) { + ERROR("Failed to create BPDT header!\n"); + return -1; + } + + ifwi.bpdt_ops->update_checksum(ifwi.bpdt_hdr, NULL); + + if (ifwi.bpdt_ops->write_hdr(&wbuff, ifwi.bpdt_hdr)) { + ERROR("Failed to write BPDT header!\n"); + return -1; + } + + buffer_write_file(&buff, params.image_name); + return 0; +} + +static int cmd_add(void) +{ + if (!params.partition_name && params.partition_type == NO_PARTITION_TYPE) { + ERROR("Partition name/type is required for add!\n"); + return -1; + } + + int type; + + if (params.partition_name) { + type = subpart_get_type_from_name(params.partition_name); + if (type == NO_PARTITION_TYPE) { + ERROR("Invalid partition %s\n", params.partition_name); + return -1; + } + } else { + type = params.partition_type; + if (type > MAX_SUBPARTS) { + ERROR("Invalid type %d\n", type); + return -1; + } + } + + struct bpdt_entry *e = find_bpdt_entry(type); + if (e) { + ERROR("Partition %s(%d) already exists!\n", params.partition_name ? : "", type); + return -1; + } + + e = new_bpdt_entry(); + if (e == NULL) + return -1; + + e->type = type; + e->offset = 0; + e->size = 0; + + ifwi.repack = true; + + if (params.input_file == NULL) + return 0; + + struct buffer *buff = subpart_buff(type); + if (buffer_from_file_aligned_size(buff, params.input_file, BUFF_SIZE_ALIGN)) { + ERROR("Failed to read input file %s\n", params.input_file); + return -1; + } + + e->offset = ALIGN_UP(ifwi.file_end_offset, BUFF_SIZE_ALIGN); + e->size = buffer_size(buff); + + ifwi.file_end_offset = e->offset + e->size; + + return 0; +} + +static void parse_region(struct region *r, char *arg) +{ + char *tok; + + tok = strtok(arg, ":"); + r->offset = strtol(tok, NULL, 0); + + tok = strtok(NULL, ":"); + r->size = strtol(tok, NULL, 0); +} + +static struct command { + const char *name; + const char *optstring; + int (*cb)(void); + bool parse_ifwi; +} commands[] = { + { "print", "n:st:?", cmd_print, true }, + { "dump", "n:o:t:?", cmd_dump, true }, + { "create-layout", "v:?", cmd_create_layout, false }, + { "print-layout", "v:?", cmd_print_layout, false }, + { "create-bpdt", "v:?", cmd_create_bpdt, false }, + { "add", "f:n:t:v:?", cmd_add, true }, +}; + +enum { + LONGOPT_START = 256, + LONGOPT_BP1 = LONGOPT_START, + LONGOPT_BP2, + LONGOPT_BP3, + LONGOPT_BP4, + LONGOPT_DATA, + + LONGOPT_END, +}; + +static struct option long_options[] = { + {"help", required_argument, 0, 'h'}, + {"parition_name", required_argument, 0, 'n'}, + {"output_dir", required_argument, 0, 'o'}, + {"sub_partition", no_argument, 0, 's'}, + {"version", required_argument, 0, 'v'}, + {"bp1", required_argument, 0, LONGOPT_BP1}, + {"bp2", required_argument, 0, LONGOPT_BP2}, + {"bp3", required_argument, 0, LONGOPT_BP3}, + {"bp4", required_argument, 0, LONGOPT_BP4}, + {"dp", required_argument, 0, LONGOPT_DATA}, + {NULL, 0, 0, 0 } +}; + +static bool valid_opt(size_t i, int c) +{ + /* Check if it is one of the optstrings supported by the command. */ + if (strchr(commands[i].optstring, c)) + return true; + + /* + * Check if it is one of the non-ASCII characters. Currently, the + * non-ASCII characters are only checked against the valid list + * irrespective of the command. + */ + return c >= LONGOPT_START && c < LONGOPT_END; +} + +static void usage(const char *name) +{ + printf("%s: Utility for stitching CSE components\n" + "USAGE:\n" + " %s FILE COMMAND\n\n" + "COMMANDs:\n" + " print [-s][-n NAME][-t TYPE]\n" + " dump [-o DIR][-n NAME]\n" + " create-layout --dp <offset:size> --bp1 <offset:size> --bp2 <offset:size> -v VERSION\n" + " print-layout -v VERSION\n" + " create-bpdt -v VERSION\n" + " add [-n NAME][-t TYPE][-f INPUT_FILE]\n" + "\nOPTIONS:\n" + " -f INPUT_FILE : Input file\n" + " -n NAME : Sub-partition name\n" + " -o DIR : Output directory\n" + " -s : Print sub-partition info\n" + " -t TYPE : Sub-partition type\n" + " -v VERSION : BPDT version\n" + " --dp <offset:size> : Offset and size of data partition\n" + " --bp1 <offset:size> : Offset and size of BP1\n" + " --bp2 <offset:size> : Offset and size of BP2\n" + " --bp3 <offset:size> : Offset and size of BP3\n" + " --bp4 <offset:size> : Offset and size of BP4\n" + "\n", + name, name); +} + +int main(int argc, char **argv) +{ + if (argc < 3) { + printf("Incorrect number of args(%d)!\n", argc); + usage(argv[0]); + return 1; + } + + const char *prog_name = argv[0]; + const char *image_name = argv[1]; + const char *cmd = argv[2]; + + size_t i; + + params.partition_type = NO_PARTITION_TYPE; + params.image_name = image_name; + + for (i = 0; i < ARRAY_SIZE(commands); i++) { + if (strcmp(cmd, commands[i].name)) + continue; + + int c; + int option_index; + + while (1) { + c = getopt_long(argc, argv, commands[i].optstring, + long_options, &option_index); + + if (c == -1) + break; + + if (!valid_opt(i, c)) { + if (c < LONGOPT_START) { + ERROR("Invalid option -- '%c'\n", c); + } else { + ERROR("Invalid option -- '%d'\n", c); + } + usage(prog_name); + return 1; + } + + switch (c) { + case 'f': + params.input_file = optarg; + break; + case 'n': + params.partition_name = optarg; + break; + case 'o': + params.output_dir = optarg; + break; + case 's': + params.print_sub_parts = true; + break; + case 'v': + params.version_str = optarg; + break; + case 't': + params.partition_type = atoi(optarg); + break; + case LONGOPT_BP1: + parse_region(¶ms.layout_regions.bp1, optarg); + break; + case LONGOPT_BP2: + parse_region(¶ms.layout_regions.bp2, optarg); + break; + case LONGOPT_BP3: + parse_region(¶ms.layout_regions.bp3, optarg); + break; + case LONGOPT_BP4: + parse_region(¶ms.layout_regions.bp4, optarg); + break; + case LONGOPT_DATA: + parse_region(¶ms.layout_regions.data_partition, optarg); + break; + case 'h': + case '?': + default: + usage(prog_name); + return 1; + } + } + + break; + } + + if (i == ARRAY_SIZE(commands)) { + printf("No command match %s!\n", cmd); + usage(prog_name); + return 1; + } + + if (commands[i].parse_ifwi && ifwi_parse(image_name)) + return 1; + + if (commands[i].cb()) + return 1; + + return ifwi_repack(); +} |