Attention is currently required from: Zheng Bao. Hello Zheng Bao,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/56773
to review the following change.
Change subject: [WIP]amdfwtool: add support for A/B recovery ......................................................................
[WIP]amdfwtool: add support for A/B recovery
The rom layout for A/B recovery: EFS -> PSP L1 0x48 -> PSP L2 A -> BIOS L2 A 0x4A -> PSP L2 B -> BIOS L2 B
Change-Id: I27f5d3476f648fcecafb8d258ccb6cfad4f50036 Signed-off-by: Zheng Bao fishbaozi@gmail.com --- M src/soc/amd/cezanne/Makefile.inc M util/amdfwtool/amdfwtool.c M util/amdfwtool/amdfwtool.h M util/amdfwtool/data_parse.c 4 files changed, 188 insertions(+), 15 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/73/56773/1
diff --git a/src/soc/amd/cezanne/Makefile.inc b/src/soc/amd/cezanne/Makefile.inc index d693ec6..53ace8a 100644 --- a/src/soc/amd/cezanne/Makefile.inc +++ b/src/soc/amd/cezanne/Makefile.inc @@ -192,6 +192,9 @@
OPT_WHITELIST_FILE=$(call add_opt_prefix, $(PSP_WHITELIST_FILE), --whitelist)
+OPT_RECOVERY_AB="--recovery-ab" +#OPT_RECOVERY_AB= + # Add all the files listed in the config file POUND_SIGN=$(call strip_quotes, "#") DEP_FILES= $(patsubst %,$(FIRMWARE_LOCATION)/%, $(shell sed -e /^$(POUND_SIGN)/d -e /*/d -e /^FIRMWARE_LOCATION/d $(CONFIG_AMDFW_CONFIG_FILE) | awk '{print $$2}' )) @@ -236,6 +239,7 @@ $(OPT_VERSTAGE_SIG_FILE) \ --location $(shell printf "%#x" $(CEZANNE_FWM_POSITION)) \ --multilevel \ + $(OPT_RECOVERY_AB) \ --output $@
$(PSP_BIOSBIN_FILE): $(PSP_ELF_FILE) $(AMDCOMPRESS) diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c index b4d1c0c..451eebf 100644 --- a/util/amdfwtool/amdfwtool.c +++ b/util/amdfwtool/amdfwtool.c @@ -370,12 +370,21 @@ ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
ptr = BUFF_CURRENT(*ctx); + ((psp_directory_header *)ptr)->num_entries = 0; ((psp_directory_header *)ptr)->additional_info = ctx->current; ctx->current += sizeof(psp_directory_header) + MAX_PSP_ENTRIES * sizeof(psp_directory_entry); return ptr; }
+static void *new_ish_dir(context *ctx) +{ + void *ptr; + ctx->current = ALIGN(ctx->current, 0x1000); + ptr = BUFF_CURRENT(*ctx); + ctx->current += 0x1000; /* TODO: What is the size of ISH */ + return ptr; +} #if PSP_COMBO static void *new_combo_dir(context *ctx) { @@ -455,6 +464,51 @@ }
} +#if 0 +static void recalc_dir_header(void *directory, uint32_t count) +{ + psp_combo_directory *cdir = directory; + psp_directory_table *dir = directory; + bios_directory_table *bdir = directory; + uint32_t cookie = *(uint32_t *)directory; + + if (!count) + return; + if (directory == NULL) { + fprintf(stderr, "Calling %s with NULL pointers\n", __func__); + return; + } + + switch (cookie) { + case PSP2_COOKIE: + /* caller is responsible for lookup mode */ + cdir->header.num_entries = count; + /* checksum everything that comes after the Checksum field */ + cdir->header.checksum = fletcher32(&cdir->header.num_entries, + count * sizeof(psp_combo_entry) + + sizeof(cdir->header.num_entries) + + sizeof(cdir->header.lookup) + + 2 * sizeof(cdir->header.reserved[0])); + break; + case PSP_COOKIE: + case PSPL2_COOKIE: + dir->header.num_entries = count; + dir->header.checksum = fletcher32(&dir->header.num_entries, + count * sizeof(psp_directory_entry) + + sizeof(dir->header.num_entries) + + sizeof(dir->header.additional_info)); + break; + case BDT1_COOKIE: + case BDT2_COOKIE: + bdir->header.num_entries = count; + bdir->header.checksum = fletcher32(&bdir->header.num_entries, + count * sizeof(bios_directory_entry) + + sizeof(bdir->header.num_entries) + + sizeof(bdir->header.additional_info)); + break; + } +} +#endif
static ssize_t copy_blob(void *dest, const char *src_file, size_t room) { @@ -582,15 +636,46 @@ } }
+static void integrate_psp_ab(context *ctx, psp_directory_table *pspdir, + psp_directory_table *pspdir2, ish_directory_table *ish, char ab) +{ + int count; + + count = pspdir->header.num_entries; + if (ish != NULL) { + ish->pl2_location = BUFF_TO_RUN(*ctx, pspdir2); + ish->boot_priority = 0xFFFFFFFF; + ish->update_retry_count = 1; + ish->glitch_retry_count = 0; + ish->checksum = fletcher32(&ish->boot_priority, sizeof(ish_directory_table) - sizeof(uint32_t)); + ish->psp_id = 0xbc0d0400; /* TODO: hardcode for now */ + } + pspdir->entries[count].type = ab == 'a' ? 0x48 : 0x4A; /* TODO: hardcode for now */ + pspdir->entries[count].subprog = 0; + pspdir->entries[count].rsvd = 0; + pspdir->entries[count].size = pspdir2->header.num_entries * 32 + 32; + if (ish != NULL) + pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, ish); + else + pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, pspdir2); + + count ++; + pspdir->header.num_entries ++; +} + + static void integrate_psp_firmwares(context *ctx, psp_directory_table *pspdir, psp_directory_table *pspdir2, + psp_directory_table *pspdir2_b, amd_fw_entry *fw_table, uint32_t cookie) { ssize_t bytes; unsigned int i, count; int level; + //int recovery_ab = 0; /* TODO: flag */ + ish_directory_table *ish_a_dir = NULL, *ish_b_dir = NULL;
/* This function can create a primary table, a secondary table, or a * flattened table which contains all applicable types. These if-else @@ -677,7 +762,16 @@ } }
- if (pspdir2) { + if (pspdir2_b && pspdir2) { /* pspdir2_b not being null means A/B recovery */ + if (0) { /* Need ISH */ + ish_a_dir = new_ish_dir(ctx); + ish_b_dir = new_ish_dir(ctx); + } + pspdir->header.num_entries = count; + integrate_psp_ab(ctx, pspdir, pspdir2, ish_a_dir, 'a'); + integrate_psp_ab(ctx, pspdir, pspdir2_b, ish_b_dir, 'b'); + count = pspdir->header.num_entries; + } else if (pspdir2) { pspdir->entries[count].type = AMD_FW_L2_PTR; pspdir->entries[count].subprog = 0; pspdir->entries[count].rsvd = 0; @@ -689,6 +783,8 @@ count++; }
+ /* BIOS TABLE */ + if (count > MAX_PSP_ENTRIES) { fprintf(stderr, "Error: PSP entries exceed max allowed items\n"); free(ctx->rom); @@ -698,6 +794,30 @@ fill_dir_header(pspdir, count, cookie, ctx); }
+static void add_psp_firmware_entry(context *ctx, + psp_directory_table *pspdir, + void *table, uint32_t size) +{ + uint32_t count = pspdir->header.num_entries; + + pspdir->entries[count].type = 0x49; /* TODO: hardcoded for now */ + pspdir->entries[count].subprog = 0; + pspdir->entries[count].rsvd = 0; + pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, table); + pspdir->entries[count].size = size; + count ++; + if (count > MAX_PSP_ENTRIES) { + fprintf(stderr, "Error: PSP entries exceed max allowed items\n"); + free(ctx->rom); + exit(1); + } + + pspdir->header.num_entries = count; + pspdir->header.checksum = fletcher32(&pspdir->header.num_entries, + count * sizeof(psp_directory_entry) + + sizeof(pspdir->header.num_entries) + + sizeof(pspdir->header.additional_info)); +} static void *new_bios_dir(context *ctx, int multi) { void *ptr; @@ -970,6 +1090,7 @@ AMDFW_OPT_IMC, AMDFW_OPT_GEC, AMDFW_OPT_COMBO, + AMDFW_OPT_RECOVERY_AB, AMDFW_OPT_MULTILEVEL, AMDFW_OPT_NVRAM,
@@ -1016,6 +1137,7 @@ {"gec", required_argument, 0, AMDFW_OPT_GEC }, /* PSP Directory Table items */ {"combo-capable", no_argument, 0, AMDFW_OPT_COMBO }, + {"recovery-ab", no_argument, 0, AMDFW_OPT_RECOVERY_AB }, {"multilevel", no_argument, 0, AMDFW_OPT_MULTILEVEL }, {"nvram", required_argument, 0, AMDFW_OPT_NVRAM }, {"soft-fuse", required_argument, 0, AMDFW_OPT_FUSE }, @@ -1145,6 +1267,7 @@ PLATFORM_PICASSO, PLATFORM_RENOIR, PLATFORM_CEZANNE, + PLATFORM_MENDOCINO, PLATFORM_LUCIENNE, };
@@ -1182,6 +1305,7 @@ case PLATFORM_RENOIR: case PLATFORM_LUCIENNE: case PLATFORM_CEZANNE: + case PLATFORM_MENDOCINO: amd_romsig->efs_gen.gen = EFS_SECOND_GEN; amd_romsig->spi_readmode_f17_mod_30_3f = efs_spi_readmode; amd_romsig->spi_fastspeed_f17_mod_30_3f = efs_spi_speed; @@ -1218,6 +1342,8 @@ return PLATFORM_PICASSO; else if (!strcasecmp(soc_name, "Cezanne")) return PLATFORM_CEZANNE; + else if (!strcasecmp(soc_name, "Mendocino")) + return PLATFORM_MENDOCINO; else if (!strcasecmp(soc_name, "Renoir")) return PLATFORM_RENOIR; else if (!strcasecmp(soc_name, "Lucienne")) @@ -1234,7 +1360,7 @@ char *tmp; char *rom = NULL; embedded_firmware *amd_romsig; - psp_directory_table *pspdir; + psp_directory_table *pspdir, *pspdir2 = NULL, *pspdir2_b = NULL; int comboable = 0; int fuse_defined = 0; int targetfd; @@ -1287,6 +1413,9 @@ case AMDFW_OPT_COMBO: comboable = 1; break; + case AMDFW_OPT_RECOVERY_AB: + cb_config.recovery_ab = 1; + break; case AMDFW_OPT_MULTILEVEL: multi = 1; break; @@ -1568,17 +1697,27 @@
if (multi) { /* Do 2nd PSP directory followed by 1st */ - psp_directory_table *pspdir2 = new_psp_dir(&ctx, multi); - integrate_psp_firmwares(&ctx, pspdir2, 0, + pspdir2 = new_psp_dir(&ctx, multi); + integrate_psp_firmwares(&ctx, pspdir2, NULL, 0, amd_psp_fw_table, PSPL2_COOKIE); - - pspdir = new_psp_dir(&ctx, multi); - integrate_psp_firmwares(&ctx, pspdir, pspdir2, - amd_psp_fw_table, PSP_COOKIE); + if (cb_config.recovery_ab == 1) { + pspdir2_b = new_psp_dir(&ctx, multi); /* same as above */ + integrate_psp_firmwares(&ctx, pspdir2_b, NULL, 0, + amd_psp_fw_table, PSPL2_COOKIE); + } + if (cb_config.recovery_ab == 1) { + pspdir = new_psp_dir(&ctx, multi); + integrate_psp_firmwares(&ctx, pspdir, pspdir2, pspdir2_b, + amd_psp_fw_table, PSP_COOKIE); + } else { + pspdir = new_psp_dir(&ctx, multi); + integrate_psp_firmwares(&ctx, pspdir, pspdir2, NULL, + amd_psp_fw_table, PSP_COOKIE); + } } else { /* flat: PSP 1 cookie and no pointer to 2nd table */ pspdir = new_psp_dir(&ctx, multi); - integrate_psp_firmwares(&ctx, pspdir, 0, + integrate_psp_firmwares(&ctx, pspdir, 0, NULL, amd_psp_fw_table, PSP_COOKIE); }
@@ -1601,28 +1740,44 @@ #endif
if (have_bios_tables(amd_bios_table)) { - bios_directory_table *biosdir; + bios_directory_table *biosdir = NULL; if (multi) { /* Do 2nd level BIOS directory followed by 1st */ bios_directory_table *biosdir2 = - new_bios_dir(&ctx, multi); + new_bios_dir(&ctx, multi), *biosdir2_b = NULL; integrate_bios_firmwares(&ctx, biosdir2, 0, amd_bios_table, BDT2_COOKIE); + if (cb_config.recovery_ab) { + biosdir2_b = new_bios_dir(&ctx, multi); + integrate_bios_firmwares(&ctx, biosdir2_b, 0, + amd_bios_table, BDT2_COOKIE); + } else { + //biosdir = new_bios_dir(&ctx, multi); /* TODO: move here? */ + }
- biosdir = new_bios_dir(&ctx, multi); - integrate_bios_firmwares(&ctx, biosdir, biosdir2, + if (cb_config.recovery_ab) { + add_psp_firmware_entry(&ctx, pspdir2, biosdir2, 0x1000); + add_psp_firmware_entry(&ctx, pspdir2_b, biosdir2_b, 0x1000); + } else { + biosdir = new_bios_dir(&ctx, multi); + integrate_bios_firmwares(&ctx, biosdir, biosdir2, amd_bios_table, BDT1_COOKIE); + } } else { /* flat: BDT1 cookie and no pointer to 2nd table */ biosdir = new_bios_dir(&ctx, multi); integrate_bios_firmwares(&ctx, biosdir, 0, amd_bios_table, BDT1_COOKIE); } + switch (soc_id) { case PLATFORM_RENOIR: case PLATFORM_LUCIENNE: case PLATFORM_CEZANNE: - amd_romsig->bios3_entry = BUFF_TO_RUN(ctx, biosdir); + if (cb_config.recovery_ab != 1) + amd_romsig->bios3_entry = BUFF_TO_RUN(ctx, biosdir); + break; + case PLATFORM_MENDOCINO: break; case PLATFORM_STONEYRIDGE: case PLATFORM_RAVEN: diff --git a/util/amdfwtool/amdfwtool.h b/util/amdfwtool/amdfwtool.h index 6db74f6..e7fa95f 100644 --- a/util/amdfwtool/amdfwtool.h +++ b/util/amdfwtool/amdfwtool.h @@ -201,6 +201,16 @@ int level; } amd_bios_entry;
+typedef struct _ish_directory_table { + uint32_t checksum; + uint32_t boot_priority; + uint32_t update_retry_count; + uint32_t glitch_retry_count; + uint32_t pl2_location; + uint32_t psp_id; + uint32_t slot_max_size; + uint32_t reserved; +} ish_directory_table; #define EMBEDDED_FW_SIGNATURE 0x55aa55aa #define PSP_COOKIE 0x50535024 /* 'PSP$' */ #define PSPL2_COOKIE 0x324c5024 /* '2LP$' */ @@ -210,7 +220,10 @@
#define PSP_LVL1 0x1 #define PSP_LVL2 0x2 +#define PSP_LVL1_AB 0x4 +#define PSP_LVL2_AB 0x8 #define PSP_BOTH (PSP_LVL1 | PSP_LVL2) +#define PSP_BOTH_AB (PSP_LVL1_AB | PSP_LVL2_AB) typedef struct _amd_fw_entry { amd_fw_type type; char *filename; @@ -225,6 +238,7 @@ uint8_t use_secureos; uint8_t load_mp2_fw; uint8_t s0i3; + uint8_t recovery_ab; } amd_cb_config;
void register_fw_fuse(char *str); diff --git a/util/amdfwtool/data_parse.c b/util/amdfwtool/data_parse.c index 6b773e0..4d30f47 100644 --- a/util/amdfwtool/data_parse.c +++ b/util/amdfwtool/data_parse.c @@ -243,7 +243,7 @@ fw_type = AMD_RPMC_NVRAM; subprog = 0; } else if (strcmp(fw_name, "PSPBTLDR_AB_FILE") == 0) { - if (cb_config->have_whitelist == 0) { + if (cb_config->have_whitelist == 0 || cb_config->recovery_ab == 1) { fw_type = AMD_FW_PSP_BOOTLOADER_AB; subprog = 0; } else {