blob: b2b7c42219b6f38a046fa004fc01eec02d0b254d [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/*
4 * ROMSIG At ROMBASE + 0x20000:
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 * +------------+---------------+----------------+------------+
zbaoc3b0b722016-02-19 13:47:31 +08009 * | PSPDIR ADDR|PSPDIR ADDR |<-- Field 0x14 could be either
10 * +------------+---------------+ 2nd PSP directory or PSP COMBO directory
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080011 * EC ROM should be 64K aligned.
12 *
Zheng Bao4fcc9f22015-11-20 12:29:04 +080013 * PSP directory (Where "PSPDIR ADDR" points)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080014 * +------------+---------------+----------------+------------+
15 * | 'PSP$' | Fletcher | Count | Reserved |
16 * +------------+---------------+----------------+------------+
17 * | 0 | size | Base address | Reserved | Pubkey
18 * +------------+---------------+----------------+------------+
19 * | 1 | size | Base address | Reserved | Bootloader
20 * +------------+---------------+----------------+------------+
21 * | 8 | size | Base address | Reserved | Smu Firmware
22 * +------------+---------------+----------------+------------+
23 * | 3 | size | Base address | Reserved | Recovery Firmware
24 * +------------+---------------+----------------+------------+
25 * | |
26 * | |
27 * | Other PSP Firmware |
28 * | |
29 * | |
30 * +------------+---------------+----------------+------------+
Zheng Bao4fcc9f22015-11-20 12:29:04 +080031 *
zbaoc3b0b722016-02-19 13:47:31 +080032 * PSP Combo directory
Zheng Bao4fcc9f22015-11-20 12:29:04 +080033 * +------------+---------------+----------------+------------+
zbao6e2f3d12016-02-19 13:34:59 +080034 * | 'PSP2' | Fletcher | Count |Look up mode|
Zheng Bao4fcc9f22015-11-20 12:29:04 +080035 * +------------+---------------+----------------+------------+
zbaoc3a08a92016-03-02 14:47:27 +080036 * | R e s e r v e d |
37 * +------------+---------------+----------------+------------+
zbao6e2f3d12016-02-19 13:34:59 +080038 * | ID-Sel | PSP ID | PSPDIR ADDR | | 2nd PSP directory
Zheng Bao4fcc9f22015-11-20 12:29:04 +080039 * +------------+---------------+----------------+------------+
zbao6e2f3d12016-02-19 13:34:59 +080040 * | ID-Sel | PSP ID | PSPDIR ADDR | | 3rd PSP directory
Zheng Bao4fcc9f22015-11-20 12:29:04 +080041 * +------------+---------------+----------------+------------+
42 * | |
43 * | Other PSP |
44 * | |
45 * +------------+---------------+----------------+------------+
46 *
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080047 */
48
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080049#include <fcntl.h>
50#include <errno.h>
Martin Roth37305e72020-04-07 14:16:39 -060051#include <stdbool.h>
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080052#include <stdio.h>
53#include <sys/stat.h>
54#include <sys/types.h>
55#include <unistd.h>
56#include <string.h>
57#include <stdlib.h>
58#include <getopt.h>
Zheng Baoc5e28ab2020-10-28 11:38:09 +080059#include <libgen.h>
Idwer Vollering93df1d92020-12-30 00:01:59 +010060#include <stdint.h>
Zheng Baoc5e28ab2020-10-28 11:38:09 +080061
62#include "amdfwtool.h"
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080063
Martin Roth60f15512016-11-08 09:55:01 -070064#define AMD_ROMSIG_OFFSET 0x20000
65#define MIN_ROM_KB 256
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080066
Martin Rothcd15bc82016-11-08 11:34:02 -070067#define ALIGN(val, by) (((val) + (by) - 1) & ~((by) - 1))
Marshall Dawson7c1e1422019-04-11 09:44:43 -060068#define _MAX(A, B) (((A) > (B)) ? (A) : (B))
69#define ERASE_ALIGNMENT 0x1000U
Marshall Dawson2794a862019-03-04 16:53:15 -070070#define TABLE_ALIGNMENT 0x1000U
71#define BLOB_ALIGNMENT 0x100U
Marshall Dawson24f73d42019-04-01 10:48:43 -060072#define TABLE_ERASE_ALIGNMENT _MAX(TABLE_ALIGNMENT, ERASE_ALIGNMENT)
Marshall Dawson7c1e1422019-04-11 09:44:43 -060073#define BLOB_ERASE_ALIGNMENT _MAX(BLOB_ALIGNMENT, ERASE_ALIGNMENT)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080074
Marshall Dawsonef79fcc2019-04-01 10:16:41 -060075#define DEFAULT_SOFT_FUSE_CHAIN "0x1"
76
Marshall Dawson239286c2019-02-23 16:42:46 -070077#define EMBEDDED_FW_SIGNATURE 0x55aa55aa
Marshall Dawson24f73d42019-04-01 10:48:43 -060078#define PSP_COOKIE 0x50535024 /* 'PSP$' */
79#define PSPL2_COOKIE 0x324c5024 /* '2LP$' */
80#define PSP2_COOKIE 0x50535032 /* 'PSP2' */
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -060081#define BDT1_COOKIE 0x44484224 /* 'DHB$ */
82#define BDT2_COOKIE 0x324c4224 /* '2LB$ */
Marshall Dawson239286c2019-02-23 16:42:46 -070083
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080084/*
Marshall Dawson0e02ce82019-03-04 16:50:37 -070085 * Beginning with Family 15h Models 70h-7F, a.k.a Stoney Ridge, the PSP
86 * can support an optional "combo" implementation. If the PSP sees the
87 * PSP2 cookie, it interprets the table as a roadmap to additional PSP
88 * tables. Using this, support for multiple product generations may be
89 * built into one image. If the PSP$ cookie is found, the table is a
90 * normal directory table.
91 *
92 * Modern generations supporting the combo directories require the
93 * pointer to be at offset 0x14 of the Embedded Firmware Structure,
94 * regardless of the type of directory used. The --combo-capable
95 * argument enforces this placement.
96 *
97 * TODO: Future work may require fully implementing the PSP_COMBO feature.
zbaoc3b0b722016-02-19 13:47:31 +080098 */
Marshall Dawson0e02ce82019-03-04 16:50:37 -070099#define PSP_COMBO 0
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800100
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800101/*
102 * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
103 * The checksum field of the passed PDU does not need to be reset to zero.
104 *
105 * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of
106 * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an
107 * alternative to cyclical redundancy checks because it provides error-
108 * detection properties similar to cyclical redundancy checks but at the
109 * cost of a simple summation technique. Its characteristics were first
110 * published in IEEE Transactions on Communications in January 1982. One
111 * version has been adopted by ISO for use in the class-4 transport layer
112 * of the network protocol.
113 *
114 * This program expects:
115 * stdin: The input file to compute a checksum for. The input file
116 * not be longer than 256 bytes.
117 * stdout: Copied from the input file with the Fletcher's Checksum
118 * inserted 8 bytes after the beginning of the file.
119 * stderr: Used to print out error messages.
120 */
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700121static uint32_t fletcher32(const void *data, int length)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800122{
123 uint32_t c0;
124 uint32_t c1;
125 uint32_t checksum;
126 int index;
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700127 const uint16_t *pptr = data;
128
129 length /= 2;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800130
131 c0 = 0xFFFF;
132 c1 = 0xFFFF;
133
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600134 while (length) {
135 index = length >= 359 ? 359 : length;
136 length -= index;
137 do {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800138 c0 += *(pptr++);
139 c1 += c0;
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600140 } while (--index);
141 c0 = (c0 & 0xFFFF) + (c0 >> 16);
142 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800143 }
144
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700145 /* Sums[0,1] mod 64K + overflow */
146 c0 = (c0 & 0xFFFF) + (c0 >> 16);
147 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800148 checksum = (c1 << 16) | c0;
149
150 return checksum;
151}
152
Martin Roth8806f7f2016-11-08 10:44:18 -0700153static void usage(void)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800154{
Martin Roth0e940622016-11-08 10:37:53 -0700155 printf("amdfwtool: Create AMD Firmware combination\n");
156 printf("Usage: amdfwtool [options] -f <size> -o <filename>\n");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600157 printf("-x | --xhci <FILE> Add XHCI blob\n");
158 printf("-i | --imc <FILE> Add IMC blob\n");
159 printf("-g | --gec <FILE> Add GEC blob\n");
Martin Roth0e940622016-11-08 10:37:53 -0700160
161 printf("\nPSP options:\n");
Marshall Dawson67d868d2019-02-28 11:43:40 -0700162 printf("-A | --combo-capable Place PSP directory pointer at Embedded Firmware\n");
163 printf(" offset able to support combo directory\n");
Marshall Dawson24f73d42019-04-01 10:48:43 -0600164 printf("-M | --multilevel Generate primary and secondary tables\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800165 printf("-n | --nvram <FILE> Add nvram binary\n");
166 printf("-T | --soft-fuse Set soft fuse\n");
167 printf("-U | --token-unlock Set token unlock\n");
168 printf("-W | --whitelist Set if there is a whitelist\n");
169 printf("-S | --use-pspsecureos Set if psp secure OS is needed\n");
170 printf("-p | --load-mp2-fw Set if load MP2 firmware\n");
171 printf("-L | --load-s0i3 Set if load s0i3 firmware\n");
Martin Rothd3ce8c82019-07-13 20:13:07 -0600172 printf("-Z | --verstage <FILE> Add verstage\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800173 printf("-E | --verstage_sig Add verstage signature");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600174 printf("\nBIOS options:\n");
175 printf("-I | --instance <number> Sets instance field for the next BIOS firmware\n");
176 printf("-a | --apcb <FILE> Add AGESA PSP customization block\n");
177 printf("-Q | --apob-base <HEX_VAL> Destination for AGESA PSP output block\n");
178 printf("-F | --apob-nv-base <HEX_VAL> Location of S3 resume data\n");
179 printf("-H | --apob-nv-size <HEX_VAL> Size of S3 resume data\n");
Martin Rothec933132019-07-13 20:03:34 -0600180 printf("-O | --ucode <FILE> Add microcode patch\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600181 printf("-V | --bios-bin <FILE> Add compressed image; auto source address\n");
182 printf("-e | --bios-bin-src <HEX_VAL> Address in flash of source if -V not used\n");
183 printf("-v | --bios-bin-dest <HEX_VAL> Destination for uncompressed BIOS\n");
184 printf("-j | --bios-uncomp-size <HEX> Uncompressed size of BIOS image\n");
Martin Roth0e940622016-11-08 10:37:53 -0700185 printf("\n-o | --output <filename> output filename\n");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600186 printf("-f | --flashsize <HEX_VAL> ROM size in bytes\n");
187 printf(" size must be larger than %dKB\n",
Martin Roth0e940622016-11-08 10:37:53 -0700188 MIN_ROM_KB);
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600189 printf(" and must a multiple of 1024\n");
Martin Roth0d3b1182017-10-03 14:16:04 -0600190 printf("-l | --location Location of Directory\n");
Martin Roth37305e72020-04-07 14:16:39 -0600191 printf("-q | --anywhere Use any 64-byte aligned addr for Directory\n");
Martin Roth94554742020-04-14 14:59:36 -0600192 printf("-R | --sharedmem Location of PSP/FW shared memory\n");
193 printf("-P | --sharedmem-size Maximum size of the PSP/FW shared memory area\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500194 printf("-C | --soc-name <socname> Specify SOC name. Supported names are\n");
195 printf(" Stoneyridge, Raven, Picasso, Renoir or Lucienne");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600196 printf("-h | --help show this help\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500197 printf("\nEmbedded Firmware Structure options used by the PSP:\n");
198 printf("--spi-speed <HEX_VAL> SPI fast speed to place in EFS Table\n");
199 printf(" 0x0 66.66Mhz\n");
200 printf(" 0x1 33.33MHz\n");
201 printf(" 0x2 22.22MHz\n");
202 printf(" 0x3 16.66MHz\n");
203 printf(" 0x4 100MHz\n");
204 printf(" 0x5 800KHz\n");
205 printf("--spi-read-mode <HEX_VAL> SPI read mode to place in EFS Table\n");
206 printf(" 0x0 Normal Read (up to 33M)\n");
207 printf(" 0x1 Reserved\n");
208 printf(" 0x2 Dual IO (1-1-2)\n");
209 printf(" 0x3 Quad IO (1-1-4)\n");
210 printf(" 0x4 Dual IO (1-2-2)\n");
211 printf(" 0x5 Quad IO (1-4-4)\n");
212 printf(" 0x6 Normal Read (up to 66M)\n");
213 printf(" 0x7 Fast Read\n");
214 printf("--spi-micron-flag <HEX_VAL> Micron SPI part support for RV and later SOC\n");
215 printf(" 0x0 Micron parts are not used\n");
216 printf(" 0x1 Micron parts are always used\n");
217 printf(" 0x2 Micron parts optional, this option is only\n");
218 printf(" supported with RN/LCN SOC\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800219 printf("-c | --config <config file> Config file\n");
Zheng Bao9e908072020-10-28 11:39:13 +0800220 printf("-d | --debug Print debug message\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800221 printf("-D | --depend List out the firmware files\n");
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800222}
223
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800224amd_fw_entry amd_psp_fw_table[] = {
Marshall Dawson24f73d42019-04-01 10:48:43 -0600225 { .type = AMD_FW_PSP_PUBKEY, .level = PSP_BOTH },
226 { .type = AMD_FW_PSP_BOOTLOADER, .level = PSP_BOTH },
227 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 0, .level = PSP_BOTH },
228 { .type = AMD_FW_PSP_RECOVERY, .level = PSP_LVL1 },
229 { .type = AMD_FW_PSP_RTM_PUBKEY, .level = PSP_BOTH },
230 { .type = AMD_FW_PSP_SECURED_OS, .level = PSP_LVL2 },
231 { .type = AMD_FW_PSP_NVRAM, .level = PSP_LVL2 },
232 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 2, .level = PSP_BOTH },
233 { .type = AMD_FW_PSP_SECURED_DEBUG, .level = PSP_LVL2 },
234 { .type = AMD_FW_PSP_TRUSTLETS, .level = PSP_LVL2 },
235 { .type = AMD_FW_PSP_TRUSTLETKEY, .level = PSP_LVL2 },
236 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 2, .level = PSP_BOTH },
237 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
238 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
239 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .level = PSP_BOTH },
240 { .type = AMD_FW_PSP_SMUSCS, .level = PSP_BOTH },
241 { .type = AMD_PSP_FUSE_CHAIN, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600242 { .type = AMD_DEBUG_UNLOCK, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800243 { .type = AMD_HW_IPCFG, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600244 { .type = AMD_WRAPPED_IKEK, .level = PSP_BOTH },
245 { .type = AMD_TOKEN_UNLOCK, .level = PSP_BOTH },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800246 { .type = AMD_SEC_GASKET, .subprog = 0, .level = PSP_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600247 { .type = AMD_SEC_GASKET, .subprog = 2, .level = PSP_BOTH },
248 { .type = AMD_SEC_GASKET, .subprog = 1, .level = PSP_BOTH },
249 { .type = AMD_MP2_FW, .subprog = 2, .level = PSP_LVL2 },
250 { .type = AMD_MP2_FW, .subprog = 1, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800251 { .type = AMD_MP2_FW, .subprog = 0, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600252 { .type = AMD_DRIVER_ENTRIES, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800253 { .type = AMD_FW_KVM_IMAGE, .level = PSP_LVL2},
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600254 { .type = AMD_S0I3_DRIVER, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800255 { .type = AMD_VBIOS_BTLOADER, .level = PSP_BOTH },
256 { .type = AMD_FW_TOS_SEC_POLICY, .level = PSP_BOTH },
257 { .type = AMD_FW_USB_PHY, .level = PSP_LVL2 },
258 { .type = AMD_FW_DRTM_TA, .level = PSP_LVL2 },
259 { .type = AMD_FW_KEYDB_BL, .level = PSP_BOTH },
260 { .type = AMD_FW_KEYDB_TOS, .level = PSP_LVL2 },
261 { .type = AMD_FW_DMCU_ERAM, .level = PSP_LVL2 },
262 { .type = AMD_FW_DMCU_ISR, .level = PSP_LVL2 },
263 { .type = AMD_RPMC_NVRAM, .level = PSP_LVL2 },
Zheng Baob993cb22021-02-02 18:48:23 +0800264 { .type = AMD_FW_PSP_BOOTLOADER_AB, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600265 { .type = AMD_ABL0, .level = PSP_BOTH },
266 { .type = AMD_ABL1, .level = PSP_BOTH },
267 { .type = AMD_ABL2, .level = PSP_BOTH },
268 { .type = AMD_ABL3, .level = PSP_BOTH },
269 { .type = AMD_ABL4, .level = PSP_BOTH },
270 { .type = AMD_ABL5, .level = PSP_BOTH },
271 { .type = AMD_ABL6, .level = PSP_BOTH },
272 { .type = AMD_ABL7, .level = PSP_BOTH },
Marshall Dawson24f73d42019-04-01 10:48:43 -0600273 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
274 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600275 { .type = AMD_FW_PSP_WHITELIST, .level = PSP_LVL2 },
Martin Rothd3ce8c82019-07-13 20:13:07 -0600276 { .type = AMD_FW_PSP_VERSTAGE, .level = PSP_BOTH },
Martin Rothb1f648f2020-09-01 09:36:59 -0600277 { .type = AMD_FW_VERSTAGE_SIG, .level = PSP_BOTH },
zbaoc3a08a92016-03-02 14:47:27 +0800278 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800279};
280
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800281amd_fw_entry amd_fw_table[] = {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800282 { .type = AMD_FW_XHCI },
283 { .type = AMD_FW_IMC },
284 { .type = AMD_FW_GEC },
zbaoc3a08a92016-03-02 14:47:27 +0800285 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800286};
287
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800288amd_bios_entry amd_bios_table[] = {
Zheng Baobf29a0d2020-12-03 23:00:48 +0800289 { .type = AMD_BIOS_RTM_PUBKEY, .inst = 0, .level = BDT_BOTH },
Marshall Dawson0581bf62019-09-25 11:03:53 -0600290 { .type = AMD_BIOS_APCB, .inst = 0, .level = BDT_BOTH },
291 { .type = AMD_BIOS_APCB, .inst = 1, .level = BDT_BOTH },
292 { .type = AMD_BIOS_APCB, .inst = 2, .level = BDT_BOTH },
293 { .type = AMD_BIOS_APCB, .inst = 3, .level = BDT_BOTH },
294 { .type = AMD_BIOS_APCB, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700295 { .type = AMD_BIOS_APCB, .inst = 5, .level = BDT_BOTH },
296 { .type = AMD_BIOS_APCB, .inst = 6, .level = BDT_BOTH },
297 { .type = AMD_BIOS_APCB, .inst = 7, .level = BDT_BOTH },
298 { .type = AMD_BIOS_APCB, .inst = 8, .level = BDT_BOTH },
299 { .type = AMD_BIOS_APCB, .inst = 9, .level = BDT_BOTH },
300 { .type = AMD_BIOS_APCB, .inst = 10, .level = BDT_BOTH },
301 { .type = AMD_BIOS_APCB, .inst = 11, .level = BDT_BOTH },
302 { .type = AMD_BIOS_APCB, .inst = 12, .level = BDT_BOTH },
303 { .type = AMD_BIOS_APCB, .inst = 13, .level = BDT_BOTH },
304 { .type = AMD_BIOS_APCB, .inst = 14, .level = BDT_BOTH },
305 { .type = AMD_BIOS_APCB, .inst = 15, .level = BDT_BOTH },
Marshall Dawson2dd3b5c2020-01-03 17:57:48 -0700306 { .type = AMD_BIOS_APCB_BK, .inst = 0, .level = BDT_BOTH },
307 { .type = AMD_BIOS_APCB_BK, .inst = 1, .level = BDT_BOTH },
308 { .type = AMD_BIOS_APCB_BK, .inst = 2, .level = BDT_BOTH },
309 { .type = AMD_BIOS_APCB_BK, .inst = 3, .level = BDT_BOTH },
310 { .type = AMD_BIOS_APCB_BK, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700311 { .type = AMD_BIOS_APCB_BK, .inst = 5, .level = BDT_BOTH },
312 { .type = AMD_BIOS_APCB_BK, .inst = 6, .level = BDT_BOTH },
313 { .type = AMD_BIOS_APCB_BK, .inst = 7, .level = BDT_BOTH },
314 { .type = AMD_BIOS_APCB_BK, .inst = 8, .level = BDT_BOTH },
315 { .type = AMD_BIOS_APCB_BK, .inst = 9, .level = BDT_BOTH },
316 { .type = AMD_BIOS_APCB_BK, .inst = 10, .level = BDT_BOTH },
317 { .type = AMD_BIOS_APCB_BK, .inst = 11, .level = BDT_BOTH },
318 { .type = AMD_BIOS_APCB_BK, .inst = 12, .level = BDT_BOTH },
319 { .type = AMD_BIOS_APCB_BK, .inst = 13, .level = BDT_BOTH },
320 { .type = AMD_BIOS_APCB_BK, .inst = 14, .level = BDT_BOTH },
321 { .type = AMD_BIOS_APCB_BK, .inst = 15, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600322 { .type = AMD_BIOS_APOB, .level = BDT_BOTH },
323 { .type = AMD_BIOS_BIN,
324 .reset = 1, .copy = 1, .zlib = 1, .level = BDT_BOTH },
325 { .type = AMD_BIOS_APOB_NV, .level = BDT_LVL2 },
326 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 0, .level = BDT_BOTH },
327 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 0, .level = BDT_BOTH },
328 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 0, .level = BDT_BOTH },
329 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 0, .level = BDT_BOTH },
330 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 1, .level = BDT_BOTH },
331 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 1, .level = BDT_BOTH },
332 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 1, .level = BDT_BOTH },
333 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 1, .level = BDT_BOTH },
334 { .type = AMD_BIOS_UCODE, .inst = 0, .level = BDT_LVL2 },
335 { .type = AMD_BIOS_UCODE, .inst = 1, .level = BDT_LVL2 },
336 { .type = AMD_BIOS_UCODE, .inst = 2, .level = BDT_LVL2 },
337 { .type = AMD_BIOS_MP2_CFG, .level = BDT_LVL2 },
Martin Roth94554742020-04-14 14:59:36 -0600338 { .type = AMD_BIOS_PSP_SHARED_MEM, .inst = 0, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600339 { .type = AMD_BIOS_INVALID },
340};
341
Marshall Dawson13ec0292020-11-19 14:02:29 -0700342struct second_gen_efs { /* todo: expand for Server products */
343 int gen:1; /* Client products only use bit 0 */
344 int reserved:31;
345} __attribute__((packed));
346
347#define EFS_SECOND_GEN 0
348
Marshall Dawson239286c2019-02-23 16:42:46 -0700349typedef struct _embedded_firmware {
350 uint32_t signature; /* 0x55aa55aa */
351 uint32_t imc_entry;
352 uint32_t gec_entry;
353 uint32_t xhci_entry;
354 uint32_t psp_entry;
355 uint32_t comboable;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600356 uint32_t bios0_entry; /* todo: add way to select correct entry */
357 uint32_t bios1_entry;
Marshall Dawson94f24922019-09-28 08:49:09 -0600358 uint32_t bios2_entry;
Marshall Dawson13ec0292020-11-19 14:02:29 -0700359 struct second_gen_efs efs_gen;
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500360 uint32_t bios3_entry;
361 uint32_t reserved_2Ch;
362 uint32_t promontory_fw_ptr;
363 uint32_t lp_promontory_fw_ptr;
364 uint32_t reserved_38h;
365 uint32_t reserved_3Ch;
366 uint8_t spi_readmode_f15_mod_60_6f;
367 uint8_t fast_speed_new_f15_mod_60_6f;
368 uint8_t reserved_42h;
369 uint8_t spi_readmode_f17_mod_00_2f;
370 uint8_t spi_fastspeed_f17_mod_00_2f;
371 uint8_t qpr_dummy_cycle_f17_mod_00_2f;
372 uint8_t reserved_46h;
373 uint8_t spi_readmode_f17_mod_30_3f;
374 uint8_t spi_fastspeed_f17_mod_30_3f;
375 uint8_t micron_detect_f17_mod_30_3f;
376 uint8_t reserved_4Ah;
377 uint8_t reserved_4Bh;
378 uint32_t reserved_4Ch;
Marshall Dawson239286c2019-02-23 16:42:46 -0700379} __attribute__((packed, aligned(16))) embedded_firmware;
380
381typedef struct _psp_directory_header {
382 uint32_t cookie;
383 uint32_t checksum;
384 uint32_t num_entries;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800385 uint32_t additional_info;
Marshall Dawson239286c2019-02-23 16:42:46 -0700386} __attribute__((packed, aligned(16))) psp_directory_header;
387
388typedef struct _psp_directory_entry {
Marshall Dawsondbae6322019-03-04 10:31:03 -0700389 uint8_t type;
390 uint8_t subprog;
391 uint16_t rsvd;
Marshall Dawson239286c2019-02-23 16:42:46 -0700392 uint32_t size;
393 uint64_t addr; /* or a value in some cases */
394} __attribute__((packed)) psp_directory_entry;
395
396typedef struct _psp_directory_table {
397 psp_directory_header header;
398 psp_directory_entry entries[];
Martin Rotha8e31ca2021-02-13 21:42:46 -0700399} __attribute__((packed, aligned(16))) psp_directory_table;
Marshall Dawson239286c2019-02-23 16:42:46 -0700400
Marshall Dawson2794a862019-03-04 16:53:15 -0700401#define MAX_PSP_ENTRIES 0x1f
402
Marshall Dawson239286c2019-02-23 16:42:46 -0700403typedef struct _psp_combo_header {
404 uint32_t cookie;
405 uint32_t checksum;
406 uint32_t num_entries;
407 uint32_t lookup;
408 uint64_t reserved[2];
409} __attribute__((packed, aligned(16))) psp_combo_header;
410
411typedef struct _psp_combo_entry {
412 uint32_t id_sel;
413 uint32_t id;
414 uint64_t lvl2_addr;
415} __attribute__((packed)) psp_combo_entry;
416
417typedef struct _psp_combo_directory {
418 psp_combo_header header;
419 psp_combo_entry entries[];
Martin Rotha8e31ca2021-02-13 21:42:46 -0700420} __attribute__((packed, aligned(16))) psp_combo_directory;
Marshall Dawson239286c2019-02-23 16:42:46 -0700421
Marshall Dawson2794a862019-03-04 16:53:15 -0700422#define MAX_COMBO_ENTRIES 1
423
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600424typedef struct _bios_directory_hdr {
425 uint32_t cookie;
426 uint32_t checksum;
427 uint32_t num_entries;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800428 uint32_t additional_info;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600429} __attribute__((packed, aligned(16))) bios_directory_hdr;
430
431typedef struct _bios_directory_entry {
432 uint8_t type;
433 uint8_t region_type;
434 int reset:1;
435 int copy:1;
436 int ro:1;
437 int compressed:1;
438 int inst:4;
439 uint8_t subprog; /* b[7:3] reserved */
440 uint32_t size;
441 uint64_t source;
442 uint64_t dest;
443} __attribute__((packed)) bios_directory_entry;
444
445typedef struct _bios_directory_table {
446 bios_directory_hdr header;
447 bios_directory_entry entries[];
448} bios_directory_table;
449
Martin Roth94554742020-04-14 14:59:36 -0600450#define MAX_BIOS_ENTRIES 0x2f
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600451
Marshall Dawson2794a862019-03-04 16:53:15 -0700452typedef struct _context {
453 char *rom; /* target buffer, size of flash device */
454 uint32_t rom_size; /* size of flash device */
455 uint32_t current; /* pointer within flash & proxy buffer */
456} context;
457
458#define RUN_BASE(ctx) (0xFFFFFFFF - (ctx).rom_size + 1)
459#define RUN_OFFSET(ctx, offset) (RUN_BASE(ctx) + (offset))
460#define RUN_CURRENT(ctx) RUN_OFFSET((ctx), (ctx).current)
461#define BUFF_OFFSET(ctx, offset) ((void *)((ctx).rom + (offset)))
462#define BUFF_CURRENT(ctx) BUFF_OFFSET((ctx), (ctx).current)
463#define BUFF_TO_RUN(ctx, ptr) RUN_OFFSET((ctx), ((char *)(ptr) - (ctx).rom))
464#define BUFF_ROOM(ctx) ((ctx).rom_size - (ctx).current)
465
Marshall Dawson24f73d42019-04-01 10:48:43 -0600466static void *new_psp_dir(context *ctx, int multi)
Marshall Dawson2794a862019-03-04 16:53:15 -0700467{
468 void *ptr;
469
Marshall Dawson24f73d42019-04-01 10:48:43 -0600470 /*
471 * Force both onto boundary when multi. Primary table is after
472 * updatable table, so alignment ensures primary can stay intact
473 * if secondary is reprogrammed.
474 */
475 if (multi)
476 ctx->current = ALIGN(ctx->current, TABLE_ERASE_ALIGNMENT);
477 else
478 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
479
Marshall Dawson2794a862019-03-04 16:53:15 -0700480 ptr = BUFF_CURRENT(*ctx);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800481 ((psp_directory_header *)ptr)->additional_info = ctx->current;
Marshall Dawson2794a862019-03-04 16:53:15 -0700482 ctx->current += sizeof(psp_directory_header)
483 + MAX_PSP_ENTRIES * sizeof(psp_directory_entry);
484 return ptr;
485}
486
Martin Rothec933132019-07-13 20:03:34 -0600487#if PSP_COMBO
Marshall Dawson2794a862019-03-04 16:53:15 -0700488static void *new_combo_dir(context *ctx)
489{
490 void *ptr;
491
492 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
493 ptr = BUFF_CURRENT(*ctx);
494 ctx->current += sizeof(psp_combo_header)
495 + MAX_COMBO_ENTRIES * sizeof(psp_combo_entry);
496 return ptr;
497}
Martin Rothec933132019-07-13 20:03:34 -0600498#endif
Marshall Dawson2794a862019-03-04 16:53:15 -0700499
Zheng Baobf29a0d2020-12-03 23:00:48 +0800500static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie, context *ctx)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800501{
Marshall Dawson24f73d42019-04-01 10:48:43 -0600502 psp_combo_directory *cdir = directory;
503 psp_directory_table *dir = directory;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600504 bios_directory_table *bdir = directory;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800505 uint32_t table_size = 0;
Marshall Dawson24f73d42019-04-01 10:48:43 -0600506
507 if (!count)
508 return;
509
Zheng Baobf29a0d2020-12-03 23:00:48 +0800510 /* The table size needs to be 0x1000 aligned. So align the end of table. */
511 if (ctx != NULL)
512 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
513
Marshall Dawson24f73d42019-04-01 10:48:43 -0600514 switch (cookie) {
515 case PSP2_COOKIE:
Marshall Dawsona378c222019-03-04 16:52:07 -0700516 /* caller is responsible for lookup mode */
Marshall Dawsona378c222019-03-04 16:52:07 -0700517 cdir->header.cookie = cookie;
518 cdir->header.num_entries = count;
519 cdir->header.reserved[0] = 0;
520 cdir->header.reserved[1] = 0;
521 /* checksum everything that comes after the Checksum field */
522 cdir->header.checksum = fletcher32(&cdir->header.num_entries,
523 count * sizeof(psp_combo_entry)
524 + sizeof(cdir->header.num_entries)
525 + sizeof(cdir->header.lookup)
526 + 2 * sizeof(cdir->header.reserved[0]));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600527 break;
528 case PSP_COOKIE:
529 case PSPL2_COOKIE:
Zheng Baobf29a0d2020-12-03 23:00:48 +0800530 table_size = ctx->current - dir->header.additional_info;
531 if ((table_size % TABLE_ALIGNMENT) != 0) {
532 fprintf(stderr, "The PSP table size should be 4K aligned\n");
533 exit(1);
534 }
Marshall Dawsona378c222019-03-04 16:52:07 -0700535 dir->header.cookie = cookie;
536 dir->header.num_entries = count;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800537 dir->header.additional_info = (table_size / 0x1000) | (1 << 10);
Marshall Dawsona378c222019-03-04 16:52:07 -0700538 /* checksum everything that comes after the Checksum field */
539 dir->header.checksum = fletcher32(&dir->header.num_entries,
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700540 count * sizeof(psp_directory_entry)
Marshall Dawsona378c222019-03-04 16:52:07 -0700541 + sizeof(dir->header.num_entries)
Zheng Baobf29a0d2020-12-03 23:00:48 +0800542 + sizeof(dir->header.additional_info));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600543 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600544 case BDT1_COOKIE:
545 case BDT2_COOKIE:
Zheng Baobf29a0d2020-12-03 23:00:48 +0800546 table_size = ctx->current - bdir->header.additional_info;
547 if ((table_size % TABLE_ALIGNMENT) != 0) {
548 fprintf(stderr, "The BIOS table size should be 4K aligned\n");
549 exit(1);
550 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600551 bdir->header.cookie = cookie;
552 bdir->header.num_entries = count;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800553 bdir->header.additional_info = (table_size / 0x1000) | (1 << 10);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600554 /* checksum everything that comes after the Checksum field */
555 bdir->header.checksum = fletcher32(&bdir->header.num_entries,
556 count * sizeof(bios_directory_entry)
557 + sizeof(bdir->header.num_entries)
Zheng Baobf29a0d2020-12-03 23:00:48 +0800558 + sizeof(bdir->header.additional_info));
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600559 break;
Marshall Dawsona378c222019-03-04 16:52:07 -0700560 }
Zheng Baobf29a0d2020-12-03 23:00:48 +0800561
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800562}
563
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700564static ssize_t copy_blob(void *dest, const char *src_file, size_t room)
565{
566 int fd;
567 struct stat fd_stat;
568 ssize_t bytes;
569
570 fd = open(src_file, O_RDONLY);
571 if (fd < 0) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800572 fprintf(stderr, "Error opening file: %s: %s\n",
Eric Peersaf505672020-03-05 16:04:15 -0700573 src_file, strerror(errno));
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700574 return -1;
575 }
576
577 if (fstat(fd, &fd_stat)) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800578 fprintf(stderr, "fstat error: %s\n", strerror(errno));
Jacob Garber967f8622019-07-02 10:35:10 -0600579 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700580 return -2;
581 }
582
Zheng Bao6d402ac2020-10-01 16:16:30 +0800583 if ((size_t)fd_stat.st_size > room) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800584 fprintf(stderr, "Error: %s will not fit. Exiting.\n", src_file);
Jacob Garber967f8622019-07-02 10:35:10 -0600585 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700586 return -3;
587 }
588
589 bytes = read(fd, dest, (size_t)fd_stat.st_size);
590 close(fd);
591 if (bytes != (ssize_t)fd_stat.st_size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800592 fprintf(stderr, "Error while reading %s\n", src_file);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700593 return -4;
594 }
595
596 return bytes;
597}
598
Marshall Dawson2794a862019-03-04 16:53:15 -0700599static void integrate_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -0700600 embedded_firmware *romsig,
Marshall Dawson2794a862019-03-04 16:53:15 -0700601 amd_fw_entry *fw_table)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800602{
Richard Spiegel137484d2018-01-17 10:23:19 -0700603 ssize_t bytes;
Zheng Bao6d402ac2020-10-01 16:16:30 +0800604 uint32_t i;
Marshall Dawson2794a862019-03-04 16:53:15 -0700605
606 ctx->current += sizeof(embedded_firmware);
607 ctx->current = ALIGN(ctx->current, BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800608
Martin Rothcd15bc82016-11-08 11:34:02 -0700609 for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
zbaoc3a08a92016-03-02 14:47:27 +0800610 if (fw_table[i].filename != NULL) {
zbaoc3a08a92016-03-02 14:47:27 +0800611 switch (fw_table[i].type) {
612 case AMD_FW_IMC:
Marshall Dawson2794a862019-03-04 16:53:15 -0700613 ctx->current = ALIGN(ctx->current, 0x10000U);
614 romsig->imc_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800615 break;
616 case AMD_FW_GEC:
Marshall Dawson2794a862019-03-04 16:53:15 -0700617 romsig->gec_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800618 break;
619 case AMD_FW_XHCI:
Marshall Dawson2794a862019-03-04 16:53:15 -0700620 romsig->xhci_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800621 break;
622 default:
623 /* Error */
624 break;
625 }
626
Marshall Dawson2794a862019-03-04 16:53:15 -0700627 bytes = copy_blob(BUFF_CURRENT(*ctx),
628 fw_table[i].filename, BUFF_ROOM(*ctx));
Marshall Dawson02bd7732019-03-13 14:43:17 -0600629 if (bytes < 0) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700630 free(ctx->rom);
Martin Roth60f15512016-11-08 09:55:01 -0700631 exit(1);
632 }
633
Marshall Dawson2794a862019-03-04 16:53:15 -0700634 ctx->current = ALIGN(ctx->current + bytes,
635 BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800636 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800637 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800638}
639
Zheng Bao9e908072020-10-28 11:39:13 +0800640/* For debugging */
641static void dump_psp_firmwares(amd_fw_entry *fw_table)
642{
643 amd_fw_entry *index;
644
645 printf("PSP firmware components:");
646 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
647 if (index->filename)
648 printf(" filename=%s\n", index->filename);
649 }
650}
651
652static void dump_bdt_firmwares(amd_bios_entry *fw_table)
653{
654 amd_bios_entry *index;
655
656 printf("BIOS Directory Table (BDT) components:");
657 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
658 if (index->filename)
659 printf(" filename=%s\n", index->filename);
660 }
661}
662
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800663static void free_psp_firmware_filenames(amd_fw_entry *fw_table)
664{
665 amd_fw_entry *index;
666
667 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
668 if (index->filename &&
669 index->type != AMD_FW_VERSTAGE_SIG &&
670 index->type != AMD_FW_PSP_VERSTAGE &&
671 index->type != AMD_FW_PSP_WHITELIST) {
672 free(index->filename);
673 }
674 }
675}
676
677static void free_bdt_firmware_filenames(amd_bios_entry *fw_table)
678{
679 amd_bios_entry *index;
680
681 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
682 if (index->filename &&
683 index->type != AMD_BIOS_APCB &&
684 index->type != AMD_BIOS_BIN &&
685 index->type != AMD_BIOS_APCB_BK)
686 free(index->filename);
687 }
688}
689
Marshall Dawson2794a862019-03-04 16:53:15 -0700690static void integrate_psp_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -0700691 psp_directory_table *pspdir,
Marshall Dawson24f73d42019-04-01 10:48:43 -0600692 psp_directory_table *pspdir2,
693 amd_fw_entry *fw_table,
694 uint32_t cookie)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800695{
Richard Spiegel137484d2018-01-17 10:23:19 -0700696 ssize_t bytes;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700697 unsigned int i, count;
Marshall Dawson24f73d42019-04-01 10:48:43 -0600698 int level;
699
700 /* This function can create a primary table, a secondary table, or a
701 * flattened table which contains all applicable types. These if-else
702 * statements infer what the caller intended. If a 2nd-level cookie
703 * is passed, clearly a 2nd-level table is intended. However, a
704 * 1st-level cookie may indicate level 1 or flattened. If the caller
705 * passes a pointer to a 2nd-level table, then assume not flat.
706 */
707 if (cookie == PSPL2_COOKIE)
708 level = PSP_LVL2;
709 else if (pspdir2)
710 level = PSP_LVL1;
711 else
712 level = PSP_BOTH;
Marshall Dawson2794a862019-03-04 16:53:15 -0700713
Zheng Baobf29a0d2020-12-03 23:00:48 +0800714 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800715
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700716 for (i = 0, count = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
Marshall Dawson24f73d42019-04-01 10:48:43 -0600717 if (!(fw_table[i].level & level))
718 continue;
719
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600720 if (fw_table[i].type == AMD_TOKEN_UNLOCK) {
721 if (!fw_table[i].other)
722 continue;
723 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
724 pspdir->entries[count].type = fw_table[i].type;
725 pspdir->entries[count].size = 4096; /* TODO: doc? */
726 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
727 pspdir->entries[count].subprog = fw_table[i].subprog;
728 pspdir->entries[count].rsvd = 0;
729 ctx->current = ALIGN(ctx->current + 4096, 0x100U);
730 count++;
731 } else if (fw_table[i].type == AMD_PSP_FUSE_CHAIN) {
Marshall Dawson239286c2019-02-23 16:42:46 -0700732 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -0700733 pspdir->entries[count].subprog = fw_table[i].subprog;
734 pspdir->entries[count].rsvd = 0;
Marshall Dawson239286c2019-02-23 16:42:46 -0700735 pspdir->entries[count].size = 0xFFFFFFFF;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -0600736 pspdir->entries[count].addr = fw_table[i].other;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700737 count++;
Marshall Dawson7c1e1422019-04-11 09:44:43 -0600738 } else if (fw_table[i].type == AMD_FW_PSP_NVRAM) {
739 if (fw_table[i].filename == NULL)
740 continue;
741 /* TODO: Add a way to reserve for NVRAM without
742 * requiring a filename. This isn't a feature used
743 * by coreboot systems, so priority is very low.
744 */
745 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
746 bytes = copy_blob(BUFF_CURRENT(*ctx),
747 fw_table[i].filename, BUFF_ROOM(*ctx));
748 if (bytes <= 0) {
749 free(ctx->rom);
750 exit(1);
751 }
752
753 pspdir->entries[count].type = fw_table[i].type;
754 pspdir->entries[count].subprog = fw_table[i].subprog;
755 pspdir->entries[count].rsvd = 0;
756 pspdir->entries[count].size = ALIGN(bytes,
757 ERASE_ALIGNMENT);
758 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
759
760 ctx->current = ALIGN(ctx->current + bytes,
761 BLOB_ERASE_ALIGNMENT);
762 count++;
zbaoc3a08a92016-03-02 14:47:27 +0800763 } else if (fw_table[i].filename != NULL) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700764 bytes = copy_blob(BUFF_CURRENT(*ctx),
765 fw_table[i].filename, BUFF_ROOM(*ctx));
Marshall Dawson02bd7732019-03-13 14:43:17 -0600766 if (bytes < 0) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700767 free(ctx->rom);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700768 exit(1);
769 }
770
Marshall Dawson239286c2019-02-23 16:42:46 -0700771 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -0700772 pspdir->entries[count].subprog = fw_table[i].subprog;
773 pspdir->entries[count].rsvd = 0;
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700774 pspdir->entries[count].size = (uint32_t)bytes;
Marshall Dawson2794a862019-03-04 16:53:15 -0700775 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800776
Marshall Dawson2794a862019-03-04 16:53:15 -0700777 ctx->current = ALIGN(ctx->current + bytes,
778 BLOB_ALIGNMENT);
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700779 count++;
zbaoc3a08a92016-03-02 14:47:27 +0800780 } else {
781 /* This APU doesn't have this firmware. */
782 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800783 }
Marshall Dawson2794a862019-03-04 16:53:15 -0700784
Marshall Dawson24f73d42019-04-01 10:48:43 -0600785 if (pspdir2) {
786 pspdir->entries[count].type = AMD_FW_L2_PTR;
787 pspdir->entries[count].subprog = 0;
788 pspdir->entries[count].rsvd = 0;
789 pspdir->entries[count].size = sizeof(pspdir2->header)
790 + pspdir2->header.num_entries
791 * sizeof(psp_directory_entry);
792
793 pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, pspdir2);
794 count++;
795 }
796
Marshall Dawson2794a862019-03-04 16:53:15 -0700797 if (count > MAX_PSP_ENTRIES) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800798 fprintf(stderr, "Error: PSP entries exceed max allowed items\n");
Marshall Dawson2794a862019-03-04 16:53:15 -0700799 free(ctx->rom);
800 exit(1);
801 }
802
Zheng Baobf29a0d2020-12-03 23:00:48 +0800803 fill_dir_header(pspdir, count, cookie, ctx);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800804}
805
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600806static void *new_bios_dir(context *ctx, int multi)
807{
808 void *ptr;
809
810 /*
811 * Force both onto boundary when multi. Primary table is after
812 * updatable table, so alignment ensures primary can stay intact
813 * if secondary is reprogrammed.
814 */
815 if (multi)
816 ctx->current = ALIGN(ctx->current, TABLE_ERASE_ALIGNMENT);
817 else
818 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
819 ptr = BUFF_CURRENT(*ctx);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800820 ((bios_directory_hdr *) ptr)->additional_info = ctx->current;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600821 ctx->current += sizeof(bios_directory_hdr)
822 + MAX_BIOS_ENTRIES * sizeof(bios_directory_entry);
823 return ptr;
824}
825
826static int locate_bdt2_bios(bios_directory_table *level2,
827 uint64_t *source, uint32_t *size)
828{
Zheng Bao6d402ac2020-10-01 16:16:30 +0800829 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600830
831 *source = 0;
832 *size = 0;
833 if (!level2)
834 return 0;
835
836 for (i = 0 ; i < level2->header.num_entries ; i++) {
837 if (level2->entries[i].type == AMD_BIOS_BIN) {
838 *source = level2->entries[i].source;
839 *size = level2->entries[i].size;
840 return 1;
841 }
842 }
843 return 0;
844}
845
846static int have_bios_tables(amd_bios_entry *table)
847{
848 int i;
849
850 for (i = 0 ; table[i].type != AMD_BIOS_INVALID; i++) {
851 if (table[i].level & BDT_LVL1 && table[i].filename)
852 return 1;
853 }
854 return 0;
855}
856
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700857static int find_bios_entry(amd_bios_type type)
858{
859 int i;
860
861 for (i = 0; amd_bios_table[i].type != AMD_BIOS_INVALID; i++) {
862 if (amd_bios_table[i].type == type)
863 return i;
864 }
865 return -1;
866}
867
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600868static void integrate_bios_firmwares(context *ctx,
869 bios_directory_table *biosdir,
870 bios_directory_table *biosdir2,
871 amd_bios_entry *fw_table,
872 uint32_t cookie)
873{
874 ssize_t bytes;
Martin Rothec933132019-07-13 20:03:34 -0600875 unsigned int i, count;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600876 int level;
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700877 int apob_idx;
Martin Rotheca423b2020-09-01 10:54:11 -0600878 uint32_t size;
879 uint64_t source;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600880
881 /* This function can create a primary table, a secondary table, or a
882 * flattened table which contains all applicable types. These if-else
883 * statements infer what the caller intended. If a 2nd-level cookie
884 * is passed, clearly a 2nd-level table is intended. However, a
885 * 1st-level cookie may indicate level 1 or flattened. If the caller
886 * passes a pointer to a 2nd-level table, then assume not flat.
887 */
888 if (cookie == BDT2_COOKIE)
889 level = BDT_LVL2;
890 else if (biosdir2)
891 level = BDT_LVL1;
892 else
893 level = BDT_BOTH;
894
Zheng Baobf29a0d2020-12-03 23:00:48 +0800895 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600896
897 for (i = 0, count = 0; fw_table[i].type != AMD_BIOS_INVALID; i++) {
898 if (!(fw_table[i].level & level))
899 continue;
900 if (fw_table[i].filename == NULL && (
901 fw_table[i].type != AMD_BIOS_APOB &&
902 fw_table[i].type != AMD_BIOS_APOB_NV &&
903 fw_table[i].type != AMD_BIOS_L2_PTR &&
Martin Roth94554742020-04-14 14:59:36 -0600904 fw_table[i].type != AMD_BIOS_BIN &&
905 fw_table[i].type != AMD_BIOS_PSP_SHARED_MEM))
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600906 continue;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600907
908 /* BIOS Directory items may have additional requirements */
909
Martin Roth48dd9fe2020-07-29 16:32:25 -0600910 /* Check APOB_NV requirements */
911 if (fw_table[i].type == AMD_BIOS_APOB_NV) {
912 if (!fw_table[i].size && !fw_table[i].src)
913 continue; /* APOB_NV not used */
914 if (fw_table[i].src && !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800915 fprintf(stderr, "Error: APOB NV address provided, but no size\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600916 free(ctx->rom);
917 exit(1);
918 }
Martin Roth48dd9fe2020-07-29 16:32:25 -0600919 /* If the APOB isn't used, APOB_NV isn't used either */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700920 apob_idx = find_bios_entry(AMD_BIOS_APOB);
Martin Roth48dd9fe2020-07-29 16:32:25 -0600921 if (apob_idx < 0 || !fw_table[apob_idx].dest)
922 continue; /* APOV NV not supported */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700923 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600924
925 /* APOB_DATA needs destination */
926 if (fw_table[i].type == AMD_BIOS_APOB && !fw_table[i].dest) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800927 fprintf(stderr, "Error: APOB destination not provided\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600928 free(ctx->rom);
929 exit(1);
930 }
931
932 /* BIOS binary must have destination and uncompressed size. If
933 * no filename given, then user must provide a source address.
934 */
935 if (fw_table[i].type == AMD_BIOS_BIN) {
936 if (!fw_table[i].dest || !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800937 fprintf(stderr, "Error: BIOS binary destination and uncompressed size are required\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600938 free(ctx->rom);
939 exit(1);
940 }
941 if (!fw_table[i].filename && !fw_table[i].src) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800942 fprintf(stderr, "Error: BIOS binary assumed outside amdfw.rom but no source address given\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600943 free(ctx->rom);
944 exit(1);
945 }
946 }
947
Martin Roth94554742020-04-14 14:59:36 -0600948 /* PSP_SHARED_MEM needs a destination and size */
949 if (fw_table[i].type == AMD_BIOS_PSP_SHARED_MEM &&
950 (!fw_table[i].dest || !fw_table[i].size))
951 continue;
952
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600953 biosdir->entries[count].type = fw_table[i].type;
954 biosdir->entries[count].region_type = fw_table[i].region_type;
955 biosdir->entries[count].dest = fw_table[i].dest ?
956 fw_table[i].dest : (uint64_t)-1;
957 biosdir->entries[count].reset = fw_table[i].reset;
958 biosdir->entries[count].copy = fw_table[i].copy;
959 biosdir->entries[count].ro = fw_table[i].ro;
960 biosdir->entries[count].compressed = fw_table[i].zlib;
961 biosdir->entries[count].inst = fw_table[i].inst;
962 biosdir->entries[count].subprog = fw_table[i].subpr;
963
964 switch (fw_table[i].type) {
965 case AMD_BIOS_APOB:
966 biosdir->entries[count].size = fw_table[i].size;
967 biosdir->entries[count].source = fw_table[i].src;
968 break;
969 case AMD_BIOS_APOB_NV:
970 if (fw_table[i].src) {
971 /* If source is given, use that and its size */
972 biosdir->entries[count].source = fw_table[i].src;
973 biosdir->entries[count].size = fw_table[i].size;
974 } else {
975 /* Else reserve size bytes within amdfw.rom */
976 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
977 biosdir->entries[count].source = RUN_CURRENT(*ctx);
978 biosdir->entries[count].size = ALIGN(
979 fw_table[i].size, ERASE_ALIGNMENT);
980 memset(BUFF_CURRENT(*ctx), 0xff,
981 biosdir->entries[count].size);
982 ctx->current = ctx->current
983 + biosdir->entries[count].size;
984 }
985 break;
986 case AMD_BIOS_BIN:
987 /* Don't make a 2nd copy, point to the same one */
Martin Rotheca423b2020-09-01 10:54:11 -0600988 if (level == BDT_LVL1 && locate_bdt2_bios(biosdir2, &source, &size)) {
989 biosdir->entries[count].source = source;
990 biosdir->entries[count].size = size;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600991 break;
Martin Rotheca423b2020-09-01 10:54:11 -0600992 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600993
994 /* level 2, or level 1 and no copy found in level 2 */
995 biosdir->entries[count].source = fw_table[i].src;
996 biosdir->entries[count].dest = fw_table[i].dest;
997 biosdir->entries[count].size = fw_table[i].size;
998
999 if (!fw_table[i].filename)
1000 break;
1001
1002 bytes = copy_blob(BUFF_CURRENT(*ctx),
1003 fw_table[i].filename, BUFF_ROOM(*ctx));
1004 if (bytes <= 0) {
1005 free(ctx->rom);
1006 exit(1);
1007 }
1008
1009 biosdir->entries[count].source = RUN_CURRENT(*ctx);
1010
1011 ctx->current = ALIGN(ctx->current + bytes, 0x100U);
1012 break;
Martin Roth94554742020-04-14 14:59:36 -06001013 case AMD_BIOS_PSP_SHARED_MEM:
1014 biosdir->entries[count].dest = fw_table[i].dest;
1015 biosdir->entries[count].size = fw_table[i].size;
1016 break;
1017
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001018 default: /* everything else is copied from input */
1019 if (fw_table[i].type == AMD_BIOS_APCB ||
1020 fw_table[i].type == AMD_BIOS_APCB_BK)
1021 ctx->current = ALIGN(
1022 ctx->current, ERASE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001023 bytes = copy_blob(BUFF_CURRENT(*ctx),
1024 fw_table[i].filename, BUFF_ROOM(*ctx));
1025 if (bytes <= 0) {
1026 free(ctx->rom);
1027 exit(1);
1028 }
1029
1030 biosdir->entries[count].size = (uint32_t)bytes;
1031 biosdir->entries[count].source = RUN_CURRENT(*ctx);
1032
1033 ctx->current = ALIGN(ctx->current + bytes, 0x100U);
1034 break;
1035 }
1036
1037 count++;
1038 }
1039
1040 if (biosdir2) {
1041 biosdir->entries[count].type = AMD_BIOS_L2_PTR;
1042 biosdir->entries[count].size =
1043 + MAX_BIOS_ENTRIES
1044 * sizeof(bios_directory_entry);
1045 biosdir->entries[count].source =
1046 BUFF_TO_RUN(*ctx, biosdir2);
1047 biosdir->entries[count].subprog = 0;
1048 biosdir->entries[count].inst = 0;
1049 biosdir->entries[count].copy = 0;
1050 biosdir->entries[count].compressed = 0;
1051 biosdir->entries[count].dest = -1;
1052 biosdir->entries[count].reset = 0;
1053 biosdir->entries[count].ro = 0;
1054 count++;
1055 }
1056
1057 if (count > MAX_BIOS_ENTRIES) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001058 fprintf(stderr, "Error: BIOS entries (%d) exceeds max allowed items "
Rob Barnes18fd26c2020-03-03 10:35:02 -07001059 "(%d)\n", count, MAX_BIOS_ENTRIES);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001060 free(ctx->rom);
1061 exit(1);
1062 }
1063
Zheng Baobf29a0d2020-12-03 23:00:48 +08001064 fill_dir_header(biosdir, count, cookie, ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001065}
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001066
1067enum {
1068 /* begin after ASCII characters */
1069 LONGOPT_SPI_READ_MODE = 256,
1070 LONGOPT_SPI_SPEED = 257,
1071 LONGOPT_SPI_MICRON_FLAG = 258,
1072};
1073
Zheng Bao9e908072020-10-28 11:39:13 +08001074/* Unused values: BGJKNXYbkmprstuwyz*/
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001075static const char *optstring = "x:i:g:AMn:T:SPLUW:I:a:Q:V:e:v:j:O:F:"
Zheng Bao9e908072020-10-28 11:39:13 +08001076 "H:o:f:l:hZ:qR:C:c:E:dD";
Marc Jones90099b62016-09-20 21:05:45 -06001077
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001078static struct option long_options[] = {
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001079 {"xhci", required_argument, 0, 'x' },
1080 {"imc", required_argument, 0, 'i' },
1081 {"gec", required_argument, 0, 'g' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001082 /* PSP Directory Table items */
Marshall Dawson67d868d2019-02-28 11:43:40 -07001083 {"combo-capable", no_argument, 0, 'A' },
Marshall Dawson24f73d42019-04-01 10:48:43 -06001084 {"multilevel", no_argument, 0, 'M' },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001085 {"nvram", required_argument, 0, 'n' },
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001086 {"soft-fuse", required_argument, 0, 'T' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001087 {"token-unlock", no_argument, 0, 'U' },
1088 {"whitelist", required_argument, 0, 'W' },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001089 {"use-pspsecureos", no_argument, 0, 'S' },
1090 {"load-mp2-fw", no_argument, 0, 'p' },
1091 {"load-s0i3", no_argument, 0, 'L' },
Martin Rothd3ce8c82019-07-13 20:13:07 -06001092 {"verstage", required_argument, 0, 'Z' },
Martin Rothb1f648f2020-09-01 09:36:59 -06001093 {"verstage_sig", required_argument, 0, 'E' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001094 /* BIOS Directory Table items */
1095 {"instance", required_argument, 0, 'I' },
1096 {"apcb", required_argument, 0, 'a' },
1097 {"apob-base", required_argument, 0, 'Q' },
1098 {"bios-bin", required_argument, 0, 'V' },
1099 {"bios-bin-src", required_argument, 0, 'e' },
1100 {"bios-bin-dest", required_argument, 0, 'v' },
1101 {"bios-uncomp-size", required_argument, 0, 'j' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001102 {"ucode", required_argument, 0, 'O' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001103 {"apob-nv-base", required_argument, 0, 'F' },
1104 {"apob-nv-size", required_argument, 0, 'H' },
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001105 /* Embedded Firmware Structure items*/
1106 {"spi-read-mode", required_argument, 0, LONGOPT_SPI_READ_MODE },
1107 {"spi-speed", required_argument, 0, LONGOPT_SPI_SPEED },
1108 {"spi-micron-flag", required_argument, 0, LONGOPT_SPI_MICRON_FLAG },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001109 /* other */
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001110 {"output", required_argument, 0, 'o' },
1111 {"flashsize", required_argument, 0, 'f' },
Martin Roth0d3b1182017-10-03 14:16:04 -06001112 {"location", required_argument, 0, 'l' },
Martin Roth37305e72020-04-07 14:16:39 -06001113 {"anywhere", no_argument, 0, 'q' },
Martin Roth94554742020-04-14 14:59:36 -06001114 {"sharedmem", required_argument, 0, 'R' },
1115 {"sharedmem-size", required_argument, 0, 'P' },
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001116 {"soc-name", required_argument, 0, 'C' },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001117
1118 {"config", required_argument, 0, 'c' },
Zheng Bao9e908072020-10-28 11:39:13 +08001119 {"debug", no_argument, 0, 'd' },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001120 {"help", no_argument, 0, 'h' },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001121 {"depend", no_argument, 0, 'D' },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001122 {NULL, 0, 0, 0 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001123};
1124
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001125void register_fw_fuse(char *str)
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001126{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001127 uint32_t i;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001128
1129 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1130 if (amd_psp_fw_table[i].type != AMD_PSP_FUSE_CHAIN)
1131 continue;
1132
1133 amd_psp_fw_table[i].other = strtoull(str, NULL, 16);
1134 return;
1135 }
1136}
1137
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001138static void register_fw_token_unlock(void)
1139{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001140 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001141
1142 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1143 if (amd_psp_fw_table[i].type != AMD_TOKEN_UNLOCK)
1144 continue;
1145
1146 amd_psp_fw_table[i].other = 1;
1147 return;
1148 }
1149}
1150
Marshall Dawsondbae6322019-03-04 10:31:03 -07001151static void register_fw_filename(amd_fw_type type, uint8_t sub, char filename[])
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001152{
Martin Roth8806f7f2016-11-08 10:44:18 -07001153 unsigned int i;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001154
Martin Rothcd15bc82016-11-08 11:34:02 -07001155 for (i = 0; i < sizeof(amd_fw_table) / sizeof(amd_fw_entry); i++) {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001156 if (amd_fw_table[i].type == type) {
1157 amd_fw_table[i].filename = filename;
1158 return;
1159 }
1160 }
1161
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001162 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
Marshall Dawsondbae6322019-03-04 10:31:03 -07001163 if (amd_psp_fw_table[i].type != type)
1164 continue;
1165
1166 if (amd_psp_fw_table[i].subprog == sub) {
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001167 amd_psp_fw_table[i].filename = filename;
1168 return;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001169 }
1170 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001171}
1172
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001173static void register_bdt_data(amd_bios_type type, int sub, int ins, char name[])
1174{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001175 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001176
1177 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
1178 if (amd_bios_table[i].type == type
1179 && amd_bios_table[i].inst == ins
1180 && amd_bios_table[i].subpr == sub) {
1181 amd_bios_table[i].filename = name;
1182 return;
1183 }
1184 }
1185}
1186
Martin Rothec933132019-07-13 20:03:34 -06001187static void register_fw_addr(amd_bios_type type, char *src_str,
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001188 char *dst_str, char *size_str)
1189{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001190 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001191 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
1192 if (amd_bios_table[i].type != type)
1193 continue;
1194
1195 if (src_str)
1196 amd_bios_table[i].src = strtoull(src_str, NULL, 16);
1197 if (dst_str)
1198 amd_bios_table[i].dest = strtoull(dst_str, NULL, 16);
1199 if (size_str)
1200 amd_bios_table[i].size = strtoul(size_str, NULL, 16);
1201
1202 return;
1203 }
1204}
1205
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001206enum platform {
1207 PLATFORM_UNKNOWN,
1208 PLATFORM_STONEYRIDGE,
1209 PLATFORM_RAVEN,
1210 PLATFORM_PICASSO,
1211 PLATFORM_RENOIR,
Zheng Baobf29a0d2020-12-03 23:00:48 +08001212 PLATFORM_CEZANNE,
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001213 PLATFORM_LUCIENNE,
1214};
1215
1216static int set_efs_table(uint8_t soc_id, embedded_firmware *amd_romsig,
1217 uint8_t efs_spi_readmode, uint8_t efs_spi_speed,
1218 uint8_t efs_spi_micron_flag)
1219{
1220 if ((efs_spi_readmode == 0xFF) || (efs_spi_speed == 0xFF)) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001221 fprintf(stderr, "Error: EFS read mode and SPI speed must be set\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001222 return 1;
1223 }
1224 switch (soc_id) {
1225 case PLATFORM_STONEYRIDGE:
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001226 amd_romsig->spi_readmode_f15_mod_60_6f = efs_spi_readmode;
1227 amd_romsig->fast_speed_new_f15_mod_60_6f = efs_spi_speed;
1228 break;
1229 case PLATFORM_RAVEN:
1230 case PLATFORM_PICASSO:
Marshall Dawson13ec0292020-11-19 14:02:29 -07001231 /* amd_romsig->efs_gen introduced after RAVEN/PICASSO.
1232 * Leave as 0xffffffff for first gen */
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001233 amd_romsig->spi_readmode_f17_mod_00_2f = efs_spi_readmode;
1234 amd_romsig->spi_fastspeed_f17_mod_00_2f = efs_spi_speed;
1235 switch (efs_spi_micron_flag) {
1236 case 0:
1237 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xff;
1238 break;
1239 case 1:
1240 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xa;
1241 break;
1242 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001243 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001244 return 1;
1245 }
1246 break;
1247 case PLATFORM_RENOIR:
1248 case PLATFORM_LUCIENNE:
Zheng Baobf29a0d2020-12-03 23:00:48 +08001249 case PLATFORM_CEZANNE:
Marshall Dawson13ec0292020-11-19 14:02:29 -07001250 amd_romsig->efs_gen.gen = EFS_SECOND_GEN;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001251 amd_romsig->spi_readmode_f17_mod_30_3f = efs_spi_readmode;
1252 amd_romsig->spi_fastspeed_f17_mod_30_3f = efs_spi_speed;
1253 switch (efs_spi_micron_flag) {
1254 case 0:
1255 amd_romsig->micron_detect_f17_mod_30_3f = 0xff;
1256 break;
1257 case 1:
1258 amd_romsig->micron_detect_f17_mod_30_3f = 0xaa;
1259 break;
1260 case 2:
1261 amd_romsig->micron_detect_f17_mod_30_3f = 0x55;
1262 break;
1263 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001264 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001265 return 1;
1266 }
1267 break;
1268 case PLATFORM_UNKNOWN:
1269 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001270 fprintf(stderr, "Error: Invalid SOC name.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001271 return 1;
1272 }
1273 return 0;
1274}
1275
1276static int identify_platform(char *soc_name)
1277{
1278 if (!strcasecmp(soc_name, "Stoneyridge"))
1279 return PLATFORM_STONEYRIDGE;
1280 else if (!strcasecmp(soc_name, "Raven"))
1281 return PLATFORM_RAVEN;
1282 else if (!strcasecmp(soc_name, "Picasso"))
1283 return PLATFORM_PICASSO;
Zheng Baobf29a0d2020-12-03 23:00:48 +08001284 else if (!strcasecmp(soc_name, "Cezanne"))
1285 return PLATFORM_CEZANNE;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001286 else if (!strcasecmp(soc_name, "Renoir"))
1287 return PLATFORM_RENOIR;
1288 else if (!strcasecmp(soc_name, "Lucienne"))
1289 return PLATFORM_LUCIENNE;
1290 else
1291 return PLATFORM_UNKNOWN;
1292
1293}
1294
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001295int main(int argc, char **argv)
1296{
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001297 int c;
Martin Roth31d95a22016-11-08 11:22:12 -07001298 int retval = 0;
Martin Roth60f15512016-11-08 09:55:01 -07001299 char *tmp;
Martin Roth8806f7f2016-11-08 10:44:18 -07001300 char *rom = NULL;
Marshall Dawson239286c2019-02-23 16:42:46 -07001301 embedded_firmware *amd_romsig;
1302 psp_directory_table *pspdir;
Marshall Dawson67d868d2019-02-28 11:43:40 -07001303 int comboable = 0;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001304 int fuse_defined = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001305 int targetfd;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001306 char *output = NULL, *config = NULL;
1307 FILE *config_handle;
Zheng Bao9c8ce3e2020-09-28 10:36:29 +08001308 context ctx = { 0 };
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001309 /* Values cleared after each firmware or parameter, regardless if N/A */
1310 uint8_t sub = 0, instance = 0;
Martin Roth0d3b1182017-10-03 14:16:04 -06001311 uint32_t dir_location = 0;
Martin Roth37305e72020-04-07 14:16:39 -06001312 bool any_location = 0;
Martin Roth0d3b1182017-10-03 14:16:04 -06001313 uint32_t romsig_offset;
Martin Roth60f15512016-11-08 09:55:01 -07001314 uint32_t rom_base_address;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001315 uint8_t soc_id = PLATFORM_UNKNOWN;
1316 uint8_t efs_spi_readmode = 0xff;
1317 uint8_t efs_spi_speed = 0xff;
1318 uint8_t efs_spi_micron_flag = 0xff;
1319
Marshall Dawson24f73d42019-04-01 10:48:43 -06001320 int multi = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001321 amd_cb_config cb_config;
Zheng Bao9e908072020-10-28 11:39:13 +08001322 int debug = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001323 int list_deps = 0;
1324
1325 cb_config.have_whitelist = 0;
1326 cb_config.unlock_secure = 0;
1327 cb_config.use_secureos = 0;
1328 cb_config.load_mp2_fw = 0;
1329 cb_config.s0i3 = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001330
1331 while (1) {
1332 int optindex = 0;
1333
1334 c = getopt_long(argc, argv, optstring, long_options, &optindex);
1335
1336 if (c == -1)
1337 break;
1338
1339 switch (c) {
1340 case 'x':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001341 register_fw_filename(AMD_FW_XHCI, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001342 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001343 break;
1344 case 'i':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001345 register_fw_filename(AMD_FW_IMC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001346 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001347 break;
1348 case 'g':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001349 register_fw_filename(AMD_FW_GEC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001350 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001351 break;
Marshall Dawson67d868d2019-02-28 11:43:40 -07001352 case 'A':
1353 comboable = 1;
1354 break;
Marshall Dawson24f73d42019-04-01 10:48:43 -06001355 case 'M':
1356 multi = 1;
1357 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001358 case 'U':
1359 register_fw_token_unlock();
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001360 cb_config.unlock_secure = 1;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001361 sub = instance = 0;
1362 break;
Marshall Dawsondbae6322019-03-04 10:31:03 -07001363 case 'S':
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001364 cb_config.use_secureos = 1;
Marshall Dawsondbae6322019-03-04 10:31:03 -07001365 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001366 case 'I':
1367 instance = strtoul(optarg, &tmp, 16);
1368 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001369 case 'p':
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001370 cb_config.load_mp2_fw = 1;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001371 break;
1372 case 'n':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001373 register_fw_filename(AMD_FW_PSP_NVRAM, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001374 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001375 break;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001376 case 'T':
1377 register_fw_fuse(optarg);
1378 fuse_defined = 1;
1379 sub = 0;
1380 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001381 case 'a':
Zheng Bao5caca942020-12-04 16:39:38 +08001382 if ((instance & 0xF0) == 0)
1383 register_bdt_data(AMD_BIOS_APCB, sub, instance & 0xF, optarg);
1384 else
1385 register_bdt_data(AMD_BIOS_APCB_BK, sub,
1386 instance & 0xF, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001387 sub = instance = 0;
1388 break;
1389 case 'Q':
1390 /* APOB destination */
1391 register_fw_addr(AMD_BIOS_APOB, 0, optarg, 0);
1392 sub = instance = 0;
1393 break;
1394 case 'F':
1395 /* APOB NV source */
1396 register_fw_addr(AMD_BIOS_APOB_NV, optarg, 0, 0);
1397 sub = instance = 0;
1398 break;
1399 case 'H':
1400 /* APOB NV size */
1401 register_fw_addr(AMD_BIOS_APOB_NV, 0, 0, optarg);
1402 sub = instance = 0;
1403 break;
1404 case 'V':
1405 register_bdt_data(AMD_BIOS_BIN, sub, instance, optarg);
1406 sub = instance = 0;
1407 break;
1408 case 'e':
1409 /* BIOS source */
1410 register_fw_addr(AMD_BIOS_BIN, optarg, 0, 0);
1411 sub = instance = 0;
1412 break;
1413 case 'v':
1414 /* BIOS destination */
1415 register_fw_addr(AMD_BIOS_BIN, 0, optarg, 0);
1416 sub = instance = 0;
1417 break;
1418 case 'j':
1419 /* BIOS destination size */
1420 register_fw_addr(AMD_BIOS_BIN, 0, 0, optarg);
1421 sub = instance = 0;
1422 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001423 case 'O':
1424 register_bdt_data(AMD_BIOS_UCODE, sub,
1425 instance, optarg);
1426 sub = instance = 0;
1427 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001428 case 'L':
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001429 cb_config.s0i3 = 1;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001430 break;
1431 case 'W':
1432 register_fw_filename(AMD_FW_PSP_WHITELIST, sub, optarg);
1433 sub = instance = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001434 cb_config.have_whitelist = 1;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001435 break;
Martin Rothd3ce8c82019-07-13 20:13:07 -06001436 case 'Z':
1437 register_fw_filename(AMD_FW_PSP_VERSTAGE, sub, optarg);
1438 sub = instance = 0;
1439 break;
Martin Rothb1f648f2020-09-01 09:36:59 -06001440 case 'E':
1441 register_fw_filename(AMD_FW_VERSTAGE_SIG, sub, optarg);
1442 sub = instance = 0;
1443 break;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001444 case 'C':
1445 soc_id = identify_platform(optarg);
1446 if (soc_id == PLATFORM_UNKNOWN) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001447 fprintf(stderr, "Error: Invalid SOC name specified\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001448 retval = 1;
1449 }
1450 sub = instance = 0;
1451 break;
1452 case LONGOPT_SPI_READ_MODE:
1453 efs_spi_readmode = strtoull(optarg, NULL, 16);
1454 sub = instance = 0;
1455 break;
1456 case LONGOPT_SPI_SPEED:
1457 efs_spi_speed = strtoull(optarg, NULL, 16);
1458 sub = instance = 0;
1459 break;
1460 case LONGOPT_SPI_MICRON_FLAG:
1461 efs_spi_micron_flag = strtoull(optarg, NULL, 16);
1462 sub = instance = 0;
1463 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001464 case 'o':
1465 output = optarg;
1466 break;
Martin Roth60f15512016-11-08 09:55:01 -07001467 case 'f':
Marshall Dawson2794a862019-03-04 16:53:15 -07001468 ctx.rom_size = (uint32_t)strtoul(optarg, &tmp, 16);
Martin Roth60f15512016-11-08 09:55:01 -07001469 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08001470 fprintf(stderr, "Error: ROM size specified"
Martin Roth60f15512016-11-08 09:55:01 -07001471 " incorrectly (%s)\n\n", optarg);
Martin Roth31d95a22016-11-08 11:22:12 -07001472 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07001473 }
1474 break;
Martin Roth0d3b1182017-10-03 14:16:04 -06001475 case 'l':
1476 dir_location = (uint32_t)strtoul(optarg, &tmp, 16);
1477 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08001478 fprintf(stderr, "Error: Directory Location specified"
Martin Roth0d3b1182017-10-03 14:16:04 -06001479 " incorrectly (%s)\n\n", optarg);
1480 retval = 1;
1481 }
1482 break;
Martin Roth37305e72020-04-07 14:16:39 -06001483 case 'q':
1484 any_location = 1;
1485 break;
Martin Roth94554742020-04-14 14:59:36 -06001486 case 'R':
1487 /* shared memory destination */
1488 register_fw_addr(AMD_BIOS_PSP_SHARED_MEM, 0, optarg, 0);
1489 sub = instance = 0;
1490 break;
1491 case 'P':
1492 /* shared memory size */
1493 register_fw_addr(AMD_BIOS_PSP_SHARED_MEM, NULL, NULL, optarg);
1494 sub = instance = 0;
1495 break;
Martin Roth0d3b1182017-10-03 14:16:04 -06001496
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001497 case 'c':
1498 config = optarg;
1499 break;
Zheng Bao9e908072020-10-28 11:39:13 +08001500 case 'd':
1501 debug = 1;
1502 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001503 case 'h':
1504 usage();
Martin Roth31d95a22016-11-08 11:22:12 -07001505 return 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001506 case 'D':
1507 list_deps = 1;
1508 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001509 default:
1510 break;
1511 }
1512 }
1513
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001514 if (config) {
1515 config_handle = fopen(config, "r");
1516 if (config_handle == NULL) {
1517 fprintf(stderr, "Can not open file %s for reading: %s\n",
1518 config, strerror(errno));
1519 exit(1);
1520 }
1521 if (process_config(config_handle, &cb_config, list_deps) == 0) {
1522 fprintf(stderr, "Configuration file %s parsing error\n", config);
1523 fclose(config_handle);
1524 exit(1);
1525 }
1526 fclose(config_handle);
1527 }
Zheng Bao9e908072020-10-28 11:39:13 +08001528 /* For debug. */
1529 if (debug) {
1530 dump_psp_firmwares(amd_psp_fw_table);
1531 dump_bdt_firmwares(amd_bios_table);
1532 }
1533
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001534 if (!fuse_defined)
1535 register_fw_fuse(DEFAULT_SOFT_FUSE_CHAIN);
1536
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001537 if (!output && !list_deps) {
1538 fprintf(stderr, "Error: Output value is not specified.\n\n");
Martin Roth31d95a22016-11-08 11:22:12 -07001539 retval = 1;
1540 }
1541
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001542 if ((ctx.rom_size % 1024 != 0) && !list_deps) {
1543 fprintf(stderr, "Error: ROM Size (%d bytes) should be a multiple of"
Marshall Dawson2794a862019-03-04 16:53:15 -07001544 " 1024 bytes.\n\n", ctx.rom_size);
Martin Roth31d95a22016-11-08 11:22:12 -07001545 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07001546 }
1547
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001548 if ((ctx.rom_size < MIN_ROM_KB * 1024) && !list_deps) {
1549 fprintf(stderr, "Error: ROM Size (%dKB) must be at least %dKB.\n\n",
Marshall Dawson2794a862019-03-04 16:53:15 -07001550 ctx.rom_size / 1024, MIN_ROM_KB);
Martin Roth31d95a22016-11-08 11:22:12 -07001551 retval = 1;
1552 }
1553
1554 if (retval) {
1555 usage();
1556 return retval;
Martin Roth60f15512016-11-08 09:55:01 -07001557 }
1558
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001559 if (list_deps) {
1560 return retval;
1561 }
1562
Marshall Dawson2794a862019-03-04 16:53:15 -07001563 printf(" AMDFWTOOL Using ROM size of %dKB\n", ctx.rom_size / 1024);
Martin Roth60f15512016-11-08 09:55:01 -07001564
Marshall Dawson2794a862019-03-04 16:53:15 -07001565 rom_base_address = 0xFFFFFFFF - ctx.rom_size + 1;
Martin Roth0d3b1182017-10-03 14:16:04 -06001566 if (dir_location && (dir_location < rom_base_address)) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001567 fprintf(stderr, "Error: Directory location outside of ROM.\n\n");
Martin Roth0d3b1182017-10-03 14:16:04 -06001568 return 1;
1569 }
1570
Martin Roth37305e72020-04-07 14:16:39 -06001571 if (any_location) {
1572 if (dir_location & 0x3f) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001573 fprintf(stderr, "Error: Invalid Directory location.\n");
1574 fprintf(stderr, " Valid locations are 64-byte aligned\n");
Martin Roth37305e72020-04-07 14:16:39 -06001575 return 1;
1576 }
1577 } else {
1578 switch (dir_location) {
1579 case 0: /* Fall through */
1580 case 0xFFFA0000: /* Fall through */
1581 case 0xFFF20000: /* Fall through */
1582 case 0xFFE20000: /* Fall through */
1583 case 0xFFC20000: /* Fall through */
1584 case 0xFF820000: /* Fall through */
1585 case 0xFF020000: /* Fall through */
1586 break;
1587 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001588 fprintf(stderr, "Error: Invalid Directory location.\n");
1589 fprintf(stderr, " Valid locations are 0xFFFA0000, 0xFFF20000,\n");
1590 fprintf(stderr, " 0xFFE20000, 0xFFC20000, 0xFF820000, 0xFF020000\n");
Martin Roth37305e72020-04-07 14:16:39 -06001591 return 1;
1592 }
Martin Roth0d3b1182017-10-03 14:16:04 -06001593 }
Marshall Dawson2794a862019-03-04 16:53:15 -07001594 ctx.rom = malloc(ctx.rom_size);
1595 if (!ctx.rom) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001596 fprintf(stderr, "Error: Failed to allocate memory\n");
Martin Roth31d95a22016-11-08 11:22:12 -07001597 return 1;
Marshall Dawson2794a862019-03-04 16:53:15 -07001598 }
1599 memset(ctx.rom, 0xFF, ctx.rom_size);
Martin Roth60f15512016-11-08 09:55:01 -07001600
Martin Roth0d3b1182017-10-03 14:16:04 -06001601 if (dir_location)
Marshall Dawson2794a862019-03-04 16:53:15 -07001602 romsig_offset = ctx.current = dir_location - rom_base_address;
Martin Roth0d3b1182017-10-03 14:16:04 -06001603 else
Marshall Dawson2794a862019-03-04 16:53:15 -07001604 romsig_offset = ctx.current = AMD_ROMSIG_OFFSET;
1605 printf(" AMDFWTOOL Using firmware directory location of 0x%08x\n",
1606 RUN_CURRENT(ctx));
Martin Roth0d3b1182017-10-03 14:16:04 -06001607
Marshall Dawson2794a862019-03-04 16:53:15 -07001608 amd_romsig = BUFF_OFFSET(ctx, romsig_offset);
Marshall Dawson239286c2019-02-23 16:42:46 -07001609 amd_romsig->signature = EMBEDDED_FW_SIGNATURE;
1610 amd_romsig->imc_entry = 0;
1611 amd_romsig->gec_entry = 0;
1612 amd_romsig->xhci_entry = 0;
Martin Roth60f15512016-11-08 09:55:01 -07001613
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001614 if (soc_id != PLATFORM_UNKNOWN) {
1615 retval = set_efs_table(soc_id, amd_romsig, efs_spi_readmode,
1616 efs_spi_speed, efs_spi_micron_flag);
1617 if (retval) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001618 fprintf(stderr, "ERROR: Failed to initialize EFS table!\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001619 return retval;
1620 }
1621 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08001622 fprintf(stderr, "WARNING: No SOC name specified.\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001623 }
1624
Marshall Dawson2794a862019-03-04 16:53:15 -07001625 integrate_firmwares(&ctx, amd_romsig, amd_fw_table);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001626
Patrick Georgi900a2542020-02-17 16:52:40 +01001627 ctx.current = ALIGN(ctx.current, 0x10000U); /* TODO: is it necessary? */
Marshall Dawson2794a862019-03-04 16:53:15 -07001628
Marshall Dawson24f73d42019-04-01 10:48:43 -06001629 if (multi) {
1630 /* Do 2nd PSP directory followed by 1st */
1631 psp_directory_table *pspdir2 = new_psp_dir(&ctx, multi);
1632 integrate_psp_firmwares(&ctx, pspdir2, 0,
1633 amd_psp_fw_table, PSPL2_COOKIE);
1634
1635 pspdir = new_psp_dir(&ctx, multi);
1636 integrate_psp_firmwares(&ctx, pspdir, pspdir2,
1637 amd_psp_fw_table, PSP_COOKIE);
1638 } else {
1639 /* flat: PSP 1 cookie and no pointer to 2nd table */
1640 pspdir = new_psp_dir(&ctx, multi);
1641 integrate_psp_firmwares(&ctx, pspdir, 0,
1642 amd_psp_fw_table, PSP_COOKIE);
1643 }
Marshall Dawson2794a862019-03-04 16:53:15 -07001644
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001645 if (comboable)
Marshall Dawson2794a862019-03-04 16:53:15 -07001646 amd_romsig->comboable = BUFF_TO_RUN(ctx, pspdir);
Marshall Dawson67d868d2019-02-28 11:43:40 -07001647 else
Marshall Dawson2794a862019-03-04 16:53:15 -07001648 amd_romsig->psp_entry = BUFF_TO_RUN(ctx, pspdir);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001649
zbaoc3a08a92016-03-02 14:47:27 +08001650#if PSP_COMBO
Marshall Dawson2794a862019-03-04 16:53:15 -07001651 psp_combo_directory *combo_dir = new_combo_dir(&ctx);
1652 amd_romsig->comboable = BUFF_TO_RUN(ctx, combo_dir);
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001653 /* 0 -Compare PSP ID, 1 -Compare chip family ID */
1654 combo_dir->entries[0].id_sel = 0;
1655 /* TODO: PSP ID. Documentation is needed. */
1656 combo_dir->entries[0].id = 0x10220B00;
Marshall Dawson2794a862019-03-04 16:53:15 -07001657 combo_dir->entries[0].lvl2_addr = BUFF_TO_RUN(ctx, pspdir);
Zheng Bao4fcc9f22015-11-20 12:29:04 +08001658
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001659 combo_dir->header.lookup = 1;
Zheng Baobf29a0d2020-12-03 23:00:48 +08001660 fill_dir_header(combo_dir, 1, PSP2_COOKIE, NULL);
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001661#endif
Zheng Bao4fcc9f22015-11-20 12:29:04 +08001662
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001663 if (have_bios_tables(amd_bios_table)) {
1664 bios_directory_table *biosdir;
1665 if (multi) {
1666 /* Do 2nd level BIOS directory followed by 1st */
1667 bios_directory_table *biosdir2 =
1668 new_bios_dir(&ctx, multi);
1669 integrate_bios_firmwares(&ctx, biosdir2, 0,
1670 amd_bios_table, BDT2_COOKIE);
1671
1672 biosdir = new_bios_dir(&ctx, multi);
1673 integrate_bios_firmwares(&ctx, biosdir, biosdir2,
1674 amd_bios_table, BDT1_COOKIE);
1675 } else {
1676 /* flat: BDT1 cookie and no pointer to 2nd table */
1677 biosdir = new_bios_dir(&ctx, multi);
1678 integrate_bios_firmwares(&ctx, biosdir, 0,
1679 amd_bios_table, BDT1_COOKIE);
1680 }
Zheng Baobf29a0d2020-12-03 23:00:48 +08001681 switch (soc_id) {
1682 case PLATFORM_RENOIR:
1683 case PLATFORM_LUCIENNE:
1684 case PLATFORM_CEZANNE:
1685 amd_romsig->bios3_entry = BUFF_TO_RUN(ctx, biosdir);
1686 break;
1687 case PLATFORM_STONEYRIDGE:
1688 case PLATFORM_RAVEN:
1689 case PLATFORM_PICASSO:
1690 default:
1691 amd_romsig->bios1_entry = BUFF_TO_RUN(ctx, biosdir);
1692 break;
1693 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001694 }
1695
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001696 /* Free the filename. */
1697 free_psp_firmware_filenames(amd_psp_fw_table);
1698 free_bdt_firmware_filenames(amd_bios_table);
1699
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001700 targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666);
Martin Roth31d95a22016-11-08 11:22:12 -07001701 if (targetfd >= 0) {
Zheng Bao47396912020-09-29 17:33:17 +08001702 ssize_t bytes;
1703 bytes = write(targetfd, amd_romsig, ctx.current - romsig_offset);
1704 if (bytes != ctx.current - romsig_offset) {
1705 fprintf(stderr, "Error: Writing to file %s failed\n", output);
1706 retval = 1;
1707 }
Martin Roth31d95a22016-11-08 11:22:12 -07001708 close(targetfd);
1709 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08001710 fprintf(stderr, "Error: could not open file: %s\n", output);
Martin Roth31d95a22016-11-08 11:22:12 -07001711 retval = 1;
1712 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001713
Martin Roth31d95a22016-11-08 11:22:12 -07001714 free(rom);
1715 return retval;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001716}