Martin Roth merged this change.

View Change

Approvals: build bot (Jenkins): Verified Martin Roth: Looks good to me, approved
util/amdfwtool: Add multilevel PSP directory table

Add the ability to generate two PSP directory table levels. The PSP
is capable of supporting two levels, with the primary intended to
remain pristine for the life of the system, and the second updatable.
In the event the second becomes corrupted, the primary is still
sufficient to allow a recovery of the other.

This patch modifies no directory table structures currently in use.
The soc or southbridge must pass an argument to force building the
secondary table.

BUG=b:126593573
TEST=Used with WIP Picasso

Change-Id: Id321f5142e461d4a7f3343c0835a09a1a1128728
Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/33398
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
---
M util/amdfwtool/amdfwtool.c
1 file changed, 110 insertions(+), 32 deletions(-)

diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c
index 4a05dfe..ac9ee48 100644
--- a/util/amdfwtool/amdfwtool.c
+++ b/util/amdfwtool/amdfwtool.c
@@ -81,13 +81,15 @@
#define ERASE_ALIGNMENT 0x1000U
#define TABLE_ALIGNMENT 0x1000U
#define BLOB_ALIGNMENT 0x100U
+#define TABLE_ERASE_ALIGNMENT _MAX(TABLE_ALIGNMENT, ERASE_ALIGNMENT)
#define BLOB_ERASE_ALIGNMENT _MAX(BLOB_ALIGNMENT, ERASE_ALIGNMENT)

#define DEFAULT_SOFT_FUSE_CHAIN "0x1"

#define EMBEDDED_FW_SIGNATURE 0x55aa55aa
-#define PSP_COOKIE 0x50535024 /* 'PSP$' */
-#define PSP2_COOKIE 0x50535032 /* 'PSP2' */
+#define PSP_COOKIE 0x50535024 /* 'PSP$' */
+#define PSPL2_COOKIE 0x324c5024 /* '2LP$' */
+#define PSP2_COOKIE 0x50535032 /* 'PSP2' */

/*
* Beginning with Family 15h Models 70h-7F, a.k.a Stoney Ridge, the PSP
@@ -176,6 +178,7 @@
printf("\nPSP options:\n");
printf("-A | --combo-capable Place PSP directory pointer at Embedded Firmware\n");
printf(" offset able to support combo directory\n");
+ printf("-M | --multilevel Generate primary and secondary tables\n");
printf("-p | --pubkey <FILE> Add pubkey\n");
printf("-b | --bootloader <FILE> Add bootloader\n");
printf("-S | --subprogram <number> Sets subprogram field for the next firmware\n");
@@ -213,36 +216,44 @@
AMD_FW_PSP_SMU_FIRMWARE2 = 18,
AMD_PSP_FUSE_CHAIN = 11,
AMD_FW_PSP_SMUSCS = 95,
-
+ AMD_FW_L2_PTR = 0x40,
AMD_FW_IMC,
AMD_FW_GEC,
AMD_FW_XHCI,
AMD_FW_INVALID,
} amd_fw_type;

+#define PSP_LVL1 0x1
+#define PSP_LVL2 0x2
+#define PSP_BOTH (PSP_LVL1 | PSP_LVL2)
typedef struct _amd_fw_entry {
amd_fw_type type;
uint8_t subprog;
char *filename;
+ int level;
uint64_t other;
} amd_fw_entry;

static amd_fw_entry amd_psp_fw_table[] = {
- { .type = AMD_FW_PSP_PUBKEY },
- { .type = AMD_FW_PSP_BOOTLOADER },
- { .type = AMD_FW_PSP_SMU_FIRMWARE },
- { .type = AMD_FW_PSP_RECOVERY },
- { .type = AMD_FW_PSP_RTM_PUBKEY },
- { .type = AMD_FW_PSP_SECURED_OS },
- { .type = AMD_FW_PSP_NVRAM },
- { .type = AMD_FW_PSP_SECURED_DEBUG },
- { .type = AMD_FW_PSP_TRUSTLETS },
- { .type = AMD_FW_PSP_TRUSTLETKEY },
- { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1 },
- { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1 },
- { .type = AMD_FW_PSP_SMU_FIRMWARE2 },
- { .type = AMD_FW_PSP_SMUSCS },
- { .type = AMD_PSP_FUSE_CHAIN },
+ { .type = AMD_FW_PSP_PUBKEY, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_BOOTLOADER, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 0, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_RECOVERY, .level = PSP_LVL1 },
+ { .type = AMD_FW_PSP_RTM_PUBKEY, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SECURED_OS, .level = PSP_LVL2 },
+ { .type = AMD_FW_PSP_NVRAM, .level = PSP_LVL2 },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 2, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SECURED_DEBUG, .level = PSP_LVL2 },
+ { .type = AMD_FW_PSP_TRUSTLETS, .level = PSP_LVL2 },
+ { .type = AMD_FW_PSP_TRUSTLETKEY, .level = PSP_LVL2 },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 2, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE2, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SMUSCS, .level = PSP_BOTH },
+ { .type = AMD_PSP_FUSE_CHAIN, .level = PSP_LVL2 },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
+ { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
{ .type = AMD_FW_INVALID },
};

@@ -319,11 +330,20 @@
#define BUFF_TO_RUN(ctx, ptr) RUN_OFFSET((ctx), ((char *)(ptr) - (ctx).rom))
#define BUFF_ROOM(ctx) ((ctx).rom_size - (ctx).current)

-static void *new_psp_dir(context *ctx)
+static void *new_psp_dir(context *ctx, int multi)
{
void *ptr;

- ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
+ /*
+ * Force both onto boundary when multi. Primary table is after
+ * updatable table, so alignment ensures primary can stay intact
+ * if secondary is reprogrammed.
+ */
+ if (multi)
+ ctx->current = ALIGN(ctx->current, TABLE_ERASE_ALIGNMENT);
+ else
+ ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
+
ptr = BUFF_CURRENT(*ctx);
ctx->current += sizeof(psp_directory_header)
+ MAX_PSP_ENTRIES * sizeof(psp_directory_entry);
@@ -343,9 +363,15 @@

static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie)
{
- if (cookie == PSP2_COOKIE) {
+ psp_combo_directory *cdir = directory;
+ psp_directory_table *dir = directory;
+
+ if (!count)
+ return;
+
+ switch (cookie) {
+ case PSP2_COOKIE:
/* caller is responsible for lookup mode */
- psp_combo_directory *cdir = directory;
cdir->header.cookie = cookie;
cdir->header.num_entries = count;
cdir->header.reserved[0] = 0;
@@ -356,8 +382,9 @@
+ sizeof(cdir->header.num_entries)
+ sizeof(cdir->header.lookup)
+ 2 * sizeof(cdir->header.reserved[0]));
- } else {
- psp_directory_table *dir = directory;
+ break;
+ case PSP_COOKIE:
+ case PSPL2_COOKIE:
dir->header.cookie = cookie;
dir->header.num_entries = count;
dir->header.reserved = 0;
@@ -366,6 +393,7 @@
count * sizeof(psp_directory_entry)
+ sizeof(dir->header.num_entries)
+ sizeof(dir->header.reserved));
+ break;
}
}

@@ -444,14 +472,34 @@

static void integrate_psp_firmwares(context *ctx,
psp_directory_table *pspdir,
- amd_fw_entry *fw_table)
+ psp_directory_table *pspdir2,
+ amd_fw_entry *fw_table,
+ uint32_t cookie)
{
ssize_t bytes;
unsigned int i, count;
+ int level;
+
+ /* This function can create a primary table, a secondary table, or a
+ * flattened table which contains all applicable types. These if-else
+ * statements infer what the caller intended. If a 2nd-level cookie
+ * is passed, clearly a 2nd-level table is intended. However, a
+ * 1st-level cookie may indicate level 1 or flattened. If the caller
+ * passes a pointer to a 2nd-level table, then assume not flat.
+ */
+ if (cookie == PSPL2_COOKIE)
+ level = PSP_LVL2;
+ else if (pspdir2)
+ level = PSP_LVL1;
+ else
+ level = PSP_BOTH;

ctx->current = ALIGN(ctx->current, BLOB_ALIGNMENT);

for (i = 0, count = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
+ if (!(fw_table[i].level & level))
+ continue;
+
if (fw_table[i].type == AMD_PSP_FUSE_CHAIN) {
pspdir->entries[count].type = fw_table[i].type;
pspdir->entries[count].subprog = fw_table[i].subprog;
@@ -506,16 +554,28 @@
}
}

+ if (pspdir2) {
+ pspdir->entries[count].type = AMD_FW_L2_PTR;
+ pspdir->entries[count].subprog = 0;
+ pspdir->entries[count].rsvd = 0;
+ pspdir->entries[count].size = sizeof(pspdir2->header)
+ + pspdir2->header.num_entries
+ * sizeof(psp_directory_entry);
+
+ pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, pspdir2);
+ count++;
+ }
+
if (count > MAX_PSP_ENTRIES) {
printf("Error: PSP entries exceed max allowed items\n");
free(ctx->rom);
exit(1);
}

- fill_dir_header(pspdir, count, PSP_COOKIE);
+ fill_dir_header(pspdir, count, cookie);
}

-static const char *optstring = "x:i:g:AS:p:b:s:r:k:c:n:d:t:u:w:m:T:o:f:l:h";
+static const char *optstring = "x:i:g:AMS:p:b:s:r:k:c:n:d:t:u:w:m:T:o:f:l:h";

static struct option long_options[] = {
{"xhci", required_argument, 0, 'x' },
@@ -523,6 +583,7 @@
{"gec", required_argument, 0, 'g' },
/* PSP */
{"combo-capable", no_argument, 0, 'A' },
+ {"multilevel", no_argument, 0, 'M' },
{"subprogram", required_argument, 0, 'S' },
{"pubkey", required_argument, 0, 'p' },
{"bootloader", required_argument, 0, 'b' },
@@ -599,6 +660,7 @@
uint32_t romsig_offset;
uint32_t rom_base_address;
uint8_t sub = 0;
+ int multi = 0;

while (1) {
int optindex = 0;
@@ -611,19 +673,22 @@
switch (c) {
case 'x':
register_fw_filename(AMD_FW_XHCI, sub, optarg);
- sub = 0; /* subprogram is N/A but clear anyway */
+ sub = 0;
break;
case 'i':
register_fw_filename(AMD_FW_IMC, sub, optarg);
- sub = 0; /* subprogram is N/A but clear anyway */
+ sub = 0;
break;
case 'g':
register_fw_filename(AMD_FW_GEC, sub, optarg);
- sub = 0; /* subprogram is N/A but clear anyway */
+ sub = 0;
break;
case 'A':
comboable = 1;
break;
+ case 'M':
+ multi = 1;
+ break;
case 'S':
sub = (uint8_t)strtoul(optarg, &tmp, 16);
break;
@@ -788,8 +853,21 @@

ctx.current = ALIGN(ctx.current, 0x10000U); /* todo: is necessary? */

- pspdir = new_psp_dir(&ctx);
- integrate_psp_firmwares(&ctx, pspdir, amd_psp_fw_table);
+ if (multi) {
+ /* Do 2nd PSP directory followed by 1st */
+ psp_directory_table *pspdir2 = new_psp_dir(&ctx, multi);
+ integrate_psp_firmwares(&ctx, pspdir2, 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);
+ } else {
+ /* flat: PSP 1 cookie and no pointer to 2nd table */
+ pspdir = new_psp_dir(&ctx, multi);
+ integrate_psp_firmwares(&ctx, pspdir, 0,
+ amd_psp_fw_table, PSP_COOKIE);
+ }

if (comboable)
amd_romsig->comboable = BUFF_TO_RUN(ctx, pspdir);

To view, visit change 33398. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Id321f5142e461d4a7f3343c0835a09a1a1128728
Gerrit-Change-Number: 33398
Gerrit-PatchSet: 3
Gerrit-Owner: Marshall Dawson <marshalldawson3rd@gmail.com>
Gerrit-Reviewer: Marshall Dawson <marshalldawson3rd@gmail.com>
Gerrit-Reviewer: Martin Roth <martinroth@google.com>
Gerrit-Reviewer: build bot (Jenkins) <no-reply@coreboot.org>
Gerrit-CC: Paul Menzel <paulepanter@users.sourceforge.net>
Gerrit-MessageType: merged