summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/cbfstool/cbfstool.c35
-rw-r--r--util/cbfstool/fit.c133
-rw-r--r--util/cbfstool/fit.h12
3 files changed, 138 insertions, 42 deletions
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index 0544e8f2f4..54e2e952bb 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -59,6 +59,7 @@ static struct param {
const char *source_region;
const char *bootblock;
const char *ignore_section;
+ const char *ucode_region;
uint64_t u64val;
uint32_t type;
uint32_t baseaddress;
@@ -1209,8 +1210,25 @@ static int cbfs_update_fit(void)
param.headeroffset))
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,
- param.fit_empty_entries, convert_to_from_top_aligned))
+ param.fit_empty_entries, convert_to_from_top_aligned,
+ param.topswap_size, addr))
return 1;
// 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},
{"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?j:q:", cbfs_update_fit, true, true},
{"write", "r:f:i:Fudvh?", cbfs_write, true, true},
{"expand", "r:h?", cbfs_expand, true, true},
{"truncate", "r:h?", cbfs_truncate, true, true},
@@ -1334,6 +1352,7 @@ static struct option long_options[] = {
{"offset", required_argument, 0, 'o' },
{"padding", required_argument, 0, 'p' },
{"page-size", required_argument, 0, 'P' },
+ {"ucode-region", required_argument, 0, 'q' },
{"size", required_argument, 0, 's' },
{"top-aligned", required_argument, 0, 'T' },
{"type", required_argument, 0, 't' },
@@ -1464,8 +1483,13 @@ static void usage(char *name)
" expand [-r fmap-region] "
"Expand CBFS to span entire region\n"
" update-fit [-r image,regions] -n MICROCODE_BLOB_NAME \\\n"
- " -x EMTPY_FIT_ENTRIES "
- "Updates the FIT table with microcode entries\n"
+ " -x EMTPY_FIT_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"
"OFFSETs:\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())
return 1;
break;
+ case 'q':
+ param.ucode_region = optarg;
+ break;
case 'v':
verbose++;
break;
diff --git a/util/cbfstool/fit.c b/util/cbfstool/fit.c
index d33cb56749..31ab3dec82 100644
--- a/util/cbfstool/fit.c
+++ b/util/cbfstool/fit.c
@@ -115,6 +115,26 @@ static inline uint32_t offset_to_ptr(fit_offset_converter_t helper,
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,
struct buffer *buffer)
{
@@ -131,23 +151,10 @@ static struct fit_table *locate_fit_table(fit_offset_converter_t offset_helper,
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,
- sizeof(table->header.address)))
+ if (!fit_table_verified(table))
return NULL;
-
- 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;
+ else
+ return table;
}
static void update_fit_checksum(struct fit_table *fit)
@@ -166,24 +173,46 @@ static void update_fit_checksum(struct fit_table *fit)
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,
const struct cbfs_image *image,
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 microcode_entry *mcu = &mcus[i];
-
- 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;
- entry->checksum = 0;
- fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
+ update_fit_ucode_entry(fit, entry, offset_to_ptr(offset_helper,
+ &image->buffer, mcu->offset));
+ mcu++;
}
}
@@ -209,8 +238,9 @@ static int fit_header(void *ptr, uint32_t *current_offset, uint32_t *file_length
}
static int parse_microcode_blob(struct cbfs_image *image,
- struct cbfs_file *mcode_file,
- struct microcode_entry *mcus, int *total_mcus)
+ struct cbfs_file *mcode_file,
+ struct microcode_entry *mcus,
+ int total_entries, int *mcus_found)
{
int num_mcus;
uint32_t current_offset;
@@ -245,25 +275,28 @@ static int parse_microcode_blob(struct cbfs_image *image,
num_mcus++;
/* Reached limit of FIT entries. */
- if (num_mcus == *total_mcus)
+ if (num_mcus == total_entries)
break;
if (file_length < sizeof(struct microcode_header))
break;
}
/* Update how many microcode updates we found. */
- *total_mcus = num_mcus;
+ *mcus_found = num_mcus;
return 0;
}
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)
+ 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 microcode_entry *mcus;
+ int mcus_found;
+
int ret = 0;
// 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;
}
- 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");
ret = 1;
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);
+ /* 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:
free(mcus);
return ret;
diff --git a/util/cbfstool/fit.h b/util/cbfstool/fit.h
index 5f1b80bf0b..42b3b4722a 100644
--- a/util/cbfstool/fit.h
+++ b/util/cbfstool/fit.h
@@ -28,7 +28,15 @@
typedef unsigned (*fit_offset_converter_t)(const struct buffer *region,
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,
- const char *microcode_blob_name, int empty_entries,
- fit_offset_converter_t offset_fn);
+ const char *microcode_blob_name, int empty_entries,
+ fit_offset_converter_t offset_fn,
+ uint32_t topswap_size, uint32_t first_mcu_addr);
#endif