blob: 72a06cbea5a93f5074ece78362b90a8ae9403959 [file] [log] [blame]
Patrick Georgi7333a112020-05-08 20:48:04 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002
3/*
Zheng Baodd4c5422021-10-14 16:14:09 +08004 * ROMSIG At ROMBASE + 0x[0,2,4,8]20000:
zbaoc3b0b722016-02-19 13:47:31 +08005 * 0 4 8 C
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08006 * +------------+---------------+----------------+------------+
7 * | 0x55AA55AA |EC ROM Address |GEC ROM Address |USB3 ROM |
8 * +------------+---------------+----------------+------------+
Zheng Baodd4c5422021-10-14 16:14:09 +08009 * | PSPDIR ADDR|PSPDIR ADDR(C) | BDT ADDR 0 | BDT ADDR 1 |
10 * +------------+---------------+----------------+------------+
11 * | BDT ADDR 2 | | BDT ADDR 3(C) | |
12 * +------------+---------------+----------------+------------+
13 * (C): Could be a combo header
14 *
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080015 * EC ROM should be 64K aligned.
16 *
Zheng Bao4fcc9f22015-11-20 12:29:04 +080017 * PSP directory (Where "PSPDIR ADDR" points)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080018 * +------------+---------------+----------------+------------+
19 * | 'PSP$' | Fletcher | Count | Reserved |
20 * +------------+---------------+----------------+------------+
21 * | 0 | size | Base address | Reserved | Pubkey
22 * +------------+---------------+----------------+------------+
23 * | 1 | size | Base address | Reserved | Bootloader
24 * +------------+---------------+----------------+------------+
25 * | 8 | size | Base address | Reserved | Smu Firmware
26 * +------------+---------------+----------------+------------+
27 * | 3 | size | Base address | Reserved | Recovery Firmware
28 * +------------+---------------+----------------+------------+
29 * | |
30 * | |
Zheng Baodd4c5422021-10-14 16:14:09 +080031 * | Other PSP Firmware |
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080032 * | |
33 * +------------+---------------+----------------+------------+
Zheng Baodd4c5422021-10-14 16:14:09 +080034 * | 40 | size | Base address | Reserved |---+
35 * +------------+---------------+----------------+------------+ |
36 * :or 48(A/B A): size : Base address : Reserved : |
37 * + - - + - - + - - + - - + |
38 * : 4A(A/B B): size : Base address : Reserved : |
39 * +------------+---------------+----------------+------------+ |
40 * (A/B A) & (A/B B): Similar as 40, pointing to PSP level 2 |
41 * for A/B recovery |
42 * |
43 * |
44 * +------------+---------------+----------------+------------+ |
45 * | '2LP$' | Fletcher | Count | Reserved |<--+
46 * +------------+---------------+----------------+------------+
47 * | |
48 * | |
49 * | PSP Firmware |
50 * | (2nd-level is not required on all families) |
51 * | |
52 * +------------+---------------+----------------+------------+
53 * BIOS Directory Table (BDT) is similar
Zheng Bao4fcc9f22015-11-20 12:29:04 +080054 *
zbaoc3b0b722016-02-19 13:47:31 +080055 * PSP Combo directory
Zheng Bao4fcc9f22015-11-20 12:29:04 +080056 * +------------+---------------+----------------+------------+
zbao6e2f3d12016-02-19 13:34:59 +080057 * | 'PSP2' | Fletcher | Count |Look up mode|
Zheng Bao4fcc9f22015-11-20 12:29:04 +080058 * +------------+---------------+----------------+------------+
zbaoc3a08a92016-03-02 14:47:27 +080059 * | R e s e r v e d |
60 * +------------+---------------+----------------+------------+
Zheng Baodd4c5422021-10-14 16:14:09 +080061 * | ID-Sel | PSP ID | PSPDIR ADDR | | 1st PSP directory
Zheng Bao4fcc9f22015-11-20 12:29:04 +080062 * +------------+---------------+----------------+------------+
Zheng Baodd4c5422021-10-14 16:14:09 +080063 * | ID-Sel | PSP ID | PSPDIR ADDR | | 2nd PSP directory
Zheng Bao4fcc9f22015-11-20 12:29:04 +080064 * +------------+---------------+----------------+------------+
65 * | |
66 * | Other PSP |
67 * | |
68 * +------------+---------------+----------------+------------+
Zheng Baodd4c5422021-10-14 16:14:09 +080069 * BDT Combo is similar
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080070 */
71
Elyes Haouas7d67a192022-10-14 09:58:29 +020072#include <commonlib/bsd/helpers.h>
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080073#include <fcntl.h>
74#include <errno.h>
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -060075#include <limits.h>
Kangheui Won5b84dfd2021-12-21 15:45:06 +110076#include <openssl/sha.h>
Martin Roth37305e72020-04-07 14:16:39 -060077#include <stdbool.h>
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080078#include <stdio.h>
79#include <sys/stat.h>
80#include <sys/types.h>
81#include <unistd.h>
82#include <string.h>
83#include <stdlib.h>
84#include <getopt.h>
Zheng Baoc5e28ab2020-10-28 11:38:09 +080085#include <libgen.h>
Idwer Vollering93df1d92020-12-30 00:01:59 +010086#include <stdint.h>
Zheng Baoc5e28ab2020-10-28 11:38:09 +080087
88#include "amdfwtool.h"
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080089
Martin Roth60f15512016-11-08 09:55:01 -070090#define AMD_ROMSIG_OFFSET 0x20000
91#define MIN_ROM_KB 256
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080092
Marshall Dawson7c1e1422019-04-11 09:44:43 -060093#define _MAX(A, B) (((A) > (B)) ? (A) : (B))
94#define ERASE_ALIGNMENT 0x1000U
Marshall Dawson2794a862019-03-04 16:53:15 -070095#define TABLE_ALIGNMENT 0x1000U
96#define BLOB_ALIGNMENT 0x100U
Marshall Dawson24f73d42019-04-01 10:48:43 -060097#define TABLE_ERASE_ALIGNMENT _MAX(TABLE_ALIGNMENT, ERASE_ALIGNMENT)
Marshall Dawson7c1e1422019-04-11 09:44:43 -060098#define BLOB_ERASE_ALIGNMENT _MAX(BLOB_ALIGNMENT, ERASE_ALIGNMENT)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080099
Marshall Dawsonef79fcc2019-04-01 10:16:41 -0600100#define DEFAULT_SOFT_FUSE_CHAIN "0x1"
101
Kangheui Won5b84dfd2021-12-21 15:45:06 +1100102/* Defines related to hashing signed binaries */
103enum hash_header_ver {
104 HASH_HDR_V1 = 1,
105};
106/* Signature ID enums are defined by PSP based on the algorithm used. */
107enum signature_id {
108 SIG_ID_RSA2048,
109 SIG_ID_RSA4096 = 2,
110};
111#define HASH_FILE_SUFFIX ".hash"
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -0600112#define EFS_FILE_SUFFIX ".efs"
113#define TMP_FILE_SUFFIX ".tmp"
Zheng Bao69ea83c2023-01-22 21:08:18 +0800114#define BODY_FILE_SUFFIX ".body"
Kangheui Won5b84dfd2021-12-21 15:45:06 +1100115
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800116/*
Marshall Dawson0e02ce82019-03-04 16:50:37 -0700117 * Beginning with Family 15h Models 70h-7F, a.k.a Stoney Ridge, the PSP
118 * can support an optional "combo" implementation. If the PSP sees the
119 * PSP2 cookie, it interprets the table as a roadmap to additional PSP
120 * tables. Using this, support for multiple product generations may be
121 * built into one image. If the PSP$ cookie is found, the table is a
122 * normal directory table.
123 *
124 * Modern generations supporting the combo directories require the
125 * pointer to be at offset 0x14 of the Embedded Firmware Structure,
Zheng Baoc91867a2023-02-26 12:31:31 +0800126 * regardless of the type of directory used. The --use-combo
Marshall Dawson0e02ce82019-03-04 16:50:37 -0700127 * argument enforces this placement.
128 *
129 * TODO: Future work may require fully implementing the PSP_COMBO feature.
zbaoc3b0b722016-02-19 13:47:31 +0800130 */
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800131
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800132/*
133 * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
134 * The checksum field of the passed PDU does not need to be reset to zero.
135 *
136 * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of
137 * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an
138 * alternative to cyclical redundancy checks because it provides error-
139 * detection properties similar to cyclical redundancy checks but at the
140 * cost of a simple summation technique. Its characteristics were first
141 * published in IEEE Transactions on Communications in January 1982. One
142 * version has been adopted by ISO for use in the class-4 transport layer
143 * of the network protocol.
144 *
145 * This program expects:
146 * stdin: The input file to compute a checksum for. The input file
147 * not be longer than 256 bytes.
148 * stdout: Copied from the input file with the Fletcher's Checksum
149 * inserted 8 bytes after the beginning of the file.
150 * stderr: Used to print out error messages.
151 */
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700152static uint32_t fletcher32(const void *data, int length)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800153{
154 uint32_t c0;
155 uint32_t c1;
156 uint32_t checksum;
157 int index;
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700158 const uint16_t *pptr = data;
159
160 length /= 2;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800161
162 c0 = 0xFFFF;
163 c1 = 0xFFFF;
164
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600165 while (length) {
166 index = length >= 359 ? 359 : length;
167 length -= index;
Zheng Baoc88f2b52021-10-14 16:15:11 +0800168 do {
169 c0 += *(pptr++);
170 c1 += c0;
171 } while (--index);
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600172 c0 = (c0 & 0xFFFF) + (c0 >> 16);
173 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800174 }
175
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700176 /* Sums[0,1] mod 64K + overflow */
177 c0 = (c0 & 0xFFFF) + (c0 >> 16);
178 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800179 checksum = (c1 << 16) | c0;
180
181 return checksum;
182}
183
Martin Roth8806f7f2016-11-08 10:44:18 -0700184static void usage(void)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800185{
Martin Roth0e940622016-11-08 10:37:53 -0700186 printf("amdfwtool: Create AMD Firmware combination\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800187 printf("Usage: amdfwtool [options] --flashsize <size> --output <filename>\n");
188 printf("--xhci <FILE> Add XHCI blob\n");
189 printf("--imc <FILE> Add IMC blob\n");
190 printf("--gec <FILE> Add GEC blob\n");
Martin Roth0e940622016-11-08 10:37:53 -0700191
192 printf("\nPSP options:\n");
Zheng Bao993b43f2021-11-10 12:21:46 +0800193 printf("--use-combo Use the COMBO layout\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800194 printf("--multilevel Generate primary and secondary tables\n");
195 printf("--nvram <FILE> Add nvram binary\n");
196 printf("--soft-fuse Set soft fuse\n");
197 printf("--token-unlock Set token unlock\n");
Ritul Gurua2cb3402022-08-29 00:51:08 +0530198 printf("--nvram-base <HEX_VAL> Base address of nvram\n");
199 printf("--nvram-size <HEX_VAL> Size of nvram\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800200 printf("--whitelist Set if there is a whitelist\n");
201 printf("--use-pspsecureos Set if psp secure OS is needed\n");
202 printf("--load-mp2-fw Set if load MP2 firmware\n");
203 printf("--load-s0i3 Set if load s0i3 firmware\n");
204 printf("--verstage <FILE> Add verstage\n");
205 printf("--verstage_sig Add verstage signature\n");
Zheng Bao990d1542021-09-17 13:24:54 +0800206 printf("--recovery-ab Use the recovery A/B layout\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600207 printf("\nBIOS options:\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800208 printf("--instance <number> Sets instance field for the next BIOS\n");
Zheng Bao6f0b3612021-04-27 17:19:43 +0800209 printf(" firmware\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800210 printf("--apcb <FILE> Add AGESA PSP customization block\n");
211 printf("--apob-base <HEX_VAL> Destination for AGESA PSP output block\n");
212 printf("--apob-nv-base <HEX_VAL> Location of S3 resume data\n");
213 printf("--apob-nv-size <HEX_VAL> Size of S3 resume data\n");
214 printf("--ucode <FILE> Add microcode patch\n");
215 printf("--bios-bin <FILE> Add compressed image; auto source address\n");
216 printf("--bios-bin-src <HEX_VAL> Address in flash of source if -V not used\n");
217 printf("--bios-bin-dest <HEX_VAL> Destination for uncompressed BIOS\n");
218 printf("--bios-uncomp-size <HEX> Uncompressed size of BIOS image\n");
219 printf("--output <filename> output filename\n");
220 printf("--flashsize <HEX_VAL> ROM size in bytes\n");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600221 printf(" size must be larger than %dKB\n",
Martin Roth0e940622016-11-08 10:37:53 -0700222 MIN_ROM_KB);
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600223 printf(" and must a multiple of 1024\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800224 printf("--location Location of Directory\n");
225 printf("--anywhere Use any 64-byte aligned addr for Directory\n");
226 printf("--sharedmem Location of PSP/FW shared memory\n");
227 printf("--sharedmem-size Maximum size of the PSP/FW shared memory\n");
Zheng Bao6f0b3612021-04-27 17:19:43 +0800228 printf(" area\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500229 printf("\nEmbedded Firmware Structure options used by the PSP:\n");
230 printf("--spi-speed <HEX_VAL> SPI fast speed to place in EFS Table\n");
231 printf(" 0x0 66.66Mhz\n");
232 printf(" 0x1 33.33MHz\n");
233 printf(" 0x2 22.22MHz\n");
234 printf(" 0x3 16.66MHz\n");
235 printf(" 0x4 100MHz\n");
236 printf(" 0x5 800KHz\n");
237 printf("--spi-read-mode <HEX_VAL> SPI read mode to place in EFS Table\n");
238 printf(" 0x0 Normal Read (up to 33M)\n");
239 printf(" 0x1 Reserved\n");
240 printf(" 0x2 Dual IO (1-1-2)\n");
241 printf(" 0x3 Quad IO (1-1-4)\n");
242 printf(" 0x4 Dual IO (1-2-2)\n");
243 printf(" 0x5 Quad IO (1-4-4)\n");
244 printf(" 0x6 Normal Read (up to 66M)\n");
245 printf(" 0x7 Fast Read\n");
246 printf("--spi-micron-flag <HEX_VAL> Micron SPI part support for RV and later SOC\n");
247 printf(" 0x0 Micron parts are not used\n");
248 printf(" 0x1 Micron parts are always used\n");
249 printf(" 0x2 Micron parts optional, this option is only\n");
250 printf(" supported with RN/LCN SOC\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800251 printf("\nGeneral options:\n");
252 printf("-c|--config <config file> Config file\n");
253 printf("-d|--debug Print debug message\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800254 printf("-h|--help Show this help\n");
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800255}
256
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800257amd_fw_entry amd_psp_fw_table[] = {
Kangheui Won3c164e12021-12-03 20:25:05 +1100258 { .type = AMD_FW_PSP_PUBKEY, .level = PSP_BOTH | PSP_LVL2_AB, .skip_hashing = true },
Zheng Baofb9b7842022-02-24 15:15:50 +0800259 { .type = AMD_FW_PSP_BOOTLOADER, .level = PSP_BOTH | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800260 { .type = AMD_FW_PSP_SECURED_OS, .level = PSP_LVL2 | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200261 { .type = AMD_FW_PSP_RECOVERY, .level = PSP_LVL1 },
Zheng Bao990d1542021-09-17 13:24:54 +0800262 { .type = AMD_FW_PSP_NVRAM, .level = PSP_LVL2 | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200263 { .type = AMD_FW_PSP_RTM_PUBKEY, .level = PSP_BOTH },
264 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 0, .level = PSP_BOTH | PSP_LVL2_AB },
265 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800266 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 2, .level = PSP_BOTH | PSP_LVL2_AB },
Kangheui Won3c164e12021-12-03 20:25:05 +1100267 { .type = AMD_FW_PSP_SECURED_DEBUG, .level = PSP_LVL2 | PSP_LVL2_AB,
268 .skip_hashing = true },
Arthur Heymans1f05c802022-10-04 17:50:21 +0200269 { .type = AMD_FW_ABL_PUBKEY, .level = PSP_BOTH | PSP_BOTH_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200270 { .type = AMD_PSP_FUSE_CHAIN, .level = PSP_LVL2 | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800271 { .type = AMD_FW_PSP_TRUSTLETS, .level = PSP_LVL2 | PSP_LVL2_AB },
272 { .type = AMD_FW_PSP_TRUSTLETKEY, .level = PSP_LVL2 | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800273 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .level = PSP_BOTH | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200274 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH | PSP_LVL2_AB },
275 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 2, .level = PSP_BOTH | PSP_LVL2_AB },
Zheng Bao8eba6622022-10-16 20:29:03 +0800276 { .type = AMD_BOOT_DRIVER, .level = PSP_BOTH | PSP_LVL2_AB },
277 { .type = AMD_SOC_DRIVER, .level = PSP_BOTH | PSP_LVL2_AB },
278 { .type = AMD_DEBUG_DRIVER, .level = PSP_BOTH | PSP_LVL2_AB },
279 { .type = AMD_INTERFACE_DRIVER, .level = PSP_BOTH | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800280 { .type = AMD_DEBUG_UNLOCK, .level = PSP_LVL2 | PSP_LVL2_AB },
Zheng Bao9bb62cb2023-03-07 19:48:11 +0800281 { .type = AMD_HW_IPCFG, .subprog = 0, .level = PSP_LVL2 | PSP_LVL2_AB },
282 { .type = AMD_HW_IPCFG, .subprog = 1, .level = PSP_LVL2 | PSP_LVL2_AB },
Kangheui Won3c164e12021-12-03 20:25:05 +1100283 { .type = AMD_WRAPPED_IKEK, .level = PSP_BOTH | PSP_LVL2_AB, .skip_hashing = true },
Zheng Bao990d1542021-09-17 13:24:54 +0800284 { .type = AMD_TOKEN_UNLOCK, .level = PSP_BOTH | PSP_LVL2_AB },
285 { .type = AMD_SEC_GASKET, .subprog = 0, .level = PSP_BOTH | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800286 { .type = AMD_SEC_GASKET, .subprog = 1, .level = PSP_BOTH | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200287 { .type = AMD_SEC_GASKET, .subprog = 2, .level = PSP_BOTH | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800288 { .type = AMD_MP2_FW, .subprog = 0, .level = PSP_LVL2 | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200289 { .type = AMD_MP2_FW, .subprog = 1, .level = PSP_LVL2 | PSP_LVL2_AB },
290 { .type = AMD_MP2_FW, .subprog = 2, .level = PSP_LVL2 | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800291 { .type = AMD_DRIVER_ENTRIES, .level = PSP_LVL2 | PSP_LVL2_AB },
292 { .type = AMD_FW_KVM_IMAGE, .level = PSP_LVL2 | PSP_LVL2_AB },
Arthur Heymans1f05c802022-10-04 17:50:21 +0200293 { .type = AMD_FW_MP5, .subprog = 0, .level = PSP_BOTH | PSP_BOTH_AB },
294 { .type = AMD_FW_MP5, .subprog = 1, .level = PSP_BOTH | PSP_BOTH_AB },
295 { .type = AMD_FW_MP5, .subprog = 2, .level = PSP_BOTH | PSP_BOTH_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800296 { .type = AMD_S0I3_DRIVER, .level = PSP_LVL2 | PSP_LVL2_AB },
Zheng Bao990d1542021-09-17 13:24:54 +0800297 { .type = AMD_ABL0, .level = PSP_BOTH | PSP_LVL2_AB },
298 { .type = AMD_ABL1, .level = PSP_BOTH | PSP_LVL2_AB },
299 { .type = AMD_ABL2, .level = PSP_BOTH | PSP_LVL2_AB },
300 { .type = AMD_ABL3, .level = PSP_BOTH | PSP_LVL2_AB },
301 { .type = AMD_ABL4, .level = PSP_BOTH | PSP_LVL2_AB },
302 { .type = AMD_ABL5, .level = PSP_BOTH | PSP_LVL2_AB },
303 { .type = AMD_ABL6, .level = PSP_BOTH | PSP_LVL2_AB },
304 { .type = AMD_ABL7, .level = PSP_BOTH | PSP_LVL2_AB },
Arthur Heymans1f05c802022-10-04 17:50:21 +0200305 { .type = AMD_SEV_DATA, .level = PSP_LVL2 | PSP_LVL2_AB },
306 { .type = AMD_SEV_CODE, .level = PSP_LVL2 | PSP_LVL2_AB },
Karthikeyan Ramasubramanian51f914d2022-07-28 16:42:12 -0600307 { .type = AMD_FW_PSP_WHITELIST, .level = PSP_LVL2 | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200308 { .type = AMD_VBIOS_BTLOADER, .level = PSP_BOTH | PSP_LVL2_AB },
Arthur Heymans1f05c802022-10-04 17:50:21 +0200309 { .type = AMD_FW_DXIO, .level = PSP_BOTH | PSP_BOTH_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200310 { .type = AMD_FW_USB_PHY, .level = PSP_LVL2 | PSP_LVL2_AB },
311 { .type = AMD_FW_TOS_SEC_POLICY, .level = PSP_BOTH | PSP_LVL2_AB },
312 { .type = AMD_FW_DRTM_TA, .level = PSP_LVL2 | PSP_LVL2_AB },
313 { .type = AMD_FW_KEYDB_BL, .level = PSP_BOTH | PSP_LVL2_AB },
314 { .type = AMD_FW_KEYDB_TOS, .level = PSP_LVL2 | PSP_LVL2_AB },
Karthikeyan Ramasubramanian234e3702022-07-25 09:49:24 -0600315 { .type = AMD_FW_PSP_VERSTAGE, .level = PSP_BOTH | PSP_LVL2_AB },
316 { .type = AMD_FW_VERSTAGE_SIG, .level = PSP_BOTH | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200317 { .type = AMD_RPMC_NVRAM, .level = PSP_LVL2 | PSP_LVL2_AB },
318 { .type = AMD_FW_SPL, .level = PSP_LVL2 | PSP_LVL2_AB },
319 { .type = AMD_FW_DMCU_ERAM, .level = PSP_LVL2 | PSP_LVL2_AB },
320 { .type = AMD_FW_DMCU_ISR, .level = PSP_LVL2 | PSP_LVL2_AB },
321 { .type = AMD_FW_MSMU, .level = PSP_LVL2 | PSP_LVL2_AB },
322 { .type = AMD_FW_SPIROM_CFG, .level = PSP_LVL2 | PSP_LVL2_AB },
Nikolai Vyssotskibfc9ca72023-03-07 15:09:09 -0600323 { .type = AMD_FW_MPIO, .level = PSP_LVL2 | PSP_LVL2_AB },
Zheng Bao8eba6622022-10-16 20:29:03 +0800324 { .type = AMD_FW_PSP_SMUSCS, .level = PSP_BOTH | PSP_LVL2_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200325 { .type = AMD_FW_DMCUB, .level = PSP_LVL2 | PSP_LVL2_AB },
326 { .type = AMD_FW_PSP_BOOTLOADER_AB, .level = PSP_LVL2 | PSP_LVL2_AB },
Zheng Bao85ee1fd2023-01-30 13:52:30 +0800327 { .type = AMD_RIB, .subprog = 0, .level = PSP_LVL2 | PSP_LVL2_AB },
328 { .type = AMD_RIB, .subprog = 1, .level = PSP_LVL2 | PSP_LVL2_AB },
Arthur Heymans1f05c802022-10-04 17:50:21 +0200329 { .type = AMD_FW_MPDMA_TF, .level = PSP_BOTH | PSP_BOTH_AB },
Arthur Heymansaafbe132022-09-30 08:33:28 +0200330 { .type = AMD_TA_IKEK, .level = PSP_BOTH | PSP_LVL2_AB, .skip_hashing = true },
Arthur Heymans1f05c802022-10-04 17:50:21 +0200331 { .type = AMD_FW_GMI3_PHY, .level = PSP_BOTH | PSP_BOTH_AB },
332 { .type = AMD_FW_MPDMA_PM, .level = PSP_BOTH | PSP_BOTH_AB },
Zheng Bao8eba6622022-10-16 20:29:03 +0800333 { .type = AMD_FW_AMF_SRAM, .level = PSP_LVL2 | PSP_LVL2_AB },
334 { .type = AMD_FW_AMF_DRAM, .inst = 0, .level = PSP_LVL2 | PSP_LVL2_AB },
335 { .type = AMD_FW_AMF_DRAM, .inst = 1, .level = PSP_LVL2 | PSP_LVL2_AB },
336 { .type = AMD_FW_FCFG_TABLE, .level = PSP_LVL2 | PSP_LVL2_AB },
337 { .type = AMD_FW_AMF_WLAN, .inst = 0, .level = PSP_LVL2 | PSP_LVL2_AB },
338 { .type = AMD_FW_AMF_WLAN, .inst = 1, .level = PSP_LVL2 | PSP_LVL2_AB },
339 { .type = AMD_FW_AMF_MFD, .level = PSP_LVL2 | PSP_LVL2_AB },
340 { .type = AMD_TA_IKEK, .level = PSP_BOTH | PSP_LVL2_AB, .skip_hashing = true },
341 { .type = AMD_FW_MPCCX, .level = PSP_LVL2 | PSP_LVL2_AB },
342 { .type = AMD_FW_LSDMA, .level = PSP_LVL2 | PSP_LVL2_AB },
343 { .type = AMD_FW_C20_MP, .level = PSP_BOTH | PSP_LVL2_AB },
344 { .type = AMD_FW_MINIMSMU, .inst = 0, .level = PSP_BOTH | PSP_LVL2_AB },
345 { .type = AMD_FW_MINIMSMU, .inst = 1, .level = PSP_BOTH | PSP_LVL2_AB },
346 { .type = AMD_FW_SRAM_FW_EXT, .level = PSP_LVL2 | PSP_LVL2_AB },
Fred Reitbergerc4f3a332023-02-07 12:12:40 -0500347 { .type = AMD_FW_UMSMU, .level = PSP_LVL2 | PSP_LVL2_AB },
zbaoc3a08a92016-03-02 14:47:27 +0800348 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800349};
350
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800351amd_fw_entry amd_fw_table[] = {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800352 { .type = AMD_FW_XHCI },
353 { .type = AMD_FW_IMC },
354 { .type = AMD_FW_GEC },
zbaoc3a08a92016-03-02 14:47:27 +0800355 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800356};
357
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800358amd_bios_entry amd_bios_table[] = {
Zheng Baobf29a0d2020-12-03 23:00:48 +0800359 { .type = AMD_BIOS_RTM_PUBKEY, .inst = 0, .level = BDT_BOTH },
Ritul Guru9a321f32022-07-29 11:06:40 +0530360 { .type = AMD_BIOS_SIG, .inst = 0, .level = BDT_BOTH },
Marshall Dawson0581bf62019-09-25 11:03:53 -0600361 { .type = AMD_BIOS_APCB, .inst = 0, .level = BDT_BOTH },
362 { .type = AMD_BIOS_APCB, .inst = 1, .level = BDT_BOTH },
363 { .type = AMD_BIOS_APCB, .inst = 2, .level = BDT_BOTH },
364 { .type = AMD_BIOS_APCB, .inst = 3, .level = BDT_BOTH },
365 { .type = AMD_BIOS_APCB, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700366 { .type = AMD_BIOS_APCB, .inst = 5, .level = BDT_BOTH },
367 { .type = AMD_BIOS_APCB, .inst = 6, .level = BDT_BOTH },
368 { .type = AMD_BIOS_APCB, .inst = 7, .level = BDT_BOTH },
369 { .type = AMD_BIOS_APCB, .inst = 8, .level = BDT_BOTH },
370 { .type = AMD_BIOS_APCB, .inst = 9, .level = BDT_BOTH },
371 { .type = AMD_BIOS_APCB, .inst = 10, .level = BDT_BOTH },
372 { .type = AMD_BIOS_APCB, .inst = 11, .level = BDT_BOTH },
373 { .type = AMD_BIOS_APCB, .inst = 12, .level = BDT_BOTH },
374 { .type = AMD_BIOS_APCB, .inst = 13, .level = BDT_BOTH },
375 { .type = AMD_BIOS_APCB, .inst = 14, .level = BDT_BOTH },
376 { .type = AMD_BIOS_APCB, .inst = 15, .level = BDT_BOTH },
Marshall Dawson2dd3b5c2020-01-03 17:57:48 -0700377 { .type = AMD_BIOS_APCB_BK, .inst = 0, .level = BDT_BOTH },
378 { .type = AMD_BIOS_APCB_BK, .inst = 1, .level = BDT_BOTH },
379 { .type = AMD_BIOS_APCB_BK, .inst = 2, .level = BDT_BOTH },
380 { .type = AMD_BIOS_APCB_BK, .inst = 3, .level = BDT_BOTH },
381 { .type = AMD_BIOS_APCB_BK, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700382 { .type = AMD_BIOS_APCB_BK, .inst = 5, .level = BDT_BOTH },
383 { .type = AMD_BIOS_APCB_BK, .inst = 6, .level = BDT_BOTH },
384 { .type = AMD_BIOS_APCB_BK, .inst = 7, .level = BDT_BOTH },
385 { .type = AMD_BIOS_APCB_BK, .inst = 8, .level = BDT_BOTH },
386 { .type = AMD_BIOS_APCB_BK, .inst = 9, .level = BDT_BOTH },
387 { .type = AMD_BIOS_APCB_BK, .inst = 10, .level = BDT_BOTH },
388 { .type = AMD_BIOS_APCB_BK, .inst = 11, .level = BDT_BOTH },
389 { .type = AMD_BIOS_APCB_BK, .inst = 12, .level = BDT_BOTH },
390 { .type = AMD_BIOS_APCB_BK, .inst = 13, .level = BDT_BOTH },
391 { .type = AMD_BIOS_APCB_BK, .inst = 14, .level = BDT_BOTH },
392 { .type = AMD_BIOS_APCB_BK, .inst = 15, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600393 { .type = AMD_BIOS_APOB, .level = BDT_BOTH },
394 { .type = AMD_BIOS_BIN,
Zheng Bao3d426f32022-10-16 20:34:57 +0800395 .reset = 1, .copy = 1, .zlib = 1, .inst = 0, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600396 { .type = AMD_BIOS_APOB_NV, .level = BDT_LVL2 },
397 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 0, .level = BDT_BOTH },
398 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 0, .level = BDT_BOTH },
Zheng Baoe220faa2022-02-17 17:22:15 +0800399 { .type = AMD_BIOS_PMUI, .inst = 2, .subpr = 0, .level = BDT_BOTH },
400 { .type = AMD_BIOS_PMUD, .inst = 2, .subpr = 0, .level = BDT_BOTH },
Arthur Heymansa83c5022022-10-04 20:37:10 +0200401 { .type = AMD_BIOS_PMUI, .inst = 3, .subpr = 0, .level = BDT_BOTH },
402 { .type = AMD_BIOS_PMUD, .inst = 3, .subpr = 0, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600403 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 0, .level = BDT_BOTH },
404 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 0, .level = BDT_BOTH },
Zheng Bao8eba6622022-10-16 20:29:03 +0800405 { .type = AMD_BIOS_PMUI, .inst = 5, .subpr = 0, .level = BDT_BOTH },
406 { .type = AMD_BIOS_PMUD, .inst = 5, .subpr = 0, .level = BDT_BOTH },
407 { .type = AMD_BIOS_PMUI, .inst = 6, .subpr = 0, .level = BDT_BOTH },
408 { .type = AMD_BIOS_PMUD, .inst = 6, .subpr = 0, .level = BDT_BOTH },
409 { .type = AMD_BIOS_PMUI, .inst = 7, .subpr = 0, .level = BDT_BOTH },
410 { .type = AMD_BIOS_PMUD, .inst = 7, .subpr = 0, .level = BDT_BOTH },
Arthur Heymansa83c5022022-10-04 20:37:10 +0200411 { .type = AMD_BIOS_PMUI, .inst = 9, .subpr = 0, .level = BDT_BOTH },
412 { .type = AMD_BIOS_PMUD, .inst = 9, .subpr = 0, .level = BDT_BOTH },
413 { .type = AMD_BIOS_PMUI, .inst = 10, .subpr = 0, .level = BDT_BOTH },
414 { .type = AMD_BIOS_PMUD, .inst = 10, .subpr = 0, .level = BDT_BOTH },
Zheng Bao8eba6622022-10-16 20:29:03 +0800415 { .type = AMD_BIOS_PMUI, .inst = 11, .subpr = 0, .level = BDT_BOTH },
416 { .type = AMD_BIOS_PMUD, .inst = 11, .subpr = 0, .level = BDT_BOTH },
417 { .type = AMD_BIOS_PMUI, .inst = 12, .subpr = 0, .level = BDT_BOTH },
418 { .type = AMD_BIOS_PMUD, .inst = 12, .subpr = 0, .level = BDT_BOTH },
419 { .type = AMD_BIOS_PMUI, .inst = 13, .subpr = 0, .level = BDT_BOTH },
420 { .type = AMD_BIOS_PMUD, .inst = 13, .subpr = 0, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600421 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 1, .level = BDT_BOTH },
422 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 1, .level = BDT_BOTH },
Zheng Baoe220faa2022-02-17 17:22:15 +0800423 { .type = AMD_BIOS_PMUI, .inst = 2, .subpr = 1, .level = BDT_BOTH },
424 { .type = AMD_BIOS_PMUD, .inst = 2, .subpr = 1, .level = BDT_BOTH },
Arthur Heymansa83c5022022-10-04 20:37:10 +0200425 { .type = AMD_BIOS_PMUI, .inst = 3, .subpr = 1, .level = BDT_BOTH },
426 { .type = AMD_BIOS_PMUD, .inst = 3, .subpr = 1, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600427 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 1, .level = BDT_BOTH },
428 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 1, .level = BDT_BOTH },
Zheng Bao8eba6622022-10-16 20:29:03 +0800429 { .type = AMD_BIOS_PMUI, .inst = 5, .subpr = 1, .level = BDT_BOTH },
430 { .type = AMD_BIOS_PMUD, .inst = 5, .subpr = 1, .level = BDT_BOTH },
431 { .type = AMD_BIOS_PMUI, .inst = 6, .subpr = 1, .level = BDT_BOTH },
432 { .type = AMD_BIOS_PMUD, .inst = 6, .subpr = 1, .level = BDT_BOTH },
433 { .type = AMD_BIOS_PMUI, .inst = 7, .subpr = 1, .level = BDT_BOTH },
434 { .type = AMD_BIOS_PMUD, .inst = 7, .subpr = 1, .level = BDT_BOTH },
Arthur Heymansa83c5022022-10-04 20:37:10 +0200435 { .type = AMD_BIOS_PMUI, .inst = 9, .subpr = 1, .level = BDT_BOTH },
436 { .type = AMD_BIOS_PMUD, .inst = 9, .subpr = 1, .level = BDT_BOTH },
437 { .type = AMD_BIOS_PMUI, .inst = 10, .subpr = 1, .level = BDT_BOTH },
438 { .type = AMD_BIOS_PMUD, .inst = 10, .subpr = 1, .level = BDT_BOTH },
Zheng Bao8eba6622022-10-16 20:29:03 +0800439 { .type = AMD_BIOS_PMUI, .inst = 11, .subpr = 1, .level = BDT_BOTH },
440 { .type = AMD_BIOS_PMUD, .inst = 11, .subpr = 1, .level = BDT_BOTH },
441 { .type = AMD_BIOS_PMUI, .inst = 12, .subpr = 1, .level = BDT_BOTH },
442 { .type = AMD_BIOS_PMUD, .inst = 12, .subpr = 1, .level = BDT_BOTH },
443 { .type = AMD_BIOS_PMUI, .inst = 13, .subpr = 1, .level = BDT_BOTH },
444 { .type = AMD_BIOS_PMUD, .inst = 13, .subpr = 1, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600445 { .type = AMD_BIOS_UCODE, .inst = 0, .level = BDT_LVL2 },
446 { .type = AMD_BIOS_UCODE, .inst = 1, .level = BDT_LVL2 },
447 { .type = AMD_BIOS_UCODE, .inst = 2, .level = BDT_LVL2 },
Arthur Heymansa83c5022022-10-04 20:37:10 +0200448 { .type = AMD_BIOS_UCODE, .inst = 3, .level = BDT_LVL2 },
449 { .type = AMD_BIOS_UCODE, .inst = 4, .level = BDT_LVL2 },
450 { .type = AMD_BIOS_UCODE, .inst = 5, .level = BDT_LVL2 },
451 { .type = AMD_BIOS_UCODE, .inst = 6, .level = BDT_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600452 { .type = AMD_BIOS_MP2_CFG, .level = BDT_LVL2 },
Martin Roth94554742020-04-14 14:59:36 -0600453 { .type = AMD_BIOS_PSP_SHARED_MEM, .inst = 0, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600454 { .type = AMD_BIOS_INVALID },
455};
456
Marshall Dawson2794a862019-03-04 16:53:15 -0700457typedef struct _context {
458 char *rom; /* target buffer, size of flash device */
459 uint32_t rom_size; /* size of flash device */
Zheng Bao6fff2492021-11-15 19:53:21 +0800460 uint32_t address_mode; /* 0:abs address; 1:relative to flash; 2: relative to table */
Marshall Dawson2794a862019-03-04 16:53:15 -0700461 uint32_t current; /* pointer within flash & proxy buffer */
Zheng Baoc26108f2023-02-17 11:01:07 +0800462 uint32_t current_pointer_saved;
Zheng Bao6fff2492021-11-15 19:53:21 +0800463 uint32_t current_table;
Marshall Dawson2794a862019-03-04 16:53:15 -0700464} context;
465
466#define RUN_BASE(ctx) (0xFFFFFFFF - (ctx).rom_size + 1)
Zheng Bao6fff2492021-11-15 19:53:21 +0800467#define RUN_OFFSET_MODE(ctx, offset, mode) \
Robert Zieba29bc79f2022-03-14 15:59:12 -0600468 ((mode) == AMD_ADDR_PHYSICAL ? RUN_BASE(ctx) + (offset) : \
469 ((mode) == AMD_ADDR_REL_BIOS ? (offset) : \
Zheng Baoc38f7642023-02-21 10:43:08 +0800470 ((mode) == AMD_ADDR_REL_TAB ? (offset) - (ctx).current_table : (offset))))
Zheng Bao6fff2492021-11-15 19:53:21 +0800471#define RUN_OFFSET(ctx, offset) RUN_OFFSET_MODE((ctx), (offset), (ctx).address_mode)
Robert Zieba29bc79f2022-03-14 15:59:12 -0600472#define RUN_TO_OFFSET(ctx, run) ((ctx).address_mode == AMD_ADDR_PHYSICAL ? \
Zheng Bao6fff2492021-11-15 19:53:21 +0800473 (run) - RUN_BASE(ctx) : (run)) /* TODO: */
Marshall Dawson2794a862019-03-04 16:53:15 -0700474#define RUN_CURRENT(ctx) RUN_OFFSET((ctx), (ctx).current)
Zheng Bao6fff2492021-11-15 19:53:21 +0800475/* The mode in entry can not be higher than the header's.
476 For example, if table mode is 0, all the entry mode will be 0. */
477#define RUN_CURRENT_MODE(ctx, mode) RUN_OFFSET_MODE((ctx), (ctx).current, \
478 (ctx).address_mode < (mode) ? (ctx).address_mode : (mode))
Marshall Dawson2794a862019-03-04 16:53:15 -0700479#define BUFF_OFFSET(ctx, offset) ((void *)((ctx).rom + (offset)))
480#define BUFF_CURRENT(ctx) BUFF_OFFSET((ctx), (ctx).current)
481#define BUFF_TO_RUN(ctx, ptr) RUN_OFFSET((ctx), ((char *)(ptr) - (ctx).rom))
Zheng Bao6fff2492021-11-15 19:53:21 +0800482#define BUFF_TO_RUN_MODE(ctx, ptr, mode) RUN_OFFSET_MODE((ctx), ((char *)(ptr) - (ctx).rom), \
483 (ctx).address_mode < (mode) ? (ctx).address_mode : (mode))
Marshall Dawson2794a862019-03-04 16:53:15 -0700484#define BUFF_ROOM(ctx) ((ctx).rom_size - (ctx).current)
Zheng Bao6fff2492021-11-15 19:53:21 +0800485/* Only set the address mode in entry if the table is mode 2. */
486#define SET_ADDR_MODE(table, mode) \
487 ((table)->header.additional_info_fields.address_mode == \
Robert Zieba29bc79f2022-03-14 15:59:12 -0600488 AMD_ADDR_REL_TAB ? (mode) : 0)
Zheng Bao6fff2492021-11-15 19:53:21 +0800489#define SET_ADDR_MODE_BY_TABLE(table) \
490 SET_ADDR_MODE((table), (table)->header.additional_info_fields.address_mode)
Marshall Dawson2794a862019-03-04 16:53:15 -0700491
Zheng Bao7c5ad882023-02-19 13:02:52 +0800492
493static void free_psp_firmware_filenames(amd_fw_entry *fw_table)
494{
495 amd_fw_entry *index;
496
497 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
498 if (index->filename &&
499 index->type != AMD_FW_VERSTAGE_SIG &&
500 index->type != AMD_FW_PSP_VERSTAGE &&
501 index->type != AMD_FW_SPL &&
502 index->type != AMD_FW_PSP_WHITELIST) {
503 free(index->filename);
504 index->filename = NULL;
505 }
506 }
507}
508
509static void free_bdt_firmware_filenames(amd_bios_entry *fw_table)
510{
511 amd_bios_entry *index;
512
513 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
514 if (index->filename &&
515 index->type != AMD_BIOS_APCB &&
516 index->type != AMD_BIOS_BIN &&
517 index->type != AMD_BIOS_APCB_BK &&
518 index->type != AMD_BIOS_UCODE) {
519 free(index->filename);
520 index->filename = NULL;
521 }
522 }
523}
524
525static void amdfwtool_cleanup(context *ctx)
526{
527 free(ctx->rom);
528 ctx->rom = NULL;
529
530 /* Free the filename. */
531 free_psp_firmware_filenames(amd_psp_fw_table);
532 free_bdt_firmware_filenames(amd_bios_table);
533}
534
Zheng Bao5164e4b2021-10-30 12:09:07 +0800535void assert_fw_entry(uint32_t count, uint32_t max, context *ctx)
536{
537 if (count >= max) {
538 fprintf(stderr, "Error: BIOS entries (%d) exceeds max allowed items "
539 "(%d)\n", count, max);
Zheng Bao7c5ad882023-02-19 13:02:52 +0800540 amdfwtool_cleanup(ctx);
Zheng Bao5164e4b2021-10-30 12:09:07 +0800541 exit(1);
542 }
543}
544
Zheng Baoc26108f2023-02-17 11:01:07 +0800545static void set_current_pointer(context *ctx, uint32_t value)
546{
547 if (ctx->current_pointer_saved != 0xFFFFFFFF &&
548 ctx->current_pointer_saved != ctx->current) {
549 fprintf(stderr, "Error: The pointer is changed elsewhere\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +0800550 amdfwtool_cleanup(ctx);
Zheng Baoc26108f2023-02-17 11:01:07 +0800551 exit(1);
552 }
553
554 ctx->current = value;
555
556 if (ctx->current > ctx->rom_size) {
557 fprintf(stderr, "Error: Packing data causes overflow\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +0800558 amdfwtool_cleanup(ctx);
Zheng Baoc26108f2023-02-17 11:01:07 +0800559 exit(1);
560 }
561
562 ctx->current_pointer_saved = ctx->current;
563}
564
565static void adjust_current_pointer(context *ctx, uint32_t add, uint32_t align)
566{
567 /* Get */
568 set_current_pointer(ctx, ALIGN_UP(ctx->current + add, align));
569}
570
Marshall Dawson24f73d42019-04-01 10:48:43 -0600571static void *new_psp_dir(context *ctx, int multi)
Marshall Dawson2794a862019-03-04 16:53:15 -0700572{
573 void *ptr;
574
Marshall Dawson24f73d42019-04-01 10:48:43 -0600575 /*
576 * Force both onto boundary when multi. Primary table is after
577 * updatable table, so alignment ensures primary can stay intact
578 * if secondary is reprogrammed.
579 */
580 if (multi)
Zheng Baoc26108f2023-02-17 11:01:07 +0800581 adjust_current_pointer(ctx, 0, TABLE_ERASE_ALIGNMENT);
Marshall Dawson24f73d42019-04-01 10:48:43 -0600582 else
Zheng Baoc26108f2023-02-17 11:01:07 +0800583 adjust_current_pointer(ctx, 0, TABLE_ALIGNMENT);
Marshall Dawson24f73d42019-04-01 10:48:43 -0600584
Marshall Dawson2794a862019-03-04 16:53:15 -0700585 ptr = BUFF_CURRENT(*ctx);
Zheng Bao990d1542021-09-17 13:24:54 +0800586 ((psp_directory_header *)ptr)->num_entries = 0;
Zheng Bao6fff2492021-11-15 19:53:21 +0800587 ((psp_directory_header *)ptr)->additional_info = 0;
588 ((psp_directory_header *)ptr)->additional_info_fields.address_mode = ctx->address_mode;
Zheng Baoc26108f2023-02-17 11:01:07 +0800589 adjust_current_pointer(ctx,
590 sizeof(psp_directory_header) + MAX_PSP_ENTRIES * sizeof(psp_directory_entry),
591 1);
Marshall Dawson2794a862019-03-04 16:53:15 -0700592 return ptr;
593}
594
Zheng Baofdd47ef2021-09-17 13:30:08 +0800595static void *new_ish_dir(context *ctx)
596{
597 void *ptr;
Zheng Baoc26108f2023-02-17 11:01:07 +0800598 adjust_current_pointer(ctx, 0, TABLE_ALIGNMENT);
Zheng Baofdd47ef2021-09-17 13:30:08 +0800599 ptr = BUFF_CURRENT(*ctx);
Zheng Baoc26108f2023-02-17 11:01:07 +0800600 adjust_current_pointer(ctx, TABLE_ALIGNMENT, 1);
601
Zheng Baofdd47ef2021-09-17 13:30:08 +0800602 return ptr;
603}
604
Marshall Dawson2794a862019-03-04 16:53:15 -0700605static void *new_combo_dir(context *ctx)
606{
607 void *ptr;
608
Zheng Baoc26108f2023-02-17 11:01:07 +0800609 adjust_current_pointer(ctx, 0, TABLE_ALIGNMENT);
Marshall Dawson2794a862019-03-04 16:53:15 -0700610 ptr = BUFF_CURRENT(*ctx);
Zheng Baoc26108f2023-02-17 11:01:07 +0800611 adjust_current_pointer(ctx,
612 sizeof(psp_combo_header) + MAX_COMBO_ENTRIES * sizeof(psp_combo_entry),
613 1);
Marshall Dawson2794a862019-03-04 16:53:15 -0700614 return ptr;
615}
616
Zheng Baobf29a0d2020-12-03 23:00:48 +0800617static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie, context *ctx)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800618{
Marshall Dawson24f73d42019-04-01 10:48:43 -0600619 psp_combo_directory *cdir = directory;
620 psp_directory_table *dir = directory;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600621 bios_directory_table *bdir = directory;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800622 uint32_t table_size = 0;
Marshall Dawson24f73d42019-04-01 10:48:43 -0600623
624 if (!count)
625 return;
Zheng Baob035f582021-05-27 11:26:12 +0800626 if (ctx == NULL || directory == NULL) {
627 fprintf(stderr, "Calling %s with NULL pointers\n", __func__);
628 return;
629 }
Marshall Dawson24f73d42019-04-01 10:48:43 -0600630
Zheng Baobf29a0d2020-12-03 23:00:48 +0800631 /* The table size needs to be 0x1000 aligned. So align the end of table. */
Zheng Baoc26108f2023-02-17 11:01:07 +0800632 adjust_current_pointer(ctx, 0, TABLE_ALIGNMENT);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800633
Marshall Dawson24f73d42019-04-01 10:48:43 -0600634 switch (cookie) {
635 case PSP2_COOKIE:
Zheng Bao84fb9ea2022-08-18 15:54:47 +0800636 case BHD2_COOKIE:
Marshall Dawsona378c222019-03-04 16:52:07 -0700637 cdir->header.cookie = cookie;
Zheng Baofd51af62022-08-18 15:26:39 +0800638 /* lookup mode is hardcoded for now. */
639 cdir->header.lookup = 1;
Marshall Dawsona378c222019-03-04 16:52:07 -0700640 cdir->header.num_entries = count;
641 cdir->header.reserved[0] = 0;
642 cdir->header.reserved[1] = 0;
643 /* checksum everything that comes after the Checksum field */
644 cdir->header.checksum = fletcher32(&cdir->header.num_entries,
645 count * sizeof(psp_combo_entry)
646 + sizeof(cdir->header.num_entries)
647 + sizeof(cdir->header.lookup)
648 + 2 * sizeof(cdir->header.reserved[0]));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600649 break;
650 case PSP_COOKIE:
651 case PSPL2_COOKIE:
Zheng Bao6fff2492021-11-15 19:53:21 +0800652 table_size = ctx->current - ctx->current_table;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800653 if ((table_size % TABLE_ALIGNMENT) != 0) {
654 fprintf(stderr, "The PSP table size should be 4K aligned\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +0800655 amdfwtool_cleanup(ctx);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800656 exit(1);
657 }
Marshall Dawsona378c222019-03-04 16:52:07 -0700658 dir->header.cookie = cookie;
659 dir->header.num_entries = count;
Zheng Bao6fff2492021-11-15 19:53:21 +0800660 dir->header.additional_info_fields.dir_size = table_size / TABLE_ALIGNMENT;
661 dir->header.additional_info_fields.spi_block_size = 1;
662 dir->header.additional_info_fields.base_addr = 0;
Marshall Dawsona378c222019-03-04 16:52:07 -0700663 /* checksum everything that comes after the Checksum field */
664 dir->header.checksum = fletcher32(&dir->header.num_entries,
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700665 count * sizeof(psp_directory_entry)
Marshall Dawsona378c222019-03-04 16:52:07 -0700666 + sizeof(dir->header.num_entries)
Zheng Baobf29a0d2020-12-03 23:00:48 +0800667 + sizeof(dir->header.additional_info));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600668 break;
Zheng Bao96a33712021-06-11 15:54:40 +0800669 case BHD_COOKIE:
670 case BHDL2_COOKIE:
Zheng Bao6fff2492021-11-15 19:53:21 +0800671 table_size = ctx->current - ctx->current_table;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800672 if ((table_size % TABLE_ALIGNMENT) != 0) {
673 fprintf(stderr, "The BIOS table size should be 4K aligned\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +0800674 amdfwtool_cleanup(ctx);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800675 exit(1);
676 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600677 bdir->header.cookie = cookie;
678 bdir->header.num_entries = count;
Zheng Bao6fff2492021-11-15 19:53:21 +0800679 bdir->header.additional_info_fields.dir_size = table_size / TABLE_ALIGNMENT;
680 bdir->header.additional_info_fields.spi_block_size = 1;
681 bdir->header.additional_info_fields.base_addr = 0;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600682 /* checksum everything that comes after the Checksum field */
683 bdir->header.checksum = fletcher32(&bdir->header.num_entries,
684 count * sizeof(bios_directory_entry)
685 + sizeof(bdir->header.num_entries)
Zheng Baobf29a0d2020-12-03 23:00:48 +0800686 + sizeof(bdir->header.additional_info));
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600687 break;
Marshall Dawsona378c222019-03-04 16:52:07 -0700688 }
Zheng Baobf29a0d2020-12-03 23:00:48 +0800689
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800690}
691
Zheng Bao2f6b7d52023-02-11 22:27:49 +0800692static void fill_psp_directory_to_efs(embedded_firmware *amd_romsig, void *pspdir,
693 context *ctx, amd_cb_config *cb_config)
694{
695 switch (cb_config->soc_id) {
696 case PLATFORM_UNKNOWN:
697 amd_romsig->psp_directory =
698 BUFF_TO_RUN_MODE(*ctx, pspdir, AMD_ADDR_REL_BIOS);
699 break;
700 case PLATFORM_CEZANNE:
701 case PLATFORM_MENDOCINO:
702 case PLATFORM_PHOENIX:
703 case PLATFORM_GLINDA:
704 case PLATFORM_CARRIZO:
705 case PLATFORM_STONEYRIDGE:
706 case PLATFORM_RAVEN:
707 case PLATFORM_PICASSO:
708 case PLATFORM_LUCIENNE:
709 case PLATFORM_RENOIR:
710 default:
711 /* for combo, it is also combo_psp_directory */
712 amd_romsig->new_psp_directory =
713 BUFF_TO_RUN_MODE(*ctx, pspdir, AMD_ADDR_REL_BIOS);
714 break;
715 }
716}
717
718static void fill_bios_directory_to_efs(embedded_firmware *amd_romsig, void *biosdir,
719 context *ctx, amd_cb_config *cb_config)
720{
721 switch (cb_config->soc_id) {
722 case PLATFORM_RENOIR:
723 case PLATFORM_LUCIENNE:
724 case PLATFORM_CEZANNE:
725 if (!cb_config->recovery_ab)
726 amd_romsig->bios3_entry =
727 BUFF_TO_RUN_MODE(*ctx, biosdir, AMD_ADDR_REL_BIOS);
728 break;
729 case PLATFORM_MENDOCINO:
730 case PLATFORM_PHOENIX:
731 case PLATFORM_GLINDA:
732 break;
733 case PLATFORM_CARRIZO:
734 case PLATFORM_STONEYRIDGE:
735 case PLATFORM_RAVEN:
736 case PLATFORM_PICASSO:
737 default:
738 amd_romsig->bios1_entry =
739 BUFF_TO_RUN_MODE(*ctx, biosdir, AMD_ADDR_REL_BIOS);
740 break;
741 }
742}
743
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700744static ssize_t copy_blob(void *dest, const char *src_file, size_t room)
745{
746 int fd;
747 struct stat fd_stat;
748 ssize_t bytes;
749
750 fd = open(src_file, O_RDONLY);
751 if (fd < 0) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800752 fprintf(stderr, "Error opening file: %s: %s\n",
Eric Peersaf505672020-03-05 16:04:15 -0700753 src_file, strerror(errno));
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700754 return -1;
755 }
756
757 if (fstat(fd, &fd_stat)) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800758 fprintf(stderr, "fstat error: %s\n", strerror(errno));
Jacob Garber967f8622019-07-02 10:35:10 -0600759 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700760 return -2;
761 }
762
Zheng Bao6d402ac2020-10-01 16:16:30 +0800763 if ((size_t)fd_stat.st_size > room) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800764 fprintf(stderr, "Error: %s will not fit. Exiting.\n", src_file);
Jacob Garber967f8622019-07-02 10:35:10 -0600765 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700766 return -3;
767 }
768
769 bytes = read(fd, dest, (size_t)fd_stat.st_size);
770 close(fd);
771 if (bytes != (ssize_t)fd_stat.st_size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800772 fprintf(stderr, "Error while reading %s\n", src_file);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700773 return -4;
774 }
775
776 return bytes;
777}
778
Kangheui Won3c164e12021-12-03 20:25:05 +1100779static ssize_t read_from_file_to_buf(int fd, void *buf, size_t buf_size)
780{
781 ssize_t bytes;
782 size_t total_bytes = 0;
783
784 do {
785 bytes = read(fd, buf + total_bytes, buf_size - total_bytes);
786 if (bytes == 0) {
787 fprintf(stderr, "Reached EOF probably\n");
788 break;
789 }
790
791 if (bytes < 0 && errno == EAGAIN)
792 bytes = 0;
793
794 if (bytes < 0) {
795 fprintf(stderr, "Read failure %s\n", strerror(errno));
796 return bytes;
797 }
798
799 total_bytes += bytes;
800 } while (total_bytes < buf_size);
801
802 if (total_bytes != buf_size) {
803 fprintf(stderr, "Read data size(%zu) != buffer size(%zu)\n",
804 total_bytes, buf_size);
805 return -1;
806 }
807 return buf_size;
808}
809
810static ssize_t write_from_buf_to_file(int fd, const void *buf, size_t buf_size)
811{
812 ssize_t bytes;
813 size_t total_bytes = 0;
814
815 do {
816 bytes = write(fd, buf + total_bytes, buf_size - total_bytes);
817 if (bytes < 0 && errno == EAGAIN)
818 bytes = 0;
819
820 if (bytes < 0) {
821 fprintf(stderr, "Write failure %s\n", strerror(errno));
822 lseek(fd, SEEK_CUR, -total_bytes);
823 return bytes;
824 }
825
826 total_bytes += bytes;
827 } while (total_bytes < buf_size);
828
829 if (total_bytes != buf_size) {
830 fprintf(stderr, "Wrote more data(%zu) than buffer size(%zu)\n",
831 total_bytes, buf_size);
832 lseek(fd, SEEK_CUR, -total_bytes);
833 return -1;
834 }
835
836 return buf_size;
837}
838
Zheng Baoeb0404e2021-10-14 15:09:09 +0800839static uint32_t get_psp_id(enum platform soc_id)
840{
841 uint32_t psp_id;
842 switch (soc_id) {
843 case PLATFORM_RAVEN:
844 case PLATFORM_PICASSO:
845 psp_id = 0xBC0A0000;
846 break;
847 case PLATFORM_RENOIR:
848 case PLATFORM_LUCIENNE:
849 psp_id = 0xBC0C0000;
850 break;
851 case PLATFORM_CEZANNE:
852 psp_id = 0xBC0C0140;
853 break;
854 case PLATFORM_MENDOCINO:
855 psp_id = 0xBC0D0900;
856 break;
857 case PLATFORM_STONEYRIDGE:
858 psp_id = 0x10220B00;
859 break;
Zheng Baode6f1982022-10-16 20:32:43 +0800860 case PLATFORM_GLINDA:
861 psp_id = 0xBC0E0200;
862 break;
863 case PLATFORM_PHOENIX:
864 psp_id = 0xBC0D0400;
865 break;
Zheng Bao3d7623f2022-08-17 11:52:30 +0800866 case PLATFORM_CARRIZO:
Zheng Baoeb0404e2021-10-14 15:09:09 +0800867 default:
868 psp_id = 0;
869 break;
870 }
871 return psp_id;
872}
873
Kangheui Won3c164e12021-12-03 20:25:05 +1100874static uint16_t get_psp_fw_type(enum platform soc_id, struct amd_fw_header *header)
875{
876 switch (soc_id) {
877 case PLATFORM_MENDOCINO:
Zheng Bao4044e852023-02-02 09:26:20 +0800878 case PLATFORM_PHOENIX:
879 case PLATFORM_GLINDA:
Kangheui Won3c164e12021-12-03 20:25:05 +1100880 /* Fallback to fw_type if fw_id is not populated, which serves the same
881 purpose on older SoCs. */
882 return header->fw_id ? header->fw_id : header->fw_type;
883 default:
884 return header->fw_type;
885 }
886}
887
Kangheui Won5b84dfd2021-12-21 15:45:06 +1100888static int add_single_sha(amd_fw_entry_hash *entry, void *buf, enum platform soc_id)
889{
890 uint8_t hash[SHA384_DIGEST_LENGTH];
891 struct amd_fw_header *header = (struct amd_fw_header *)buf;
892 /* Include only signed part for hash calculation. */
893 size_t len = header->fw_size_signed + sizeof(struct amd_fw_header);
894 uint8_t *body = (uint8_t *)buf;
895
896 if (len > header->size_total)
897 return -1;
898
899 if (header->sig_id == SIG_ID_RSA4096) {
900 SHA384(body, len, hash);
901 entry->sha_len = SHA384_DIGEST_LENGTH;
902 } else if (header->sig_id == SIG_ID_RSA2048) {
903 SHA256(body, len, hash);
904 entry->sha_len = SHA256_DIGEST_LENGTH;
905 } else {
906 fprintf(stderr, "%s: Unknown signature id: 0x%08x\n",
907 __func__, header->sig_id);
908 return -1;
909 }
910
911 memcpy(entry->sha, hash, entry->sha_len);
912 entry->fw_id = get_psp_fw_type(soc_id, header);
913 entry->subtype = header->fw_subtype;
914
915 return 0;
916}
917
918static int get_num_binaries(void *buf, size_t buf_size)
919{
920 struct amd_fw_header *header = (struct amd_fw_header *)buf;
921 size_t total_len = 0;
922 int num_binaries = 0;
923
924 while (total_len < buf_size) {
925 num_binaries++;
926 total_len += header->size_total;
927 header = (struct amd_fw_header *)(buf + total_len);
928 }
929
930 if (total_len != buf_size) {
931 fprintf(stderr, "Malformed binary\n");
932 return -1;
933 }
934 return num_binaries;
935}
936
937static int add_sha(amd_fw_entry *entry, void *buf, size_t buf_size, enum platform soc_id)
938{
939 struct amd_fw_header *header = (struct amd_fw_header *)buf;
940 /* Include only signed part for hash calculation. */
941 size_t total_len = 0;
942 int num_binaries = get_num_binaries(buf, buf_size);
943
944 if (num_binaries <= 0)
945 return num_binaries;
946
947 entry->hash_entries = malloc(num_binaries * sizeof(amd_fw_entry_hash));
948 if (!entry->hash_entries) {
949 fprintf(stderr, "Error allocating memory to add FW hash\n");
950 return -1;
951 }
952 entry->num_hash_entries = num_binaries;
953
954 /* Iterate through each binary */
955 for (int i = 0; i < num_binaries; i++) {
956 if (add_single_sha(&entry->hash_entries[i], buf + total_len, soc_id)) {
957 free(entry->hash_entries);
958 return -1;
959 }
960 total_len += header->size_total;
961 header = (struct amd_fw_header *)(buf + total_len);
962 }
963
964 return 0;
965}
966
Marshall Dawson2794a862019-03-04 16:53:15 -0700967static void integrate_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -0700968 embedded_firmware *romsig,
Marshall Dawson2794a862019-03-04 16:53:15 -0700969 amd_fw_entry *fw_table)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800970{
Richard Spiegel137484d2018-01-17 10:23:19 -0700971 ssize_t bytes;
Zheng Bao6d402ac2020-10-01 16:16:30 +0800972 uint32_t i;
Marshall Dawson2794a862019-03-04 16:53:15 -0700973
Zheng Baoc26108f2023-02-17 11:01:07 +0800974 adjust_current_pointer(ctx, 0, BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800975
Martin Rothcd15bc82016-11-08 11:34:02 -0700976 for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
zbaoc3a08a92016-03-02 14:47:27 +0800977 if (fw_table[i].filename != NULL) {
zbaoc3a08a92016-03-02 14:47:27 +0800978 switch (fw_table[i].type) {
979 case AMD_FW_IMC:
Zheng Baoc26108f2023-02-17 11:01:07 +0800980 adjust_current_pointer(ctx, 0, 0x10000U);
Marshall Dawson2794a862019-03-04 16:53:15 -0700981 romsig->imc_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800982 break;
983 case AMD_FW_GEC:
Marshall Dawson2794a862019-03-04 16:53:15 -0700984 romsig->gec_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800985 break;
986 case AMD_FW_XHCI:
Marshall Dawson2794a862019-03-04 16:53:15 -0700987 romsig->xhci_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800988 break;
989 default:
990 /* Error */
991 break;
992 }
993
Marshall Dawson2794a862019-03-04 16:53:15 -0700994 bytes = copy_blob(BUFF_CURRENT(*ctx),
995 fw_table[i].filename, BUFF_ROOM(*ctx));
Marshall Dawson02bd7732019-03-13 14:43:17 -0600996 if (bytes < 0) {
Zheng Bao7c5ad882023-02-19 13:02:52 +0800997 amdfwtool_cleanup(ctx);
Martin Roth60f15512016-11-08 09:55:01 -0700998 exit(1);
999 }
1000
Zheng Baoc26108f2023-02-17 11:01:07 +08001001 adjust_current_pointer(ctx, bytes, BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001002 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001003 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001004}
1005
Zheng Bao9e908072020-10-28 11:39:13 +08001006/* For debugging */
1007static void dump_psp_firmwares(amd_fw_entry *fw_table)
1008{
1009 amd_fw_entry *index;
1010
1011 printf("PSP firmware components:");
1012 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
1013 if (index->filename)
Zheng Bao826f1c42021-05-25 16:26:55 +08001014 printf(" %2x: %s\n", index->type, index->filename);
Zheng Bao9e908072020-10-28 11:39:13 +08001015 }
1016}
1017
1018static void dump_bdt_firmwares(amd_bios_entry *fw_table)
1019{
1020 amd_bios_entry *index;
1021
1022 printf("BIOS Directory Table (BDT) components:");
1023 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
1024 if (index->filename)
Zheng Bao826f1c42021-05-25 16:26:55 +08001025 printf(" %2x: %s\n", index->type, index->filename);
Zheng Bao9e908072020-10-28 11:39:13 +08001026 }
1027}
1028
Kangheui Won5b84dfd2021-12-21 15:45:06 +11001029static void write_or_fail(int fd, void *ptr, size_t size)
1030{
1031 ssize_t written;
1032
1033 written = write_from_buf_to_file(fd, ptr, size);
1034 if (written < 0 || (size_t)written != size) {
1035 fprintf(stderr, "%s: Error writing %zu bytes - written %zd bytes\n",
1036 __func__, size, written);
1037 exit(-1);
1038 }
1039}
1040
1041static void write_one_psp_firmware_hash_entry(int fd, amd_fw_entry_hash *entry)
1042{
1043 uint16_t type = entry->fw_id;
1044 uint16_t subtype = entry->subtype;
1045
1046 write_or_fail(fd, &type, sizeof(type));
1047 write_or_fail(fd, &subtype, sizeof(subtype));
1048 write_or_fail(fd, entry->sha, entry->sha_len);
1049}
1050
1051static void write_psp_firmware_hash(const char *filename,
1052 amd_fw_entry *fw_table)
1053{
1054 struct psp_fw_hash_table hash_header = {0};
1055 int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
1056
1057 if (fd < 0) {
1058 fprintf(stderr, "Error opening file: %s: %s\n",
1059 filename, strerror(errno));
1060 exit(-1);
1061 }
1062
1063 hash_header.version = HASH_HDR_V1;
1064 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
1065 for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
1066 if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) {
1067 hash_header.no_of_entries_256++;
1068 } else if (fw_table[i].hash_entries[j].sha_len ==
1069 SHA384_DIGEST_LENGTH) {
1070 hash_header.no_of_entries_384++;
1071 } else if (fw_table[i].hash_entries[j].sha_len) {
1072 fprintf(stderr, "%s: Error invalid sha_len %d\n",
1073 __func__, fw_table[i].hash_entries[j].sha_len);
1074 exit(-1);
1075 }
1076 }
1077 }
1078
1079 write_or_fail(fd, &hash_header, sizeof(hash_header));
1080
1081 /* Add all the SHA256 hash entries first followed by SHA384 entries. PSP verstage
1082 processes the table in that order. Mixing and matching SHA256 and SHA384 entries
1083 will cause the hash verification failure at run-time. */
1084 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
1085 for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
1086 if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH)
1087 write_one_psp_firmware_hash_entry(fd,
1088 &fw_table[i].hash_entries[j]);
1089 }
1090 }
1091
1092 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
1093 for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
1094 if (fw_table[i].hash_entries[j].sha_len == SHA384_DIGEST_LENGTH)
1095 write_one_psp_firmware_hash_entry(fd,
1096 &fw_table[i].hash_entries[j]);
1097 }
1098 }
1099
1100 close(fd);
1101 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
1102 if (!fw_table[i].num_hash_entries || !fw_table[i].hash_entries)
1103 continue;
1104
1105 free(fw_table[i].hash_entries);
1106 fw_table[i].hash_entries = NULL;
1107 fw_table[i].num_hash_entries = 0;
1108 }
1109}
1110
Kangheui Won3c164e12021-12-03 20:25:05 +11001111/**
1112 * process_signed_psp_firmwares() - Process the signed PSP binaries to keep them separate
1113 * @signed_rom: Output file path grouping all the signed PSP binaries.
1114 * @fw_table: Table of all the PSP firmware entries/binaries to be processed.
1115 * @signed_start_addr: Offset of the FMAP section, within the flash device, to hold
1116 * the signed PSP binaries.
1117 * @soc_id: SoC ID of the PSP binaries.
1118 */
1119static void process_signed_psp_firmwares(const char *signed_rom,
1120 amd_fw_entry *fw_table,
1121 uint64_t signed_start_addr,
1122 enum platform soc_id)
1123{
1124 unsigned int i;
1125 int fd;
1126 int signed_rom_fd;
1127 ssize_t bytes, align_bytes;
1128 uint8_t *buf;
Kangheui Won5b84dfd2021-12-21 15:45:06 +11001129 char *signed_rom_hash;
1130 size_t signed_rom_hash_strlen;
Kangheui Won3c164e12021-12-03 20:25:05 +11001131 struct amd_fw_header header;
1132 struct stat fd_stat;
1133 /* Every blob in amdfw*.rom has to start at address aligned to 0x100. Prepare an
1134 alignment data with 0xff to pad the blobs and meet the alignment requirement. */
1135 uint8_t align_data[BLOB_ALIGNMENT - 1];
1136
1137 memset(align_data, 0xff, sizeof(align_data));
1138 signed_rom_fd = open(signed_rom, O_RDWR | O_CREAT | O_TRUNC,
1139 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
1140 if (signed_rom_fd < 0) {
1141 fprintf(stderr, "Error opening file: %s: %s\n",
1142 signed_rom, strerror(errno));
1143 return;
1144 }
1145
1146 for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
Kangheui Won5b84dfd2021-12-21 15:45:06 +11001147 fw_table[i].num_hash_entries = 0;
1148 fw_table[i].hash_entries = NULL;
1149
Kangheui Won3c164e12021-12-03 20:25:05 +11001150 if (!(fw_table[i].filename) || fw_table[i].skip_hashing)
1151 continue;
1152
1153 memset(&header, 0, sizeof(header));
1154
1155 fd = open(fw_table[i].filename, O_RDONLY);
1156 if (fd < 0) {
1157 /* Keep the file along with set of unsigned PSP binaries & continue. */
1158 fprintf(stderr, "Error opening file: %s: %s\n",
1159 fw_table[i].filename, strerror(errno));
1160 continue;
1161 }
1162
1163 if (fstat(fd, &fd_stat)) {
1164 /* Keep the file along with set of unsigned PSP binaries & continue. */
1165 fprintf(stderr, "fstat error: %s\n", strerror(errno));
1166 close(fd);
1167 continue;
1168 }
1169
1170 bytes = read_from_file_to_buf(fd, &header, sizeof(struct amd_fw_header));
1171 if (bytes != (ssize_t)sizeof(struct amd_fw_header)) {
1172 /* Keep the file along with set of unsigned PSP binaries & continue. */
1173 fprintf(stderr, "%s: Error reading header from %s\n",
1174 __func__, fw_table[i].filename);
1175 close(fd);
1176 continue;
1177 }
1178
1179 /* If firmware header looks like invalid, assume it's not signed */
1180 if (!header.fw_type && !header.fw_id) {
1181 fprintf(stderr, "%s: Invalid FWID for %s\n",
1182 __func__, fw_table[i].filename);
1183 close(fd);
1184 continue;
1185 }
1186
Kangheui Won3c164e12021-12-03 20:25:05 +11001187
1188 /* PSP binary is not signed and should not be part of signed PSP binaries
1189 set. */
1190 if (header.sig_opt != 1) {
1191 close(fd);
1192 continue;
1193 }
1194
1195 buf = malloc(fd_stat.st_size);
1196 if (!buf) {
1197 /* Keep the file along with set of unsigned PSP binaries & continue. */
1198 fprintf(stderr, "%s: failed to allocate memory with size %lld\n",
1199 __func__, (long long)fd_stat.st_size);
1200 close(fd);
1201 continue;
1202 }
1203
1204 lseek(fd, SEEK_SET, 0);
1205 bytes = read_from_file_to_buf(fd, buf, fd_stat.st_size);
1206 if (bytes != fd_stat.st_size) {
1207 /* Keep the file along with set of unsigned PSP binaries & continue. */
1208 fprintf(stderr, "%s: failed to read %s\n",
1209 __func__, fw_table[i].filename);
1210 free(buf);
1211 close(fd);
1212 continue;
1213 }
1214
1215 bytes = write_from_buf_to_file(signed_rom_fd, buf, fd_stat.st_size);
1216 if (bytes != fd_stat.st_size) {
1217 /* Keep the file along with set of unsigned PSP binaries & continue. */
1218 fprintf(stderr, "%s: failed to write %s\n",
1219 __func__, fw_table[i].filename);
1220 free(buf);
1221 close(fd);
1222 continue;
1223 }
1224
1225 /* Write Blob alignment bytes */
1226 align_bytes = 0;
1227 if (fd_stat.st_size & (BLOB_ALIGNMENT - 1)) {
1228 align_bytes = BLOB_ALIGNMENT -
1229 (fd_stat.st_size & (BLOB_ALIGNMENT - 1));
1230 bytes = write_from_buf_to_file(signed_rom_fd, align_data, align_bytes);
1231 if (bytes != align_bytes) {
1232 fprintf(stderr, "%s: failed to write alignment data for %s\n",
1233 __func__, fw_table[i].filename);
1234 lseek(signed_rom_fd, SEEK_CUR, -fd_stat.st_size);
1235 free(buf);
1236 close(fd);
1237 continue;
1238 }
1239 }
1240
Kangheui Won5b84dfd2021-12-21 15:45:06 +11001241 if (add_sha(&fw_table[i], buf, fd_stat.st_size, soc_id))
1242 exit(-1);
1243
Kangheui Won3c164e12021-12-03 20:25:05 +11001244 /* File is successfully processed and is part of signed PSP binaries set. */
1245 fw_table[i].fw_id = get_psp_fw_type(soc_id, &header);
1246 fw_table[i].addr_signed = signed_start_addr;
1247 fw_table[i].file_size = (uint32_t)fd_stat.st_size;
1248
1249 signed_start_addr += fd_stat.st_size + align_bytes;
1250
1251 free(buf);
1252 close(fd);
1253 }
1254
1255 close(signed_rom_fd);
Kangheui Won5b84dfd2021-12-21 15:45:06 +11001256
1257 /* signed_rom file name + ".hash" + '\0' */
1258 signed_rom_hash_strlen = strlen(signed_rom) + strlen(HASH_FILE_SUFFIX) + 1;
1259 signed_rom_hash = malloc(signed_rom_hash_strlen);
1260 if (!signed_rom_hash) {
1261 fprintf(stderr, "malloc(%lu) failed\n", signed_rom_hash_strlen);
1262 exit(-1);
1263 }
1264 strcpy(signed_rom_hash, signed_rom);
1265 strcat(signed_rom_hash, HASH_FILE_SUFFIX);
1266 write_psp_firmware_hash(signed_rom_hash, fw_table);
1267 free(signed_rom_hash);
Kangheui Won3c164e12021-12-03 20:25:05 +11001268}
1269
Zheng Bao990d1542021-09-17 13:24:54 +08001270static void integrate_psp_ab(context *ctx, psp_directory_table *pspdir,
Zheng Baofdd47ef2021-09-17 13:30:08 +08001271 psp_directory_table *pspdir2, ish_directory_table *ish,
1272 amd_fw_type ab, enum platform soc_id)
Zheng Bao990d1542021-09-17 13:24:54 +08001273{
1274 uint32_t count;
1275 uint32_t current_table_save;
1276
1277 current_table_save = ctx->current_table;
1278 ctx->current_table = (char *)pspdir - ctx->rom;
1279 count = pspdir->header.num_entries;
1280 assert_fw_entry(count, MAX_PSP_ENTRIES, ctx);
1281 pspdir->entries[count].type = (uint8_t)ab;
1282 pspdir->entries[count].subprog = 0;
1283 pspdir->entries[count].rsvd = 0;
Zheng Baofdd47ef2021-09-17 13:30:08 +08001284 if (ish != NULL) {
Robert Zieba29bc79f2022-03-14 15:59:12 -06001285 ish->pl2_location = BUFF_TO_RUN_MODE(*ctx, pspdir2, AMD_ADDR_REL_BIOS);
Zheng Baofdd47ef2021-09-17 13:30:08 +08001286 ish->boot_priority = ab == AMD_FW_RECOVERYAB_A ? 0xFFFFFFFF : 1;
1287 ish->update_retry_count = 2;
1288 ish->glitch_retry_count = 0;
1289 ish->psp_id = get_psp_id(soc_id);
1290 ish->checksum = fletcher32(&ish->boot_priority,
1291 sizeof(ish_directory_table) - sizeof(uint32_t));
1292 pspdir->entries[count].addr =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001293 BUFF_TO_RUN_MODE(*ctx, ish, AMD_ADDR_REL_BIOS);
Zheng Baofdd47ef2021-09-17 13:30:08 +08001294 pspdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001295 SET_ADDR_MODE(pspdir, AMD_ADDR_REL_BIOS);
Zheng Baofdd47ef2021-09-17 13:30:08 +08001296 pspdir->entries[count].size = TABLE_ALIGNMENT;
1297 } else {
1298 pspdir->entries[count].addr =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001299 BUFF_TO_RUN_MODE(*ctx, pspdir2, AMD_ADDR_REL_BIOS);
Zheng Baofdd47ef2021-09-17 13:30:08 +08001300 pspdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001301 SET_ADDR_MODE(pspdir, AMD_ADDR_REL_BIOS);
Zheng Baofdd47ef2021-09-17 13:30:08 +08001302 pspdir->entries[count].size = pspdir2->header.num_entries *
Zheng Bao990d1542021-09-17 13:24:54 +08001303 sizeof(psp_directory_entry) +
1304 sizeof(psp_directory_header);
Zheng Baofdd47ef2021-09-17 13:30:08 +08001305 }
Zheng Bao990d1542021-09-17 13:24:54 +08001306
1307 count++;
1308 pspdir->header.num_entries = count;
1309 ctx->current_table = current_table_save;
1310}
1311
Marshall Dawson2794a862019-03-04 16:53:15 -07001312static void integrate_psp_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -07001313 psp_directory_table *pspdir,
Marshall Dawson24f73d42019-04-01 10:48:43 -06001314 psp_directory_table *pspdir2,
Zheng Bao990d1542021-09-17 13:24:54 +08001315 psp_directory_table *pspdir2_b,
Marshall Dawson24f73d42019-04-01 10:48:43 -06001316 amd_fw_entry *fw_table,
Zheng Bao20795892021-08-20 14:58:22 +08001317 uint32_t cookie,
1318 amd_cb_config *cb_config)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001319{
Richard Spiegel137484d2018-01-17 10:23:19 -07001320 ssize_t bytes;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -07001321 unsigned int i, count;
Marshall Dawson24f73d42019-04-01 10:48:43 -06001322 int level;
Ritul Gurua2cb3402022-08-29 00:51:08 +05301323 uint32_t size;
1324 uint64_t addr;
Zheng Bao6fff2492021-11-15 19:53:21 +08001325 uint32_t current_table_save;
Zheng Bao990d1542021-09-17 13:24:54 +08001326 bool recovery_ab = cb_config->recovery_ab;
Zheng Baofdd47ef2021-09-17 13:30:08 +08001327 ish_directory_table *ish_a_dir = NULL, *ish_b_dir = NULL;
Marshall Dawson24f73d42019-04-01 10:48:43 -06001328
1329 /* This function can create a primary table, a secondary table, or a
1330 * flattened table which contains all applicable types. These if-else
1331 * statements infer what the caller intended. If a 2nd-level cookie
1332 * is passed, clearly a 2nd-level table is intended. However, a
1333 * 1st-level cookie may indicate level 1 or flattened. If the caller
1334 * passes a pointer to a 2nd-level table, then assume not flat.
1335 */
Zheng Baoba3af5e2021-11-04 18:56:47 +08001336 if (!cb_config->multi_level)
Zheng Bao20795892021-08-20 14:58:22 +08001337 level = PSP_BOTH;
1338 else if (cookie == PSPL2_COOKIE)
Marshall Dawson24f73d42019-04-01 10:48:43 -06001339 level = PSP_LVL2;
1340 else if (pspdir2)
1341 level = PSP_LVL1;
1342 else
1343 level = PSP_BOTH;
Marshall Dawson2794a862019-03-04 16:53:15 -07001344
Zheng Bao990d1542021-09-17 13:24:54 +08001345 if (recovery_ab) {
1346 if (cookie == PSPL2_COOKIE)
1347 level = PSP_LVL2_AB;
1348 else if (pspdir2)
1349 level = PSP_LVL1_AB;
1350 else
1351 level = PSP_BOTH_AB;
1352 }
Zheng Bao6fff2492021-11-15 19:53:21 +08001353 current_table_save = ctx->current_table;
1354 ctx->current_table = (char *)pspdir - ctx->rom;
Zheng Baoc26108f2023-02-17 11:01:07 +08001355 adjust_current_pointer(ctx, 0, TABLE_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001356
Marshall Dawsonc38c0c92019-02-23 16:41:35 -07001357 for (i = 0, count = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
Marshall Dawson24f73d42019-04-01 10:48:43 -06001358 if (!(fw_table[i].level & level))
1359 continue;
1360
Zheng Bao5164e4b2021-10-30 12:09:07 +08001361 assert_fw_entry(count, MAX_PSP_ENTRIES, ctx);
1362
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001363 if (fw_table[i].type == AMD_TOKEN_UNLOCK) {
1364 if (!fw_table[i].other)
1365 continue;
Zheng Baoc26108f2023-02-17 11:01:07 +08001366 adjust_current_pointer(ctx, 0, ERASE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001367 pspdir->entries[count].type = fw_table[i].type;
1368 pspdir->entries[count].size = 4096; /* TODO: doc? */
1369 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
Zheng Bao6fff2492021-11-15 19:53:21 +08001370 pspdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(pspdir);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001371 pspdir->entries[count].subprog = fw_table[i].subprog;
1372 pspdir->entries[count].rsvd = 0;
Zheng Baoc26108f2023-02-17 11:01:07 +08001373 adjust_current_pointer(ctx, 4096, 0x100U);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001374 count++;
1375 } else if (fw_table[i].type == AMD_PSP_FUSE_CHAIN) {
Marshall Dawson239286c2019-02-23 16:42:46 -07001376 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -07001377 pspdir->entries[count].subprog = fw_table[i].subprog;
1378 pspdir->entries[count].rsvd = 0;
Marshall Dawson239286c2019-02-23 16:42:46 -07001379 pspdir->entries[count].size = 0xFFFFFFFF;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001380 pspdir->entries[count].addr = fw_table[i].other;
Zheng Bao6fff2492021-11-15 19:53:21 +08001381 pspdir->entries[count].address_mode = 0;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -07001382 count++;
Marshall Dawson7c1e1422019-04-11 09:44:43 -06001383 } else if (fw_table[i].type == AMD_FW_PSP_NVRAM) {
Ritul Gurua2cb3402022-08-29 00:51:08 +05301384 if (fw_table[i].filename == NULL) {
1385 if (fw_table[i].size == 0)
1386 continue;
1387 size = fw_table[i].size;
1388 addr = fw_table[i].dest;
Elyes Haouas7d67a192022-10-14 09:58:29 +02001389 if (addr != ALIGN_UP(addr, ERASE_ALIGNMENT)) {
Ritul Gurua2cb3402022-08-29 00:51:08 +05301390 fprintf(stderr,
1391 "Error: PSP NVRAM section not aligned with erase block size.\n\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +08001392 amdfwtool_cleanup(ctx);
Ritul Gurua2cb3402022-08-29 00:51:08 +05301393 exit(1);
1394 }
1395 } else {
Zheng Baoc26108f2023-02-17 11:01:07 +08001396 adjust_current_pointer(ctx, 0, ERASE_ALIGNMENT);
Ritul Gurua2cb3402022-08-29 00:51:08 +05301397 bytes = copy_blob(BUFF_CURRENT(*ctx),
1398 fw_table[i].filename, BUFF_ROOM(*ctx));
1399 if (bytes <= 0) {
Zheng Bao7c5ad882023-02-19 13:02:52 +08001400 amdfwtool_cleanup(ctx);
Ritul Gurua2cb3402022-08-29 00:51:08 +05301401 exit(1);
1402 }
1403
Elyes Haouas7d67a192022-10-14 09:58:29 +02001404 size = ALIGN_UP(bytes, ERASE_ALIGNMENT);
Ritul Gurua2cb3402022-08-29 00:51:08 +05301405 addr = RUN_CURRENT(*ctx);
Zheng Baoc26108f2023-02-17 11:01:07 +08001406 adjust_current_pointer(ctx, bytes, BLOB_ERASE_ALIGNMENT);
Marshall Dawson7c1e1422019-04-11 09:44:43 -06001407 }
1408
1409 pspdir->entries[count].type = fw_table[i].type;
1410 pspdir->entries[count].subprog = fw_table[i].subprog;
1411 pspdir->entries[count].rsvd = 0;
Ritul Gurua2cb3402022-08-29 00:51:08 +05301412 pspdir->entries[count].size = size;
1413 pspdir->entries[count].addr = addr;
1414
Zheng Bao6fff2492021-11-15 19:53:21 +08001415 pspdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001416 SET_ADDR_MODE(pspdir, AMD_ADDR_REL_BIOS);
Marshall Dawson7c1e1422019-04-11 09:44:43 -06001417
Marshall Dawson7c1e1422019-04-11 09:44:43 -06001418 count++;
zbaoc3a08a92016-03-02 14:47:27 +08001419 } else if (fw_table[i].filename != NULL) {
Kangheui Won3c164e12021-12-03 20:25:05 +11001420 if (fw_table[i].addr_signed) {
1421 pspdir->entries[count].addr =
1422 RUN_OFFSET(*ctx, fw_table[i].addr_signed);
1423 pspdir->entries[count].address_mode =
1424 SET_ADDR_MODE_BY_TABLE(pspdir);
1425 bytes = fw_table[i].file_size;
1426 } else {
1427 bytes = copy_blob(BUFF_CURRENT(*ctx),
1428 fw_table[i].filename, BUFF_ROOM(*ctx));
1429 if (bytes < 0) {
Zheng Bao7c5ad882023-02-19 13:02:52 +08001430 amdfwtool_cleanup(ctx);
Kangheui Won3c164e12021-12-03 20:25:05 +11001431 exit(1);
1432 }
1433 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
1434 pspdir->entries[count].address_mode =
1435 SET_ADDR_MODE_BY_TABLE(pspdir);
Zheng Baoc26108f2023-02-17 11:01:07 +08001436 adjust_current_pointer(ctx, bytes, BLOB_ALIGNMENT);
Marshall Dawson8e0dca02019-02-27 18:40:49 -07001437 }
1438
Marshall Dawson239286c2019-02-23 16:42:46 -07001439 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -07001440 pspdir->entries[count].subprog = fw_table[i].subprog;
1441 pspdir->entries[count].rsvd = 0;
Fred Reitberger75191be2023-03-07 11:00:49 -05001442 pspdir->entries[count].inst = fw_table[i].inst;
Marshall Dawson8e0dca02019-02-27 18:40:49 -07001443 pspdir->entries[count].size = (uint32_t)bytes;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001444
Marshall Dawsonc38c0c92019-02-23 16:41:35 -07001445 count++;
zbaoc3a08a92016-03-02 14:47:27 +08001446 } else {
1447 /* This APU doesn't have this firmware. */
1448 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001449 }
Marshall Dawson2794a862019-03-04 16:53:15 -07001450
Zheng Bao990d1542021-09-17 13:24:54 +08001451 if (recovery_ab && (pspdir2 != NULL)) {
Zheng Baofdd47ef2021-09-17 13:30:08 +08001452 if (cb_config->need_ish) { /* Need ISH */
1453 ish_a_dir = new_ish_dir(ctx);
1454 if (pspdir2_b != NULL)
1455 ish_b_dir = new_ish_dir(ctx);
1456 }
Zheng Bao990d1542021-09-17 13:24:54 +08001457 pspdir->header.num_entries = count;
Zheng Baofdd47ef2021-09-17 13:30:08 +08001458 integrate_psp_ab(ctx, pspdir, pspdir2, ish_a_dir,
Zheng Bao4bf6f492023-01-25 22:37:29 +08001459 AMD_FW_RECOVERYAB_A, cb_config->soc_id);
Zheng Bao990d1542021-09-17 13:24:54 +08001460 if (pspdir2_b != NULL)
Zheng Baofdd47ef2021-09-17 13:30:08 +08001461 integrate_psp_ab(ctx, pspdir, pspdir2_b, ish_b_dir,
Zheng Bao4bf6f492023-01-25 22:37:29 +08001462 AMD_FW_RECOVERYAB_B, cb_config->soc_id);
Karthikeyan Ramasubramanianad06bae2022-04-08 14:19:55 -06001463 else
Karthikeyan Ramasubramaniane5af14a2022-08-02 11:34:48 -06001464 integrate_psp_ab(ctx, pspdir, pspdir2, ish_a_dir,
Zheng Bao4bf6f492023-01-25 22:37:29 +08001465 AMD_FW_RECOVERYAB_B, cb_config->soc_id);
Karthikeyan Ramasubramanianad06bae2022-04-08 14:19:55 -06001466
Zheng Bao990d1542021-09-17 13:24:54 +08001467 count = pspdir->header.num_entries;
1468 } else if (pspdir2 != NULL) {
Zheng Bao5164e4b2021-10-30 12:09:07 +08001469 assert_fw_entry(count, MAX_PSP_ENTRIES, ctx);
Marshall Dawson24f73d42019-04-01 10:48:43 -06001470 pspdir->entries[count].type = AMD_FW_L2_PTR;
1471 pspdir->entries[count].subprog = 0;
1472 pspdir->entries[count].rsvd = 0;
1473 pspdir->entries[count].size = sizeof(pspdir2->header)
1474 + pspdir2->header.num_entries
1475 * sizeof(psp_directory_entry);
1476
Zheng Bao6fff2492021-11-15 19:53:21 +08001477 pspdir->entries[count].addr =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001478 BUFF_TO_RUN_MODE(*ctx, pspdir2, AMD_ADDR_REL_BIOS);
Zheng Bao6fff2492021-11-15 19:53:21 +08001479 pspdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001480 SET_ADDR_MODE(pspdir, AMD_ADDR_REL_BIOS);
Marshall Dawson24f73d42019-04-01 10:48:43 -06001481 count++;
1482 }
1483
Zheng Baobf29a0d2020-12-03 23:00:48 +08001484 fill_dir_header(pspdir, count, cookie, ctx);
Zheng Bao6fff2492021-11-15 19:53:21 +08001485 ctx->current_table = current_table_save;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001486}
1487
Zheng Bao990d1542021-09-17 13:24:54 +08001488static void add_psp_firmware_entry(context *ctx,
1489 psp_directory_table *pspdir,
1490 void *table, amd_fw_type type, uint32_t size)
1491{
1492 uint32_t count = pspdir->header.num_entries;
1493 uint32_t index;
1494 uint32_t current_table_save;
1495
1496 current_table_save = ctx->current_table;
1497 ctx->current_table = (char *)pspdir - ctx->rom;
1498
1499 /* If there is an entry of "type", replace it. */
1500 for (index = 0; index < count; index++) {
1501 if (pspdir->entries[index].type == (uint8_t)type)
1502 break;
1503 }
1504
1505 assert_fw_entry(count, MAX_PSP_ENTRIES, ctx);
1506 pspdir->entries[index].type = (uint8_t)type;
1507 pspdir->entries[index].subprog = 0;
1508 pspdir->entries[index].rsvd = 0;
1509 pspdir->entries[index].addr = BUFF_TO_RUN(*ctx, table);
1510 pspdir->entries[index].address_mode = SET_ADDR_MODE_BY_TABLE(pspdir);
1511 pspdir->entries[index].size = size;
1512 if (index == count)
1513 count++;
1514
1515 pspdir->header.num_entries = count;
1516 pspdir->header.checksum = fletcher32(&pspdir->header.num_entries,
1517 count * sizeof(psp_directory_entry)
1518 + sizeof(pspdir->header.num_entries)
1519 + sizeof(pspdir->header.additional_info));
1520
1521 ctx->current_table = current_table_save;
1522}
1523
Zheng Baoba3af5e2021-11-04 18:56:47 +08001524static void *new_bios_dir(context *ctx, bool multi)
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001525{
1526 void *ptr;
1527
1528 /*
1529 * Force both onto boundary when multi. Primary table is after
1530 * updatable table, so alignment ensures primary can stay intact
1531 * if secondary is reprogrammed.
1532 */
1533 if (multi)
Zheng Baoc26108f2023-02-17 11:01:07 +08001534 adjust_current_pointer(ctx, 0, TABLE_ERASE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001535 else
Zheng Baoc26108f2023-02-17 11:01:07 +08001536 adjust_current_pointer(ctx, 0, TABLE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001537 ptr = BUFF_CURRENT(*ctx);
Zheng Bao6fff2492021-11-15 19:53:21 +08001538 ((bios_directory_hdr *) ptr)->additional_info = 0;
1539 ((bios_directory_hdr *) ptr)->additional_info_fields.address_mode = ctx->address_mode;
1540 ctx->current_table = ctx->current;
Zheng Baoc26108f2023-02-17 11:01:07 +08001541 adjust_current_pointer(ctx,
1542 sizeof(bios_directory_hdr) + MAX_BIOS_ENTRIES * sizeof(bios_directory_entry),
1543 1);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001544 return ptr;
1545}
1546
1547static int locate_bdt2_bios(bios_directory_table *level2,
1548 uint64_t *source, uint32_t *size)
1549{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001550 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001551
1552 *source = 0;
1553 *size = 0;
1554 if (!level2)
1555 return 0;
1556
1557 for (i = 0 ; i < level2->header.num_entries ; i++) {
1558 if (level2->entries[i].type == AMD_BIOS_BIN) {
1559 *source = level2->entries[i].source;
1560 *size = level2->entries[i].size;
1561 return 1;
1562 }
1563 }
1564 return 0;
1565}
1566
1567static int have_bios_tables(amd_bios_entry *table)
1568{
1569 int i;
1570
1571 for (i = 0 ; table[i].type != AMD_BIOS_INVALID; i++) {
1572 if (table[i].level & BDT_LVL1 && table[i].filename)
1573 return 1;
1574 }
1575 return 0;
1576}
1577
Marshall Dawsonc4a8c482020-01-21 17:17:59 -07001578static int find_bios_entry(amd_bios_type type)
1579{
1580 int i;
1581
1582 for (i = 0; amd_bios_table[i].type != AMD_BIOS_INVALID; i++) {
1583 if (amd_bios_table[i].type == type)
1584 return i;
1585 }
1586 return -1;
1587}
1588
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001589static void integrate_bios_firmwares(context *ctx,
1590 bios_directory_table *biosdir,
1591 bios_directory_table *biosdir2,
1592 amd_bios_entry *fw_table,
Zheng Bao20795892021-08-20 14:58:22 +08001593 uint32_t cookie,
1594 amd_cb_config *cb_config)
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001595{
1596 ssize_t bytes;
Martin Rothec933132019-07-13 20:03:34 -06001597 unsigned int i, count;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001598 int level;
Marshall Dawsonc4a8c482020-01-21 17:17:59 -07001599 int apob_idx;
Martin Rotheca423b2020-09-01 10:54:11 -06001600 uint32_t size;
1601 uint64_t source;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001602
1603 /* This function can create a primary table, a secondary table, or a
1604 * flattened table which contains all applicable types. These if-else
1605 * statements infer what the caller intended. If a 2nd-level cookie
1606 * is passed, clearly a 2nd-level table is intended. However, a
1607 * 1st-level cookie may indicate level 1 or flattened. If the caller
1608 * passes a pointer to a 2nd-level table, then assume not flat.
1609 */
Zheng Baoba3af5e2021-11-04 18:56:47 +08001610 if (!cb_config->multi_level)
Zheng Bao20795892021-08-20 14:58:22 +08001611 level = BDT_BOTH;
Zheng Bao96a33712021-06-11 15:54:40 +08001612 else if (cookie == BHDL2_COOKIE)
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001613 level = BDT_LVL2;
1614 else if (biosdir2)
1615 level = BDT_LVL1;
1616 else
1617 level = BDT_BOTH;
1618
Zheng Baoc26108f2023-02-17 11:01:07 +08001619 adjust_current_pointer(ctx, 0, TABLE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001620
1621 for (i = 0, count = 0; fw_table[i].type != AMD_BIOS_INVALID; i++) {
1622 if (!(fw_table[i].level & level))
1623 continue;
1624 if (fw_table[i].filename == NULL && (
Ritul Guru9a321f32022-07-29 11:06:40 +05301625 fw_table[i].type != AMD_BIOS_SIG &&
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001626 fw_table[i].type != AMD_BIOS_APOB &&
1627 fw_table[i].type != AMD_BIOS_APOB_NV &&
1628 fw_table[i].type != AMD_BIOS_L2_PTR &&
Martin Roth94554742020-04-14 14:59:36 -06001629 fw_table[i].type != AMD_BIOS_BIN &&
1630 fw_table[i].type != AMD_BIOS_PSP_SHARED_MEM))
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001631 continue;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001632
1633 /* BIOS Directory items may have additional requirements */
1634
Ritul Guru9a321f32022-07-29 11:06:40 +05301635 /* SIG needs a size, else no choice but to skip */
1636 if (fw_table[i].type == AMD_BIOS_SIG && !fw_table[i].size)
1637 continue;
1638
Martin Roth48dd9fe2020-07-29 16:32:25 -06001639 /* Check APOB_NV requirements */
1640 if (fw_table[i].type == AMD_BIOS_APOB_NV) {
1641 if (!fw_table[i].size && !fw_table[i].src)
1642 continue; /* APOB_NV not used */
1643 if (fw_table[i].src && !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001644 fprintf(stderr, "Error: APOB NV address provided, but no size\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +08001645 amdfwtool_cleanup(ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001646 exit(1);
1647 }
Martin Roth48dd9fe2020-07-29 16:32:25 -06001648 /* If the APOB isn't used, APOB_NV isn't used either */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -07001649 apob_idx = find_bios_entry(AMD_BIOS_APOB);
Martin Roth48dd9fe2020-07-29 16:32:25 -06001650 if (apob_idx < 0 || !fw_table[apob_idx].dest)
1651 continue; /* APOV NV not supported */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -07001652 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001653
1654 /* APOB_DATA needs destination */
1655 if (fw_table[i].type == AMD_BIOS_APOB && !fw_table[i].dest) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001656 fprintf(stderr, "Error: APOB destination not provided\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +08001657 amdfwtool_cleanup(ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001658 exit(1);
1659 }
1660
1661 /* BIOS binary must have destination and uncompressed size. If
1662 * no filename given, then user must provide a source address.
1663 */
1664 if (fw_table[i].type == AMD_BIOS_BIN) {
1665 if (!fw_table[i].dest || !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001666 fprintf(stderr, "Error: BIOS binary destination and uncompressed size are required\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +08001667 amdfwtool_cleanup(ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001668 exit(1);
1669 }
1670 if (!fw_table[i].filename && !fw_table[i].src) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001671 fprintf(stderr, "Error: BIOS binary assumed outside amdfw.rom but no source address given\n");
Zheng Bao7c5ad882023-02-19 13:02:52 +08001672 amdfwtool_cleanup(ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001673 exit(1);
1674 }
1675 }
1676
Martin Roth94554742020-04-14 14:59:36 -06001677 /* PSP_SHARED_MEM needs a destination and size */
1678 if (fw_table[i].type == AMD_BIOS_PSP_SHARED_MEM &&
1679 (!fw_table[i].dest || !fw_table[i].size))
1680 continue;
Zheng Bao5164e4b2021-10-30 12:09:07 +08001681 assert_fw_entry(count, MAX_BIOS_ENTRIES, ctx);
Martin Roth94554742020-04-14 14:59:36 -06001682
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001683 biosdir->entries[count].type = fw_table[i].type;
1684 biosdir->entries[count].region_type = fw_table[i].region_type;
1685 biosdir->entries[count].dest = fw_table[i].dest ?
1686 fw_table[i].dest : (uint64_t)-1;
1687 biosdir->entries[count].reset = fw_table[i].reset;
1688 biosdir->entries[count].copy = fw_table[i].copy;
1689 biosdir->entries[count].ro = fw_table[i].ro;
1690 biosdir->entries[count].compressed = fw_table[i].zlib;
1691 biosdir->entries[count].inst = fw_table[i].inst;
1692 biosdir->entries[count].subprog = fw_table[i].subpr;
1693
1694 switch (fw_table[i].type) {
Ritul Guru9a321f32022-07-29 11:06:40 +05301695 case AMD_BIOS_SIG:
1696 /* Reserve size bytes within amdfw.rom */
1697 biosdir->entries[count].size = fw_table[i].size;
1698 biosdir->entries[count].source = RUN_CURRENT(*ctx);
1699 biosdir->entries[count].address_mode =
1700 SET_ADDR_MODE_BY_TABLE(biosdir);
1701 memset(BUFF_CURRENT(*ctx), 0xff,
1702 biosdir->entries[count].size);
Zheng Baoc26108f2023-02-17 11:01:07 +08001703 adjust_current_pointer(ctx, biosdir->entries[count].size, 0x100U);
Ritul Guru9a321f32022-07-29 11:06:40 +05301704 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001705 case AMD_BIOS_APOB:
1706 biosdir->entries[count].size = fw_table[i].size;
1707 biosdir->entries[count].source = fw_table[i].src;
Zheng Bao6fff2492021-11-15 19:53:21 +08001708 biosdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(biosdir);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001709 break;
1710 case AMD_BIOS_APOB_NV:
1711 if (fw_table[i].src) {
1712 /* If source is given, use that and its size */
1713 biosdir->entries[count].source = fw_table[i].src;
Zheng Bao6fff2492021-11-15 19:53:21 +08001714 biosdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001715 SET_ADDR_MODE(biosdir, AMD_ADDR_REL_BIOS);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001716 biosdir->entries[count].size = fw_table[i].size;
1717 } else {
1718 /* Else reserve size bytes within amdfw.rom */
Zheng Baoc26108f2023-02-17 11:01:07 +08001719 adjust_current_pointer(ctx, 0, ERASE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001720 biosdir->entries[count].source = RUN_CURRENT(*ctx);
Zheng Bao6fff2492021-11-15 19:53:21 +08001721 biosdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001722 SET_ADDR_MODE(biosdir, AMD_ADDR_REL_BIOS);
Elyes Haouas7d67a192022-10-14 09:58:29 +02001723 biosdir->entries[count].size = ALIGN_UP(
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001724 fw_table[i].size, ERASE_ALIGNMENT);
1725 memset(BUFF_CURRENT(*ctx), 0xff,
1726 biosdir->entries[count].size);
Zheng Baoc26108f2023-02-17 11:01:07 +08001727 adjust_current_pointer(ctx, biosdir->entries[count].size, 1);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001728 }
1729 break;
1730 case AMD_BIOS_BIN:
1731 /* Don't make a 2nd copy, point to the same one */
Martin Rotheca423b2020-09-01 10:54:11 -06001732 if (level == BDT_LVL1 && locate_bdt2_bios(biosdir2, &source, &size)) {
1733 biosdir->entries[count].source = source;
Zheng Bao6fff2492021-11-15 19:53:21 +08001734 biosdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001735 SET_ADDR_MODE(biosdir, AMD_ADDR_REL_BIOS);
Martin Rotheca423b2020-09-01 10:54:11 -06001736 biosdir->entries[count].size = size;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001737 break;
Martin Rotheca423b2020-09-01 10:54:11 -06001738 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001739
1740 /* level 2, or level 1 and no copy found in level 2 */
1741 biosdir->entries[count].source = fw_table[i].src;
Zheng Bao6fff2492021-11-15 19:53:21 +08001742 biosdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001743 SET_ADDR_MODE(biosdir, AMD_ADDR_REL_BIOS);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001744 biosdir->entries[count].dest = fw_table[i].dest;
1745 biosdir->entries[count].size = fw_table[i].size;
1746
1747 if (!fw_table[i].filename)
1748 break;
1749
1750 bytes = copy_blob(BUFF_CURRENT(*ctx),
1751 fw_table[i].filename, BUFF_ROOM(*ctx));
1752 if (bytes <= 0) {
Zheng Bao7c5ad882023-02-19 13:02:52 +08001753 amdfwtool_cleanup(ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001754 exit(1);
1755 }
1756
Zheng Bao6fff2492021-11-15 19:53:21 +08001757 biosdir->entries[count].source =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001758 RUN_CURRENT_MODE(*ctx, AMD_ADDR_REL_BIOS);
Zheng Bao6fff2492021-11-15 19:53:21 +08001759 biosdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001760 SET_ADDR_MODE(biosdir, AMD_ADDR_REL_BIOS);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001761
Zheng Baoc26108f2023-02-17 11:01:07 +08001762 adjust_current_pointer(ctx, bytes, 0x100U);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001763 break;
Martin Roth94554742020-04-14 14:59:36 -06001764 case AMD_BIOS_PSP_SHARED_MEM:
1765 biosdir->entries[count].dest = fw_table[i].dest;
1766 biosdir->entries[count].size = fw_table[i].size;
1767 break;
1768
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001769 default: /* everything else is copied from input */
1770 if (fw_table[i].type == AMD_BIOS_APCB ||
1771 fw_table[i].type == AMD_BIOS_APCB_BK)
Zheng Baoc26108f2023-02-17 11:01:07 +08001772 adjust_current_pointer(ctx, 0, ERASE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001773 bytes = copy_blob(BUFF_CURRENT(*ctx),
1774 fw_table[i].filename, BUFF_ROOM(*ctx));
1775 if (bytes <= 0) {
Zheng Bao7c5ad882023-02-19 13:02:52 +08001776 amdfwtool_cleanup(ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001777 exit(1);
1778 }
1779
1780 biosdir->entries[count].size = (uint32_t)bytes;
1781 biosdir->entries[count].source = RUN_CURRENT(*ctx);
Zheng Bao6fff2492021-11-15 19:53:21 +08001782 biosdir->entries[count].address_mode = SET_ADDR_MODE_BY_TABLE(biosdir);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001783
Zheng Baoc26108f2023-02-17 11:01:07 +08001784 adjust_current_pointer(ctx, bytes, 0x100U);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001785 break;
1786 }
1787
1788 count++;
1789 }
1790
1791 if (biosdir2) {
Zheng Bao5164e4b2021-10-30 12:09:07 +08001792 assert_fw_entry(count, MAX_BIOS_ENTRIES, ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001793 biosdir->entries[count].type = AMD_BIOS_L2_PTR;
Zheng Baoe8e60432021-05-24 16:11:12 +08001794 biosdir->entries[count].region_type = 0;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001795 biosdir->entries[count].size =
1796 + MAX_BIOS_ENTRIES
1797 * sizeof(bios_directory_entry);
1798 biosdir->entries[count].source =
1799 BUFF_TO_RUN(*ctx, biosdir2);
Zheng Bao6fff2492021-11-15 19:53:21 +08001800 biosdir->entries[count].address_mode =
Robert Zieba29bc79f2022-03-14 15:59:12 -06001801 SET_ADDR_MODE(biosdir, AMD_ADDR_REL_BIOS);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001802 biosdir->entries[count].subprog = 0;
1803 biosdir->entries[count].inst = 0;
1804 biosdir->entries[count].copy = 0;
1805 biosdir->entries[count].compressed = 0;
1806 biosdir->entries[count].dest = -1;
1807 biosdir->entries[count].reset = 0;
1808 biosdir->entries[count].ro = 0;
1809 count++;
1810 }
1811
Zheng Baobf29a0d2020-12-03 23:00:48 +08001812 fill_dir_header(biosdir, count, cookie, ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001813}
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001814
1815enum {
Zheng Bao806892a2021-04-27 17:21:54 +08001816 AMDFW_OPT_CONFIG = 'c',
1817 AMDFW_OPT_DEBUG = 'd',
1818 AMDFW_OPT_HELP = 'h',
Zheng Bao806892a2021-04-27 17:21:54 +08001819
1820 AMDFW_OPT_XHCI = 128,
1821 AMDFW_OPT_IMC,
1822 AMDFW_OPT_GEC,
Zheng Bao990d1542021-09-17 13:24:54 +08001823 AMDFW_OPT_RECOVERY_AB,
Karthikeyan Ramasubramanianad06bae2022-04-08 14:19:55 -06001824 AMDFW_OPT_RECOVERY_AB_SINGLE_COPY,
Zheng Bao993b43f2021-11-10 12:21:46 +08001825 AMDFW_OPT_USE_COMBO,
Zheng Bao0e3d18b2023-03-07 15:28:57 +08001826 AMDFW_OPT_COMBO1_CONFIG,
Zheng Bao806892a2021-04-27 17:21:54 +08001827 AMDFW_OPT_MULTILEVEL,
1828 AMDFW_OPT_NVRAM,
1829
1830 AMDFW_OPT_FUSE,
1831 AMDFW_OPT_UNLOCK,
1832 AMDFW_OPT_WHITELIST,
1833 AMDFW_OPT_USE_PSPSECUREOS,
1834 AMDFW_OPT_LOAD_MP2FW,
1835 AMDFW_OPT_LOAD_S0I3,
Zheng Bao6c5ec8e2022-02-11 11:51:26 +08001836 AMDFW_OPT_SPL_TABLE,
Zheng Bao806892a2021-04-27 17:21:54 +08001837 AMDFW_OPT_VERSTAGE,
1838 AMDFW_OPT_VERSTAGE_SIG,
1839
1840 AMDFW_OPT_INSTANCE,
1841 AMDFW_OPT_APCB,
1842 AMDFW_OPT_APOBBASE,
1843 AMDFW_OPT_BIOSBIN,
1844 AMDFW_OPT_BIOSBIN_SOURCE,
1845 AMDFW_OPT_BIOSBIN_DEST,
1846 AMDFW_OPT_BIOS_UNCOMP_SIZE,
Karthikeyan Ramasubramanianbd9dd422022-12-22 15:45:56 -07001847 AMDFW_OPT_BIOSBIN_UNCOMP,
Zheng Bao806892a2021-04-27 17:21:54 +08001848 AMDFW_OPT_UCODE,
1849 AMDFW_OPT_APOB_NVBASE,
1850 AMDFW_OPT_APOB_NVSIZE,
1851
1852 AMDFW_OPT_OUTPUT,
1853 AMDFW_OPT_FLASHSIZE,
1854 AMDFW_OPT_LOCATION,
1855 AMDFW_OPT_ANYWHERE,
1856 AMDFW_OPT_SHAREDMEM,
1857 AMDFW_OPT_SHAREDMEM_SIZE,
Kangheui Won3c164e12021-12-03 20:25:05 +11001858 AMDFW_OPT_SIGNED_OUTPUT,
1859 AMDFW_OPT_SIGNED_ADDR,
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06001860 AMDFW_OPT_BODY_LOCATION,
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001861 /* begin after ASCII characters */
1862 LONGOPT_SPI_READ_MODE = 256,
1863 LONGOPT_SPI_SPEED = 257,
1864 LONGOPT_SPI_MICRON_FLAG = 258,
Ritul Guru9a321f32022-07-29 11:06:40 +05301865 LONGOPT_BIOS_SIG = 259,
Ritul Gurua2cb3402022-08-29 00:51:08 +05301866 LONGOPT_NVRAM_BASE = 260,
1867 LONGOPT_NVRAM_SIZE = 261,
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001868};
1869
Zheng Bao806892a2021-04-27 17:21:54 +08001870static char const optstring[] = {AMDFW_OPT_CONFIG, ':',
Zheng Bao994ff522023-03-09 11:43:55 +08001871 AMDFW_OPT_DEBUG, AMDFW_OPT_HELP
Zheng Bao806892a2021-04-27 17:21:54 +08001872};
Marc Jones90099b62016-09-20 21:05:45 -06001873
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001874static struct option long_options[] = {
Zheng Bao806892a2021-04-27 17:21:54 +08001875 {"xhci", required_argument, 0, AMDFW_OPT_XHCI },
1876 {"imc", required_argument, 0, AMDFW_OPT_IMC },
1877 {"gec", required_argument, 0, AMDFW_OPT_GEC },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001878 /* PSP Directory Table items */
Zheng Bao990d1542021-09-17 13:24:54 +08001879 {"recovery-ab", no_argument, 0, AMDFW_OPT_RECOVERY_AB },
Karthikeyan Ramasubramanianad06bae2022-04-08 14:19:55 -06001880 {"recovery-ab-single-copy", no_argument, 0, AMDFW_OPT_RECOVERY_AB_SINGLE_COPY },
Zheng Bao993b43f2021-11-10 12:21:46 +08001881 {"use-combo", no_argument, 0, AMDFW_OPT_USE_COMBO },
Zheng Bao0e3d18b2023-03-07 15:28:57 +08001882 {"combo-config1", required_argument, 0, AMDFW_OPT_COMBO1_CONFIG },
Zheng Bao806892a2021-04-27 17:21:54 +08001883 {"multilevel", no_argument, 0, AMDFW_OPT_MULTILEVEL },
1884 {"nvram", required_argument, 0, AMDFW_OPT_NVRAM },
Ritul Gurua2cb3402022-08-29 00:51:08 +05301885 {"nvram-base", required_argument, 0, LONGOPT_NVRAM_BASE },
1886 {"nvram-size", required_argument, 0, LONGOPT_NVRAM_SIZE },
Zheng Bao806892a2021-04-27 17:21:54 +08001887 {"soft-fuse", required_argument, 0, AMDFW_OPT_FUSE },
1888 {"token-unlock", no_argument, 0, AMDFW_OPT_UNLOCK },
1889 {"whitelist", required_argument, 0, AMDFW_OPT_WHITELIST },
1890 {"use-pspsecureos", no_argument, 0, AMDFW_OPT_USE_PSPSECUREOS },
1891 {"load-mp2-fw", no_argument, 0, AMDFW_OPT_LOAD_MP2FW },
1892 {"load-s0i3", no_argument, 0, AMDFW_OPT_LOAD_S0I3 },
Zheng Bao6c5ec8e2022-02-11 11:51:26 +08001893 {"spl-table", required_argument, 0, AMDFW_OPT_SPL_TABLE },
Zheng Bao806892a2021-04-27 17:21:54 +08001894 {"verstage", required_argument, 0, AMDFW_OPT_VERSTAGE },
1895 {"verstage_sig", required_argument, 0, AMDFW_OPT_VERSTAGE_SIG },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001896 /* BIOS Directory Table items */
Zheng Bao806892a2021-04-27 17:21:54 +08001897 {"instance", required_argument, 0, AMDFW_OPT_INSTANCE },
1898 {"apcb", required_argument, 0, AMDFW_OPT_APCB },
1899 {"apob-base", required_argument, 0, AMDFW_OPT_APOBBASE },
1900 {"bios-bin", required_argument, 0, AMDFW_OPT_BIOSBIN },
1901 {"bios-bin-src", required_argument, 0, AMDFW_OPT_BIOSBIN_SOURCE },
1902 {"bios-bin-dest", required_argument, 0, AMDFW_OPT_BIOSBIN_DEST },
1903 {"bios-uncomp-size", required_argument, 0, AMDFW_OPT_BIOS_UNCOMP_SIZE },
Karthikeyan Ramasubramanianbd9dd422022-12-22 15:45:56 -07001904 {"bios-bin-uncomp", no_argument, 0, AMDFW_OPT_BIOSBIN_UNCOMP },
Ritul Guru9a321f32022-07-29 11:06:40 +05301905 {"bios-sig-size", required_argument, 0, LONGOPT_BIOS_SIG },
Zheng Bao806892a2021-04-27 17:21:54 +08001906 {"ucode", required_argument, 0, AMDFW_OPT_UCODE },
1907 {"apob-nv-base", required_argument, 0, AMDFW_OPT_APOB_NVBASE },
1908 {"apob-nv-size", required_argument, 0, AMDFW_OPT_APOB_NVSIZE },
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001909 /* Embedded Firmware Structure items*/
1910 {"spi-read-mode", required_argument, 0, LONGOPT_SPI_READ_MODE },
1911 {"spi-speed", required_argument, 0, LONGOPT_SPI_SPEED },
1912 {"spi-micron-flag", required_argument, 0, LONGOPT_SPI_MICRON_FLAG },
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06001913 {"body-location", required_argument, 0, AMDFW_OPT_BODY_LOCATION },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001914 /* other */
Zheng Bao806892a2021-04-27 17:21:54 +08001915 {"output", required_argument, 0, AMDFW_OPT_OUTPUT },
1916 {"flashsize", required_argument, 0, AMDFW_OPT_FLASHSIZE },
1917 {"location", required_argument, 0, AMDFW_OPT_LOCATION },
1918 {"anywhere", no_argument, 0, AMDFW_OPT_ANYWHERE },
1919 {"sharedmem", required_argument, 0, AMDFW_OPT_SHAREDMEM },
1920 {"sharedmem-size", required_argument, 0, AMDFW_OPT_SHAREDMEM_SIZE },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001921
Kangheui Won3c164e12021-12-03 20:25:05 +11001922 {"signed-output", required_argument, 0, AMDFW_OPT_SIGNED_OUTPUT },
1923 {"signed-addr", required_argument, 0, AMDFW_OPT_SIGNED_ADDR },
1924
Zheng Bao806892a2021-04-27 17:21:54 +08001925 {"config", required_argument, 0, AMDFW_OPT_CONFIG },
1926 {"debug", no_argument, 0, AMDFW_OPT_DEBUG },
1927 {"help", no_argument, 0, AMDFW_OPT_HELP },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001928 {NULL, 0, 0, 0 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001929};
1930
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001931void register_fw_fuse(char *str)
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001932{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001933 uint32_t i;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001934
1935 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1936 if (amd_psp_fw_table[i].type != AMD_PSP_FUSE_CHAIN)
1937 continue;
1938
1939 amd_psp_fw_table[i].other = strtoull(str, NULL, 16);
1940 return;
1941 }
1942}
1943
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001944static void register_fw_token_unlock(void)
1945{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001946 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001947
1948 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1949 if (amd_psp_fw_table[i].type != AMD_TOKEN_UNLOCK)
1950 continue;
1951
1952 amd_psp_fw_table[i].other = 1;
1953 return;
1954 }
1955}
1956
Marshall Dawsondbae6322019-03-04 10:31:03 -07001957static void register_fw_filename(amd_fw_type type, uint8_t sub, char filename[])
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001958{
Martin Roth8806f7f2016-11-08 10:44:18 -07001959 unsigned int i;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001960
Martin Rothcd15bc82016-11-08 11:34:02 -07001961 for (i = 0; i < sizeof(amd_fw_table) / sizeof(amd_fw_entry); i++) {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001962 if (amd_fw_table[i].type == type) {
1963 amd_fw_table[i].filename = filename;
1964 return;
1965 }
1966 }
1967
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001968 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
Marshall Dawsondbae6322019-03-04 10:31:03 -07001969 if (amd_psp_fw_table[i].type != type)
1970 continue;
1971
1972 if (amd_psp_fw_table[i].subprog == sub) {
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001973 amd_psp_fw_table[i].filename = filename;
1974 return;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001975 }
1976 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001977}
1978
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001979static void register_bdt_data(amd_bios_type type, int sub, int ins, char name[])
1980{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001981 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001982
1983 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
1984 if (amd_bios_table[i].type == type
1985 && amd_bios_table[i].inst == ins
1986 && amd_bios_table[i].subpr == sub) {
1987 amd_bios_table[i].filename = name;
1988 return;
1989 }
1990 }
1991}
1992
Ritul Gurua2cb3402022-08-29 00:51:08 +05301993static void register_amd_psp_fw_addr(amd_fw_type type, int sub,
1994 char *dst_str, char *size_str)
1995{
1996 unsigned int i;
1997
1998 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1999 if (amd_psp_fw_table[i].type != type)
2000 continue;
2001
2002 if (amd_psp_fw_table[i].subprog == sub) {
2003 if (dst_str)
2004 amd_psp_fw_table[i].dest = strtoull(dst_str, NULL, 16);
2005 if (size_str)
2006 amd_psp_fw_table[i].size = strtoul(size_str, NULL, 16);
2007 return;
2008 }
2009 }
2010}
2011
2012static void register_bios_fw_addr(amd_bios_type type, char *src_str,
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002013 char *dst_str, char *size_str)
2014{
Zheng Bao6d402ac2020-10-01 16:16:30 +08002015 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002016 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
2017 if (amd_bios_table[i].type != type)
2018 continue;
2019
2020 if (src_str)
2021 amd_bios_table[i].src = strtoull(src_str, NULL, 16);
2022 if (dst_str)
2023 amd_bios_table[i].dest = strtoull(dst_str, NULL, 16);
2024 if (size_str)
2025 amd_bios_table[i].size = strtoul(size_str, NULL, 16);
2026
2027 return;
2028 }
2029}
2030
Zheng Baoc3007f32022-04-03 12:53:51 +08002031static int set_efs_table(uint8_t soc_id, amd_cb_config *cb_config,
2032 embedded_firmware *amd_romsig, uint8_t efs_spi_readmode,
2033 uint8_t efs_spi_speed, uint8_t efs_spi_micron_flag)
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002034{
2035 if ((efs_spi_readmode == 0xFF) || (efs_spi_speed == 0xFF)) {
Zheng Bao77a2c672020-10-01 17:05:43 +08002036 fprintf(stderr, "Error: EFS read mode and SPI speed must be set\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002037 return 1;
2038 }
Zheng Baoc3007f32022-04-03 12:53:51 +08002039
2040 /* amd_romsig->efs_gen introduced after RAVEN/PICASSO.
2041 * Leave as 0xffffffff for first gen */
2042 if (cb_config->second_gen) {
2043 amd_romsig->efs_gen.gen = EFS_SECOND_GEN;
2044 amd_romsig->efs_gen.reserved = 0;
2045 } else {
Zheng Bao487d0452022-04-03 12:50:07 +08002046 amd_romsig->efs_gen.gen = EFS_BEFORE_SECOND_GEN;
2047 amd_romsig->efs_gen.reserved = ~0;
Zheng Baoc3007f32022-04-03 12:53:51 +08002048 }
2049
2050 switch (soc_id) {
Zheng Bao3d7623f2022-08-17 11:52:30 +08002051 case PLATFORM_CARRIZO:
Zheng Baoc3007f32022-04-03 12:53:51 +08002052 case PLATFORM_STONEYRIDGE:
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002053 amd_romsig->spi_readmode_f15_mod_60_6f = efs_spi_readmode;
2054 amd_romsig->fast_speed_new_f15_mod_60_6f = efs_spi_speed;
2055 break;
2056 case PLATFORM_RAVEN:
2057 case PLATFORM_PICASSO:
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002058 amd_romsig->spi_readmode_f17_mod_00_2f = efs_spi_readmode;
2059 amd_romsig->spi_fastspeed_f17_mod_00_2f = efs_spi_speed;
2060 switch (efs_spi_micron_flag) {
2061 case 0:
2062 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xff;
2063 break;
2064 case 1:
2065 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xa;
2066 break;
2067 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08002068 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002069 return 1;
2070 }
2071 break;
2072 case PLATFORM_RENOIR:
2073 case PLATFORM_LUCIENNE:
Zheng Baobf29a0d2020-12-03 23:00:48 +08002074 case PLATFORM_CEZANNE:
Zheng Bao535ec532021-08-12 16:30:19 +08002075 case PLATFORM_MENDOCINO:
Zheng Baode6f1982022-10-16 20:32:43 +08002076 case PLATFORM_PHOENIX:
2077 case PLATFORM_GLINDA:
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002078 amd_romsig->spi_readmode_f17_mod_30_3f = efs_spi_readmode;
2079 amd_romsig->spi_fastspeed_f17_mod_30_3f = efs_spi_speed;
2080 switch (efs_spi_micron_flag) {
2081 case 0:
2082 amd_romsig->micron_detect_f17_mod_30_3f = 0xff;
2083 break;
2084 case 1:
2085 amd_romsig->micron_detect_f17_mod_30_3f = 0xaa;
2086 break;
2087 case 2:
2088 amd_romsig->micron_detect_f17_mod_30_3f = 0x55;
2089 break;
2090 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08002091 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002092 return 1;
2093 }
2094 break;
2095 case PLATFORM_UNKNOWN:
2096 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08002097 fprintf(stderr, "Error: Invalid SOC name.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002098 return 1;
2099 }
2100 return 0;
2101}
2102
Zheng Bao69ea83c2023-01-22 21:08:18 +08002103static ssize_t write_body(char *output, void *body_offset, ssize_t body_size, context *ctx)
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002104{
Zheng Bao69ea83c2023-01-22 21:08:18 +08002105 char body_name[PATH_MAX], body_tmp_name[PATH_MAX];
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002106 int ret;
2107 int fd;
2108 ssize_t bytes = -1;
2109
2110 /* Create a tmp file and rename it at the end so that make does not get confused
2111 if amdfwtool is killed for some unexpected reasons. */
Zheng Bao69ea83c2023-01-22 21:08:18 +08002112 ret = snprintf(body_tmp_name, sizeof(body_tmp_name), "%s%s%s",
2113 output, BODY_FILE_SUFFIX, TMP_FILE_SUFFIX);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002114 if (ret < 0) {
Zheng Bao69ea83c2023-01-22 21:08:18 +08002115 fprintf(stderr, "Error %s forming BODY tmp file name: %d\n",
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002116 strerror(errno), ret);
Zheng Bao7c5ad882023-02-19 13:02:52 +08002117 amdfwtool_cleanup(ctx);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002118 exit(1);
Zheng Bao69ea83c2023-01-22 21:08:18 +08002119 } else if ((unsigned int)ret >= sizeof(body_tmp_name)) {
2120 fprintf(stderr, "BODY File name %d > %zu\n", ret, sizeof(body_tmp_name));
Zheng Bao7c5ad882023-02-19 13:02:52 +08002121 amdfwtool_cleanup(ctx);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002122 exit(1);
2123 }
2124
Zheng Bao69ea83c2023-01-22 21:08:18 +08002125 fd = open(body_tmp_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002126 if (fd < 0) {
Zheng Bao69ea83c2023-01-22 21:08:18 +08002127 fprintf(stderr, "Error: Opening %s file: %s\n", body_tmp_name, strerror(errno));
Zheng Bao7c5ad882023-02-19 13:02:52 +08002128 amdfwtool_cleanup(ctx);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002129 exit(1);
2130 }
2131
Zheng Bao69ea83c2023-01-22 21:08:18 +08002132 bytes = write_from_buf_to_file(fd, body_offset, body_size);
2133 if (bytes != body_size) {
2134 fprintf(stderr, "Error: Writing to file %s failed\n", body_tmp_name);
Zheng Bao7c5ad882023-02-19 13:02:52 +08002135 amdfwtool_cleanup(ctx);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002136 exit(1);
2137 }
2138 close(fd);
2139
2140 /* Rename the tmp file */
Zheng Bao69ea83c2023-01-22 21:08:18 +08002141 ret = snprintf(body_name, sizeof(body_name), "%s%s", output, BODY_FILE_SUFFIX);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002142 if (ret < 0) {
Zheng Bao69ea83c2023-01-22 21:08:18 +08002143 fprintf(stderr, "Error %s forming BODY file name: %d\n", strerror(errno), ret);
Zheng Bao7c5ad882023-02-19 13:02:52 +08002144 amdfwtool_cleanup(ctx);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002145 exit(1);
2146 }
2147
Zheng Bao69ea83c2023-01-22 21:08:18 +08002148 if (rename(body_tmp_name, body_name)) {
2149 fprintf(stderr, "Error: renaming file %s to %s\n", body_tmp_name, body_name);
Zheng Bao7c5ad882023-02-19 13:02:52 +08002150 amdfwtool_cleanup(ctx);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002151 exit(1);
2152 }
2153
2154 return bytes;
2155}
2156
Zheng Bao994ff522023-03-09 11:43:55 +08002157void open_process_config(char *config, amd_cb_config *cb_config, int debug)
Zheng Bao39cae562023-03-07 18:37:43 +08002158{
2159 FILE *config_handle;
2160
2161 if (config) {
2162 config_handle = fopen(config, "r");
2163 if (config_handle == NULL) {
2164 fprintf(stderr, "Can not open file %s for reading: %s\n",
2165 config, strerror(errno));
2166 exit(1);
2167 }
Zheng Bao994ff522023-03-09 11:43:55 +08002168 if (process_config(config_handle, cb_config) == 0) {
Zheng Bao39cae562023-03-07 18:37:43 +08002169 fprintf(stderr, "Configuration file %s parsing error\n",
2170 config);
2171 fclose(config_handle);
2172 exit(1);
2173 }
2174 fclose(config_handle);
2175 }
2176
2177 /* For debug. */
2178 if (debug) {
2179 dump_psp_firmwares(amd_psp_fw_table);
2180 dump_bdt_firmwares(amd_bios_table);
2181 }
2182}
2183
Karthikeyan Ramasubramanian225b4b32023-03-08 10:24:50 -07002184static bool is_initial_alignment_required(enum platform soc_id)
2185{
2186 switch (soc_id) {
2187 case PLATFORM_MENDOCINO:
2188 case PLATFORM_PHOENIX:
2189 case PLATFORM_GLINDA:
2190 return false;
2191 default:
2192 return true;
2193 }
2194}
2195
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002196int main(int argc, char **argv)
2197{
Marshall Dawson0e02ce82019-03-04 16:50:37 -07002198 int c;
Martin Roth31d95a22016-11-08 11:22:12 -07002199 int retval = 0;
Martin Roth60f15512016-11-08 09:55:01 -07002200 char *tmp;
Marshall Dawson239286c2019-02-23 16:42:46 -07002201 embedded_firmware *amd_romsig;
Zheng Bao990d1542021-09-17 13:24:54 +08002202 psp_directory_table *pspdir = NULL;
2203 psp_directory_table *pspdir2 = NULL;
2204 psp_directory_table *pspdir2_b = NULL;
Zheng Bao84fb9ea2022-08-18 15:54:47 +08002205 psp_combo_directory *psp_combo_dir = NULL, *bhd_combo_dir = NULL;
Zheng Bao0e3d18b2023-03-07 15:28:57 +08002206 char *combo_config[MAX_COMBO_ENTRIES] = { 0 };
2207 int combo_index = 0;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06002208 int fuse_defined = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002209 int targetfd;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08002210 char *output = NULL, *config = NULL;
Zheng Bao9c8ce3e2020-09-28 10:36:29 +08002211 context ctx = { 0 };
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002212 /* Values cleared after each firmware or parameter, regardless if N/A */
2213 uint8_t sub = 0, instance = 0;
Zheng Bao99945dc2023-01-02 10:55:56 +08002214 uint32_t body_location = 0;
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002215 uint32_t efs_location = 0;
Martin Roth37305e72020-04-07 14:16:39 -06002216 bool any_location = 0;
Martin Roth0d3b1182017-10-03 14:16:04 -06002217 uint32_t romsig_offset;
Martin Roth60f15512016-11-08 09:55:01 -07002218 uint32_t rom_base_address;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002219 uint8_t efs_spi_readmode = 0xff;
2220 uint8_t efs_spi_speed = 0xff;
2221 uint8_t efs_spi_micron_flag = 0xff;
Kangheui Won3c164e12021-12-03 20:25:05 +11002222 const char *signed_output_file = NULL;
2223 uint64_t signed_start_addr = 0x0;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002224
Fred Reitbergerf36b0132022-06-29 13:54:57 -04002225 amd_cb_config cb_config = { 0 };
Zheng Bao9e908072020-10-28 11:39:13 +08002226 int debug = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08002227
Zheng Baoc26108f2023-02-17 11:01:07 +08002228 ctx.current_pointer_saved = 0xFFFFFFFF;
2229
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002230 while (1) {
2231 int optindex = 0;
Karthikeyan Ramasubramanianbd9dd422022-12-22 15:45:56 -07002232 int bios_tbl_index = -1;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002233
2234 c = getopt_long(argc, argv, optstring, long_options, &optindex);
2235
2236 if (c == -1)
2237 break;
2238
2239 switch (c) {
Zheng Bao806892a2021-04-27 17:21:54 +08002240 case AMDFW_OPT_XHCI:
Marshall Dawsondbae6322019-03-04 10:31:03 -07002241 register_fw_filename(AMD_FW_XHCI, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002242 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002243 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002244 case AMDFW_OPT_IMC:
Marshall Dawsondbae6322019-03-04 10:31:03 -07002245 register_fw_filename(AMD_FW_IMC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002246 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002247 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002248 case AMDFW_OPT_GEC:
Marshall Dawsondbae6322019-03-04 10:31:03 -07002249 register_fw_filename(AMD_FW_GEC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002250 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002251 break;
Zheng Bao990d1542021-09-17 13:24:54 +08002252 case AMDFW_OPT_RECOVERY_AB:
2253 cb_config.recovery_ab = true;
2254 break;
Karthikeyan Ramasubramanianad06bae2022-04-08 14:19:55 -06002255 case AMDFW_OPT_RECOVERY_AB_SINGLE_COPY:
2256 cb_config.recovery_ab = true;
2257 cb_config.recovery_ab_single_copy = true;
2258 break;
Zheng Bao993b43f2021-11-10 12:21:46 +08002259 case AMDFW_OPT_USE_COMBO:
2260 cb_config.use_combo = true;
2261 break;
Zheng Bao0e3d18b2023-03-07 15:28:57 +08002262 case AMDFW_OPT_COMBO1_CONFIG:
2263 cb_config.use_combo = true;
2264 combo_config[1] = optarg;
2265 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002266 case AMDFW_OPT_MULTILEVEL:
Zheng Baoba3af5e2021-11-04 18:56:47 +08002267 cb_config.multi_level = true;
Marshall Dawson24f73d42019-04-01 10:48:43 -06002268 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002269 case AMDFW_OPT_UNLOCK:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002270 register_fw_token_unlock();
Zheng Baoba3af5e2021-11-04 18:56:47 +08002271 cb_config.unlock_secure = true;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002272 sub = instance = 0;
2273 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002274 case AMDFW_OPT_USE_PSPSECUREOS:
Zheng Baoba3af5e2021-11-04 18:56:47 +08002275 cb_config.use_secureos = true;
Marshall Dawsondbae6322019-03-04 10:31:03 -07002276 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002277 case AMDFW_OPT_INSTANCE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002278 instance = strtoul(optarg, &tmp, 16);
2279 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002280 case AMDFW_OPT_LOAD_MP2FW:
Zheng Baoba3af5e2021-11-04 18:56:47 +08002281 cb_config.load_mp2_fw = true;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002282 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002283 case AMDFW_OPT_NVRAM:
Marshall Dawsondbae6322019-03-04 10:31:03 -07002284 register_fw_filename(AMD_FW_PSP_NVRAM, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002285 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002286 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002287 case AMDFW_OPT_FUSE:
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06002288 register_fw_fuse(optarg);
2289 fuse_defined = 1;
2290 sub = 0;
2291 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002292 case AMDFW_OPT_APCB:
Zheng Bao5caca942020-12-04 16:39:38 +08002293 if ((instance & 0xF0) == 0)
2294 register_bdt_data(AMD_BIOS_APCB, sub, instance & 0xF, optarg);
2295 else
2296 register_bdt_data(AMD_BIOS_APCB_BK, sub,
2297 instance & 0xF, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002298 sub = instance = 0;
2299 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002300 case AMDFW_OPT_APOBBASE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002301 /* APOB destination */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302302 register_bios_fw_addr(AMD_BIOS_APOB, 0, optarg, 0);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002303 sub = instance = 0;
2304 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002305 case AMDFW_OPT_APOB_NVBASE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002306 /* APOB NV source */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302307 register_bios_fw_addr(AMD_BIOS_APOB_NV, optarg, 0, 0);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002308 sub = instance = 0;
2309 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002310 case AMDFW_OPT_APOB_NVSIZE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002311 /* APOB NV size */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302312 register_bios_fw_addr(AMD_BIOS_APOB_NV, 0, 0, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002313 sub = instance = 0;
2314 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002315 case AMDFW_OPT_BIOSBIN:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002316 register_bdt_data(AMD_BIOS_BIN, sub, instance, optarg);
2317 sub = instance = 0;
2318 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002319 case AMDFW_OPT_BIOSBIN_SOURCE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002320 /* BIOS source */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302321 register_bios_fw_addr(AMD_BIOS_BIN, optarg, 0, 0);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002322 sub = instance = 0;
2323 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002324 case AMDFW_OPT_BIOSBIN_DEST:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002325 /* BIOS destination */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302326 register_bios_fw_addr(AMD_BIOS_BIN, 0, optarg, 0);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002327 sub = instance = 0;
2328 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002329 case AMDFW_OPT_BIOS_UNCOMP_SIZE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002330 /* BIOS destination size */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302331 register_bios_fw_addr(AMD_BIOS_BIN, 0, 0, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002332 sub = instance = 0;
2333 break;
Karthikeyan Ramasubramanianbd9dd422022-12-22 15:45:56 -07002334 case AMDFW_OPT_BIOSBIN_UNCOMP:
2335 bios_tbl_index = find_bios_entry(AMD_BIOS_BIN);
2336 if (bios_tbl_index != -1)
2337 amd_bios_table[bios_tbl_index].zlib = 0;
2338 break;
Ritul Guru9a321f32022-07-29 11:06:40 +05302339 case LONGOPT_BIOS_SIG:
2340 /* BIOS signature size */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302341 register_bios_fw_addr(AMD_BIOS_SIG, 0, 0, optarg);
Ritul Guru9a321f32022-07-29 11:06:40 +05302342 sub = instance = 0;
2343 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002344 case AMDFW_OPT_UCODE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002345 register_bdt_data(AMD_BIOS_UCODE, sub,
2346 instance, optarg);
2347 sub = instance = 0;
2348 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002349 case AMDFW_OPT_LOAD_S0I3:
Zheng Baoba3af5e2021-11-04 18:56:47 +08002350 cb_config.s0i3 = true;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002351 break;
Zheng Bao6c5ec8e2022-02-11 11:51:26 +08002352 case AMDFW_OPT_SPL_TABLE:
2353 register_fw_filename(AMD_FW_SPL, sub, optarg);
2354 sub = instance = 0;
2355 cb_config.have_mb_spl = true;
2356 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002357 case AMDFW_OPT_WHITELIST:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002358 register_fw_filename(AMD_FW_PSP_WHITELIST, sub, optarg);
2359 sub = instance = 0;
Zheng Baoba3af5e2021-11-04 18:56:47 +08002360 cb_config.have_whitelist = true;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002361 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002362 case AMDFW_OPT_VERSTAGE:
Martin Rothd3ce8c82019-07-13 20:13:07 -06002363 register_fw_filename(AMD_FW_PSP_VERSTAGE, sub, optarg);
2364 sub = instance = 0;
2365 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002366 case AMDFW_OPT_VERSTAGE_SIG:
Martin Rothb1f648f2020-09-01 09:36:59 -06002367 register_fw_filename(AMD_FW_VERSTAGE_SIG, sub, optarg);
2368 sub = instance = 0;
2369 break;
Kangheui Won3c164e12021-12-03 20:25:05 +11002370 case AMDFW_OPT_SIGNED_OUTPUT:
2371 signed_output_file = optarg;
2372 sub = instance = 0;
2373 break;
2374 case AMDFW_OPT_SIGNED_ADDR:
2375 signed_start_addr = strtoull(optarg, NULL, 10);
2376 sub = instance = 0;
2377 break;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002378 case LONGOPT_SPI_READ_MODE:
2379 efs_spi_readmode = strtoull(optarg, NULL, 16);
2380 sub = instance = 0;
2381 break;
2382 case LONGOPT_SPI_SPEED:
2383 efs_spi_speed = strtoull(optarg, NULL, 16);
2384 sub = instance = 0;
2385 break;
2386 case LONGOPT_SPI_MICRON_FLAG:
2387 efs_spi_micron_flag = strtoull(optarg, NULL, 16);
2388 sub = instance = 0;
2389 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002390 case AMDFW_OPT_OUTPUT:
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002391 output = optarg;
2392 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002393 case AMDFW_OPT_FLASHSIZE:
Marshall Dawson2794a862019-03-04 16:53:15 -07002394 ctx.rom_size = (uint32_t)strtoul(optarg, &tmp, 16);
Martin Roth60f15512016-11-08 09:55:01 -07002395 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08002396 fprintf(stderr, "Error: ROM size specified"
Martin Roth60f15512016-11-08 09:55:01 -07002397 " incorrectly (%s)\n\n", optarg);
Martin Roth31d95a22016-11-08 11:22:12 -07002398 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07002399 }
2400 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002401 case AMDFW_OPT_LOCATION:
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002402 efs_location = (uint32_t)strtoul(optarg, &tmp, 16);
Martin Roth0d3b1182017-10-03 14:16:04 -06002403 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08002404 fprintf(stderr, "Error: Directory Location specified"
Martin Roth0d3b1182017-10-03 14:16:04 -06002405 " incorrectly (%s)\n\n", optarg);
2406 retval = 1;
2407 }
Zheng Bao99945dc2023-01-02 10:55:56 +08002408 if (body_location == 0)
2409 body_location = efs_location;
Martin Roth0d3b1182017-10-03 14:16:04 -06002410 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002411 case AMDFW_OPT_ANYWHERE:
Martin Roth37305e72020-04-07 14:16:39 -06002412 any_location = 1;
2413 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002414 case AMDFW_OPT_SHAREDMEM:
Martin Roth94554742020-04-14 14:59:36 -06002415 /* shared memory destination */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302416 register_bios_fw_addr(AMD_BIOS_PSP_SHARED_MEM, 0, optarg, 0);
Martin Roth94554742020-04-14 14:59:36 -06002417 sub = instance = 0;
2418 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002419 case AMDFW_OPT_SHAREDMEM_SIZE:
Martin Roth94554742020-04-14 14:59:36 -06002420 /* shared memory size */
Ritul Gurua2cb3402022-08-29 00:51:08 +05302421 register_bios_fw_addr(AMD_BIOS_PSP_SHARED_MEM, NULL, NULL, optarg);
Martin Roth94554742020-04-14 14:59:36 -06002422 sub = instance = 0;
2423 break;
Ritul Gurua2cb3402022-08-29 00:51:08 +05302424 case LONGOPT_NVRAM_BASE:
2425 /* PSP NV base */
2426 register_amd_psp_fw_addr(AMD_FW_PSP_NVRAM, sub, optarg, 0);
2427 sub = instance = 0;
2428 break;
2429 case LONGOPT_NVRAM_SIZE:
2430 /* PSP NV size */
2431 register_amd_psp_fw_addr(AMD_FW_PSP_NVRAM, sub, 0, optarg);
2432 sub = instance = 0;
2433 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002434 case AMDFW_OPT_CONFIG:
Zheng Baoc5e28ab2020-10-28 11:38:09 +08002435 config = optarg;
2436 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002437 case AMDFW_OPT_DEBUG:
Zheng Bao9e908072020-10-28 11:39:13 +08002438 debug = 1;
2439 break;
Zheng Bao806892a2021-04-27 17:21:54 +08002440 case AMDFW_OPT_HELP:
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002441 usage();
Martin Roth31d95a22016-11-08 11:22:12 -07002442 return 0;
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002443 case AMDFW_OPT_BODY_LOCATION:
Zheng Bao99945dc2023-01-02 10:55:56 +08002444 body_location = (uint32_t)strtoul(optarg, &tmp, 16);
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002445 if (*tmp != '\0') {
2446 fprintf(stderr, "Error: Body Location specified"
2447 " incorrectly (%s)\n\n", optarg);
2448 retval = 1;
2449 }
2450 break;
2451
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002452 default:
2453 break;
2454 }
2455 }
2456
Zheng Bao994ff522023-03-09 11:43:55 +08002457 open_process_config(config, &cb_config, debug);
Zheng Bao9e908072020-10-28 11:39:13 +08002458
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06002459 if (!fuse_defined)
2460 register_fw_fuse(DEFAULT_SOFT_FUSE_CHAIN);
2461
Zheng Bao994ff522023-03-09 11:43:55 +08002462 if (!output) {
Zheng Baoc5e28ab2020-10-28 11:38:09 +08002463 fprintf(stderr, "Error: Output value is not specified.\n\n");
Martin Roth31d95a22016-11-08 11:22:12 -07002464 retval = 1;
2465 }
2466
Zheng Bao994ff522023-03-09 11:43:55 +08002467 if ((ctx.rom_size % 1024 != 0)) {
Zheng Baoc5e28ab2020-10-28 11:38:09 +08002468 fprintf(stderr, "Error: ROM Size (%d bytes) should be a multiple of"
Marshall Dawson2794a862019-03-04 16:53:15 -07002469 " 1024 bytes.\n\n", ctx.rom_size);
Martin Roth31d95a22016-11-08 11:22:12 -07002470 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07002471 }
2472
Zheng Bao994ff522023-03-09 11:43:55 +08002473 if ((ctx.rom_size < MIN_ROM_KB * 1024)) {
Zheng Baoc5e28ab2020-10-28 11:38:09 +08002474 fprintf(stderr, "Error: ROM Size (%dKB) must be at least %dKB.\n\n",
Marshall Dawson2794a862019-03-04 16:53:15 -07002475 ctx.rom_size / 1024, MIN_ROM_KB);
Martin Roth31d95a22016-11-08 11:22:12 -07002476 retval = 1;
2477 }
2478
2479 if (retval) {
2480 usage();
2481 return retval;
Martin Roth60f15512016-11-08 09:55:01 -07002482 }
2483
Marshall Dawson2794a862019-03-04 16:53:15 -07002484 printf(" AMDFWTOOL Using ROM size of %dKB\n", ctx.rom_size / 1024);
Martin Roth60f15512016-11-08 09:55:01 -07002485
Marshall Dawson2794a862019-03-04 16:53:15 -07002486 rom_base_address = 0xFFFFFFFF - ctx.rom_size + 1;
Zheng Bao9770df12023-02-14 13:23:35 +08002487
2488 if (efs_location & 0xFF000000)
2489 efs_location = efs_location - rom_base_address;
2490 if (body_location & 0xFF000000)
2491 body_location = body_location - rom_base_address;
2492
2493 if (efs_location && efs_location > ctx.rom_size) {
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002494 fprintf(stderr, "Error: EFS/Directory location outside of ROM.\n\n");
2495 return 1;
2496 }
Zheng Bao9770df12023-02-14 13:23:35 +08002497 if (body_location && body_location > ctx.rom_size) {
2498 fprintf(stderr, "Error: Body location outside of ROM.\n\n");
2499 return 1;
2500 }
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002501
Zheng Bao99945dc2023-01-02 10:55:56 +08002502 if (!efs_location && body_location) {
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002503 fprintf(stderr, "Error AMDFW body location specified without EFS location.\n");
2504 return 1;
2505 }
2506
Zheng Bao99945dc2023-01-02 10:55:56 +08002507 if (body_location != efs_location &&
2508 body_location < ALIGN(efs_location + sizeof(embedded_firmware), BLOB_ALIGNMENT)) {
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002509 fprintf(stderr, "Error: Insufficient space between EFS and Blobs.\n");
2510 fprintf(stderr, " Require safe spacing of 256 bytes\n");
Martin Roth0d3b1182017-10-03 14:16:04 -06002511 return 1;
2512 }
2513
Martin Roth37305e72020-04-07 14:16:39 -06002514 if (any_location) {
Zheng Bao99945dc2023-01-02 10:55:56 +08002515 if ((body_location & 0x3f) || (efs_location & 0x3f)) {
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002516 fprintf(stderr, "Error: Invalid Directory/EFS location.\n");
Zheng Bao77a2c672020-10-01 17:05:43 +08002517 fprintf(stderr, " Valid locations are 64-byte aligned\n");
Martin Roth37305e72020-04-07 14:16:39 -06002518 return 1;
2519 }
2520 } else {
Zheng Bao4e8fb352022-11-21 21:34:45 +08002521 /* efs_location is relative address now. */
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002522 switch (efs_location) {
Zheng Bao92c920b2022-12-08 13:56:13 +08002523 case 0:
Zheng Bao4e8fb352022-11-21 21:34:45 +08002524 case 0xFA0000:
2525 case 0xF20000:
2526 case 0xE20000:
2527 case 0xC20000:
2528 case 0x820000:
2529 case 0x020000:
2530 break;
2531 case 0x7A0000:
2532 case 0x720000:
2533 case 0x620000:
2534 case 0x420000:
2535 /* Special cases for 8M. */
2536 if (ctx.rom_size != 0x800000) {
2537 fprintf(stderr, "Error: Invalid Directory location.\n");
2538 fprintf(stderr, "%x is only for 8M image size.", efs_location);
2539 return 1;
2540 }
2541 break;
2542 case 0x3A0000:
2543 case 0x320000:
2544 case 0x220000:
2545 /* Special cases for 4M. */
2546 if (ctx.rom_size != 0x400000) {
2547 fprintf(stderr, "Error: Invalid Directory location.\n");
2548 fprintf(stderr, "%x is only for 4M image size.", efs_location);
2549 return 1;
2550 }
Martin Roth37305e72020-04-07 14:16:39 -06002551 break;
2552 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08002553 fprintf(stderr, "Error: Invalid Directory location.\n");
2554 fprintf(stderr, " Valid locations are 0xFFFA0000, 0xFFF20000,\n");
2555 fprintf(stderr, " 0xFFE20000, 0xFFC20000, 0xFF820000, 0xFF020000\n");
Zheng Bao4e8fb352022-11-21 21:34:45 +08002556 fprintf(stderr, " 0xFA0000, 0xF20000, 0xE20000, 0xC20000,\n");
2557 fprintf(stderr, " 0x820000, 0x020000\n");
Martin Roth37305e72020-04-07 14:16:39 -06002558 return 1;
2559 }
Martin Roth0d3b1182017-10-03 14:16:04 -06002560 }
Marshall Dawson2794a862019-03-04 16:53:15 -07002561 ctx.rom = malloc(ctx.rom_size);
2562 if (!ctx.rom) {
Zheng Bao77a2c672020-10-01 17:05:43 +08002563 fprintf(stderr, "Error: Failed to allocate memory\n");
Martin Roth31d95a22016-11-08 11:22:12 -07002564 return 1;
Marshall Dawson2794a862019-03-04 16:53:15 -07002565 }
2566 memset(ctx.rom, 0xFF, ctx.rom_size);
Martin Roth60f15512016-11-08 09:55:01 -07002567
Zheng Bao6095cd12023-02-21 10:52:47 +08002568 romsig_offset = efs_location ? efs_location : AMD_ROMSIG_OFFSET;
2569 set_current_pointer(&ctx, romsig_offset);
Martin Roth0d3b1182017-10-03 14:16:04 -06002570
Marshall Dawson2794a862019-03-04 16:53:15 -07002571 amd_romsig = BUFF_OFFSET(ctx, romsig_offset);
Marshall Dawson239286c2019-02-23 16:42:46 -07002572 amd_romsig->signature = EMBEDDED_FW_SIGNATURE;
2573 amd_romsig->imc_entry = 0;
2574 amd_romsig->gec_entry = 0;
2575 amd_romsig->xhci_entry = 0;
Martin Roth60f15512016-11-08 09:55:01 -07002576
Zheng Bao4bf6f492023-01-25 22:37:29 +08002577 if (cb_config.soc_id != PLATFORM_UNKNOWN) {
2578 retval = set_efs_table(cb_config.soc_id, &cb_config, amd_romsig,
2579 efs_spi_readmode, efs_spi_speed, efs_spi_micron_flag);
Zheng Bao570645d2021-11-03 10:25:03 +08002580 if (retval) {
2581 fprintf(stderr, "ERROR: Failed to initialize EFS table!\n");
2582 return retval;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002583 }
2584 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08002585 fprintf(stderr, "WARNING: No SOC name specified.\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05002586 }
2587
Felix Held21a8e382022-03-29 23:10:45 +02002588 if (cb_config.need_ish)
Robert Zieba29bc79f2022-03-14 15:59:12 -06002589 ctx.address_mode = AMD_ADDR_REL_TAB;
Zheng Baoc3007f32022-04-03 12:53:51 +08002590 else if (cb_config.second_gen)
Robert Zieba29bc79f2022-03-14 15:59:12 -06002591 ctx.address_mode = AMD_ADDR_REL_BIOS;
Zheng Baoda83d2c2021-06-04 19:03:10 +08002592 else
Robert Zieba29bc79f2022-03-14 15:59:12 -06002593 ctx.address_mode = AMD_ADDR_PHYSICAL;
Zheng Bao7c7294f2023-01-04 16:38:28 +08002594 printf(" AMDFWTOOL Using firmware directory location of address: 0x%08x",
2595 efs_location);
2596 if (body_location != efs_location)
2597 printf(" with a split body at: 0x%08x\n", body_location);
2598 else
2599 printf("\n");
Zheng Baoda83d2c2021-06-04 19:03:10 +08002600
Zheng Bao6095cd12023-02-21 10:52:47 +08002601 if (efs_location != body_location)
2602 set_current_pointer(&ctx, body_location);
2603 else
2604 set_current_pointer(&ctx, romsig_offset + sizeof(embedded_firmware));
2605
Marshall Dawson2794a862019-03-04 16:53:15 -07002606 integrate_firmwares(&ctx, amd_romsig, amd_fw_table);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002607
Karthikeyan Ramasubramanian225b4b32023-03-08 10:24:50 -07002608 if (is_initial_alignment_required(cb_config.soc_id)) {
2609 /* TODO: Check for older platforms. */
2610 adjust_current_pointer(&ctx, 0, 0x10000U);
2611 }
Zheng Bao6fff2492021-11-15 19:53:21 +08002612 ctx.current_table = 0;
Marshall Dawson2794a862019-03-04 16:53:15 -07002613
Kangheui Won3c164e12021-12-03 20:25:05 +11002614 /* If the tool is invoked with command-line options to keep the signed PSP
2615 binaries separate, process the signed binaries first. */
2616 if (signed_output_file && signed_start_addr)
2617 process_signed_psp_firmwares(signed_output_file,
2618 amd_psp_fw_table,
2619 signed_start_addr,
Zheng Bao4bf6f492023-01-25 22:37:29 +08002620 cb_config.soc_id);
Kangheui Won3c164e12021-12-03 20:25:05 +11002621
Zheng Baob2ae6a52022-08-18 15:45:27 +08002622 if (cb_config.use_combo) {
2623 psp_combo_dir = new_combo_dir(&ctx);
Zheng Bao84fb9ea2022-08-18 15:54:47 +08002624
2625 adjust_current_pointer(&ctx, 0, 0x1000U);
2626
2627 bhd_combo_dir = new_combo_dir(&ctx);
Zheng Baob2ae6a52022-08-18 15:45:27 +08002628 }
2629
Zheng Bao0e3d18b2023-03-07 15:28:57 +08002630 combo_index = 0;
2631 if (config)
2632 combo_config[0] = config;
2633
Zheng Bao4b6aa192023-03-09 11:28:47 +08002634 do {
2635 /* for non-combo image, combo_config[0] == config, and
2636 * it already is processed. Actually "combo_index >
2637 * 0" is enough. Put both of them here to make sure
2638 * and make it clear this will not affect non-combo
2639 * case.
2640 */
2641 if (cb_config.use_combo && combo_index > 0) {
2642 open_process_config(combo_config[combo_index], &cb_config,
Zheng Bao994ff522023-03-09 11:43:55 +08002643 debug);
Zheng Bao0e3d18b2023-03-07 15:28:57 +08002644
Zheng Bao4b6aa192023-03-09 11:28:47 +08002645 /* In most cases, the address modes are same. */
2646 if (cb_config.need_ish)
2647 ctx.address_mode = AMD_ADDR_REL_TAB;
2648 else if (cb_config.second_gen)
2649 ctx.address_mode = AMD_ADDR_REL_BIOS;
2650 else
2651 ctx.address_mode = AMD_ADDR_PHYSICAL;
Zheng Bao990d1542021-09-17 13:24:54 +08002652 }
Marshall Dawson2794a862019-03-04 16:53:15 -07002653
Zheng Bao481661e2021-08-20 14:47:46 +08002654 if (cb_config.multi_level) {
Zheng Bao4b6aa192023-03-09 11:28:47 +08002655 /* Do 2nd PSP directory followed by 1st */
2656 pspdir2 = new_psp_dir(&ctx, cb_config.multi_level);
2657 integrate_psp_firmwares(&ctx, pspdir2, NULL, NULL,
2658 amd_psp_fw_table, PSPL2_COOKIE, &cb_config);
2659 if (cb_config.recovery_ab && !cb_config.recovery_ab_single_copy) {
2660 /* Create a copy of PSP Directory 2 in the backup slot B.
2661 Related biosdir2_b copy will be created later. */
2662 pspdir2_b = new_psp_dir(&ctx, cb_config.multi_level);
2663 integrate_psp_firmwares(&ctx, pspdir2_b, NULL, NULL,
2664 amd_psp_fw_table, PSPL2_COOKIE, &cb_config);
Zheng Bao990d1542021-09-17 13:24:54 +08002665 } else {
Zheng Bao4b6aa192023-03-09 11:28:47 +08002666 /*
2667 * Either the platform is using only
2668 * one slot or B is same as above
2669 * directories for A. Skip creating
2670 * pspdir2_b here to save flash space.
2671 * Related biosdir2_b will be skipped
2672 * automatically.
2673 */
2674 pspdir2_b = NULL; /* More explicitly */
Zheng Bao990d1542021-09-17 13:24:54 +08002675 }
Zheng Bao4b6aa192023-03-09 11:28:47 +08002676 pspdir = new_psp_dir(&ctx, cb_config.multi_level);
2677 integrate_psp_firmwares(&ctx, pspdir, pspdir2, pspdir2_b,
2678 amd_psp_fw_table, PSP_COOKIE, &cb_config);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002679 } else {
Zheng Bao4b6aa192023-03-09 11:28:47 +08002680 /* flat: PSP 1 cookie and no pointer to 2nd table */
2681 pspdir = new_psp_dir(&ctx, cb_config.multi_level);
2682 integrate_psp_firmwares(&ctx, pspdir, NULL, NULL,
2683 amd_psp_fw_table, PSP_COOKIE, &cb_config);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002684 }
Zheng Bao84fb9ea2022-08-18 15:54:47 +08002685
Zheng Bao4b6aa192023-03-09 11:28:47 +08002686 if (!cb_config.use_combo) {
2687 fill_psp_directory_to_efs(amd_romsig, pspdir, &ctx, &cb_config);
2688 } else {
2689 fill_psp_directory_to_efs(amd_romsig, psp_combo_dir, &ctx, &cb_config);
2690 /* 0 -Compare PSP ID, 1 -Compare chip family ID */
2691 assert_fw_entry(combo_index, MAX_COMBO_ENTRIES, &ctx);
2692 psp_combo_dir->entries[combo_index].id_sel = 0;
2693 psp_combo_dir->entries[combo_index].id = get_psp_id(cb_config.soc_id);
2694 psp_combo_dir->entries[combo_index].lvl2_addr =
2695 BUFF_TO_RUN_MODE(ctx, pspdir, AMD_ADDR_REL_BIOS);
2696
2697 fill_dir_header(psp_combo_dir, combo_index + 1, PSP2_COOKIE, &ctx);
Zheng Bao84fb9ea2022-08-18 15:54:47 +08002698 }
Zheng Bao4b6aa192023-03-09 11:28:47 +08002699
2700 if (have_bios_tables(amd_bios_table)) {
2701 bios_directory_table *biosdir = NULL;
2702 if (cb_config.multi_level) {
2703 /* Do 2nd level BIOS directory followed by 1st */
2704 bios_directory_table *biosdir2 = NULL;
2705 bios_directory_table *biosdir2_b = NULL;
2706
2707 biosdir2 = new_bios_dir(&ctx, cb_config.multi_level);
2708
2709 integrate_bios_firmwares(&ctx, biosdir2, NULL,
2710 amd_bios_table, BHDL2_COOKIE, &cb_config);
2711 if (cb_config.recovery_ab) {
2712 if (pspdir2_b != NULL) {
2713 biosdir2_b = new_bios_dir(&ctx,
2714 cb_config.multi_level);
2715 integrate_bios_firmwares(&ctx, biosdir2_b, NULL,
2716 amd_bios_table, BHDL2_COOKIE,
2717 &cb_config);
2718 }
2719 add_psp_firmware_entry(&ctx, pspdir2, biosdir2,
2720 AMD_FW_BIOS_TABLE, TABLE_ALIGNMENT);
2721 if (pspdir2_b != NULL)
2722 add_psp_firmware_entry(&ctx, pspdir2_b,
2723 biosdir2_b, AMD_FW_BIOS_TABLE,
2724 TABLE_ALIGNMENT);
2725 } else {
2726 biosdir = new_bios_dir(&ctx, cb_config.multi_level);
2727 integrate_bios_firmwares(&ctx, biosdir, biosdir2,
2728 amd_bios_table, BHD_COOKIE, &cb_config);
2729 }
2730 } else {
2731 /* flat: BHD1 cookie and no pointer to 2nd table */
2732 biosdir = new_bios_dir(&ctx, cb_config.multi_level);
2733 integrate_bios_firmwares(&ctx, biosdir, NULL,
2734 amd_bios_table, BHD_COOKIE, &cb_config);
2735 }
2736 if (!cb_config.use_combo) {
2737 fill_bios_directory_to_efs(amd_romsig, biosdir,
2738 &ctx, &cb_config);
2739 } else {
2740 fill_bios_directory_to_efs(amd_romsig, bhd_combo_dir,
2741 &ctx, &cb_config);
2742 assert_fw_entry(combo_index, MAX_COMBO_ENTRIES, &ctx);
2743 bhd_combo_dir->entries[combo_index].id_sel = 0;
2744 bhd_combo_dir->entries[combo_index].id =
2745 get_psp_id(cb_config.soc_id);
2746 bhd_combo_dir->entries[combo_index].lvl2_addr =
2747 BUFF_TO_RUN_MODE(ctx, biosdir, AMD_ADDR_REL_BIOS);
2748
2749 fill_dir_header(bhd_combo_dir, combo_index + 1,
2750 BHD2_COOKIE, &ctx);
2751 }
2752 }
2753 } while (cb_config.use_combo && combo_config[++combo_index] != NULL);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06002754
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002755 targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666);
Martin Roth31d95a22016-11-08 11:22:12 -07002756 if (targetfd >= 0) {
Zheng Bao69ea83c2023-01-22 21:08:18 +08002757 uint32_t offset = efs_location;
2758 uint32_t bytes = efs_location == body_location ?
2759 ctx.current - offset : sizeof(*amd_romsig);
2760 uint32_t ret_bytes;
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002761
Zheng Bao69ea83c2023-01-22 21:08:18 +08002762 ret_bytes = write(targetfd, BUFF_OFFSET(ctx, offset), bytes);
2763 if (bytes != ret_bytes) {
Zheng Bao47396912020-09-29 17:33:17 +08002764 fprintf(stderr, "Error: Writing to file %s failed\n", output);
2765 retval = 1;
2766 }
Martin Roth31d95a22016-11-08 11:22:12 -07002767 close(targetfd);
2768 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08002769 fprintf(stderr, "Error: could not open file: %s\n", output);
Martin Roth31d95a22016-11-08 11:22:12 -07002770 retval = 1;
2771 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002772
Zheng Bao99945dc2023-01-02 10:55:56 +08002773 if (efs_location != body_location) {
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002774 ssize_t bytes;
2775
Zheng Bao69ea83c2023-01-22 21:08:18 +08002776 bytes = write_body(output, BUFF_OFFSET(ctx, body_location),
2777 ctx.current - body_location, &ctx);
2778 if (bytes != ctx.current - body_location) {
2779 fprintf(stderr, "Error: Writing body\n");
Karthikeyan Ramasubramanianecb4e312022-11-02 16:53:54 -06002780 retval = 1;
2781 }
2782 }
2783
Zheng Bao7c5ad882023-02-19 13:02:52 +08002784 amdfwtool_cleanup(&ctx);
Martin Roth31d95a22016-11-08 11:22:12 -07002785 return retval;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08002786}