diff options
-rw-r--r-- | util/amdfwtool/amdfwtool.c | 93 | ||||
-rw-r--r-- | util/amdfwtool/amdfwtool.h | 28 |
2 files changed, 99 insertions, 22 deletions
diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c index d8cda92214..fb6769ab83 100644 --- a/util/amdfwtool/amdfwtool.c +++ b/util/amdfwtool/amdfwtool.c @@ -343,17 +343,41 @@ amd_bios_entry amd_bios_table[] = { typedef struct _context { char *rom; /* target buffer, 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_table; } 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_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) +/* 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_CURRENT(ctx) BUFF_OFFSET((ctx), (ctx).current) #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) +/* 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) { @@ -380,7 +404,8 @@ static void *new_psp_dir(context *ctx, int multi) ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT); 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) + MAX_PSP_ENTRIES * sizeof(psp_directory_entry); return ptr; @@ -432,16 +457,16 @@ static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie, co break; case PSP_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) { fprintf(stderr, "The PSP table size should be 4K aligned\n"); exit(1); } dir->header.cookie = cookie; dir->header.num_entries = count; - dir->header.additional_info = (table_size / 0x1000) | (1 << 10); - if (ctx->abs_address == 0) - dir->header.additional_info |= 1 << 29; + dir->header.additional_info_fields.dir_size = table_size / TABLE_ALIGNMENT; + dir->header.additional_info_fields.spi_block_size = 1; + dir->header.additional_info_fields.base_addr = 0; /* checksum everything that comes after the Checksum field */ dir->header.checksum = fletcher32(&dir->header.num_entries, count * sizeof(psp_directory_entry) @@ -450,16 +475,16 @@ static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie, co break; case BDT1_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) { fprintf(stderr, "The BIOS table size should be 4K aligned\n"); exit(1); } bdir->header.cookie = cookie; bdir->header.num_entries = count; - bdir->header.additional_info = (table_size / 0x1000) | (1 << 10); - if (ctx->abs_address == 0) - bdir->header.additional_info |= 1 << 29; + bdir->header.additional_info_fields.dir_size = table_size / TABLE_ALIGNMENT; + bdir->header.additional_info_fields.spi_block_size = 1; + bdir->header.additional_info_fields.base_addr = 0; /* checksum everything that comes after the Checksum field */ bdir->header.checksum = fletcher32(&bdir->header.num_entries, count * sizeof(bios_directory_entry) @@ -645,6 +670,7 @@ static void integrate_psp_firmwares(context *ctx, ssize_t bytes; unsigned int i, count; int level; + uint32_t current_table_save; /* This function can create a primary table, a secondary table, or a * flattened table which contains all applicable types. These if-else @@ -662,6 +688,8 @@ static void integrate_psp_firmwares(context *ctx, else level = PSP_BOTH; + current_table_save = ctx->current_table; + ctx->current_table = (char *)pspdir - ctx->rom; ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT); 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].size = 4096; /* TODO: doc? */ 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].rsvd = 0; 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].size = 0xFFFFFFFF; pspdir->entries[count].addr = fw_table[i].other; + pspdir->entries[count].address_mode = 0; count++; } else if (fw_table[i].type == AMD_FW_PSP_NVRAM) { 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].size = ALIGN(bytes, 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, BLOB_ERASE_ALIGNMENT); @@ -726,6 +759,7 @@ static void integrate_psp_firmwares(context *ctx, pspdir->entries[count].rsvd = 0; pspdir->entries[count].size = (uint32_t)bytes; pspdir->entries[count].addr = RUN_CURRENT(*ctx); + pspdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(pspdir); ctx->current = ALIGN(ctx->current + bytes, BLOB_ALIGNMENT); @@ -744,11 +778,15 @@ static void integrate_psp_firmwares(context *ctx, + pspdir2->header.num_entries * 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++; } fill_dir_header(pspdir, count, cookie, ctx); + ctx->current_table = current_table_save; } static void *new_bios_dir(context *ctx, bool multi) @@ -765,7 +803,9 @@ static void *new_bios_dir(context *ctx, bool multi) else ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT); 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) + MAX_BIOS_ENTRIES * sizeof(bios_directory_entry); return ptr; @@ -917,16 +957,21 @@ static void integrate_bios_firmwares(context *ctx, case AMD_BIOS_APOB: biosdir->entries[count].size = fw_table[i].size; biosdir->entries[count].source = fw_table[i].src; + biosdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(biosdir); break; case AMD_BIOS_APOB_NV: if (fw_table[i].src) { /* If source is given, use that and its size */ 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; } else { /* Else reserve size bytes within amdfw.rom */ ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT); 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( fw_table[i].size, ERASE_ALIGNMENT); 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 */ if (level == BDT_LVL1 && locate_bdt2_bios(biosdir2, &source, &size)) { biosdir->entries[count].source = source; + biosdir->entries[count].address_mode = + SET_ADDR_MODE(biosdir, ADDRESS_MODE_1_REL_BIOS); biosdir->entries[count].size = size; break; } /* level 2, or level 1 and no copy found in level 2 */ 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].size = fw_table[i].size; @@ -958,7 +1007,10 @@ static void integrate_bios_firmwares(context *ctx, 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); break; @@ -981,6 +1033,7 @@ static void integrate_bios_firmwares(context *ctx, biosdir->entries[count].size = (uint32_t)bytes; 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); break; @@ -998,6 +1051,8 @@ static void integrate_bios_firmwares(context *ctx, * sizeof(bios_directory_entry); biosdir->entries[count].source = 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].inst = 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) - ctx.abs_address = 0; + ctx.address_mode = ADDRESS_MODE_1_REL_BIOS; else - ctx.abs_address = 1; + ctx.address_mode = ADDRESS_MODE_0_PHY; 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); ctx.current = ALIGN(ctx.current, 0x10000U); /* TODO: is it necessary? */ + ctx.current_table = 0; if (cb_config.multi_level) { /* Do 2nd PSP directory followed by 1st */ diff --git a/util/amdfwtool/amdfwtool.h b/util/amdfwtool/amdfwtool.h index 3136bf6034..2ffbfc6362 100644 --- a/util/amdfwtool/amdfwtool.h +++ b/util/amdfwtool/amdfwtool.h @@ -121,7 +121,16 @@ typedef struct _psp_directory_header { uint32_t cookie; uint32_t checksum; 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; typedef struct _psp_directory_entry { @@ -129,7 +138,8 @@ typedef struct _psp_directory_entry { uint8_t subprog; uint16_t rsvd; 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; typedef struct _psp_directory_table { @@ -164,7 +174,16 @@ typedef struct _bios_directory_hdr { uint32_t cookie; uint32_t checksum; 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; typedef struct _bios_directory_entry { @@ -177,7 +196,8 @@ typedef struct _bios_directory_entry { int inst:4; uint8_t subprog; /* b[7:3] reserved */ uint32_t size; - uint64_t source; + uint64_t source:62; + uint64_t address_mode:2; uint64_t dest; } __attribute__((packed)) bios_directory_entry; |