blob: b894936543ef361d99eeb45cce98ac7ec380828b [file] [log] [blame]
/* 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 region *r)
{
struct cse_layout *l = malloc(sizeof(*l));
if (!l)
return NULL;
l->data_offset = r[DP].offset;
l->data_size = r[DP].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,
};