From 6ffd42548bf10cda13a01555ff4fa56d4213cdf2 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Thu, 22 Dec 2022 19:23:29 +0000 Subject: multiboot: Refactor boot data validation, add version numbers Instead of verifying the CRC before every access of the boot data, verify the CRC once at startup and set a flag to indicate the boot data is valid. Also add a framework to support multiple boot protocol versions. Firmware declares the maximum supported protocol version using a version byte in the boot data header. The bootloader chooses the highest version supported by it and the firmware when deciding what boot protocol to use. Change-Id: I810194625dc0833f026d2a23b8d64ed467fa6aca --- firmware/common/multiboot.c | 55 ++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 21 deletions(-) (limited to 'firmware/common/multiboot.c') diff --git a/firmware/common/multiboot.c b/firmware/common/multiboot.c index c2cedc102d..c292aa1c30 100644 --- a/firmware/common/multiboot.c +++ b/firmware/common/multiboot.c @@ -26,44 +26,57 @@ #include #include +static void write_bootdata_v0(struct boot_data_t *data, unsigned int boot_volume) +{ + memset(data->payload, data->length, 0); + + data->boot_volume = boot_volume; + data->version = 0; +} + /* Write bootdata into location in FIRMWARE marked by magic header * Assumes buffer is already loaded with the firmware image * We just need to find the location and write data into the * payload region along with the crc for later verification and use. * Returns payload len on success, - * On error returns EKEY_NOT_FOUND + * On error returns false */ -int write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) +bool write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) { - struct boot_data_t bl_boot_data; - struct boot_data_t *fw_boot_data = NULL; int search_len = MIN(len, BOOT_DATA_SEARCH_SIZE) - sizeof(struct boot_data_t); - int payload_len = EKEY_NOT_FOUND; /* search for boot data header prior to search_len */ for(int i = 0; i < search_len; i++) { - fw_boot_data = (struct boot_data_t*) &buf[i]; - if (fw_boot_data->magic[0] != BOOT_DATA_MAGIC0 || - fw_boot_data->magic[1] != BOOT_DATA_MAGIC1) + struct boot_data_t *data = (struct boot_data_t *)&buf[i]; + if (data->magic[0] != BOOT_DATA_MAGIC0 || + data->magic[1] != BOOT_DATA_MAGIC1) continue; - memset(&bl_boot_data.payload, 0, BOOT_DATA_PAYLOAD_SIZE); - bl_boot_data.boot_volume = boot_volume; + /* Ignore it if the length extends past the end of the buffer. */ + int data_len = offsetof(struct boot_data_t, payload) + data->length; + if (i + data_len > len) + continue; + + /* Determine the maximum supported boot protocol version. + * Version 0 firmware may use 0 or 0xff, all other versions + * declare the highest supported version in the version byte. */ + int proto_version = 0; + if (data->version < 0xff) + proto_version = MIN(BOOT_DATA_VERSION, data->version); - memset(fw_boot_data->payload, 0, fw_boot_data->length); - /* determine maximum bytes we can write to firmware - BOOT_DATA_PAYLOAD_SIZE is the size the bootloader expects */ - payload_len = MIN(BOOT_DATA_PAYLOAD_SIZE, fw_boot_data->length); - fw_boot_data->length = payload_len; - /* copy data to FIRMWARE bootdata struct */ - memcpy(fw_boot_data->payload, &bl_boot_data.payload, payload_len); - /* crc will be used within the firmware to check validity of bootdata */ - fw_boot_data->crc = crc_32(fw_boot_data->payload, payload_len, 0xffffffff); - break; + /* Write boot data according to the selected protocol */ + if (proto_version == 0) + write_bootdata_v0(data, boot_volume); + else + break; + /* Calculate payload CRC, used by all protocol versions. */ + data->crc = crc_32(data->payload, data->length, 0xffffffff); + return true; } - return payload_len; + + return false; } #ifdef HAVE_MULTIBOOT -- cgit v1.2.3