amdfwtool: Upgrade "relative address" to four address modes

Address Mode 0: Physical Address, bit 63~56: 0x00
Address Mode 1: Relative Address to entire BIOS image, bit 63~56: 0x40
Address Mode 2: Relative Address to PSP/BIOS directory, bit 63~56: 0x80
Address Mode 3: Relative Address to slot N, bit 63~56: 0xC0

It is the expanding mode for simple relative address mode, for which
address_mode equals 1.

Only mode 2 is added. We need to record current table base address and
calculate the offset. The ctx.current_table is zero outside the
table. When it goes into the function to integrate the table, it
should backup the old value and get current table base. Before it goes
out the function, it should restore the value.

If the table address mode is 2, the address in each entry should be
also add address mode information. If not, the address mode in entry
is meanless.

The old mode 0,1 should be back compatible.

Change-Id: I29a03f4381cd0507e2b2e3b359111e3375a73de1
Signed-off-by: Zheng Bao <fishbaozi@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/59308
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
This commit is contained in:
Zheng Bao 2021-11-15 19:53:21 +08:00 committed by Felix Held
parent 8ad94770e2
commit 6fff2497b1
2 changed files with 99 additions and 22 deletions

View File

@ -343,17 +343,41 @@ amd_bios_entry amd_bios_table[] = {
typedef struct _context { typedef struct _context {
char *rom; /* target buffer, size of flash device */ char *rom; /* target buffer, size of flash device */
uint32_t rom_size; /* size of flash device */ uint32_t rom_size; /* size of flash device */
uint32_t abs_address; /* produce absolute or relative address */ uint32_t address_mode; /* 0:abs address; 1:relative to flash; 2: relative to table */
uint32_t current; /* pointer within flash & proxy buffer */ uint32_t current; /* pointer within flash & proxy buffer */
uint32_t current_table;
} context; } context;
#define ADDRESS_MODE_0_PHY 0
#define ADDRESS_MODE_1_REL_BIOS 1
#define ADDRESS_MODE_2_REL_TAB 2
#define ADDRESS_MODE_3_REL_SLOT 3
#define RUN_BASE(ctx) (0xFFFFFFFF - (ctx).rom_size + 1) #define RUN_BASE(ctx) (0xFFFFFFFF - (ctx).rom_size + 1)
#define RUN_OFFSET(ctx, offset) ((ctx).abs_address ? RUN_BASE(ctx) + (offset) : (offset)) #define RUN_OFFSET_MODE(ctx, offset, mode) \
((mode) == ADDRESS_MODE_0_PHY ? RUN_BASE(ctx) + (offset) : \
((mode) == ADDRESS_MODE_1_REL_BIOS ? (offset) : \
((mode) == ADDRESS_MODE_2_REL_TAB ? (offset) - ctx.current_table : (offset))))
#define RUN_OFFSET(ctx, offset) RUN_OFFSET_MODE((ctx), (offset), (ctx).address_mode)
#define RUN_TO_OFFSET(ctx, run) ((ctx).address_mode == ADDRESS_MODE_0_PHY ? \
(run) - RUN_BASE(ctx) : (run)) /* TODO: */
#define RUN_CURRENT(ctx) RUN_OFFSET((ctx), (ctx).current) #define RUN_CURRENT(ctx) RUN_OFFSET((ctx), (ctx).current)
/* The mode in entry can not be higher than the header's.
For example, if table mode is 0, all the entry mode will be 0. */
#define RUN_CURRENT_MODE(ctx, mode) RUN_OFFSET_MODE((ctx), (ctx).current, \
(ctx).address_mode < (mode) ? (ctx).address_mode : (mode))
#define BUFF_OFFSET(ctx, offset) ((void *)((ctx).rom + (offset))) #define BUFF_OFFSET(ctx, offset) ((void *)((ctx).rom + (offset)))
#define BUFF_CURRENT(ctx) BUFF_OFFSET((ctx), (ctx).current) #define BUFF_CURRENT(ctx) BUFF_OFFSET((ctx), (ctx).current)
#define BUFF_TO_RUN(ctx, ptr) RUN_OFFSET((ctx), ((char *)(ptr) - (ctx).rom)) #define BUFF_TO_RUN(ctx, ptr) RUN_OFFSET((ctx), ((char *)(ptr) - (ctx).rom))
#define BUFF_TO_RUN_MODE(ctx, ptr, mode) RUN_OFFSET_MODE((ctx), ((char *)(ptr) - (ctx).rom), \
(ctx).address_mode < (mode) ? (ctx).address_mode : (mode))
#define BUFF_ROOM(ctx) ((ctx).rom_size - (ctx).current) #define BUFF_ROOM(ctx) ((ctx).rom_size - (ctx).current)
/* Only set the address mode in entry if the table is mode 2. */
#define SET_ADDR_MODE(table, mode) \
((table)->header.additional_info_fields.address_mode == \
ADDRESS_MODE_2_REL_TAB ? (mode) : 0)
#define SET_ADDR_MODE_BY_TABLE(table) \
SET_ADDR_MODE((table), (table)->header.additional_info_fields.address_mode)
void assert_fw_entry(uint32_t count, uint32_t max, context *ctx) void assert_fw_entry(uint32_t count, uint32_t max, context *ctx)
{ {
@ -380,7 +404,8 @@ static void *new_psp_dir(context *ctx, int multi)
ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT); ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
ptr = BUFF_CURRENT(*ctx); ptr = BUFF_CURRENT(*ctx);
((psp_directory_header *)ptr)->additional_info = ctx->current; ((psp_directory_header *)ptr)->additional_info = 0;
((psp_directory_header *)ptr)->additional_info_fields.address_mode = ctx->address_mode;
ctx->current += sizeof(psp_directory_header) ctx->current += sizeof(psp_directory_header)
+ MAX_PSP_ENTRIES * sizeof(psp_directory_entry); + MAX_PSP_ENTRIES * sizeof(psp_directory_entry);
return ptr; return ptr;
@ -432,16 +457,16 @@ static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie, co
break; break;
case PSP_COOKIE: case PSP_COOKIE:
case PSPL2_COOKIE: case PSPL2_COOKIE:
table_size = ctx->current - dir->header.additional_info; table_size = ctx->current - ctx->current_table;
if ((table_size % TABLE_ALIGNMENT) != 0) { if ((table_size % TABLE_ALIGNMENT) != 0) {
fprintf(stderr, "The PSP table size should be 4K aligned\n"); fprintf(stderr, "The PSP table size should be 4K aligned\n");
exit(1); exit(1);
} }
dir->header.cookie = cookie; dir->header.cookie = cookie;
dir->header.num_entries = count; dir->header.num_entries = count;
dir->header.additional_info = (table_size / 0x1000) | (1 << 10); dir->header.additional_info_fields.dir_size = table_size / TABLE_ALIGNMENT;
if (ctx->abs_address == 0) dir->header.additional_info_fields.spi_block_size = 1;
dir->header.additional_info |= 1 << 29; dir->header.additional_info_fields.base_addr = 0;
/* checksum everything that comes after the Checksum field */ /* checksum everything that comes after the Checksum field */
dir->header.checksum = fletcher32(&dir->header.num_entries, dir->header.checksum = fletcher32(&dir->header.num_entries,
count * sizeof(psp_directory_entry) count * sizeof(psp_directory_entry)
@ -450,16 +475,16 @@ static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie, co
break; break;
case BDT1_COOKIE: case BDT1_COOKIE:
case BDT2_COOKIE: case BDT2_COOKIE:
table_size = ctx->current - bdir->header.additional_info; table_size = ctx->current - ctx->current_table;
if ((table_size % TABLE_ALIGNMENT) != 0) { if ((table_size % TABLE_ALIGNMENT) != 0) {
fprintf(stderr, "The BIOS table size should be 4K aligned\n"); fprintf(stderr, "The BIOS table size should be 4K aligned\n");
exit(1); exit(1);
} }
bdir->header.cookie = cookie; bdir->header.cookie = cookie;
bdir->header.num_entries = count; bdir->header.num_entries = count;
bdir->header.additional_info = (table_size / 0x1000) | (1 << 10); bdir->header.additional_info_fields.dir_size = table_size / TABLE_ALIGNMENT;
if (ctx->abs_address == 0) bdir->header.additional_info_fields.spi_block_size = 1;
bdir->header.additional_info |= 1 << 29; bdir->header.additional_info_fields.base_addr = 0;
/* checksum everything that comes after the Checksum field */ /* checksum everything that comes after the Checksum field */
bdir->header.checksum = fletcher32(&bdir->header.num_entries, bdir->header.checksum = fletcher32(&bdir->header.num_entries,
count * sizeof(bios_directory_entry) count * sizeof(bios_directory_entry)
@ -645,6 +670,7 @@ static void integrate_psp_firmwares(context *ctx,
ssize_t bytes; ssize_t bytes;
unsigned int i, count; unsigned int i, count;
int level; int level;
uint32_t current_table_save;
/* This function can create a primary table, a secondary table, or a /* This function can create a primary table, a secondary table, or a
* flattened table which contains all applicable types. These if-else * flattened table which contains all applicable types. These if-else
@ -662,6 +688,8 @@ static void integrate_psp_firmwares(context *ctx,
else else
level = PSP_BOTH; level = PSP_BOTH;
current_table_save = ctx->current_table;
ctx->current_table = (char *)pspdir - ctx->rom;
ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT); ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
for (i = 0, count = 0; fw_table[i].type != AMD_FW_INVALID; i++) { for (i = 0, count = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
@ -677,6 +705,7 @@ static void integrate_psp_firmwares(context *ctx,
pspdir->entries[count].type = fw_table[i].type; pspdir->entries[count].type = fw_table[i].type;
pspdir->entries[count].size = 4096; /* TODO: doc? */ pspdir->entries[count].size = 4096; /* TODO: doc? */
pspdir->entries[count].addr = RUN_CURRENT(*ctx); pspdir->entries[count].addr = RUN_CURRENT(*ctx);
pspdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(pspdir);
pspdir->entries[count].subprog = fw_table[i].subprog; pspdir->entries[count].subprog = fw_table[i].subprog;
pspdir->entries[count].rsvd = 0; pspdir->entries[count].rsvd = 0;
ctx->current = ALIGN(ctx->current + 4096, 0x100U); ctx->current = ALIGN(ctx->current + 4096, 0x100U);
@ -687,6 +716,7 @@ static void integrate_psp_firmwares(context *ctx,
pspdir->entries[count].rsvd = 0; pspdir->entries[count].rsvd = 0;
pspdir->entries[count].size = 0xFFFFFFFF; pspdir->entries[count].size = 0xFFFFFFFF;
pspdir->entries[count].addr = fw_table[i].other; pspdir->entries[count].addr = fw_table[i].other;
pspdir->entries[count].address_mode = 0;
count++; count++;
} else if (fw_table[i].type == AMD_FW_PSP_NVRAM) { } else if (fw_table[i].type == AMD_FW_PSP_NVRAM) {
if (fw_table[i].filename == NULL) if (fw_table[i].filename == NULL)
@ -708,7 +738,10 @@ static void integrate_psp_firmwares(context *ctx,
pspdir->entries[count].rsvd = 0; pspdir->entries[count].rsvd = 0;
pspdir->entries[count].size = ALIGN(bytes, pspdir->entries[count].size = ALIGN(bytes,
ERASE_ALIGNMENT); ERASE_ALIGNMENT);
pspdir->entries[count].addr = RUN_CURRENT(*ctx); pspdir->entries[count].addr =
RUN_CURRENT_MODE(*ctx, ADDRESS_MODE_1_REL_BIOS);
pspdir->entries[count].address_mode =
SET_ADDR_MODE(pspdir, ADDRESS_MODE_1_REL_BIOS);
ctx->current = ALIGN(ctx->current + bytes, ctx->current = ALIGN(ctx->current + bytes,
BLOB_ERASE_ALIGNMENT); BLOB_ERASE_ALIGNMENT);
@ -726,6 +759,7 @@ static void integrate_psp_firmwares(context *ctx,
pspdir->entries[count].rsvd = 0; pspdir->entries[count].rsvd = 0;
pspdir->entries[count].size = (uint32_t)bytes; pspdir->entries[count].size = (uint32_t)bytes;
pspdir->entries[count].addr = RUN_CURRENT(*ctx); pspdir->entries[count].addr = RUN_CURRENT(*ctx);
pspdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(pspdir);
ctx->current = ALIGN(ctx->current + bytes, ctx->current = ALIGN(ctx->current + bytes,
BLOB_ALIGNMENT); BLOB_ALIGNMENT);
@ -744,11 +778,15 @@ static void integrate_psp_firmwares(context *ctx,
+ pspdir2->header.num_entries + pspdir2->header.num_entries
* sizeof(psp_directory_entry); * sizeof(psp_directory_entry);
pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, pspdir2); pspdir->entries[count].addr =
BUFF_TO_RUN_MODE(*ctx, pspdir2, ADDRESS_MODE_1_REL_BIOS);
pspdir->entries[count].address_mode =
SET_ADDR_MODE(pspdir, ADDRESS_MODE_1_REL_BIOS);
count++; count++;
} }
fill_dir_header(pspdir, count, cookie, ctx); fill_dir_header(pspdir, count, cookie, ctx);
ctx->current_table = current_table_save;
} }
static void *new_bios_dir(context *ctx, bool multi) static void *new_bios_dir(context *ctx, bool multi)
@ -765,7 +803,9 @@ static void *new_bios_dir(context *ctx, bool multi)
else else
ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT); ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
ptr = BUFF_CURRENT(*ctx); ptr = BUFF_CURRENT(*ctx);
((bios_directory_hdr *) ptr)->additional_info = ctx->current; ((bios_directory_hdr *) ptr)->additional_info = 0;
((bios_directory_hdr *) ptr)->additional_info_fields.address_mode = ctx->address_mode;
ctx->current_table = ctx->current;
ctx->current += sizeof(bios_directory_hdr) ctx->current += sizeof(bios_directory_hdr)
+ MAX_BIOS_ENTRIES * sizeof(bios_directory_entry); + MAX_BIOS_ENTRIES * sizeof(bios_directory_entry);
return ptr; return ptr;
@ -917,16 +957,21 @@ static void integrate_bios_firmwares(context *ctx,
case AMD_BIOS_APOB: case AMD_BIOS_APOB:
biosdir->entries[count].size = fw_table[i].size; biosdir->entries[count].size = fw_table[i].size;
biosdir->entries[count].source = fw_table[i].src; biosdir->entries[count].source = fw_table[i].src;
biosdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(biosdir);
break; break;
case AMD_BIOS_APOB_NV: case AMD_BIOS_APOB_NV:
if (fw_table[i].src) { if (fw_table[i].src) {
/* If source is given, use that and its size */ /* If source is given, use that and its size */
biosdir->entries[count].source = fw_table[i].src; biosdir->entries[count].source = fw_table[i].src;
biosdir->entries[count].address_mode =
SET_ADDR_MODE(biosdir, ADDRESS_MODE_1_REL_BIOS);
biosdir->entries[count].size = fw_table[i].size; biosdir->entries[count].size = fw_table[i].size;
} else { } else {
/* Else reserve size bytes within amdfw.rom */ /* Else reserve size bytes within amdfw.rom */
ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT); ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
biosdir->entries[count].source = RUN_CURRENT(*ctx); biosdir->entries[count].source = RUN_CURRENT(*ctx);
biosdir->entries[count].address_mode =
SET_ADDR_MODE(biosdir, ADDRESS_MODE_1_REL_BIOS);
biosdir->entries[count].size = ALIGN( biosdir->entries[count].size = ALIGN(
fw_table[i].size, ERASE_ALIGNMENT); fw_table[i].size, ERASE_ALIGNMENT);
memset(BUFF_CURRENT(*ctx), 0xff, memset(BUFF_CURRENT(*ctx), 0xff,
@ -939,12 +984,16 @@ static void integrate_bios_firmwares(context *ctx,
/* Don't make a 2nd copy, point to the same one */ /* Don't make a 2nd copy, point to the same one */
if (level == BDT_LVL1 && locate_bdt2_bios(biosdir2, &source, &size)) { if (level == BDT_LVL1 && locate_bdt2_bios(biosdir2, &source, &size)) {
biosdir->entries[count].source = source; biosdir->entries[count].source = source;
biosdir->entries[count].address_mode =
SET_ADDR_MODE(biosdir, ADDRESS_MODE_1_REL_BIOS);
biosdir->entries[count].size = size; biosdir->entries[count].size = size;
break; break;
} }
/* level 2, or level 1 and no copy found in level 2 */ /* level 2, or level 1 and no copy found in level 2 */
biosdir->entries[count].source = fw_table[i].src; biosdir->entries[count].source = fw_table[i].src;
biosdir->entries[count].address_mode =
SET_ADDR_MODE(biosdir, ADDRESS_MODE_1_REL_BIOS);
biosdir->entries[count].dest = fw_table[i].dest; biosdir->entries[count].dest = fw_table[i].dest;
biosdir->entries[count].size = fw_table[i].size; biosdir->entries[count].size = fw_table[i].size;
@ -958,7 +1007,10 @@ static void integrate_bios_firmwares(context *ctx,
exit(1); exit(1);
} }
biosdir->entries[count].source = RUN_CURRENT(*ctx); biosdir->entries[count].source =
RUN_CURRENT_MODE(*ctx, ADDRESS_MODE_1_REL_BIOS);
biosdir->entries[count].address_mode =
SET_ADDR_MODE(biosdir, ADDRESS_MODE_1_REL_BIOS);
ctx->current = ALIGN(ctx->current + bytes, 0x100U); ctx->current = ALIGN(ctx->current + bytes, 0x100U);
break; break;
@ -981,6 +1033,7 @@ static void integrate_bios_firmwares(context *ctx,
biosdir->entries[count].size = (uint32_t)bytes; biosdir->entries[count].size = (uint32_t)bytes;
biosdir->entries[count].source = RUN_CURRENT(*ctx); biosdir->entries[count].source = RUN_CURRENT(*ctx);
biosdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(biosdir);
ctx->current = ALIGN(ctx->current + bytes, 0x100U); ctx->current = ALIGN(ctx->current + bytes, 0x100U);
break; break;
@ -998,6 +1051,8 @@ static void integrate_bios_firmwares(context *ctx,
* sizeof(bios_directory_entry); * sizeof(bios_directory_entry);
biosdir->entries[count].source = biosdir->entries[count].source =
BUFF_TO_RUN(*ctx, biosdir2); BUFF_TO_RUN(*ctx, biosdir2);
biosdir->entries[count].address_mode =
SET_ADDR_MODE(biosdir, ADDRESS_MODE_1_REL_BIOS);
biosdir->entries[count].subprog = 0; biosdir->entries[count].subprog = 0;
biosdir->entries[count].inst = 0; biosdir->entries[count].inst = 0;
biosdir->entries[count].copy = 0; biosdir->entries[count].copy = 0;
@ -1600,15 +1655,17 @@ int main(int argc, char **argv)
} }
if (amd_romsig->efs_gen.gen == EFS_SECOND_GEN) if (amd_romsig->efs_gen.gen == EFS_SECOND_GEN)
ctx.abs_address = 0; ctx.address_mode = ADDRESS_MODE_1_REL_BIOS;
else else
ctx.abs_address = 1; ctx.address_mode = ADDRESS_MODE_0_PHY;
printf(" AMDFWTOOL Using firmware directory location of %s address: 0x%08x\n", printf(" AMDFWTOOL Using firmware directory location of %s address: 0x%08x\n",
ctx.abs_address == 1 ? "absolute" : "relative", RUN_CURRENT(ctx)); ctx.address_mode == ADDRESS_MODE_0_PHY ? "absolute" : "relative",
RUN_CURRENT(ctx));
integrate_firmwares(&ctx, amd_romsig, amd_fw_table); integrate_firmwares(&ctx, amd_romsig, amd_fw_table);
ctx.current = ALIGN(ctx.current, 0x10000U); /* TODO: is it necessary? */ ctx.current = ALIGN(ctx.current, 0x10000U); /* TODO: is it necessary? */
ctx.current_table = 0;
if (cb_config.multi_level) { if (cb_config.multi_level) {
/* Do 2nd PSP directory followed by 1st */ /* Do 2nd PSP directory followed by 1st */

View File

@ -121,7 +121,16 @@ typedef struct _psp_directory_header {
uint32_t cookie; uint32_t cookie;
uint32_t checksum; uint32_t checksum;
uint32_t num_entries; uint32_t num_entries;
uint32_t additional_info; union {
uint32_t additional_info;
struct {
uint32_t dir_size:10;
uint32_t spi_block_size:4;
uint32_t base_addr:15;
uint32_t address_mode:2;
uint32_t not_used:1;
} __attribute__((packed)) additional_info_fields;
};
} __attribute__((packed, aligned(16))) psp_directory_header; } __attribute__((packed, aligned(16))) psp_directory_header;
typedef struct _psp_directory_entry { typedef struct _psp_directory_entry {
@ -129,7 +138,8 @@ typedef struct _psp_directory_entry {
uint8_t subprog; uint8_t subprog;
uint16_t rsvd; uint16_t rsvd;
uint32_t size; uint32_t size;
uint64_t addr; /* or a value in some cases */ uint64_t addr:62; /* or a value in some cases */
uint64_t address_mode:2;
} __attribute__((packed)) psp_directory_entry; } __attribute__((packed)) psp_directory_entry;
typedef struct _psp_directory_table { typedef struct _psp_directory_table {
@ -164,7 +174,16 @@ typedef struct _bios_directory_hdr {
uint32_t cookie; uint32_t cookie;
uint32_t checksum; uint32_t checksum;
uint32_t num_entries; uint32_t num_entries;
uint32_t additional_info; union {
uint32_t additional_info;
struct {
uint32_t dir_size:10;
uint32_t spi_block_size:4;
uint32_t base_addr:15;
uint32_t address_mode:2;
uint32_t not_used:1;
} __attribute__((packed)) additional_info_fields;
};
} __attribute__((packed, aligned(16))) bios_directory_hdr; } __attribute__((packed, aligned(16))) bios_directory_hdr;
typedef struct _bios_directory_entry { typedef struct _bios_directory_entry {
@ -177,7 +196,8 @@ typedef struct _bios_directory_entry {
int inst:4; int inst:4;
uint8_t subprog; /* b[7:3] reserved */ uint8_t subprog; /* b[7:3] reserved */
uint32_t size; uint32_t size;
uint64_t source; uint64_t source:62;
uint64_t address_mode:2;
uint64_t dest; uint64_t dest;
} __attribute__((packed)) bios_directory_entry; } __attribute__((packed)) bios_directory_entry;