blob: ba7376f8674efa00e7cb585451f7c4db1b52c9d0 [file] [log] [blame]
#include "sysconfig-header.h"
static bool subpartition_page_aligned(const struct sysconfig_subpartition *part,
uint64_t page_size)
{
// It shall be page-aligned.
if (part->size % page_size || part->offset % page_size) {
return false;
}
return true;
}
static bool subpartition_not_on_page0(const struct sysconfig_subpartition *part,
uint64_t page_size)
{
return part->offset >= page_size;
}
static bool subpartition_out_of_range(const struct sysconfig_subpartition *part,
uint64_t page_size,
uint64_t partition_size)
{
// It shall fit into sysconfig partition size.
if (part->size > partition_size ||
part->offset > partition_size - part->size) {
return false;
}
return true;
}
static bool subpartition_disjoint(const struct sysconfig_subpartition *part_a,
const struct sysconfig_subpartition *part_b)
{
return part_a->offset + part_a->size <= part_b->offset ||
part_b->offset + part_b->size <= part_a->offset;
}
bool
sysconfig_header_valid(const struct sysconfig_header *header,
uint64_t page_size, uint64_t partition_size)
{
// Conditions:
// 1. valid magic.
// 2. valid crc.
// 3. sub-partition fits into partition.
// 4. sub-partitions do not overlap.
// 5. the first page is reserved for header.
if (memcmp(header->magic, SYSCONFIG_HEADER_MAGIC_STR,
sizeof(header->magic))) {
syshdrP("Header has invalid magic.\n");
return false;
}
if (header->crc_value !=
sysconfig_header_crc32(0, (const uint8_t *)header,
offsetof(struct sysconfig_header,
crc_value))) {
syshdrP("Header has invalid crc.\n");
return false;
}
struct sysconfig_subpartition all_parts[] = { header->abr_metadata,
header->sysconfig_data,
header->vb_metadata_a,
header->vb_metadata_b,
header->vb_metadata_r };
int i, j;
int num_subparts =
sizeof(all_parts) / sizeof(struct sysconfig_subpartition);
for (i = 0; i < num_subparts; i++) {
if (!subpartition_page_aligned(&all_parts[i], page_size)) {
syshdrP("sub-partition %d is not page-aligned\n", i);
return false;
}
if (!subpartition_out_of_range(&all_parts[i], page_size,
partition_size)) {
syshdrP("sub-partition %d is out-of-range\n", i);
return false;
}
if (!subpartition_not_on_page0(&all_parts[i], page_size)) {
syshdrP("sub-partition %d occupies page0 reserved for header\n",
i);
return false;
}
for (j = i + 1; j < num_subparts; j++) {
if (!subpartition_disjoint(&all_parts[i],
&all_parts[j])) {
syshdrP("sub-partition %d and %d overlap\n", i,
j);
return false;
}
}
}
return true;
}
bool sysconfig_header_equal(const struct sysconfig_header *lhs,
const struct sysconfig_header *rhs)
{
return memcmp(lhs, rhs, offsetof(struct sysconfig_header, crc_value)) ==
0;
}
void update_sysconfig_header_magic_and_crc(struct sysconfig_header *header)
{
memcpy(header->magic, SYSCONFIG_HEADER_MAGIC_STR,
sizeof(header->magic));
memset(header->reserved, 0, 4);
header->crc_value = sysconfig_header_crc32(
0, (const uint8_t *)header,
offsetof(struct sysconfig_header, crc_value));
}