cbfstool: Update FIT entries in the second bootblock
Once a second bootblock has been added using topswap (-j) option, Update the entries in second FIT using -j option with update-fit command. Additionally add a -q option which allows to insert the address of a FMAP region (which should hold a microcode) as the first entry in the second FIT. BUG=None BRANCH=None TEST= Create ROM images with -j options and update FIT using -q option. example: ./build/util/cbfstool/cbfstool coreboot.tmp create \ -M build/fmap.fmap -r COREBOOT,FW_MAIN_A,FW_MAIN_B,RW_LEGACY build/util/cbfstool/cbfstool coreboot.tmp add \ -f build/cbfs/fallback/bootblock.bin -n bootblock -t \ bootblock -b -49152 -j 0x10000 build/util/cbfstool/cbfstool coreboot.tmp add-master-header -j 0x10000 build/util/cbfstool/cbfstool coreboot.tmp add -f build/cpu_microcode_blob.bin \ -n cpu_microcode_blob.bin -t microcode -r COREBOOT -a 16 build/util/cbfstool/cbfstool coreboot.tmp. update-fit \ -n cpu_microcode_blob.bin -x 4 -j 0x10000 -q FW_MAIN_A Also try the failure scenarion by providing invalid topswap size. Change-Id: I9a417031c279038903cdf1761a791f2da0fe8644 Signed-off-by: Rizwan Qureshi <rizwan.qureshi@intel.com> Reviewed-on: https://review.coreboot.org/26836 Reviewed-by: Subrata Banik <subrata.banik@intel.com> Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Furquan Shaikh <furquan@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
1dc188fad0
commit
c1072f2fc7
|
@ -59,6 +59,7 @@ static struct param {
|
||||||
const char *source_region;
|
const char *source_region;
|
||||||
const char *bootblock;
|
const char *bootblock;
|
||||||
const char *ignore_section;
|
const char *ignore_section;
|
||||||
|
const char *ucode_region;
|
||||||
uint64_t u64val;
|
uint64_t u64val;
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t baseaddress;
|
uint32_t baseaddress;
|
||||||
|
@ -1209,8 +1210,25 @@ static int cbfs_update_fit(void)
|
||||||
param.headeroffset))
|
param.headeroffset))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
uint32_t addr = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get the address of provided region for first row.
|
||||||
|
*/
|
||||||
|
if (param.ucode_region) {
|
||||||
|
struct buffer ucode;
|
||||||
|
|
||||||
|
if (partitioned_file_read_region(&ucode,
|
||||||
|
param.image_file, param.ucode_region))
|
||||||
|
addr = -convert_to_from_top_aligned(&ucode, 0);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (fit_update_table(&bootblock, &image, param.name,
|
if (fit_update_table(&bootblock, &image, param.name,
|
||||||
param.fit_empty_entries, convert_to_from_top_aligned))
|
param.fit_empty_entries, convert_to_from_top_aligned,
|
||||||
|
param.topswap_size, addr))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// The region to be written depends on the type of image, so we write it
|
// The region to be written depends on the type of image, so we write it
|
||||||
|
@ -1300,7 +1318,7 @@ static const struct command commands[] = {
|
||||||
{"print", "H:r:vkh?", cbfs_print, true, false},
|
{"print", "H:r:vkh?", 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?j:q:", cbfs_update_fit, true, true},
|
||||||
{"write", "r:f:i:Fudvh?", cbfs_write, true, true},
|
{"write", "r:f:i:Fudvh?", cbfs_write, true, true},
|
||||||
{"expand", "r:h?", cbfs_expand, true, true},
|
{"expand", "r:h?", cbfs_expand, true, true},
|
||||||
{"truncate", "r:h?", cbfs_truncate, true, true},
|
{"truncate", "r:h?", cbfs_truncate, true, true},
|
||||||
|
@ -1334,6 +1352,7 @@ static struct option long_options[] = {
|
||||||
{"offset", required_argument, 0, 'o' },
|
{"offset", required_argument, 0, 'o' },
|
||||||
{"padding", required_argument, 0, 'p' },
|
{"padding", required_argument, 0, 'p' },
|
||||||
{"page-size", required_argument, 0, 'P' },
|
{"page-size", required_argument, 0, 'P' },
|
||||||
|
{"ucode-region", required_argument, 0, 'q' },
|
||||||
{"size", required_argument, 0, 's' },
|
{"size", required_argument, 0, 's' },
|
||||||
{"top-aligned", required_argument, 0, 'T' },
|
{"top-aligned", required_argument, 0, 'T' },
|
||||||
{"type", required_argument, 0, 't' },
|
{"type", required_argument, 0, 't' },
|
||||||
|
@ -1464,8 +1483,13 @@ static void usage(char *name)
|
||||||
" expand [-r fmap-region] "
|
" expand [-r fmap-region] "
|
||||||
"Expand CBFS to span entire region\n"
|
"Expand CBFS to span entire region\n"
|
||||||
" update-fit [-r image,regions] -n MICROCODE_BLOB_NAME \\\n"
|
" update-fit [-r image,regions] -n MICROCODE_BLOB_NAME \\\n"
|
||||||
" -x EMTPY_FIT_ENTRIES "
|
" -x EMTPY_FIT_ENTRIES \\ \n"
|
||||||
"Updates the FIT table with microcode entries\n"
|
" [-j topswap-size [-q ucode-region](Intel CPUs only)] "
|
||||||
|
"Updates the FIT table with microcode entries.\n"
|
||||||
|
" "
|
||||||
|
" ucode-region is a region in the FMAP, its address is \n"
|
||||||
|
" "
|
||||||
|
" inserted as the first entry in the topswap FIT. \n"
|
||||||
"\n"
|
"\n"
|
||||||
"OFFSETs:\n"
|
"OFFSETs:\n"
|
||||||
" Numbers accompanying -b, -H, and -o switches* may be provided\n"
|
" Numbers accompanying -b, -H, and -o switches* may be provided\n"
|
||||||
|
@ -1718,6 +1742,9 @@ int main(int argc, char **argv)
|
||||||
if (!is_valid_topswap())
|
if (!is_valid_topswap())
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
case 'q':
|
||||||
|
param.ucode_region = optarg;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose++;
|
verbose++;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -115,6 +115,26 @@ static inline uint32_t offset_to_ptr(fit_offset_converter_t helper,
|
||||||
return -helper(region, offset);
|
return -helper(region, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fit_table_verified(struct fit_table *table)
|
||||||
|
{
|
||||||
|
/* Check that the address field has the proper signature. */
|
||||||
|
if (strncmp((const char *)&table->header.address, FIT_HEADER_ADDRESS,
|
||||||
|
sizeof(table->header.address)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (table->header.version != FIT_HEADER_VERSION)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (fit_entry_type(&table->header) != FIT_TYPE_HEADER)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Assume that the FIT table only contains the header */
|
||||||
|
if (fit_entry_size_bytes(&table->header) != sizeof(struct fit_entry))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct fit_table *locate_fit_table(fit_offset_converter_t offset_helper,
|
static struct fit_table *locate_fit_table(fit_offset_converter_t offset_helper,
|
||||||
struct buffer *buffer)
|
struct buffer *buffer)
|
||||||
{
|
{
|
||||||
|
@ -131,22 +151,9 @@ static struct fit_table *locate_fit_table(fit_offset_converter_t offset_helper,
|
||||||
|
|
||||||
table = rom_buffer_pointer(buffer,
|
table = rom_buffer_pointer(buffer,
|
||||||
ptr_to_offset(offset_helper, buffer, *fit_pointer));
|
ptr_to_offset(offset_helper, buffer, *fit_pointer));
|
||||||
|
if (!fit_table_verified(table))
|
||||||
/* Check that the address field has the proper signature. */
|
|
||||||
if (strncmp((const char *)&table->header.address, FIT_HEADER_ADDRESS,
|
|
||||||
sizeof(table->header.address)))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
else
|
||||||
if (table->header.version != FIT_HEADER_VERSION)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (fit_entry_type(&table->header) != FIT_TYPE_HEADER)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Assume that the FIT table only contains the header */
|
|
||||||
if (fit_entry_size_bytes(&table->header) != sizeof(struct fit_entry))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,24 +173,46 @@ static void update_fit_checksum(struct fit_table *fit)
|
||||||
fit->header.checksum = -result;
|
fit->header.checksum = -result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_fit_ucode_entry(struct fit_table *fit,
|
||||||
|
struct fit_entry *entry, uint64_t mcu_addr)
|
||||||
|
{
|
||||||
|
entry->address = mcu_addr;
|
||||||
|
/*
|
||||||
|
* While loading MCU, its size is not referred from FIT and
|
||||||
|
* rather from the MCU header, hence we can assign zero here
|
||||||
|
*/
|
||||||
|
entry->size_reserved = 0x0000;
|
||||||
|
/* Checksum valid should be cleared for MCU */
|
||||||
|
entry->type_checksum_valid = 0;
|
||||||
|
entry->version = FIT_MICROCODE_VERSION;
|
||||||
|
entry->checksum = 0;
|
||||||
|
fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
|
||||||
|
}
|
||||||
|
|
||||||
static void add_microcodde_entries(struct fit_table *fit,
|
static void add_microcodde_entries(struct fit_table *fit,
|
||||||
const struct cbfs_image *image,
|
const struct cbfs_image *image,
|
||||||
int num_mcus, struct microcode_entry *mcus,
|
int num_mcus, struct microcode_entry *mcus,
|
||||||
fit_offset_converter_t offset_helper)
|
fit_offset_converter_t offset_helper,
|
||||||
|
uint32_t first_mcu_addr)
|
||||||
{
|
{
|
||||||
int i;
|
int i = 0;
|
||||||
|
/*
|
||||||
|
* Check if an entry has to be forced into the FIT at index 0.
|
||||||
|
* first_mcu_addr is an address (in ROM) that will point to a
|
||||||
|
* microcode patch.
|
||||||
|
*/
|
||||||
|
if (first_mcu_addr) {
|
||||||
|
struct fit_entry *entry = &fit->entries[0];
|
||||||
|
update_fit_ucode_entry(fit, entry, first_mcu_addr);
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < num_mcus; i++) {
|
struct microcode_entry *mcu = &mcus[0];
|
||||||
|
for (; i < num_mcus; i++) {
|
||||||
struct fit_entry *entry = &fit->entries[i];
|
struct fit_entry *entry = &fit->entries[i];
|
||||||
struct microcode_entry *mcu = &mcus[i];
|
update_fit_ucode_entry(fit, entry, offset_to_ptr(offset_helper,
|
||||||
|
&image->buffer, mcu->offset));
|
||||||
entry->address = offset_to_ptr(offset_helper, &image->buffer,
|
mcu++;
|
||||||
mcu->offset);
|
|
||||||
fit_entry_update_size(entry, mcu->size);
|
|
||||||
entry->version = FIT_MICROCODE_VERSION;
|
|
||||||
entry->type_checksum_valid = FIT_TYPE_MICROCODE;
|
|
||||||
entry->checksum = 0;
|
|
||||||
fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +239,8 @@ static int fit_header(void *ptr, uint32_t *current_offset, uint32_t *file_length
|
||||||
|
|
||||||
static int parse_microcode_blob(struct cbfs_image *image,
|
static int parse_microcode_blob(struct cbfs_image *image,
|
||||||
struct cbfs_file *mcode_file,
|
struct cbfs_file *mcode_file,
|
||||||
struct microcode_entry *mcus, int *total_mcus)
|
struct microcode_entry *mcus,
|
||||||
|
int total_entries, int *mcus_found)
|
||||||
{
|
{
|
||||||
int num_mcus;
|
int num_mcus;
|
||||||
uint32_t current_offset;
|
uint32_t current_offset;
|
||||||
|
@ -245,25 +275,28 @@ static int parse_microcode_blob(struct cbfs_image *image,
|
||||||
num_mcus++;
|
num_mcus++;
|
||||||
|
|
||||||
/* Reached limit of FIT entries. */
|
/* Reached limit of FIT entries. */
|
||||||
if (num_mcus == *total_mcus)
|
if (num_mcus == total_entries)
|
||||||
break;
|
break;
|
||||||
if (file_length < sizeof(struct microcode_header))
|
if (file_length < sizeof(struct microcode_header))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update how many microcode updates we found. */
|
/* Update how many microcode updates we found. */
|
||||||
*total_mcus = num_mcus;
|
*mcus_found = num_mcus;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fit_update_table(struct buffer *bootblock, struct cbfs_image *image,
|
int fit_update_table(struct buffer *bootblock, struct cbfs_image *image,
|
||||||
const char *microcode_blob_name, int empty_entries,
|
const char *microcode_blob_name, int empty_entries,
|
||||||
fit_offset_converter_t offset_fn)
|
fit_offset_converter_t offset_fn, uint32_t topswap_size,
|
||||||
|
uint32_t first_mcu_addr)
|
||||||
{
|
{
|
||||||
struct fit_table *fit;
|
struct fit_table *fit, *fit2;
|
||||||
struct cbfs_file *mcode_file;
|
struct cbfs_file *mcode_file;
|
||||||
struct microcode_entry *mcus;
|
struct microcode_entry *mcus;
|
||||||
|
int mcus_found;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
// struct rom_image image = { .rom = rom, .size = romsize, };
|
// struct rom_image image = { .rom = rom, .size = romsize, };
|
||||||
|
|
||||||
|
@ -288,15 +321,43 @@ int fit_update_table(struct buffer *bootblock, struct cbfs_image *image,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_microcode_blob(image, mcode_file, mcus, &empty_entries)) {
|
if (parse_microcode_blob(image, mcode_file, mcus, empty_entries,
|
||||||
|
&mcus_found)) {
|
||||||
ERROR("Couldn't parse microcode blob.\n");
|
ERROR("Couldn't parse microcode blob.\n");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_microcodde_entries(fit, image, empty_entries, mcus, offset_fn);
|
add_microcodde_entries(fit, image, mcus_found, mcus, offset_fn, 0);
|
||||||
|
|
||||||
update_fit_checksum(fit);
|
update_fit_checksum(fit);
|
||||||
|
|
||||||
|
/* A second fit is exactly topswap size away from the bottom one */
|
||||||
|
if (topswap_size) {
|
||||||
|
|
||||||
|
fit2 = (struct fit_table *)((uintptr_t)fit - topswap_size);
|
||||||
|
|
||||||
|
if (!fit_table_verified(fit2)) {
|
||||||
|
ERROR("second FIT is invalid\n");
|
||||||
|
ret = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* Check if we have room for first entry */
|
||||||
|
if (first_mcu_addr) {
|
||||||
|
if (mcus_found >= empty_entries) {
|
||||||
|
ERROR("No room, blob mcus = %d, total entries = %d\n",
|
||||||
|
mcus_found, empty_entries);
|
||||||
|
ret = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* Add 1 for the first entry */
|
||||||
|
mcus_found++;
|
||||||
|
}
|
||||||
|
/* Add entries in the second FIT */
|
||||||
|
add_microcodde_entries(fit2, image, mcus_found, mcus,
|
||||||
|
offset_fn, first_mcu_addr);
|
||||||
|
update_fit_checksum(fit2);
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
free(mcus);
|
free(mcus);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -28,7 +28,15 @@
|
||||||
typedef unsigned (*fit_offset_converter_t)(const struct buffer *region,
|
typedef unsigned (*fit_offset_converter_t)(const struct buffer *region,
|
||||||
unsigned offset);
|
unsigned offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* populate FIT with the MCUs prepsent in the blob provided.
|
||||||
|
*
|
||||||
|
* first_mcu_addr is an address (in ROM) that will point to a
|
||||||
|
* microcode patch. When provided, it will be forced as the first
|
||||||
|
* MCU entry into the FIT located in the topswap bootblock.
|
||||||
|
*/
|
||||||
int fit_update_table(struct buffer *bootblock, struct cbfs_image *image,
|
int fit_update_table(struct buffer *bootblock, struct cbfs_image *image,
|
||||||
const char *microcode_blob_name, int empty_entries,
|
const char *microcode_blob_name, int empty_entries,
|
||||||
fit_offset_converter_t offset_fn);
|
fit_offset_converter_t offset_fn,
|
||||||
|
uint32_t topswap_size, uint32_t first_mcu_addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue