summaryrefslogtreecommitdiff
path: root/util/cbfstool/bpdt_formats
diff options
context:
space:
mode:
Diffstat (limited to 'util/cbfstool/bpdt_formats')
-rw-r--r--util/cbfstool/bpdt_formats/Makefile.inc8
-rw-r--r--util/cbfstool/bpdt_formats/bpdt_1_6.c272
-rw-r--r--util/cbfstool/bpdt_formats/bpdt_1_7.c367
-rw-r--r--util/cbfstool/bpdt_formats/subpart_entry_1.c66
-rw-r--r--util/cbfstool/bpdt_formats/subpart_hdr_1.c69
-rw-r--r--util/cbfstool/bpdt_formats/subpart_hdr_2.c72
6 files changed, 854 insertions, 0 deletions
diff --git a/util/cbfstool/bpdt_formats/Makefile.inc b/util/cbfstool/bpdt_formats/Makefile.inc
new file mode 100644
index 0000000000..c676489e9f
--- /dev/null
+++ b/util/cbfstool/bpdt_formats/Makefile.inc
@@ -0,0 +1,8 @@
+
+bpdt_formats_obj += bpdt_1_6.o
+bpdt_formats_obj += bpdt_1_7.o
+
+bpdt_formats_obj += subpart_hdr_1.o
+bpdt_formats_obj += subpart_hdr_2.o
+
+bpdt_formats_obj += subpart_entry_1.o
diff --git a/util/cbfstool/bpdt_formats/bpdt_1_6.c b/util/cbfstool/bpdt_formats/bpdt_1_6.c
new file mode 100644
index 0000000000..eaa2902670
--- /dev/null
+++ b/util/cbfstool/bpdt_formats/bpdt_1_6.c
@@ -0,0 +1,272 @@
+/* BPDT version 1.6 support */
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <sys/types.h>
+
+#include "cse_serger.h"
+
+struct bpdt_header {
+ uint32_t signature; /* BPDT_SIGNATURE */
+ uint16_t descriptor_count;
+ uint16_t version; /* Layout 1.6 = 1 */
+ uint16_t reserved;
+ uint8_t whole_checksum;
+ uint8_t rom_checksum;
+ uint32_t ifwi_version;
+ struct {
+ uint16_t major;
+ uint16_t minor;
+ uint16_t build;
+ uint16_t hotfix;
+ } fit_tool_version;
+} __packed;
+
+struct cse_layout {
+ uint8_t rom_bypass[16];
+ uint32_t data_offset;
+ uint32_t data_size;
+ uint32_t bp1_offset;
+ uint32_t bp1_size;
+ uint32_t bp2_offset;
+ uint32_t bp2_size;
+ uint32_t bp3_offset;
+ uint32_t bp3_size;
+ uint32_t reserved[16];
+ uint8_t checksum;
+} __packed;
+
+static bool match_version(const struct buffer *buff)
+{
+ const uint8_t *data = buffer_get(buff);
+ const uint32_t sig = read_le32(data);
+ const uint16_t version = read_at_le16(data, offsetof(struct bpdt_header, version));
+
+ if (sig != BPDT_SIGNATURE) {
+ ERROR("Invalid BPDT signature(0x%x)!\n", sig);
+ return false;
+ }
+
+ return version == BPDT_VERSION_1_6;
+}
+
+static bpdt_hdr_ptr create_bpdt_hdr(void)
+{
+ struct bpdt_header *h = malloc(sizeof(*h));
+
+ if (!h)
+ return NULL;
+
+ h->signature = BPDT_SIGNATURE;
+ h->descriptor_count = 0;
+ h->version = BPDT_VERSION_1_6;
+ h->reserved = 0;
+ /* TODO(b/202549343): Need to calculate checksum */
+ h->whole_checksum = 0;
+ h->rom_checksum = 0;
+ h->ifwi_version = 0;
+ h->fit_tool_version.major = 0;
+ h->fit_tool_version.minor = 0;
+ h->fit_tool_version.build = 0;
+ h->fit_tool_version.hotfix = 0;
+
+ return 0;
+}
+
+static void print_bpdt_hdr(const bpdt_hdr_ptr ptr)
+{
+ struct bpdt_header *h = ptr;
+
+ printf(" * BPDT header\n");
+ printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
+ printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
+ printf("%-25s %d (Layout 1.6)\n", "BPDT Version", h->version);
+ printf("%-25s 0x%-23x\n", "Reserved", h->reserved);
+ printf("%-25s 0x%-23x\n", "Whole Checksum", h->whole_checksum);
+ printf("%-25s 0x%-23x\n", "ROM Checksum", h->rom_checksum);
+ printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
+ printf("%-25s %d.%d.%d.%d(%.2x.%.2x.%.2x.%.2x)\n", "FIT Tool Version",
+ h->fit_tool_version.major, h->fit_tool_version.minor,
+ h->fit_tool_version.build, h->fit_tool_version.hotfix,
+ h->fit_tool_version.major, h->fit_tool_version.minor,
+ h->fit_tool_version.build, h->fit_tool_version.hotfix);
+}
+
+static bpdt_hdr_ptr read_bpdt_hdr(struct buffer *buff)
+{
+ struct bpdt_header *h = malloc(sizeof(*h));
+
+ if (!h)
+ return NULL;
+
+ READ_MEMBER(buff, h->signature);
+ READ_MEMBER(buff, h->descriptor_count);
+ READ_MEMBER(buff, h->version);
+ READ_MEMBER(buff, h->reserved);
+ READ_MEMBER(buff, h->whole_checksum);
+ READ_MEMBER(buff, h->rom_checksum);
+ READ_MEMBER(buff, h->ifwi_version);
+ READ_MEMBER(buff, h->fit_tool_version);
+
+ return h;
+}
+
+static int write_bpdt_hdr(struct buffer *buff, const bpdt_hdr_ptr ptr)
+{
+ struct bpdt_header *h = ptr;
+
+ if (buffer_size(buff) < sizeof(struct bpdt_header)) {
+ ERROR("Not enough size in buffer for BPDT header!\n");
+ return -1;
+ }
+
+ WRITE_MEMBER(buff, h->signature);
+ WRITE_MEMBER(buff, h->descriptor_count);
+ WRITE_MEMBER(buff, h->version);
+ WRITE_MEMBER(buff, h->reserved);
+ WRITE_MEMBER(buff, h->whole_checksum);
+ WRITE_MEMBER(buff, h->rom_checksum);
+ WRITE_MEMBER(buff, h->ifwi_version);
+ WRITE_MEMBER(buff, h->fit_tool_version);
+
+ return 0;
+}
+
+static size_t get_bpdt_entry_count(const bpdt_hdr_ptr ptr)
+{
+ return ((const struct bpdt_header *)ptr)->descriptor_count;
+}
+
+static void inc_bpdt_entry_count(bpdt_hdr_ptr ptr)
+{
+ struct bpdt_header *h = ptr;
+ h->descriptor_count++;
+}
+
+static cse_layout_ptr create_cse_layout(const struct cse_layout_regions *r)
+{
+ struct cse_layout *l = malloc(sizeof(*l));
+
+ if (!l)
+ return NULL;
+
+ l->data_offset = r->data_partition.offset;
+ l->data_size = r->data_partition.size;
+ l->bp1_offset = r->bp1.offset;
+ l->bp1_size = r->bp1.size;
+ l->bp2_offset = r->bp2.offset;
+ l->bp2_size = r->bp2.size;
+ l->bp3_offset = r->bp3.offset;
+ l->bp3_size = r->bp3.size;
+ l->checksum = 0; /* unused */
+
+ return 0;
+}
+
+static void print_cse_layout(const cse_layout_ptr ptr)
+{
+ struct cse_layout *l = ptr;
+
+ printf(" * CSE Layout\n\n");
+ printf("ROM Bypass: ");
+ for (size_t i = 0; i < sizeof(l->rom_bypass); i++)
+ printf("0x%x ", l->rom_bypass[i]);
+ printf("\n");
+ printf("Data partition offset: 0x%x\n", l->data_offset);
+ printf("Data partition size: 0x%x\n", l->data_size);
+ printf("BP1 offset: 0x%x\n", l->bp1_offset);
+ printf("BP1 size: 0x%x\n", l->bp1_size);
+ printf("BP2 offset: 0x%x\n", l->bp2_offset);
+ printf("BP2 size: 0x%x\n", l->bp2_size);
+ printf("BP3 offset: 0x%x\n", l->bp3_offset);
+ printf("BP3 size: 0x%x\n", l->bp3_size);
+ printf("Checksum: 0x%x\n", l->checksum);
+}
+
+static cse_layout_ptr read_cse_layout(struct buffer *buff)
+{
+ struct cse_layout *l = malloc(sizeof(*l));
+
+ if (!l)
+ return NULL;
+
+ READ_MEMBER(buff, l->rom_bypass);
+ READ_MEMBER(buff, l->data_offset);
+ READ_MEMBER(buff, l->data_size);
+ READ_MEMBER(buff, l->bp1_offset);
+ READ_MEMBER(buff, l->bp1_size);
+ READ_MEMBER(buff, l->bp2_offset);
+ READ_MEMBER(buff, l->bp2_size);
+ READ_MEMBER(buff, l->bp3_offset);
+ READ_MEMBER(buff, l->bp3_size);
+ READ_MEMBER(buff, l->reserved);
+ READ_MEMBER(buff, l->checksum);
+
+ return l;
+}
+
+static int write_cse_layout(struct buffer *buff, const cse_layout_ptr ptr)
+{
+ struct cse_layout *l = ptr;
+
+ if (buffer_size(buff) < sizeof(struct cse_layout)) {
+ ERROR("Not enough size in buffer for CSE layout!\n");
+ return -1;
+ }
+
+ WRITE_MEMBER(buff, l->rom_bypass);
+ WRITE_MEMBER(buff, l->data_offset);
+ WRITE_MEMBER(buff, l->data_size);
+ WRITE_MEMBER(buff, l->bp1_offset);
+ WRITE_MEMBER(buff, l->bp1_size);
+ WRITE_MEMBER(buff, l->bp2_offset);
+ WRITE_MEMBER(buff, l->bp2_size);
+ WRITE_MEMBER(buff, l->bp3_offset);
+ WRITE_MEMBER(buff, l->bp3_size);
+ WRITE_MEMBER(buff, l->reserved);
+ WRITE_MEMBER(buff, l->checksum);
+
+ return 0;
+}
+
+static void update_checksum(bpdt_hdr_ptr ptr, struct bpdt_entry *e)
+{
+ (void)ptr;
+ (void)e;
+
+ /* TODO(b/202549343) */
+ ERROR("Update checksum is not supported for 1.6!\n");
+}
+
+static bool validate_checksum(bpdt_hdr_ptr ptr, struct bpdt_entry *e)
+{
+ (void)e;
+ (void)ptr;
+
+ /* TODO(b/202549343) */
+ ERROR("Validate checksum is not supported for 1.6!\n");
+
+ return true;
+}
+
+const struct bpdt_ops bpdt_1_6_ops = {
+ .match_version = match_version,
+
+ .create_hdr = create_bpdt_hdr,
+ .print_hdr = print_bpdt_hdr,
+ .read_hdr = read_bpdt_hdr,
+ .write_hdr = write_bpdt_hdr,
+
+ .get_entry_count = get_bpdt_entry_count,
+ .inc_entry_count = inc_bpdt_entry_count,
+
+ .create_layout = create_cse_layout,
+ .print_layout = print_cse_layout,
+ .read_layout = read_cse_layout,
+ .write_layout = write_cse_layout,
+
+ .update_checksum = update_checksum,
+ .validate_checksum = validate_checksum,
+
+ .subpart_hdr_version = SUBPART_HDR_VERSION_1,
+ .subpart_entry_version = SUBPART_ENTRY_VERSION_1,
+};
diff --git a/util/cbfstool/bpdt_formats/bpdt_1_7.c b/util/cbfstool/bpdt_formats/bpdt_1_7.c
new file mode 100644
index 0000000000..53294242ca
--- /dev/null
+++ b/util/cbfstool/bpdt_formats/bpdt_1_7.c
@@ -0,0 +1,367 @@
+/* BPDT version 1.7 support */
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <sys/types.h>
+
+#include "cse_serger.h"
+
+enum bpdt_flags {
+ BPDT_FLAGS_REDUNDANCY_SUPPORTED = 1 << 0,
+};
+
+struct bpdt_header {
+ uint32_t signature; /* BPDT_SIGNATURE */
+ uint16_t descriptor_count;
+ uint8_t version; /* Layout 1.7 = 2 */
+ uint8_t flags; /* See enum bpdt_flags */
+ uint32_t checksum;
+ uint32_t ifwi_version;
+ struct {
+ uint16_t major;
+ uint16_t minor;
+ uint16_t build;
+ uint16_t hotfix;
+ } fit_tool_version;
+} __packed;
+
+struct cse_layout {
+ uint8_t rom_bypass[16];
+ uint16_t size;
+ uint16_t redundancy;
+ uint32_t checksum;
+ uint32_t data_offset;
+ uint32_t data_size;
+ uint32_t bp1_offset;
+ uint32_t bp1_size;
+ uint32_t bp2_offset;
+ uint32_t bp2_size;
+ uint32_t bp3_offset;
+ uint32_t bp3_size;
+ uint32_t bp4_offset;
+ uint32_t bp4_size;
+ uint32_t bp5_offset;
+ uint32_t bp5_size;
+ uint32_t temp_base_addr;
+ uint32_t temp_base_size;
+ uint32_t flog_offset;
+ uint32_t flog_size;
+} __packed;
+
+static bool match_version(const struct buffer *buff)
+{
+ const uint8_t *data = buffer_get(buff);
+ const uint32_t sig = read_le32(data);
+ const uint8_t version = read_at_le8(data, offsetof(struct bpdt_header, version));
+
+ if (sig != BPDT_SIGNATURE) {
+ ERROR("Invalid BPDT signature(0x%x)!\n", sig);
+ return false;
+ }
+
+ return version == BPDT_VERSION_1_7;
+}
+
+static bpdt_hdr_ptr create_bpdt_hdr(void)
+{
+ struct bpdt_header *h = calloc(1, sizeof(*h));
+
+ if (!h)
+ return NULL;
+
+ h->signature = BPDT_SIGNATURE;
+ h->descriptor_count = 0;
+ h->version = BPDT_VERSION_1_7;
+ h->flags = 0;
+ h->checksum = 0;
+ h->ifwi_version = 0;
+ h->fit_tool_version.major = 0;
+ h->fit_tool_version.minor = 0;
+ h->fit_tool_version.build = 0;
+ h->fit_tool_version.hotfix = 0;
+
+ return h;
+}
+
+static void print_bpdt_hdr(const bpdt_hdr_ptr ptr)
+{
+ struct bpdt_header *h = ptr;
+
+ printf(" * BPDT header\n");
+ printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
+ printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
+ printf("%-25s %d (Layout 1.7)\n", "BPDT Version", h->version);
+ printf("%-25s 0x%-23x\n", "Flags", h->flags);
+ printf("%-25s 0x%-23x\n", "Checksum", h->checksum);
+ printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
+ printf("%-25s %d.%d.%d.%d(%.2x.%.2x.%.2x.%.2x)\n", "FIT Tool Version",
+ h->fit_tool_version.major, h->fit_tool_version.minor,
+ h->fit_tool_version.build, h->fit_tool_version.hotfix,
+ h->fit_tool_version.major, h->fit_tool_version.minor,
+ h->fit_tool_version.build, h->fit_tool_version.hotfix);
+}
+
+static bpdt_hdr_ptr read_bpdt_hdr(struct buffer *buff)
+{
+ struct bpdt_header *h = calloc(1, sizeof(*h));
+
+ if (!h)
+ return NULL;
+
+ READ_MEMBER(buff, h->signature);
+ READ_MEMBER(buff, h->descriptor_count);
+ READ_MEMBER(buff, h->version);
+ READ_MEMBER(buff, h->flags);
+ READ_MEMBER(buff, h->checksum);
+ READ_MEMBER(buff, h->ifwi_version);
+ READ_MEMBER(buff, h->fit_tool_version);
+
+ return h;
+}
+
+static int write_bpdt_hdr(struct buffer *buff, const bpdt_hdr_ptr ptr)
+{
+ struct bpdt_header *h = ptr;
+
+ if (buffer_size(buff) < sizeof(struct bpdt_header)) {
+ ERROR("Not enough size in buffer for BPDT header!\n");
+ return -1;
+ }
+
+ WRITE_MEMBER(buff, h->signature);
+ WRITE_MEMBER(buff, h->descriptor_count);
+ WRITE_MEMBER(buff, h->version);
+ WRITE_MEMBER(buff, h->flags);
+ WRITE_MEMBER(buff, h->checksum);
+ WRITE_MEMBER(buff, h->ifwi_version);
+ WRITE_MEMBER(buff, h->fit_tool_version);
+
+ return 0;
+}
+
+static size_t get_bpdt_entry_count(const bpdt_hdr_ptr ptr)
+{
+ return ((const struct bpdt_header *)ptr)->descriptor_count;
+}
+
+static void inc_bpdt_entry_count(bpdt_hdr_ptr ptr)
+{
+ struct bpdt_header *h = ptr;
+ h->descriptor_count++;
+}
+
+static uint32_t crc32(uint32_t seed, const uint8_t *data, size_t len)
+{
+ uint32_t crc = seed;
+
+ for (size_t i = 0; i < len; i++) {
+ crc ^= *data++;
+
+ for (size_t b = 0; b < 8; b++) {
+ if (crc & 1)
+ crc = (crc >> 1) ^ 0xedb88320;
+ else
+ crc = crc >> 1;
+ }
+ }
+
+ return crc;
+}
+
+/*
+ * Calculate checksum by:
+ * a. stashing l->checksum in curr_checksum and setting l->checksum to 0
+ * b. calculating checksum
+ * c. restoring l->checksum and return calculated checksum value.
+ */
+static uint32_t calculate_layout_checksum(struct cse_layout *l)
+{
+ uint32_t curr_checksum = l->checksum;
+ uint32_t calc_checksum;
+
+ l->checksum = 0;
+ calc_checksum = ~crc32(0xffffffff, (void *)&l->size, l->size);
+ l->checksum = curr_checksum;
+
+ return calc_checksum;
+}
+
+static cse_layout_ptr create_cse_layout(const struct cse_layout_regions *r)
+{
+ struct cse_layout *l = calloc(1, sizeof(*l));
+
+ if (!l)
+ return NULL;
+
+ memset(l->rom_bypass, 0xff, sizeof(l->rom_bypass));
+ l->size = sizeof(struct cse_layout) - sizeof(l->rom_bypass);
+ l->redundancy = 0;
+ l->checksum = 0;
+ l->data_offset = r->data_partition.offset;
+ l->data_size = r->data_partition.size;
+ l->bp1_offset = r->bp1.offset;
+ l->bp1_size = r->bp1.size;
+ l->bp2_offset = r->bp2.offset;
+ l->bp2_size = r->bp2.size;
+ l->bp3_offset = r->bp3.offset;
+ l->bp3_size = r->bp3.size;
+ l->bp4_offset = r->bp4.offset;
+ l->bp4_size = r->bp4.size;
+ l->bp5_offset = 0;
+ l->bp5_size = 0;
+ l->temp_base_addr = 0;
+ l->temp_base_size = 0;
+ l->flog_offset = 0;
+ l->flog_size = 0;
+
+ l->checksum = calculate_layout_checksum(l);
+
+ return l;
+}
+
+static void print_cse_layout(const cse_layout_ptr ptr)
+{
+ struct cse_layout *l = ptr;
+
+ printf(" * CSE Layout\n\n");
+ printf("ROM Bypass: ");
+ for (size_t i = 0; i < sizeof(l->rom_bypass); i++)
+ printf("0x%x ", l->rom_bypass[i]);
+ printf("\n");
+ printf("Size: 0x%x\n", l->size);
+ printf("Redundancy: 0x%x\n", l->redundancy);
+ printf("Checksum: 0x%x\n", l->checksum);
+ printf("Data partition offset: 0x%x\n", l->data_offset);
+ printf("Data partition size: 0x%x\n", l->data_size);
+ printf("BP1 offset: 0x%x\n", l->bp1_offset);
+ printf("BP1 size: 0x%x\n", l->bp1_size);
+ printf("BP2 offset: 0x%x\n", l->bp2_offset);
+ printf("BP2 size: 0x%x\n", l->bp2_size);
+ printf("BP3 offset: 0x%x\n", l->bp3_offset);
+ printf("BP3 size: 0x%x\n", l->bp3_size);
+ printf("BP4 offset: 0x%x\n", l->bp4_offset);
+ printf("BP4 size: 0x%x\n", l->bp4_size);
+ printf("BP5 offset: 0x%x\n", l->bp5_offset);
+ printf("BP5 size: 0x%x\n", l->bp5_size);
+ printf("Temp base addr: 0x%x\n", l->temp_base_addr);
+ printf("Temp base size: 0x%x\n", l->temp_base_size);
+ printf("FLOG offset: 0x%x\n", l->flog_offset);
+ printf("FLOG size: 0x%x\n", l->flog_size);
+}
+
+static cse_layout_ptr read_cse_layout(struct buffer *buff)
+{
+ struct cse_layout *l = calloc(1, sizeof(*l));
+
+ if (!l)
+ return NULL;
+
+ READ_MEMBER(buff, l->rom_bypass);
+ READ_MEMBER(buff, l->size);
+ READ_MEMBER(buff, l->redundancy);
+ READ_MEMBER(buff, l->checksum);
+ READ_MEMBER(buff, l->data_offset);
+ READ_MEMBER(buff, l->data_size);
+ READ_MEMBER(buff, l->bp1_offset);
+ READ_MEMBER(buff, l->bp1_size);
+ READ_MEMBER(buff, l->bp2_offset);
+ READ_MEMBER(buff, l->bp2_size);
+ READ_MEMBER(buff, l->bp3_offset);
+ READ_MEMBER(buff, l->bp3_size);
+ READ_MEMBER(buff, l->bp4_offset);
+ READ_MEMBER(buff, l->bp4_size);
+ READ_MEMBER(buff, l->bp5_offset);
+ READ_MEMBER(buff, l->bp5_size);
+ READ_MEMBER(buff, l->temp_base_addr);
+ READ_MEMBER(buff, l->temp_base_size);
+ READ_MEMBER(buff, l->flog_offset);
+ READ_MEMBER(buff, l->flog_size);
+
+ return l;
+}
+
+static int write_cse_layout(struct buffer *buff, const cse_layout_ptr ptr)
+{
+ struct cse_layout *l = ptr;
+
+ if (buffer_size(buff) < sizeof(struct cse_layout)) {
+ ERROR("Not enough size in buffer for CSE layout!\n");
+ return -1;
+ }
+
+ WRITE_MEMBER(buff, l->rom_bypass);
+ WRITE_MEMBER(buff, l->size);
+ WRITE_MEMBER(buff, l->redundancy);
+ WRITE_MEMBER(buff, l->checksum);
+ WRITE_MEMBER(buff, l->data_offset);
+ WRITE_MEMBER(buff, l->data_size);
+ WRITE_MEMBER(buff, l->bp1_offset);
+ WRITE_MEMBER(buff, l->bp1_size);
+ WRITE_MEMBER(buff, l->bp2_offset);
+ WRITE_MEMBER(buff, l->bp2_size);
+ WRITE_MEMBER(buff, l->bp3_offset);
+ WRITE_MEMBER(buff, l->bp3_size);
+ WRITE_MEMBER(buff, l->bp4_offset);
+ WRITE_MEMBER(buff, l->bp4_size);
+ WRITE_MEMBER(buff, l->bp5_offset);
+ WRITE_MEMBER(buff, l->bp5_size);
+ WRITE_MEMBER(buff, l->temp_base_addr);
+ WRITE_MEMBER(buff, l->temp_base_size);
+ WRITE_MEMBER(buff, l->flog_offset);
+ WRITE_MEMBER(buff, l->flog_size);
+
+ return 0;
+}
+
+static uint32_t calculate_bpdt_checksum(struct bpdt_header *h, struct bpdt_entry *e)
+{
+ uint32_t calc_checksum;
+ uint32_t curr_checksum = h->checksum;
+
+ h->checksum = 0;
+
+ calc_checksum = crc32(0xffffffff, (void *)&h->descriptor_count,
+ sizeof(*h) - sizeof(h->signature));
+
+ if (e && h->descriptor_count)
+ calc_checksum = crc32(calc_checksum, (void *)e,
+ h->descriptor_count * sizeof(struct bpdt_entry));
+
+ h->checksum = curr_checksum;
+
+ return ~calc_checksum;
+}
+
+static void update_checksum(bpdt_hdr_ptr ptr, struct bpdt_entry *e)
+{
+ struct bpdt_header *h = ptr;
+ h->checksum = calculate_bpdt_checksum(h, e);
+}
+
+static bool validate_checksum(bpdt_hdr_ptr ptr, struct bpdt_entry *e)
+{
+ struct bpdt_header *h = ptr;
+ return calculate_bpdt_checksum(h, e) == h->checksum;
+}
+
+const struct bpdt_ops bpdt_1_7_ops = {
+ .match_version = match_version,
+
+ .create_hdr = create_bpdt_hdr,
+ .print_hdr = print_bpdt_hdr,
+ .read_hdr = read_bpdt_hdr,
+ .write_hdr = write_bpdt_hdr,
+
+ .get_entry_count = get_bpdt_entry_count,
+ .inc_entry_count = inc_bpdt_entry_count,
+
+ .create_layout = create_cse_layout,
+ .print_layout = print_cse_layout,
+ .read_layout = read_cse_layout,
+ .write_layout = write_cse_layout,
+
+ .update_checksum = update_checksum,
+ .validate_checksum = validate_checksum,
+
+ .subpart_hdr_version = SUBPART_HDR_VERSION_2,
+ .subpart_entry_version = SUBPART_ENTRY_VERSION_1,
+};
diff --git a/util/cbfstool/bpdt_formats/subpart_entry_1.c b/util/cbfstool/bpdt_formats/subpart_entry_1.c
new file mode 100644
index 0000000000..a5982ff132
--- /dev/null
+++ b/util/cbfstool/bpdt_formats/subpart_entry_1.c
@@ -0,0 +1,66 @@
+/* Subpart directory entry version 1 support */
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <sys/types.h>
+
+#include "cse_serger.h"
+
+#define SUBPART_OFFSET_SHIFT 0
+#define SUBPART_OFFSET_MASK 0x1ffffff
+#define SUBPART_OFFSET(x) (((x) >> SUBPART_OFFSET_SHIFT) & SUBPART_OFFSET_MASK)
+#define SUBPART_COMPRESSED_SHIFT 25
+#define SUBPART_COMPRESSED_MASK 1
+#define SUBPART_COMPRESSED(x) \
+ (((x) >> SUBPART_COMPRESSED_SHIFT) & SUBPART_COMPRESSED_MASK)
+
+struct subpart_entry {
+ uint8_t name[12];
+ uint32_t offset_bytes;
+ uint32_t length;
+ uint32_t rsvd2;
+} __packed;
+
+static void subpart_read_entry(struct buffer *buff, struct subpart_entry *e)
+{
+ READ_MEMBER(buff, e->name);
+ READ_MEMBER(buff, e->offset_bytes);
+ READ_MEMBER(buff, e->length);
+ READ_MEMBER(buff, e->rsvd2);
+}
+
+static void subpart_print_entry(const struct subpart_entry *e, size_t index)
+{
+ printf("%-25zd%-25.12s0x%-23x%-25c0x%-23x0x%-23x\n", index,
+ e->name, SUBPART_OFFSET(e->offset_bytes),
+ SUBPART_COMPRESSED(e->offset_bytes) ? 'Y' : 'N',
+ e->length, e->rsvd2);
+}
+
+static void subpart_print_entries(struct buffer *buff, size_t count)
+{
+ struct subpart_entry *e = malloc(count * sizeof(*e));
+
+ if (!e)
+ return;
+
+ for (size_t i = 0; i < count; i++)
+ subpart_read_entry(buff, &e[i]);
+
+ printf("%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
+ "Huffman Compressed?", "Length", "Rsvd");
+
+ printf("====================================================================="
+ "=====================================================================\n");
+
+ for (size_t i = 0; i < count; i++)
+ subpart_print_entry(&e[i], i + 1);
+
+ printf("====================================================================="
+ "=====================================================================\n");
+
+ free(e);
+}
+
+const struct subpart_entry_ops subpart_entry_1_ops = {
+ .print = subpart_print_entries,
+};
diff --git a/util/cbfstool/bpdt_formats/subpart_hdr_1.c b/util/cbfstool/bpdt_formats/subpart_hdr_1.c
new file mode 100644
index 0000000000..5335c7a844
--- /dev/null
+++ b/util/cbfstool/bpdt_formats/subpart_hdr_1.c
@@ -0,0 +1,69 @@
+/* Subpart directory header version 1 support */
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <sys/types.h>
+
+#include "cse_serger.h"
+
+struct subpart_hdr {
+ uint32_t signature; /* SUBPART_SIGNATURE */
+ uint32_t count;
+ uint8_t hdr_version; /* Header version = 1 */
+ uint8_t entry_version; /* Entry version = 1 */
+ uint8_t length;
+ uint8_t checksum;
+ uint8_t name[4];
+} __packed;
+
+static void subpart_hdr_print(const subpart_hdr_ptr ptr)
+{
+ const struct subpart_hdr *hdr = ptr;
+
+ printf("%-25s %.4s\n", "Signature", (const char *)&hdr->signature);
+ printf("%-25s %-25d\n", "Count", hdr->count);
+ printf("%-25s %-25d\n", "Header Version", hdr->hdr_version);
+ printf("%-25s %-25d\n", "Entry Version", hdr->entry_version);
+ printf("%-25s 0x%-23x\n", "Header Length", hdr->length);
+ printf("%-25s 0x%-23x\n", "Checksum", hdr->checksum);
+ printf("%-25s ", "Name");
+ for (size_t i = 0; i < sizeof(hdr->name); i++)
+ printf("%c", hdr->name[i]);
+ printf("\n");
+}
+
+static subpart_hdr_ptr subpart_hdr_read(struct buffer *buff)
+{
+ struct subpart_hdr *hdr = malloc(sizeof(*hdr));
+
+ if (!hdr)
+ return NULL;
+
+ READ_MEMBER(buff, hdr->signature);
+ READ_MEMBER(buff, hdr->count);
+ READ_MEMBER(buff, hdr->hdr_version);
+ READ_MEMBER(buff, hdr->entry_version);
+ READ_MEMBER(buff, hdr->length);
+ READ_MEMBER(buff, hdr->checksum);
+ READ_MEMBER(buff, hdr->name);
+
+ return hdr;
+}
+
+static size_t subpart_get_count(const subpart_hdr_ptr ptr)
+{
+ const struct subpart_hdr *hdr = ptr;
+
+ return hdr->count;
+}
+
+static void subpart_hdr_free(subpart_hdr_ptr ptr)
+{
+ free(ptr);
+}
+
+const struct subpart_hdr_ops subpart_hdr_1_ops = {
+ .read = subpart_hdr_read,
+ .print = subpart_hdr_print,
+ .get_entry_count = subpart_get_count,
+ .free = subpart_hdr_free,
+};
diff --git a/util/cbfstool/bpdt_formats/subpart_hdr_2.c b/util/cbfstool/bpdt_formats/subpart_hdr_2.c
new file mode 100644
index 0000000000..17304dc447
--- /dev/null
+++ b/util/cbfstool/bpdt_formats/subpart_hdr_2.c
@@ -0,0 +1,72 @@
+/* Subpart directory header version 2 support */
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <sys/types.h>
+
+#include "cse_serger.h"
+
+struct subpart_hdr {
+ uint32_t signature; /* SUBPART_SIGNATURE */
+ uint32_t count;
+ uint8_t hdr_version; /* Header version = 2 */
+ uint8_t entry_version; /* Entry version = 1 */
+ uint8_t length;
+ uint8_t reserved;
+ uint8_t name[4];
+ uint32_t checksum;
+} __packed;
+
+static subpart_hdr_ptr subpart_hdr_read(struct buffer *buff)
+{
+ struct subpart_hdr *hdr = malloc(sizeof(*hdr));
+
+ if (!hdr)
+ return NULL;
+
+ READ_MEMBER(buff, hdr->signature);
+ READ_MEMBER(buff, hdr->count);
+ READ_MEMBER(buff, hdr->hdr_version);
+ READ_MEMBER(buff, hdr->entry_version);
+ READ_MEMBER(buff, hdr->length);
+ READ_MEMBER(buff, hdr->reserved);
+ READ_MEMBER(buff, hdr->name);
+ READ_MEMBER(buff, hdr->checksum);
+
+ return hdr;
+}
+
+static void subpart_hdr_print(const subpart_hdr_ptr ptr)
+{
+ const struct subpart_hdr *hdr = ptr;
+
+ printf("%-25s %.4s\n", "Signature", (const char *)&hdr->signature);
+ printf("%-25s %-25d\n", "Count", hdr->count);
+ printf("%-25s %-25d\n", "Header Version", hdr->hdr_version);
+ printf("%-25s %-25d\n", "Entry Version", hdr->entry_version);
+ printf("%-25s 0x%-23x\n", "Header Length", hdr->length);
+ printf("%-25s 0x%-23x\n", "Reserved", hdr->reserved);
+ printf("%-25s ", "Name");
+ for (size_t i = 0; i < sizeof(hdr->name); i++)
+ printf("%c", hdr->name[i]);
+ printf("\n");
+ printf("%-25s 0x%-23x\n", "Checksum", hdr->checksum);
+}
+
+static size_t subpart_get_count(const subpart_hdr_ptr ptr)
+{
+ const struct subpart_hdr *hdr = ptr;
+
+ return hdr->count;
+}
+
+static void subpart_hdr_free(subpart_hdr_ptr ptr)
+{
+ free(ptr);
+}
+
+const struct subpart_hdr_ops subpart_hdr_2_ops = {
+ .read = subpart_hdr_read,
+ .print = subpart_hdr_print,
+ .get_entry_count = subpart_get_count,
+ .free = subpart_hdr_free,
+};