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 <solb@chromium.org>
Reviewed-on: http://review.coreboot.org/10137
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Sol Boucher 2015-05-06 14:44:40 -07:00 committed by Stefan Reinauer
parent 8307050412
commit 32532ac92d
3 changed files with 65 additions and 29 deletions

View File

@ -33,6 +33,8 @@
#include "fit.h" #include "fit.h"
#include "partitioned_file.h" #include "partitioned_file.h"
#define SECTION_WITH_FIT_TABLE "BOOTBLOCK"
struct command { struct command {
const char *name; const char *name;
const char *optstring; const char *optstring;
@ -677,12 +679,29 @@ static int cbfs_update_fit(void)
return 1; 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; struct cbfs_image image;
if (cbfs_image_from_buffer(&image, param.image_region, if (cbfs_image_from_buffer(&image, param.image_region,
param.headeroffset)) param.headeroffset))
return 1; 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) static int cbfs_copy(void)
@ -731,7 +750,7 @@ static const struct command commands[] = {
{"print", "H:r:vh?", cbfs_print, true, false}, {"print", "H:r:vh?", cbfs_print, true, false},
{"read", "r:f:vh?", cbfs_read, true, false}, {"read", "r:f:vh?", cbfs_read, true, false},
{"remove", "H:r:n:vh?", cbfs_remove, true, true}, {"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}, {"write", "r:f:udvh?", cbfs_write, true, true},
}; };

View File

@ -18,13 +18,10 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include "common.h"
#include "cbfs.h"
#include "cbfs_image.h"
#include "fit.h" #include "fit.h"
/* FIXME: This code assumes it is being executed on a little endian machine. */ /* FIXME: This code assumes it is being executed on a little endian machine. */
@ -69,9 +66,9 @@ struct microcode_entry {
int size; 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) 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 * in the host address space at [4G - romsize -> 4G). It also assume all
* pointers have values within this address range. * 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 * in the host address space at [4G - romsize -> 4G). It also assume all
* pointers have values within this address range. * 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; struct fit_table *table;
uint32_t *fit_pointer; uint32_t *fit_pointer;
fit_pointer = rom_buffer_pointer(image, fit_pointer = rom_buffer_pointer(buffer,
ptr_to_offset(image->buffer.size, FIT_POINTER_LOCATION)); ptr_to_offset(offset_helper, buffer,
FIT_POINTER_LOCATION));
/* Ensure pointer is below 4GiB and within 16MiB of 4GiB */ /* Ensure pointer is below 4GiB and within 16MiB of 4GiB */
if (fit_pointer[1] != 0 || fit_pointer[0] < FIT_TABLE_LOWEST_ADDRESS) if (fit_pointer[1] != 0 || fit_pointer[0] < FIT_TABLE_LOWEST_ADDRESS)
return NULL; return NULL;
table = rom_buffer_pointer(image, table = rom_buffer_pointer(buffer,
ptr_to_offset(image->buffer.size, *fit_pointer)); ptr_to_offset(offset_helper, buffer, *fit_pointer));
/* Check that the address field has the proper signature. */ /* Check that the address field has the proper signature. */
if (strncmp((const char *)&table->header.address, FIT_HEADER_ADDRESS, 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; fit->header.checksum = -result;
} }
static void add_microcodde_entries(struct cbfs_image *image, static void add_microcodde_entries(struct fit_table *fit,
struct fit_table *fit, const struct cbfs_image *image,
struct microcode_entry *mcus, int num_mcus) int num_mcus, struct microcode_entry *mcus,
fit_offset_converter_t offset_helper)
{ {
int i; int i;
@ -178,7 +180,8 @@ static void add_microcodde_entries(struct cbfs_image *image,
struct fit_entry *entry = &fit->entries[i]; struct fit_entry *entry = &fit->entries[i];
struct microcode_entry *mcu = &mcus[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); fit_entry_update_size(entry, mcu->size);
entry->version = FIT_MICROCODE_VERSION; entry->version = FIT_MICROCODE_VERSION;
entry->type_checksum_valid = FIT_TYPE_MICROCODE; entry->type_checksum_valid = FIT_TYPE_MICROCODE;
@ -213,9 +216,9 @@ static int parse_microcode_blob(struct cbfs_image *image,
num_mcus = 0; num_mcus = 0;
while (file_length > sizeof(struct microcode_header)) 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. */ /* Quickly sanity check a prospective microcode update. */
if (mcu_header->total_size < sizeof(*mcu_header)) if (mcu_header->total_size < sizeof(*mcu_header))
@ -243,8 +246,9 @@ static int parse_microcode_blob(struct cbfs_image *image,
return 0; return 0;
} }
int fit_update_table(struct cbfs_image *image, int empty_entries, int fit_update_table(struct buffer *bootblock, struct cbfs_image *image,
const char *microcode_blob_name) const char *microcode_blob_name, int empty_entries,
fit_offset_converter_t offset_fn)
{ {
struct fit_table *fit; struct fit_table *fit;
struct cbfs_file *mcode_file; struct cbfs_file *mcode_file;
@ -252,7 +256,7 @@ int fit_update_table(struct cbfs_image *image, int empty_entries,
int ret = 0; int ret = 0;
// struct rom_image image = { .rom = rom, .size = romsize, }; // struct rom_image image = { .rom = rom, .size = romsize, };
fit = locate_fit_table(image); fit = locate_fit_table(offset_fn, bootblock);
if (!fit) { if (!fit) {
ERROR("FIT not found.\n"); ERROR("FIT not found.\n");
@ -279,7 +283,7 @@ int fit_update_table(struct cbfs_image *image, int empty_entries,
goto out; goto out;
} }
add_microcodde_entries(image, fit, mcus, empty_entries); add_microcodde_entries(fit, image, empty_entries, mcus, offset_fn);
update_fit_checksum(fit); update_fit_checksum(fit);
out: out:

View File

@ -20,6 +20,19 @@
#ifndef __CBFSTOOL_FIT_H #ifndef __CBFSTOOL_FIT_H
#define __CBFSTOOL_FIT_H #define __CBFSTOOL_FIT_H
int fit_update_table(struct cbfs_image *image, #include "cbfs_image.h"
int empty_entries, const char *microcode_blob_name); #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 #endif