From 32532ac92dd83d08e5d10de2d3a41fe3c9092e2c Mon Sep 17 00:00:00 2001 From: Sol Boucher Date: Wed, 6 May 2015 14:44:40 -0700 Subject: cbfstool: Make update-fit action work on new-style images Because new images place the bootblock in a separate region from the primary CBFS, performing an update-fit operation requires reading an additional section and choosing a different destination for the write based on the image type. Since other actions are not affected by these requirements, the logic for the optional read and all writing is implemented in the cbfs_update_fit() function itself, rather than relying on the main() function for writing as the other actions do. Change-Id: I2024c59715120ecc3b9b158e007ebce75acff023 Signed-off-by: Sol Boucher Reviewed-on: http://review.coreboot.org/10137 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- util/cbfstool/cbfstool.c | 23 +++++++++++++++++++-- util/cbfstool/fit.c | 54 ++++++++++++++++++++++++++---------------------- util/cbfstool/fit.h | 17 +++++++++++++-- 3 files changed, 65 insertions(+), 29 deletions(-) diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index bd84b01e5b..06d0cef1d4 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -33,6 +33,8 @@ #include "fit.h" #include "partitioned_file.h" +#define SECTION_WITH_FIT_TABLE "BOOTBLOCK" + struct command { const char *name; const char *optstring; @@ -677,12 +679,29 @@ static int cbfs_update_fit(void) return 1; } + // Decide which region to read/write the FIT table from/to. + struct buffer bootblock; + if (partitioned_file_is_partitioned(param.image_file)) { + if (!partitioned_file_read_region(&bootblock, param.image_file, + SECTION_WITH_FIT_TABLE)) + return 1; + } else { + // In legacy images, the bootblock is part of the CBFS. + buffer_clone(&bootblock, param.image_region); + } + struct cbfs_image image; if (cbfs_image_from_buffer(&image, param.image_region, param.headeroffset)) return 1; - return fit_update_table(&image, param.fit_empty_entries, param.name); + if (fit_update_table(&bootblock, &image, param.name, + param.fit_empty_entries, convert_to_from_top_aligned)) + return 1; + + // The region to be written depends on the type of image, so we write it + // here rather than having main() write the CBFS region back as usual. + return !partitioned_file_write_region(param.image_file, &bootblock); } static int cbfs_copy(void) @@ -731,7 +750,7 @@ static const struct command commands[] = { {"print", "H:r:vh?", cbfs_print, true, false}, {"read", "r:f:vh?", cbfs_read, true, false}, {"remove", "H:r:n:vh?", cbfs_remove, true, true}, - {"update-fit", "H:r:n:x:vh?", cbfs_update_fit, true, true}, + {"update-fit", "H:r:n:x:vh?", cbfs_update_fit, true, false}, {"write", "r:f:udvh?", cbfs_write, true, true}, }; diff --git a/util/cbfstool/fit.c b/util/cbfstool/fit.c index 0a7bea5725..6039714456 100644 --- a/util/cbfstool/fit.c +++ b/util/cbfstool/fit.c @@ -18,13 +18,10 @@ */ #include +#include #include #include -#include -#include "common.h" -#include "cbfs.h" -#include "cbfs_image.h" #include "fit.h" /* FIXME: This code assumes it is being executed on a little endian machine. */ @@ -69,9 +66,9 @@ struct microcode_entry { int size; }; -static inline void *rom_buffer_pointer(struct cbfs_image *image, int offset) +static inline void *rom_buffer_pointer(struct buffer *buffer, int offset) { - return &image->buffer.data[offset]; + return &buffer->data[offset]; } static inline int fit_entry_size_bytes(struct fit_entry *entry) @@ -104,9 +101,10 @@ static inline int fit_entry_type(struct fit_entry *entry) * in the host address space at [4G - romsize -> 4G). It also assume all * pointers have values within this address range. */ -static inline int ptr_to_offset(uint32_t theromsize, uint32_t host_ptr) +static inline int ptr_to_offset(fit_offset_converter_t helper, + const struct buffer *region, uint32_t host_ptr) { - return (int)(theromsize + host_ptr); + return helper(region, -host_ptr); } /* @@ -114,25 +112,28 @@ static inline int ptr_to_offset(uint32_t theromsize, uint32_t host_ptr) * in the host address space at [4G - romsize -> 4G). It also assume all * pointers have values within this address range. */ -static inline uint32_t offset_to_ptr(uint32_t theromsize, int offset) +static inline uint32_t offset_to_ptr(fit_offset_converter_t helper, + const struct buffer *region, int offset) { - return -(theromsize - (uint32_t )offset); + return -helper(region, offset); } -static struct fit_table *locate_fit_table(struct cbfs_image *image) +static struct fit_table *locate_fit_table(fit_offset_converter_t offset_helper, + struct buffer *buffer) { struct fit_table *table; uint32_t *fit_pointer; - fit_pointer = rom_buffer_pointer(image, - ptr_to_offset(image->buffer.size, FIT_POINTER_LOCATION)); + fit_pointer = rom_buffer_pointer(buffer, + ptr_to_offset(offset_helper, buffer, + FIT_POINTER_LOCATION)); /* Ensure pointer is below 4GiB and within 16MiB of 4GiB */ if (fit_pointer[1] != 0 || fit_pointer[0] < FIT_TABLE_LOWEST_ADDRESS) return NULL; - table = rom_buffer_pointer(image, - ptr_to_offset(image->buffer.size, *fit_pointer)); + table = rom_buffer_pointer(buffer, + ptr_to_offset(offset_helper, buffer, *fit_pointer)); /* Check that the address field has the proper signature. */ if (strncmp((const char *)&table->header.address, FIT_HEADER_ADDRESS, @@ -168,9 +169,10 @@ static void update_fit_checksum(struct fit_table *fit) fit->header.checksum = -result; } -static void add_microcodde_entries(struct cbfs_image *image, - struct fit_table *fit, - struct microcode_entry *mcus, int num_mcus) +static void add_microcodde_entries(struct fit_table *fit, + const struct cbfs_image *image, + int num_mcus, struct microcode_entry *mcus, + fit_offset_converter_t offset_helper) { int i; @@ -178,7 +180,8 @@ static void add_microcodde_entries(struct cbfs_image *image, struct fit_entry *entry = &fit->entries[i]; struct microcode_entry *mcu = &mcus[i]; - entry->address = offset_to_ptr(image->buffer.size, mcu->offset); + entry->address = offset_to_ptr(offset_helper, &image->buffer, + mcu->offset); fit_entry_update_size(entry, mcu->size); entry->version = FIT_MICROCODE_VERSION; entry->type_checksum_valid = FIT_TYPE_MICROCODE; @@ -213,9 +216,9 @@ static int parse_microcode_blob(struct cbfs_image *image, num_mcus = 0; while (file_length > sizeof(struct microcode_header)) { - struct microcode_header *mcu_header; + const struct microcode_header *mcu_header; - mcu_header = rom_buffer_pointer(image, current_offset); + mcu_header = rom_buffer_pointer(&image->buffer, current_offset); /* Quickly sanity check a prospective microcode update. */ if (mcu_header->total_size < sizeof(*mcu_header)) @@ -243,8 +246,9 @@ static int parse_microcode_blob(struct cbfs_image *image, return 0; } -int fit_update_table(struct cbfs_image *image, int empty_entries, - const char *microcode_blob_name) +int fit_update_table(struct buffer *bootblock, struct cbfs_image *image, + const char *microcode_blob_name, int empty_entries, + fit_offset_converter_t offset_fn) { struct fit_table *fit; struct cbfs_file *mcode_file; @@ -252,7 +256,7 @@ int fit_update_table(struct cbfs_image *image, int empty_entries, int ret = 0; // struct rom_image image = { .rom = rom, .size = romsize, }; - fit = locate_fit_table(image); + fit = locate_fit_table(offset_fn, bootblock); if (!fit) { ERROR("FIT not found.\n"); @@ -279,7 +283,7 @@ int fit_update_table(struct cbfs_image *image, int empty_entries, goto out; } - add_microcodde_entries(image, fit, mcus, empty_entries); + add_microcodde_entries(fit, image, empty_entries, mcus, offset_fn); update_fit_checksum(fit); out: diff --git a/util/cbfstool/fit.h b/util/cbfstool/fit.h index 3f3185c758..51e3c0feca 100644 --- a/util/cbfstool/fit.h +++ b/util/cbfstool/fit.h @@ -20,6 +20,19 @@ #ifndef __CBFSTOOL_FIT_H #define __CBFSTOOL_FIT_H -int fit_update_table(struct cbfs_image *image, - int empty_entries, const char *microcode_blob_name); +#include "cbfs_image.h" +#include "common.h" + +/* + * Converts between offsets from the start of the specified image region and + * "top-aligned" offsets from the top of the entire flash image. Should work in + * both directions: accepts either type of offset and produces the other type. + * The implementation must have some notion of the flash image's total size. + */ +typedef unsigned (*fit_offset_converter_t)(const struct buffer *region, + unsigned offset); + +int fit_update_table(struct buffer *bootblock, struct cbfs_image *image, + const char *microcode_blob_name, int empty_entries, + fit_offset_converter_t offset_fn); #endif -- cgit v1.2.3