blob: 049755b6a8001bc672161339b75c187ce585b9ef [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
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080077/*
Marshall Dawson0e02ce82019-03-04 16:50:37 -070078 * Beginning with Family 15h Models 70h-7F, a.k.a Stoney Ridge, the PSP
79 * can support an optional "combo" implementation. If the PSP sees the
80 * PSP2 cookie, it interprets the table as a roadmap to additional PSP
81 * tables. Using this, support for multiple product generations may be
82 * built into one image. If the PSP$ cookie is found, the table is a
83 * normal directory table.
84 *
85 * Modern generations supporting the combo directories require the
86 * pointer to be at offset 0x14 of the Embedded Firmware Structure,
87 * regardless of the type of directory used. The --combo-capable
88 * argument enforces this placement.
89 *
90 * TODO: Future work may require fully implementing the PSP_COMBO feature.
zbaoc3b0b722016-02-19 13:47:31 +080091 */
Marshall Dawson0e02ce82019-03-04 16:50:37 -070092#define PSP_COMBO 0
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080093
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080094/*
95 * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
96 * The checksum field of the passed PDU does not need to be reset to zero.
97 *
98 * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of
99 * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an
100 * alternative to cyclical redundancy checks because it provides error-
101 * detection properties similar to cyclical redundancy checks but at the
102 * cost of a simple summation technique. Its characteristics were first
103 * published in IEEE Transactions on Communications in January 1982. One
104 * version has been adopted by ISO for use in the class-4 transport layer
105 * of the network protocol.
106 *
107 * This program expects:
108 * stdin: The input file to compute a checksum for. The input file
109 * not be longer than 256 bytes.
110 * stdout: Copied from the input file with the Fletcher's Checksum
111 * inserted 8 bytes after the beginning of the file.
112 * stderr: Used to print out error messages.
113 */
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700114static uint32_t fletcher32(const void *data, int length)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800115{
116 uint32_t c0;
117 uint32_t c1;
118 uint32_t checksum;
119 int index;
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700120 const uint16_t *pptr = data;
121
122 length /= 2;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800123
124 c0 = 0xFFFF;
125 c1 = 0xFFFF;
126
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600127 while (length) {
128 index = length >= 359 ? 359 : length;
129 length -= index;
130 do {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800131 c0 += *(pptr++);
132 c1 += c0;
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600133 } while (--index);
134 c0 = (c0 & 0xFFFF) + (c0 >> 16);
135 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800136 }
137
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700138 /* Sums[0,1] mod 64K + overflow */
139 c0 = (c0 & 0xFFFF) + (c0 >> 16);
140 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800141 checksum = (c1 << 16) | c0;
142
143 return checksum;
144}
145
Martin Roth8806f7f2016-11-08 10:44:18 -0700146static void usage(void)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800147{
Martin Roth0e940622016-11-08 10:37:53 -0700148 printf("amdfwtool: Create AMD Firmware combination\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800149 printf("Usage: amdfwtool [options] --flashsize <size> --output <filename>\n");
150 printf("--xhci <FILE> Add XHCI blob\n");
151 printf("--imc <FILE> Add IMC blob\n");
152 printf("--gec <FILE> Add GEC blob\n");
Martin Roth0e940622016-11-08 10:37:53 -0700153
154 printf("\nPSP options:\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800155 printf("--combo-capable Place PSP directory pointer at Embedded\n");
156 printf(" Firmware\n");
Marshall Dawson67d868d2019-02-28 11:43:40 -0700157 printf(" offset able to support combo directory\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800158 printf("--multilevel Generate primary and secondary tables\n");
159 printf("--nvram <FILE> Add nvram binary\n");
160 printf("--soft-fuse Set soft fuse\n");
161 printf("--token-unlock Set token unlock\n");
162 printf("--whitelist Set if there is a whitelist\n");
163 printf("--use-pspsecureos Set if psp secure OS is needed\n");
164 printf("--load-mp2-fw Set if load MP2 firmware\n");
165 printf("--load-s0i3 Set if load s0i3 firmware\n");
166 printf("--verstage <FILE> Add verstage\n");
167 printf("--verstage_sig Add verstage signature\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600168 printf("\nBIOS options:\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800169 printf("--instance <number> Sets instance field for the next BIOS\n");
Zheng Bao6f0b3612021-04-27 17:19:43 +0800170 printf(" firmware\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800171 printf("--apcb <FILE> Add AGESA PSP customization block\n");
172 printf("--apob-base <HEX_VAL> Destination for AGESA PSP output block\n");
173 printf("--apob-nv-base <HEX_VAL> Location of S3 resume data\n");
174 printf("--apob-nv-size <HEX_VAL> Size of S3 resume data\n");
175 printf("--ucode <FILE> Add microcode patch\n");
176 printf("--bios-bin <FILE> Add compressed image; auto source address\n");
177 printf("--bios-bin-src <HEX_VAL> Address in flash of source if -V not used\n");
178 printf("--bios-bin-dest <HEX_VAL> Destination for uncompressed BIOS\n");
179 printf("--bios-uncomp-size <HEX> Uncompressed size of BIOS image\n");
180 printf("--output <filename> output filename\n");
181 printf("--flashsize <HEX_VAL> ROM size in bytes\n");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600182 printf(" size must be larger than %dKB\n",
Martin Roth0e940622016-11-08 10:37:53 -0700183 MIN_ROM_KB);
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600184 printf(" and must a multiple of 1024\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800185 printf("--location Location of Directory\n");
186 printf("--anywhere Use any 64-byte aligned addr for Directory\n");
187 printf("--sharedmem Location of PSP/FW shared memory\n");
188 printf("--sharedmem-size Maximum size of the PSP/FW shared memory\n");
Zheng Bao6f0b3612021-04-27 17:19:43 +0800189 printf(" area\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800190 printf("--soc-name <socname> Specify SOC name. Supported names are\n");
Zheng Bao6f0b3612021-04-27 17:19:43 +0800191 printf(" Stoneyridge, Raven, Picasso, Renoir, Cezanne\n");
192 printf(" or Lucienne\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500193 printf("\nEmbedded Firmware Structure options used by the PSP:\n");
194 printf("--spi-speed <HEX_VAL> SPI fast speed to place in EFS Table\n");
195 printf(" 0x0 66.66Mhz\n");
196 printf(" 0x1 33.33MHz\n");
197 printf(" 0x2 22.22MHz\n");
198 printf(" 0x3 16.66MHz\n");
199 printf(" 0x4 100MHz\n");
200 printf(" 0x5 800KHz\n");
201 printf("--spi-read-mode <HEX_VAL> SPI read mode to place in EFS Table\n");
202 printf(" 0x0 Normal Read (up to 33M)\n");
203 printf(" 0x1 Reserved\n");
204 printf(" 0x2 Dual IO (1-1-2)\n");
205 printf(" 0x3 Quad IO (1-1-4)\n");
206 printf(" 0x4 Dual IO (1-2-2)\n");
207 printf(" 0x5 Quad IO (1-4-4)\n");
208 printf(" 0x6 Normal Read (up to 66M)\n");
209 printf(" 0x7 Fast Read\n");
210 printf("--spi-micron-flag <HEX_VAL> Micron SPI part support for RV and later SOC\n");
211 printf(" 0x0 Micron parts are not used\n");
212 printf(" 0x1 Micron parts are always used\n");
213 printf(" 0x2 Micron parts optional, this option is only\n");
214 printf(" supported with RN/LCN SOC\n");
Zheng Bao806892a2021-04-27 17:21:54 +0800215 printf("\nGeneral options:\n");
216 printf("-c|--config <config file> Config file\n");
217 printf("-d|--debug Print debug message\n");
218 printf("-l|--list List out the firmware files\n");
219 printf("-h|--help Show this help\n");
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800220}
221
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800222amd_fw_entry amd_psp_fw_table[] = {
Marshall Dawson24f73d42019-04-01 10:48:43 -0600223 { .type = AMD_FW_PSP_PUBKEY, .level = PSP_BOTH },
224 { .type = AMD_FW_PSP_BOOTLOADER, .level = PSP_BOTH },
225 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 0, .level = PSP_BOTH },
226 { .type = AMD_FW_PSP_RECOVERY, .level = PSP_LVL1 },
227 { .type = AMD_FW_PSP_RTM_PUBKEY, .level = PSP_BOTH },
228 { .type = AMD_FW_PSP_SECURED_OS, .level = PSP_LVL2 },
229 { .type = AMD_FW_PSP_NVRAM, .level = PSP_LVL2 },
230 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 2, .level = PSP_BOTH },
231 { .type = AMD_FW_PSP_SECURED_DEBUG, .level = PSP_LVL2 },
232 { .type = AMD_FW_PSP_TRUSTLETS, .level = PSP_LVL2 },
233 { .type = AMD_FW_PSP_TRUSTLETKEY, .level = PSP_LVL2 },
234 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 2, .level = PSP_BOTH },
235 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
236 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
237 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .level = PSP_BOTH },
238 { .type = AMD_FW_PSP_SMUSCS, .level = PSP_BOTH },
239 { .type = AMD_PSP_FUSE_CHAIN, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600240 { .type = AMD_DEBUG_UNLOCK, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800241 { .type = AMD_HW_IPCFG, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600242 { .type = AMD_WRAPPED_IKEK, .level = PSP_BOTH },
243 { .type = AMD_TOKEN_UNLOCK, .level = PSP_BOTH },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800244 { .type = AMD_SEC_GASKET, .subprog = 0, .level = PSP_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600245 { .type = AMD_SEC_GASKET, .subprog = 2, .level = PSP_BOTH },
246 { .type = AMD_SEC_GASKET, .subprog = 1, .level = PSP_BOTH },
247 { .type = AMD_MP2_FW, .subprog = 2, .level = PSP_LVL2 },
248 { .type = AMD_MP2_FW, .subprog = 1, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800249 { .type = AMD_MP2_FW, .subprog = 0, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600250 { .type = AMD_DRIVER_ENTRIES, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800251 { .type = AMD_FW_KVM_IMAGE, .level = PSP_LVL2},
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600252 { .type = AMD_S0I3_DRIVER, .level = PSP_LVL2 },
Zheng Baobf29a0d2020-12-03 23:00:48 +0800253 { .type = AMD_VBIOS_BTLOADER, .level = PSP_BOTH },
254 { .type = AMD_FW_TOS_SEC_POLICY, .level = PSP_BOTH },
255 { .type = AMD_FW_USB_PHY, .level = PSP_LVL2 },
256 { .type = AMD_FW_DRTM_TA, .level = PSP_LVL2 },
257 { .type = AMD_FW_KEYDB_BL, .level = PSP_BOTH },
258 { .type = AMD_FW_KEYDB_TOS, .level = PSP_LVL2 },
259 { .type = AMD_FW_DMCU_ERAM, .level = PSP_LVL2 },
260 { .type = AMD_FW_DMCU_ISR, .level = PSP_LVL2 },
261 { .type = AMD_RPMC_NVRAM, .level = PSP_LVL2 },
Zheng Baob993cb22021-02-02 18:48:23 +0800262 { .type = AMD_FW_PSP_BOOTLOADER_AB, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600263 { .type = AMD_ABL0, .level = PSP_BOTH },
264 { .type = AMD_ABL1, .level = PSP_BOTH },
265 { .type = AMD_ABL2, .level = PSP_BOTH },
266 { .type = AMD_ABL3, .level = PSP_BOTH },
267 { .type = AMD_ABL4, .level = PSP_BOTH },
268 { .type = AMD_ABL5, .level = PSP_BOTH },
269 { .type = AMD_ABL6, .level = PSP_BOTH },
270 { .type = AMD_ABL7, .level = PSP_BOTH },
Marshall Dawson24f73d42019-04-01 10:48:43 -0600271 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
272 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600273 { .type = AMD_FW_PSP_WHITELIST, .level = PSP_LVL2 },
Martin Rothd3ce8c82019-07-13 20:13:07 -0600274 { .type = AMD_FW_PSP_VERSTAGE, .level = PSP_BOTH },
Martin Rothb1f648f2020-09-01 09:36:59 -0600275 { .type = AMD_FW_VERSTAGE_SIG, .level = PSP_BOTH },
zbaoc3a08a92016-03-02 14:47:27 +0800276 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800277};
278
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800279amd_fw_entry amd_fw_table[] = {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800280 { .type = AMD_FW_XHCI },
281 { .type = AMD_FW_IMC },
282 { .type = AMD_FW_GEC },
zbaoc3a08a92016-03-02 14:47:27 +0800283 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800284};
285
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800286amd_bios_entry amd_bios_table[] = {
Zheng Baobf29a0d2020-12-03 23:00:48 +0800287 { .type = AMD_BIOS_RTM_PUBKEY, .inst = 0, .level = BDT_BOTH },
Marshall Dawson0581bf62019-09-25 11:03:53 -0600288 { .type = AMD_BIOS_APCB, .inst = 0, .level = BDT_BOTH },
289 { .type = AMD_BIOS_APCB, .inst = 1, .level = BDT_BOTH },
290 { .type = AMD_BIOS_APCB, .inst = 2, .level = BDT_BOTH },
291 { .type = AMD_BIOS_APCB, .inst = 3, .level = BDT_BOTH },
292 { .type = AMD_BIOS_APCB, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700293 { .type = AMD_BIOS_APCB, .inst = 5, .level = BDT_BOTH },
294 { .type = AMD_BIOS_APCB, .inst = 6, .level = BDT_BOTH },
295 { .type = AMD_BIOS_APCB, .inst = 7, .level = BDT_BOTH },
296 { .type = AMD_BIOS_APCB, .inst = 8, .level = BDT_BOTH },
297 { .type = AMD_BIOS_APCB, .inst = 9, .level = BDT_BOTH },
298 { .type = AMD_BIOS_APCB, .inst = 10, .level = BDT_BOTH },
299 { .type = AMD_BIOS_APCB, .inst = 11, .level = BDT_BOTH },
300 { .type = AMD_BIOS_APCB, .inst = 12, .level = BDT_BOTH },
301 { .type = AMD_BIOS_APCB, .inst = 13, .level = BDT_BOTH },
302 { .type = AMD_BIOS_APCB, .inst = 14, .level = BDT_BOTH },
303 { .type = AMD_BIOS_APCB, .inst = 15, .level = BDT_BOTH },
Marshall Dawson2dd3b5c2020-01-03 17:57:48 -0700304 { .type = AMD_BIOS_APCB_BK, .inst = 0, .level = BDT_BOTH },
305 { .type = AMD_BIOS_APCB_BK, .inst = 1, .level = BDT_BOTH },
306 { .type = AMD_BIOS_APCB_BK, .inst = 2, .level = BDT_BOTH },
307 { .type = AMD_BIOS_APCB_BK, .inst = 3, .level = BDT_BOTH },
308 { .type = AMD_BIOS_APCB_BK, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700309 { .type = AMD_BIOS_APCB_BK, .inst = 5, .level = BDT_BOTH },
310 { .type = AMD_BIOS_APCB_BK, .inst = 6, .level = BDT_BOTH },
311 { .type = AMD_BIOS_APCB_BK, .inst = 7, .level = BDT_BOTH },
312 { .type = AMD_BIOS_APCB_BK, .inst = 8, .level = BDT_BOTH },
313 { .type = AMD_BIOS_APCB_BK, .inst = 9, .level = BDT_BOTH },
314 { .type = AMD_BIOS_APCB_BK, .inst = 10, .level = BDT_BOTH },
315 { .type = AMD_BIOS_APCB_BK, .inst = 11, .level = BDT_BOTH },
316 { .type = AMD_BIOS_APCB_BK, .inst = 12, .level = BDT_BOTH },
317 { .type = AMD_BIOS_APCB_BK, .inst = 13, .level = BDT_BOTH },
318 { .type = AMD_BIOS_APCB_BK, .inst = 14, .level = BDT_BOTH },
319 { .type = AMD_BIOS_APCB_BK, .inst = 15, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600320 { .type = AMD_BIOS_APOB, .level = BDT_BOTH },
321 { .type = AMD_BIOS_BIN,
322 .reset = 1, .copy = 1, .zlib = 1, .level = BDT_BOTH },
323 { .type = AMD_BIOS_APOB_NV, .level = BDT_LVL2 },
324 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 0, .level = BDT_BOTH },
325 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 0, .level = BDT_BOTH },
326 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 0, .level = BDT_BOTH },
327 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 0, .level = BDT_BOTH },
328 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 1, .level = BDT_BOTH },
329 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 1, .level = BDT_BOTH },
330 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 1, .level = BDT_BOTH },
331 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 1, .level = BDT_BOTH },
332 { .type = AMD_BIOS_UCODE, .inst = 0, .level = BDT_LVL2 },
333 { .type = AMD_BIOS_UCODE, .inst = 1, .level = BDT_LVL2 },
334 { .type = AMD_BIOS_UCODE, .inst = 2, .level = BDT_LVL2 },
335 { .type = AMD_BIOS_MP2_CFG, .level = BDT_LVL2 },
Martin Roth94554742020-04-14 14:59:36 -0600336 { .type = AMD_BIOS_PSP_SHARED_MEM, .inst = 0, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600337 { .type = AMD_BIOS_INVALID },
338};
339
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600340
Martin Roth94554742020-04-14 14:59:36 -0600341#define MAX_BIOS_ENTRIES 0x2f
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600342
Marshall Dawson2794a862019-03-04 16:53:15 -0700343typedef struct _context {
344 char *rom; /* target buffer, size of flash device */
345 uint32_t rom_size; /* size of flash device */
346 uint32_t current; /* pointer within flash & proxy buffer */
347} context;
348
349#define RUN_BASE(ctx) (0xFFFFFFFF - (ctx).rom_size + 1)
Kangheui Won275ade92021-07-14 02:42:43 +0000350#define RUN_OFFSET(ctx, offset) (RUN_BASE(ctx) + (offset))
Marshall Dawson2794a862019-03-04 16:53:15 -0700351#define RUN_CURRENT(ctx) RUN_OFFSET((ctx), (ctx).current)
352#define BUFF_OFFSET(ctx, offset) ((void *)((ctx).rom + (offset)))
353#define BUFF_CURRENT(ctx) BUFF_OFFSET((ctx), (ctx).current)
354#define BUFF_TO_RUN(ctx, ptr) RUN_OFFSET((ctx), ((char *)(ptr) - (ctx).rom))
355#define BUFF_ROOM(ctx) ((ctx).rom_size - (ctx).current)
356
Marshall Dawson24f73d42019-04-01 10:48:43 -0600357static void *new_psp_dir(context *ctx, int multi)
Marshall Dawson2794a862019-03-04 16:53:15 -0700358{
359 void *ptr;
360
Marshall Dawson24f73d42019-04-01 10:48:43 -0600361 /*
362 * Force both onto boundary when multi. Primary table is after
363 * updatable table, so alignment ensures primary can stay intact
364 * if secondary is reprogrammed.
365 */
366 if (multi)
367 ctx->current = ALIGN(ctx->current, TABLE_ERASE_ALIGNMENT);
368 else
369 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
370
Marshall Dawson2794a862019-03-04 16:53:15 -0700371 ptr = BUFF_CURRENT(*ctx);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800372 ((psp_directory_header *)ptr)->additional_info = ctx->current;
Marshall Dawson2794a862019-03-04 16:53:15 -0700373 ctx->current += sizeof(psp_directory_header)
374 + MAX_PSP_ENTRIES * sizeof(psp_directory_entry);
375 return ptr;
376}
377
Martin Rothec933132019-07-13 20:03:34 -0600378#if PSP_COMBO
Marshall Dawson2794a862019-03-04 16:53:15 -0700379static void *new_combo_dir(context *ctx)
380{
381 void *ptr;
382
383 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
384 ptr = BUFF_CURRENT(*ctx);
385 ctx->current += sizeof(psp_combo_header)
386 + MAX_COMBO_ENTRIES * sizeof(psp_combo_entry);
387 return ptr;
388}
Martin Rothec933132019-07-13 20:03:34 -0600389#endif
Marshall Dawson2794a862019-03-04 16:53:15 -0700390
Zheng Baobf29a0d2020-12-03 23:00:48 +0800391static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie, context *ctx)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800392{
Marshall Dawson24f73d42019-04-01 10:48:43 -0600393 psp_combo_directory *cdir = directory;
394 psp_directory_table *dir = directory;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600395 bios_directory_table *bdir = directory;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800396 uint32_t table_size = 0;
Marshall Dawson24f73d42019-04-01 10:48:43 -0600397
398 if (!count)
399 return;
Zheng Baob035f582021-05-27 11:26:12 +0800400 if (ctx == NULL || directory == NULL) {
401 fprintf(stderr, "Calling %s with NULL pointers\n", __func__);
402 return;
403 }
Marshall Dawson24f73d42019-04-01 10:48:43 -0600404
Zheng Baobf29a0d2020-12-03 23:00:48 +0800405 /* The table size needs to be 0x1000 aligned. So align the end of table. */
Zheng Baob035f582021-05-27 11:26:12 +0800406 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800407
Marshall Dawson24f73d42019-04-01 10:48:43 -0600408 switch (cookie) {
409 case PSP2_COOKIE:
Marshall Dawsona378c222019-03-04 16:52:07 -0700410 /* caller is responsible for lookup mode */
Marshall Dawsona378c222019-03-04 16:52:07 -0700411 cdir->header.cookie = cookie;
412 cdir->header.num_entries = count;
413 cdir->header.reserved[0] = 0;
414 cdir->header.reserved[1] = 0;
415 /* checksum everything that comes after the Checksum field */
416 cdir->header.checksum = fletcher32(&cdir->header.num_entries,
417 count * sizeof(psp_combo_entry)
418 + sizeof(cdir->header.num_entries)
419 + sizeof(cdir->header.lookup)
420 + 2 * sizeof(cdir->header.reserved[0]));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600421 break;
422 case PSP_COOKIE:
423 case PSPL2_COOKIE:
Zheng Baobf29a0d2020-12-03 23:00:48 +0800424 table_size = ctx->current - dir->header.additional_info;
425 if ((table_size % TABLE_ALIGNMENT) != 0) {
426 fprintf(stderr, "The PSP table size should be 4K aligned\n");
427 exit(1);
428 }
Marshall Dawsona378c222019-03-04 16:52:07 -0700429 dir->header.cookie = cookie;
430 dir->header.num_entries = count;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800431 dir->header.additional_info = (table_size / 0x1000) | (1 << 10);
Marshall Dawsona378c222019-03-04 16:52:07 -0700432 /* checksum everything that comes after the Checksum field */
433 dir->header.checksum = fletcher32(&dir->header.num_entries,
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700434 count * sizeof(psp_directory_entry)
Marshall Dawsona378c222019-03-04 16:52:07 -0700435 + sizeof(dir->header.num_entries)
Zheng Baobf29a0d2020-12-03 23:00:48 +0800436 + sizeof(dir->header.additional_info));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600437 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600438 case BDT1_COOKIE:
439 case BDT2_COOKIE:
Zheng Baobf29a0d2020-12-03 23:00:48 +0800440 table_size = ctx->current - bdir->header.additional_info;
441 if ((table_size % TABLE_ALIGNMENT) != 0) {
442 fprintf(stderr, "The BIOS table size should be 4K aligned\n");
443 exit(1);
444 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600445 bdir->header.cookie = cookie;
446 bdir->header.num_entries = count;
Zheng Baobf29a0d2020-12-03 23:00:48 +0800447 bdir->header.additional_info = (table_size / 0x1000) | (1 << 10);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600448 /* checksum everything that comes after the Checksum field */
449 bdir->header.checksum = fletcher32(&bdir->header.num_entries,
450 count * sizeof(bios_directory_entry)
451 + sizeof(bdir->header.num_entries)
Zheng Baobf29a0d2020-12-03 23:00:48 +0800452 + sizeof(bdir->header.additional_info));
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600453 break;
Marshall Dawsona378c222019-03-04 16:52:07 -0700454 }
Zheng Baobf29a0d2020-12-03 23:00:48 +0800455
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800456}
457
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700458static ssize_t copy_blob(void *dest, const char *src_file, size_t room)
459{
460 int fd;
461 struct stat fd_stat;
462 ssize_t bytes;
463
464 fd = open(src_file, O_RDONLY);
465 if (fd < 0) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800466 fprintf(stderr, "Error opening file: %s: %s\n",
Eric Peersaf505672020-03-05 16:04:15 -0700467 src_file, strerror(errno));
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700468 return -1;
469 }
470
471 if (fstat(fd, &fd_stat)) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800472 fprintf(stderr, "fstat error: %s\n", strerror(errno));
Jacob Garber967f8622019-07-02 10:35:10 -0600473 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700474 return -2;
475 }
476
Zheng Bao6d402ac2020-10-01 16:16:30 +0800477 if ((size_t)fd_stat.st_size > room) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800478 fprintf(stderr, "Error: %s will not fit. Exiting.\n", src_file);
Jacob Garber967f8622019-07-02 10:35:10 -0600479 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700480 return -3;
481 }
482
483 bytes = read(fd, dest, (size_t)fd_stat.st_size);
484 close(fd);
485 if (bytes != (ssize_t)fd_stat.st_size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800486 fprintf(stderr, "Error while reading %s\n", src_file);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700487 return -4;
488 }
489
490 return bytes;
491}
492
Zheng Baoeb0404e2021-10-14 15:09:09 +0800493enum platform {
494 PLATFORM_UNKNOWN,
495 PLATFORM_STONEYRIDGE,
496 PLATFORM_RAVEN,
497 PLATFORM_PICASSO,
498 PLATFORM_RENOIR,
499 PLATFORM_CEZANNE,
500 PLATFORM_MENDOCINO,
501 PLATFORM_LUCIENNE,
502};
503
504static uint32_t get_psp_id(enum platform soc_id)
505{
506 uint32_t psp_id;
507 switch (soc_id) {
508 case PLATFORM_RAVEN:
509 case PLATFORM_PICASSO:
510 psp_id = 0xBC0A0000;
511 break;
512 case PLATFORM_RENOIR:
513 case PLATFORM_LUCIENNE:
514 psp_id = 0xBC0C0000;
515 break;
516 case PLATFORM_CEZANNE:
517 psp_id = 0xBC0C0140;
518 break;
519 case PLATFORM_MENDOCINO:
520 psp_id = 0xBC0D0900;
521 break;
522 case PLATFORM_STONEYRIDGE:
523 psp_id = 0x10220B00;
524 break;
525 default:
526 psp_id = 0;
527 break;
528 }
529 return psp_id;
530}
531
Marshall Dawson2794a862019-03-04 16:53:15 -0700532static void integrate_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -0700533 embedded_firmware *romsig,
Marshall Dawson2794a862019-03-04 16:53:15 -0700534 amd_fw_entry *fw_table)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800535{
Richard Spiegel137484d2018-01-17 10:23:19 -0700536 ssize_t bytes;
Zheng Bao6d402ac2020-10-01 16:16:30 +0800537 uint32_t i;
Marshall Dawson2794a862019-03-04 16:53:15 -0700538
539 ctx->current += sizeof(embedded_firmware);
540 ctx->current = ALIGN(ctx->current, BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800541
Martin Rothcd15bc82016-11-08 11:34:02 -0700542 for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
zbaoc3a08a92016-03-02 14:47:27 +0800543 if (fw_table[i].filename != NULL) {
zbaoc3a08a92016-03-02 14:47:27 +0800544 switch (fw_table[i].type) {
545 case AMD_FW_IMC:
Marshall Dawson2794a862019-03-04 16:53:15 -0700546 ctx->current = ALIGN(ctx->current, 0x10000U);
547 romsig->imc_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800548 break;
549 case AMD_FW_GEC:
Marshall Dawson2794a862019-03-04 16:53:15 -0700550 romsig->gec_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800551 break;
552 case AMD_FW_XHCI:
Marshall Dawson2794a862019-03-04 16:53:15 -0700553 romsig->xhci_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800554 break;
555 default:
556 /* Error */
557 break;
558 }
559
Marshall Dawson2794a862019-03-04 16:53:15 -0700560 bytes = copy_blob(BUFF_CURRENT(*ctx),
561 fw_table[i].filename, BUFF_ROOM(*ctx));
Marshall Dawson02bd7732019-03-13 14:43:17 -0600562 if (bytes < 0) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700563 free(ctx->rom);
Martin Roth60f15512016-11-08 09:55:01 -0700564 exit(1);
565 }
566
Marshall Dawson2794a862019-03-04 16:53:15 -0700567 ctx->current = ALIGN(ctx->current + bytes,
568 BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800569 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800570 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800571}
572
Zheng Bao9e908072020-10-28 11:39:13 +0800573/* For debugging */
574static void dump_psp_firmwares(amd_fw_entry *fw_table)
575{
576 amd_fw_entry *index;
577
578 printf("PSP firmware components:");
579 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
580 if (index->filename)
Zheng Bao826f1c42021-05-25 16:26:55 +0800581 printf(" %2x: %s\n", index->type, index->filename);
Zheng Bao9e908072020-10-28 11:39:13 +0800582 }
583}
584
585static void dump_bdt_firmwares(amd_bios_entry *fw_table)
586{
587 amd_bios_entry *index;
588
589 printf("BIOS Directory Table (BDT) components:");
590 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
591 if (index->filename)
Zheng Bao826f1c42021-05-25 16:26:55 +0800592 printf(" %2x: %s\n", index->type, index->filename);
Zheng Bao9e908072020-10-28 11:39:13 +0800593 }
594}
595
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800596static void free_psp_firmware_filenames(amd_fw_entry *fw_table)
597{
598 amd_fw_entry *index;
599
600 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
601 if (index->filename &&
602 index->type != AMD_FW_VERSTAGE_SIG &&
603 index->type != AMD_FW_PSP_VERSTAGE &&
604 index->type != AMD_FW_PSP_WHITELIST) {
605 free(index->filename);
606 }
607 }
608}
609
610static void free_bdt_firmware_filenames(amd_bios_entry *fw_table)
611{
612 amd_bios_entry *index;
613
614 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
615 if (index->filename &&
616 index->type != AMD_BIOS_APCB &&
617 index->type != AMD_BIOS_BIN &&
618 index->type != AMD_BIOS_APCB_BK)
619 free(index->filename);
620 }
621}
622
Marshall Dawson2794a862019-03-04 16:53:15 -0700623static void integrate_psp_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -0700624 psp_directory_table *pspdir,
Marshall Dawson24f73d42019-04-01 10:48:43 -0600625 psp_directory_table *pspdir2,
626 amd_fw_entry *fw_table,
Zheng Bao20795892021-08-20 14:58:22 +0800627 uint32_t cookie,
628 amd_cb_config *cb_config)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800629{
Richard Spiegel137484d2018-01-17 10:23:19 -0700630 ssize_t bytes;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700631 unsigned int i, count;
Marshall Dawson24f73d42019-04-01 10:48:43 -0600632 int level;
633
634 /* This function can create a primary table, a secondary table, or a
635 * flattened table which contains all applicable types. These if-else
636 * statements infer what the caller intended. If a 2nd-level cookie
637 * is passed, clearly a 2nd-level table is intended. However, a
638 * 1st-level cookie may indicate level 1 or flattened. If the caller
639 * passes a pointer to a 2nd-level table, then assume not flat.
640 */
Zheng Baoba3af5e2021-11-04 18:56:47 +0800641 if (!cb_config->multi_level)
Zheng Bao20795892021-08-20 14:58:22 +0800642 level = PSP_BOTH;
643 else if (cookie == PSPL2_COOKIE)
Marshall Dawson24f73d42019-04-01 10:48:43 -0600644 level = PSP_LVL2;
645 else if (pspdir2)
646 level = PSP_LVL1;
647 else
648 level = PSP_BOTH;
Marshall Dawson2794a862019-03-04 16:53:15 -0700649
Zheng Baobf29a0d2020-12-03 23:00:48 +0800650 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800651
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700652 for (i = 0, count = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
Marshall Dawson24f73d42019-04-01 10:48:43 -0600653 if (!(fw_table[i].level & level))
654 continue;
655
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600656 if (fw_table[i].type == AMD_TOKEN_UNLOCK) {
657 if (!fw_table[i].other)
658 continue;
659 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
660 pspdir->entries[count].type = fw_table[i].type;
661 pspdir->entries[count].size = 4096; /* TODO: doc? */
662 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
663 pspdir->entries[count].subprog = fw_table[i].subprog;
664 pspdir->entries[count].rsvd = 0;
665 ctx->current = ALIGN(ctx->current + 4096, 0x100U);
666 count++;
667 } else if (fw_table[i].type == AMD_PSP_FUSE_CHAIN) {
Marshall Dawson239286c2019-02-23 16:42:46 -0700668 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -0700669 pspdir->entries[count].subprog = fw_table[i].subprog;
670 pspdir->entries[count].rsvd = 0;
Marshall Dawson239286c2019-02-23 16:42:46 -0700671 pspdir->entries[count].size = 0xFFFFFFFF;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -0600672 pspdir->entries[count].addr = fw_table[i].other;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700673 count++;
Marshall Dawson7c1e1422019-04-11 09:44:43 -0600674 } else if (fw_table[i].type == AMD_FW_PSP_NVRAM) {
675 if (fw_table[i].filename == NULL)
676 continue;
677 /* TODO: Add a way to reserve for NVRAM without
678 * requiring a filename. This isn't a feature used
679 * by coreboot systems, so priority is very low.
680 */
681 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
682 bytes = copy_blob(BUFF_CURRENT(*ctx),
683 fw_table[i].filename, BUFF_ROOM(*ctx));
684 if (bytes <= 0) {
685 free(ctx->rom);
686 exit(1);
687 }
688
689 pspdir->entries[count].type = fw_table[i].type;
690 pspdir->entries[count].subprog = fw_table[i].subprog;
691 pspdir->entries[count].rsvd = 0;
692 pspdir->entries[count].size = ALIGN(bytes,
693 ERASE_ALIGNMENT);
694 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
695
696 ctx->current = ALIGN(ctx->current + bytes,
697 BLOB_ERASE_ALIGNMENT);
698 count++;
zbaoc3a08a92016-03-02 14:47:27 +0800699 } else if (fw_table[i].filename != NULL) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700700 bytes = copy_blob(BUFF_CURRENT(*ctx),
701 fw_table[i].filename, BUFF_ROOM(*ctx));
Marshall Dawson02bd7732019-03-13 14:43:17 -0600702 if (bytes < 0) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700703 free(ctx->rom);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700704 exit(1);
705 }
706
Marshall Dawson239286c2019-02-23 16:42:46 -0700707 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -0700708 pspdir->entries[count].subprog = fw_table[i].subprog;
709 pspdir->entries[count].rsvd = 0;
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700710 pspdir->entries[count].size = (uint32_t)bytes;
Marshall Dawson2794a862019-03-04 16:53:15 -0700711 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800712
Marshall Dawson2794a862019-03-04 16:53:15 -0700713 ctx->current = ALIGN(ctx->current + bytes,
714 BLOB_ALIGNMENT);
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700715 count++;
zbaoc3a08a92016-03-02 14:47:27 +0800716 } else {
717 /* This APU doesn't have this firmware. */
718 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800719 }
Marshall Dawson2794a862019-03-04 16:53:15 -0700720
Marshall Dawson24f73d42019-04-01 10:48:43 -0600721 if (pspdir2) {
722 pspdir->entries[count].type = AMD_FW_L2_PTR;
723 pspdir->entries[count].subprog = 0;
724 pspdir->entries[count].rsvd = 0;
725 pspdir->entries[count].size = sizeof(pspdir2->header)
726 + pspdir2->header.num_entries
727 * sizeof(psp_directory_entry);
728
729 pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, pspdir2);
730 count++;
731 }
732
Marshall Dawson2794a862019-03-04 16:53:15 -0700733 if (count > MAX_PSP_ENTRIES) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800734 fprintf(stderr, "Error: PSP entries exceed max allowed items\n");
Marshall Dawson2794a862019-03-04 16:53:15 -0700735 free(ctx->rom);
736 exit(1);
737 }
738
Zheng Baobf29a0d2020-12-03 23:00:48 +0800739 fill_dir_header(pspdir, count, cookie, ctx);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800740}
741
Zheng Baoba3af5e2021-11-04 18:56:47 +0800742static void *new_bios_dir(context *ctx, bool multi)
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600743{
744 void *ptr;
745
746 /*
747 * Force both onto boundary when multi. Primary table is after
748 * updatable table, so alignment ensures primary can stay intact
749 * if secondary is reprogrammed.
750 */
751 if (multi)
752 ctx->current = ALIGN(ctx->current, TABLE_ERASE_ALIGNMENT);
753 else
754 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
755 ptr = BUFF_CURRENT(*ctx);
Zheng Baobf29a0d2020-12-03 23:00:48 +0800756 ((bios_directory_hdr *) ptr)->additional_info = ctx->current;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600757 ctx->current += sizeof(bios_directory_hdr)
758 + MAX_BIOS_ENTRIES * sizeof(bios_directory_entry);
759 return ptr;
760}
761
762static int locate_bdt2_bios(bios_directory_table *level2,
763 uint64_t *source, uint32_t *size)
764{
Zheng Bao6d402ac2020-10-01 16:16:30 +0800765 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600766
767 *source = 0;
768 *size = 0;
769 if (!level2)
770 return 0;
771
772 for (i = 0 ; i < level2->header.num_entries ; i++) {
773 if (level2->entries[i].type == AMD_BIOS_BIN) {
774 *source = level2->entries[i].source;
775 *size = level2->entries[i].size;
776 return 1;
777 }
778 }
779 return 0;
780}
781
782static int have_bios_tables(amd_bios_entry *table)
783{
784 int i;
785
786 for (i = 0 ; table[i].type != AMD_BIOS_INVALID; i++) {
787 if (table[i].level & BDT_LVL1 && table[i].filename)
788 return 1;
789 }
790 return 0;
791}
792
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700793static int find_bios_entry(amd_bios_type type)
794{
795 int i;
796
797 for (i = 0; amd_bios_table[i].type != AMD_BIOS_INVALID; i++) {
798 if (amd_bios_table[i].type == type)
799 return i;
800 }
801 return -1;
802}
803
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600804static void integrate_bios_firmwares(context *ctx,
805 bios_directory_table *biosdir,
806 bios_directory_table *biosdir2,
807 amd_bios_entry *fw_table,
Zheng Bao20795892021-08-20 14:58:22 +0800808 uint32_t cookie,
809 amd_cb_config *cb_config)
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600810{
811 ssize_t bytes;
Martin Rothec933132019-07-13 20:03:34 -0600812 unsigned int i, count;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600813 int level;
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700814 int apob_idx;
Martin Rotheca423b2020-09-01 10:54:11 -0600815 uint32_t size;
816 uint64_t source;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600817
818 /* This function can create a primary table, a secondary table, or a
819 * flattened table which contains all applicable types. These if-else
820 * statements infer what the caller intended. If a 2nd-level cookie
821 * is passed, clearly a 2nd-level table is intended. However, a
822 * 1st-level cookie may indicate level 1 or flattened. If the caller
823 * passes a pointer to a 2nd-level table, then assume not flat.
824 */
Zheng Baoba3af5e2021-11-04 18:56:47 +0800825 if (!cb_config->multi_level)
Zheng Bao20795892021-08-20 14:58:22 +0800826 level = BDT_BOTH;
827 else if (cookie == BDT2_COOKIE)
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600828 level = BDT_LVL2;
829 else if (biosdir2)
830 level = BDT_LVL1;
831 else
832 level = BDT_BOTH;
833
Zheng Baobf29a0d2020-12-03 23:00:48 +0800834 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600835
836 for (i = 0, count = 0; fw_table[i].type != AMD_BIOS_INVALID; i++) {
837 if (!(fw_table[i].level & level))
838 continue;
839 if (fw_table[i].filename == NULL && (
840 fw_table[i].type != AMD_BIOS_APOB &&
841 fw_table[i].type != AMD_BIOS_APOB_NV &&
842 fw_table[i].type != AMD_BIOS_L2_PTR &&
Martin Roth94554742020-04-14 14:59:36 -0600843 fw_table[i].type != AMD_BIOS_BIN &&
844 fw_table[i].type != AMD_BIOS_PSP_SHARED_MEM))
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600845 continue;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600846
847 /* BIOS Directory items may have additional requirements */
848
Martin Roth48dd9fe2020-07-29 16:32:25 -0600849 /* Check APOB_NV requirements */
850 if (fw_table[i].type == AMD_BIOS_APOB_NV) {
851 if (!fw_table[i].size && !fw_table[i].src)
852 continue; /* APOB_NV not used */
853 if (fw_table[i].src && !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800854 fprintf(stderr, "Error: APOB NV address provided, but no size\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600855 free(ctx->rom);
856 exit(1);
857 }
Martin Roth48dd9fe2020-07-29 16:32:25 -0600858 /* If the APOB isn't used, APOB_NV isn't used either */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700859 apob_idx = find_bios_entry(AMD_BIOS_APOB);
Martin Roth48dd9fe2020-07-29 16:32:25 -0600860 if (apob_idx < 0 || !fw_table[apob_idx].dest)
861 continue; /* APOV NV not supported */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700862 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600863
864 /* APOB_DATA needs destination */
865 if (fw_table[i].type == AMD_BIOS_APOB && !fw_table[i].dest) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800866 fprintf(stderr, "Error: APOB destination not provided\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600867 free(ctx->rom);
868 exit(1);
869 }
870
871 /* BIOS binary must have destination and uncompressed size. If
872 * no filename given, then user must provide a source address.
873 */
874 if (fw_table[i].type == AMD_BIOS_BIN) {
875 if (!fw_table[i].dest || !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800876 fprintf(stderr, "Error: BIOS binary destination and uncompressed size are required\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600877 free(ctx->rom);
878 exit(1);
879 }
880 if (!fw_table[i].filename && !fw_table[i].src) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800881 fprintf(stderr, "Error: BIOS binary assumed outside amdfw.rom but no source address given\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600882 free(ctx->rom);
883 exit(1);
884 }
885 }
886
Martin Roth94554742020-04-14 14:59:36 -0600887 /* PSP_SHARED_MEM needs a destination and size */
888 if (fw_table[i].type == AMD_BIOS_PSP_SHARED_MEM &&
889 (!fw_table[i].dest || !fw_table[i].size))
890 continue;
891
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600892 biosdir->entries[count].type = fw_table[i].type;
893 biosdir->entries[count].region_type = fw_table[i].region_type;
894 biosdir->entries[count].dest = fw_table[i].dest ?
895 fw_table[i].dest : (uint64_t)-1;
896 biosdir->entries[count].reset = fw_table[i].reset;
897 biosdir->entries[count].copy = fw_table[i].copy;
898 biosdir->entries[count].ro = fw_table[i].ro;
899 biosdir->entries[count].compressed = fw_table[i].zlib;
900 biosdir->entries[count].inst = fw_table[i].inst;
901 biosdir->entries[count].subprog = fw_table[i].subpr;
902
903 switch (fw_table[i].type) {
904 case AMD_BIOS_APOB:
905 biosdir->entries[count].size = fw_table[i].size;
906 biosdir->entries[count].source = fw_table[i].src;
907 break;
908 case AMD_BIOS_APOB_NV:
909 if (fw_table[i].src) {
910 /* If source is given, use that and its size */
911 biosdir->entries[count].source = fw_table[i].src;
912 biosdir->entries[count].size = fw_table[i].size;
913 } else {
914 /* Else reserve size bytes within amdfw.rom */
915 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
916 biosdir->entries[count].source = RUN_CURRENT(*ctx);
917 biosdir->entries[count].size = ALIGN(
918 fw_table[i].size, ERASE_ALIGNMENT);
919 memset(BUFF_CURRENT(*ctx), 0xff,
920 biosdir->entries[count].size);
921 ctx->current = ctx->current
922 + biosdir->entries[count].size;
923 }
924 break;
925 case AMD_BIOS_BIN:
926 /* Don't make a 2nd copy, point to the same one */
Martin Rotheca423b2020-09-01 10:54:11 -0600927 if (level == BDT_LVL1 && locate_bdt2_bios(biosdir2, &source, &size)) {
928 biosdir->entries[count].source = source;
929 biosdir->entries[count].size = size;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600930 break;
Martin Rotheca423b2020-09-01 10:54:11 -0600931 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600932
933 /* level 2, or level 1 and no copy found in level 2 */
934 biosdir->entries[count].source = fw_table[i].src;
935 biosdir->entries[count].dest = fw_table[i].dest;
936 biosdir->entries[count].size = fw_table[i].size;
937
938 if (!fw_table[i].filename)
939 break;
940
941 bytes = copy_blob(BUFF_CURRENT(*ctx),
942 fw_table[i].filename, BUFF_ROOM(*ctx));
943 if (bytes <= 0) {
944 free(ctx->rom);
945 exit(1);
946 }
947
948 biosdir->entries[count].source = RUN_CURRENT(*ctx);
949
950 ctx->current = ALIGN(ctx->current + bytes, 0x100U);
951 break;
Martin Roth94554742020-04-14 14:59:36 -0600952 case AMD_BIOS_PSP_SHARED_MEM:
953 biosdir->entries[count].dest = fw_table[i].dest;
954 biosdir->entries[count].size = fw_table[i].size;
955 break;
956
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600957 default: /* everything else is copied from input */
958 if (fw_table[i].type == AMD_BIOS_APCB ||
959 fw_table[i].type == AMD_BIOS_APCB_BK)
960 ctx->current = ALIGN(
961 ctx->current, ERASE_ALIGNMENT);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600962 bytes = copy_blob(BUFF_CURRENT(*ctx),
963 fw_table[i].filename, BUFF_ROOM(*ctx));
964 if (bytes <= 0) {
965 free(ctx->rom);
966 exit(1);
967 }
968
969 biosdir->entries[count].size = (uint32_t)bytes;
970 biosdir->entries[count].source = RUN_CURRENT(*ctx);
971
972 ctx->current = ALIGN(ctx->current + bytes, 0x100U);
973 break;
974 }
975
976 count++;
977 }
978
979 if (biosdir2) {
980 biosdir->entries[count].type = AMD_BIOS_L2_PTR;
Zheng Baoe8e60432021-05-24 16:11:12 +0800981 biosdir->entries[count].region_type = 0;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600982 biosdir->entries[count].size =
983 + MAX_BIOS_ENTRIES
984 * sizeof(bios_directory_entry);
985 biosdir->entries[count].source =
986 BUFF_TO_RUN(*ctx, biosdir2);
987 biosdir->entries[count].subprog = 0;
988 biosdir->entries[count].inst = 0;
989 biosdir->entries[count].copy = 0;
990 biosdir->entries[count].compressed = 0;
991 biosdir->entries[count].dest = -1;
992 biosdir->entries[count].reset = 0;
993 biosdir->entries[count].ro = 0;
994 count++;
995 }
996
997 if (count > MAX_BIOS_ENTRIES) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800998 fprintf(stderr, "Error: BIOS entries (%d) exceeds max allowed items "
Rob Barnes18fd26c2020-03-03 10:35:02 -0700999 "(%d)\n", count, MAX_BIOS_ENTRIES);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001000 free(ctx->rom);
1001 exit(1);
1002 }
1003
Zheng Baobf29a0d2020-12-03 23:00:48 +08001004 fill_dir_header(biosdir, count, cookie, ctx);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001005}
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001006
1007enum {
Zheng Bao806892a2021-04-27 17:21:54 +08001008 AMDFW_OPT_CONFIG = 'c',
1009 AMDFW_OPT_DEBUG = 'd',
1010 AMDFW_OPT_HELP = 'h',
1011 AMDFW_OPT_LIST_DEPEND = 'l',
1012
1013 AMDFW_OPT_XHCI = 128,
1014 AMDFW_OPT_IMC,
1015 AMDFW_OPT_GEC,
1016 AMDFW_OPT_COMBO,
1017 AMDFW_OPT_MULTILEVEL,
1018 AMDFW_OPT_NVRAM,
1019
1020 AMDFW_OPT_FUSE,
1021 AMDFW_OPT_UNLOCK,
1022 AMDFW_OPT_WHITELIST,
1023 AMDFW_OPT_USE_PSPSECUREOS,
1024 AMDFW_OPT_LOAD_MP2FW,
1025 AMDFW_OPT_LOAD_S0I3,
1026 AMDFW_OPT_VERSTAGE,
1027 AMDFW_OPT_VERSTAGE_SIG,
1028
1029 AMDFW_OPT_INSTANCE,
1030 AMDFW_OPT_APCB,
1031 AMDFW_OPT_APOBBASE,
1032 AMDFW_OPT_BIOSBIN,
1033 AMDFW_OPT_BIOSBIN_SOURCE,
1034 AMDFW_OPT_BIOSBIN_DEST,
1035 AMDFW_OPT_BIOS_UNCOMP_SIZE,
1036 AMDFW_OPT_UCODE,
1037 AMDFW_OPT_APOB_NVBASE,
1038 AMDFW_OPT_APOB_NVSIZE,
1039
1040 AMDFW_OPT_OUTPUT,
1041 AMDFW_OPT_FLASHSIZE,
1042 AMDFW_OPT_LOCATION,
1043 AMDFW_OPT_ANYWHERE,
1044 AMDFW_OPT_SHAREDMEM,
1045 AMDFW_OPT_SHAREDMEM_SIZE,
1046 AMDFW_OPT_SOC_NAME,
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001047 /* begin after ASCII characters */
1048 LONGOPT_SPI_READ_MODE = 256,
1049 LONGOPT_SPI_SPEED = 257,
1050 LONGOPT_SPI_MICRON_FLAG = 258,
1051};
1052
Zheng Bao806892a2021-04-27 17:21:54 +08001053static char const optstring[] = {AMDFW_OPT_CONFIG, ':',
1054 AMDFW_OPT_DEBUG, AMDFW_OPT_HELP, AMDFW_OPT_LIST_DEPEND
1055};
Marc Jones90099b62016-09-20 21:05:45 -06001056
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001057static struct option long_options[] = {
Zheng Bao806892a2021-04-27 17:21:54 +08001058 {"xhci", required_argument, 0, AMDFW_OPT_XHCI },
1059 {"imc", required_argument, 0, AMDFW_OPT_IMC },
1060 {"gec", required_argument, 0, AMDFW_OPT_GEC },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001061 /* PSP Directory Table items */
Zheng Bao806892a2021-04-27 17:21:54 +08001062 {"combo-capable", no_argument, 0, AMDFW_OPT_COMBO },
1063 {"multilevel", no_argument, 0, AMDFW_OPT_MULTILEVEL },
1064 {"nvram", required_argument, 0, AMDFW_OPT_NVRAM },
1065 {"soft-fuse", required_argument, 0, AMDFW_OPT_FUSE },
1066 {"token-unlock", no_argument, 0, AMDFW_OPT_UNLOCK },
1067 {"whitelist", required_argument, 0, AMDFW_OPT_WHITELIST },
1068 {"use-pspsecureos", no_argument, 0, AMDFW_OPT_USE_PSPSECUREOS },
1069 {"load-mp2-fw", no_argument, 0, AMDFW_OPT_LOAD_MP2FW },
1070 {"load-s0i3", no_argument, 0, AMDFW_OPT_LOAD_S0I3 },
1071 {"verstage", required_argument, 0, AMDFW_OPT_VERSTAGE },
1072 {"verstage_sig", required_argument, 0, AMDFW_OPT_VERSTAGE_SIG },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001073 /* BIOS Directory Table items */
Zheng Bao806892a2021-04-27 17:21:54 +08001074 {"instance", required_argument, 0, AMDFW_OPT_INSTANCE },
1075 {"apcb", required_argument, 0, AMDFW_OPT_APCB },
1076 {"apob-base", required_argument, 0, AMDFW_OPT_APOBBASE },
1077 {"bios-bin", required_argument, 0, AMDFW_OPT_BIOSBIN },
1078 {"bios-bin-src", required_argument, 0, AMDFW_OPT_BIOSBIN_SOURCE },
1079 {"bios-bin-dest", required_argument, 0, AMDFW_OPT_BIOSBIN_DEST },
1080 {"bios-uncomp-size", required_argument, 0, AMDFW_OPT_BIOS_UNCOMP_SIZE },
1081 {"ucode", required_argument, 0, AMDFW_OPT_UCODE },
1082 {"apob-nv-base", required_argument, 0, AMDFW_OPT_APOB_NVBASE },
1083 {"apob-nv-size", required_argument, 0, AMDFW_OPT_APOB_NVSIZE },
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001084 /* Embedded Firmware Structure items*/
1085 {"spi-read-mode", required_argument, 0, LONGOPT_SPI_READ_MODE },
1086 {"spi-speed", required_argument, 0, LONGOPT_SPI_SPEED },
1087 {"spi-micron-flag", required_argument, 0, LONGOPT_SPI_MICRON_FLAG },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001088 /* other */
Zheng Bao806892a2021-04-27 17:21:54 +08001089 {"output", required_argument, 0, AMDFW_OPT_OUTPUT },
1090 {"flashsize", required_argument, 0, AMDFW_OPT_FLASHSIZE },
1091 {"location", required_argument, 0, AMDFW_OPT_LOCATION },
1092 {"anywhere", no_argument, 0, AMDFW_OPT_ANYWHERE },
1093 {"sharedmem", required_argument, 0, AMDFW_OPT_SHAREDMEM },
1094 {"sharedmem-size", required_argument, 0, AMDFW_OPT_SHAREDMEM_SIZE },
1095 {"soc-name", required_argument, 0, AMDFW_OPT_SOC_NAME },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001096
Zheng Bao806892a2021-04-27 17:21:54 +08001097 {"config", required_argument, 0, AMDFW_OPT_CONFIG },
1098 {"debug", no_argument, 0, AMDFW_OPT_DEBUG },
1099 {"help", no_argument, 0, AMDFW_OPT_HELP },
1100 {"list", no_argument, 0, AMDFW_OPT_LIST_DEPEND },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001101 {NULL, 0, 0, 0 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001102};
1103
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001104void register_fw_fuse(char *str)
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001105{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001106 uint32_t i;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001107
1108 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1109 if (amd_psp_fw_table[i].type != AMD_PSP_FUSE_CHAIN)
1110 continue;
1111
1112 amd_psp_fw_table[i].other = strtoull(str, NULL, 16);
1113 return;
1114 }
1115}
1116
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001117static void register_fw_token_unlock(void)
1118{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001119 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001120
1121 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1122 if (amd_psp_fw_table[i].type != AMD_TOKEN_UNLOCK)
1123 continue;
1124
1125 amd_psp_fw_table[i].other = 1;
1126 return;
1127 }
1128}
1129
Marshall Dawsondbae6322019-03-04 10:31:03 -07001130static void register_fw_filename(amd_fw_type type, uint8_t sub, char filename[])
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001131{
Martin Roth8806f7f2016-11-08 10:44:18 -07001132 unsigned int i;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001133
Martin Rothcd15bc82016-11-08 11:34:02 -07001134 for (i = 0; i < sizeof(amd_fw_table) / sizeof(amd_fw_entry); i++) {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001135 if (amd_fw_table[i].type == type) {
1136 amd_fw_table[i].filename = filename;
1137 return;
1138 }
1139 }
1140
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001141 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
Marshall Dawsondbae6322019-03-04 10:31:03 -07001142 if (amd_psp_fw_table[i].type != type)
1143 continue;
1144
1145 if (amd_psp_fw_table[i].subprog == sub) {
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001146 amd_psp_fw_table[i].filename = filename;
1147 return;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001148 }
1149 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001150}
1151
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001152static void register_bdt_data(amd_bios_type type, int sub, int ins, char name[])
1153{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001154 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001155
1156 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
1157 if (amd_bios_table[i].type == type
1158 && amd_bios_table[i].inst == ins
1159 && amd_bios_table[i].subpr == sub) {
1160 amd_bios_table[i].filename = name;
1161 return;
1162 }
1163 }
1164}
1165
Martin Rothec933132019-07-13 20:03:34 -06001166static void register_fw_addr(amd_bios_type type, char *src_str,
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001167 char *dst_str, char *size_str)
1168{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001169 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001170 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
1171 if (amd_bios_table[i].type != type)
1172 continue;
1173
1174 if (src_str)
1175 amd_bios_table[i].src = strtoull(src_str, NULL, 16);
1176 if (dst_str)
1177 amd_bios_table[i].dest = strtoull(dst_str, NULL, 16);
1178 if (size_str)
1179 amd_bios_table[i].size = strtoul(size_str, NULL, 16);
1180
1181 return;
1182 }
1183}
1184
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001185static int set_efs_table(uint8_t soc_id, embedded_firmware *amd_romsig,
1186 uint8_t efs_spi_readmode, uint8_t efs_spi_speed,
1187 uint8_t efs_spi_micron_flag)
1188{
1189 if ((efs_spi_readmode == 0xFF) || (efs_spi_speed == 0xFF)) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001190 fprintf(stderr, "Error: EFS read mode and SPI speed must be set\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001191 return 1;
1192 }
1193 switch (soc_id) {
1194 case PLATFORM_STONEYRIDGE:
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001195 amd_romsig->spi_readmode_f15_mod_60_6f = efs_spi_readmode;
1196 amd_romsig->fast_speed_new_f15_mod_60_6f = efs_spi_speed;
1197 break;
1198 case PLATFORM_RAVEN:
1199 case PLATFORM_PICASSO:
Marshall Dawson13ec0292020-11-19 14:02:29 -07001200 /* amd_romsig->efs_gen introduced after RAVEN/PICASSO.
1201 * Leave as 0xffffffff for first gen */
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001202 amd_romsig->spi_readmode_f17_mod_00_2f = efs_spi_readmode;
1203 amd_romsig->spi_fastspeed_f17_mod_00_2f = efs_spi_speed;
1204 switch (efs_spi_micron_flag) {
1205 case 0:
1206 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xff;
1207 break;
1208 case 1:
1209 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xa;
1210 break;
1211 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001212 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001213 return 1;
1214 }
1215 break;
1216 case PLATFORM_RENOIR:
1217 case PLATFORM_LUCIENNE:
Zheng Baobf29a0d2020-12-03 23:00:48 +08001218 case PLATFORM_CEZANNE:
Zheng Bao535ec532021-08-12 16:30:19 +08001219 case PLATFORM_MENDOCINO:
Marshall Dawson13ec0292020-11-19 14:02:29 -07001220 amd_romsig->efs_gen.gen = EFS_SECOND_GEN;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001221 amd_romsig->spi_readmode_f17_mod_30_3f = efs_spi_readmode;
1222 amd_romsig->spi_fastspeed_f17_mod_30_3f = efs_spi_speed;
1223 switch (efs_spi_micron_flag) {
1224 case 0:
1225 amd_romsig->micron_detect_f17_mod_30_3f = 0xff;
1226 break;
1227 case 1:
1228 amd_romsig->micron_detect_f17_mod_30_3f = 0xaa;
1229 break;
1230 case 2:
1231 amd_romsig->micron_detect_f17_mod_30_3f = 0x55;
1232 break;
1233 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001234 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001235 return 1;
1236 }
1237 break;
1238 case PLATFORM_UNKNOWN:
1239 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001240 fprintf(stderr, "Error: Invalid SOC name.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001241 return 1;
1242 }
1243 return 0;
1244}
1245
1246static int identify_platform(char *soc_name)
1247{
1248 if (!strcasecmp(soc_name, "Stoneyridge"))
1249 return PLATFORM_STONEYRIDGE;
1250 else if (!strcasecmp(soc_name, "Raven"))
1251 return PLATFORM_RAVEN;
1252 else if (!strcasecmp(soc_name, "Picasso"))
1253 return PLATFORM_PICASSO;
Zheng Baobf29a0d2020-12-03 23:00:48 +08001254 else if (!strcasecmp(soc_name, "Cezanne"))
1255 return PLATFORM_CEZANNE;
Zheng Bao535ec532021-08-12 16:30:19 +08001256 else if (!strcasecmp(soc_name, "Mendocino"))
1257 return PLATFORM_MENDOCINO;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001258 else if (!strcasecmp(soc_name, "Renoir"))
1259 return PLATFORM_RENOIR;
1260 else if (!strcasecmp(soc_name, "Lucienne"))
1261 return PLATFORM_LUCIENNE;
1262 else
1263 return PLATFORM_UNKNOWN;
1264
1265}
1266
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001267int main(int argc, char **argv)
1268{
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001269 int c;
Martin Roth31d95a22016-11-08 11:22:12 -07001270 int retval = 0;
Martin Roth60f15512016-11-08 09:55:01 -07001271 char *tmp;
Martin Roth8806f7f2016-11-08 10:44:18 -07001272 char *rom = NULL;
Marshall Dawson239286c2019-02-23 16:42:46 -07001273 embedded_firmware *amd_romsig;
1274 psp_directory_table *pspdir;
Marshall Dawson67d868d2019-02-28 11:43:40 -07001275 int comboable = 0;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001276 int fuse_defined = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001277 int targetfd;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001278 char *output = NULL, *config = NULL;
1279 FILE *config_handle;
Zheng Bao9c8ce3e2020-09-28 10:36:29 +08001280 context ctx = { 0 };
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001281 /* Values cleared after each firmware or parameter, regardless if N/A */
1282 uint8_t sub = 0, instance = 0;
Martin Roth0d3b1182017-10-03 14:16:04 -06001283 uint32_t dir_location = 0;
Martin Roth37305e72020-04-07 14:16:39 -06001284 bool any_location = 0;
Martin Roth0d3b1182017-10-03 14:16:04 -06001285 uint32_t romsig_offset;
Martin Roth60f15512016-11-08 09:55:01 -07001286 uint32_t rom_base_address;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001287 uint8_t soc_id = PLATFORM_UNKNOWN;
1288 uint8_t efs_spi_readmode = 0xff;
1289 uint8_t efs_spi_speed = 0xff;
1290 uint8_t efs_spi_micron_flag = 0xff;
1291
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001292 amd_cb_config cb_config;
Zheng Bao9e908072020-10-28 11:39:13 +08001293 int debug = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001294 int list_deps = 0;
1295
Zheng Baoba3af5e2021-11-04 18:56:47 +08001296 cb_config.have_whitelist = false;
1297 cb_config.unlock_secure = false;
1298 cb_config.use_secureos = false;
1299 cb_config.load_mp2_fw = false;
1300 cb_config.s0i3 = false;
1301 cb_config.multi_level = false;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001302
1303 while (1) {
1304 int optindex = 0;
1305
1306 c = getopt_long(argc, argv, optstring, long_options, &optindex);
1307
1308 if (c == -1)
1309 break;
1310
1311 switch (c) {
Zheng Bao806892a2021-04-27 17:21:54 +08001312 case AMDFW_OPT_XHCI:
Marshall Dawsondbae6322019-03-04 10:31:03 -07001313 register_fw_filename(AMD_FW_XHCI, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001314 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001315 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001316 case AMDFW_OPT_IMC:
Marshall Dawsondbae6322019-03-04 10:31:03 -07001317 register_fw_filename(AMD_FW_IMC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001318 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001319 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001320 case AMDFW_OPT_GEC:
Marshall Dawsondbae6322019-03-04 10:31:03 -07001321 register_fw_filename(AMD_FW_GEC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001322 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001323 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001324 case AMDFW_OPT_COMBO:
Zheng Baoba3af5e2021-11-04 18:56:47 +08001325 comboable = true;
Marshall Dawson67d868d2019-02-28 11:43:40 -07001326 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001327 case AMDFW_OPT_MULTILEVEL:
Zheng Baoba3af5e2021-11-04 18:56:47 +08001328 cb_config.multi_level = true;
Marshall Dawson24f73d42019-04-01 10:48:43 -06001329 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001330 case AMDFW_OPT_UNLOCK:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001331 register_fw_token_unlock();
Zheng Baoba3af5e2021-11-04 18:56:47 +08001332 cb_config.unlock_secure = true;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001333 sub = instance = 0;
1334 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001335 case AMDFW_OPT_USE_PSPSECUREOS:
Zheng Baoba3af5e2021-11-04 18:56:47 +08001336 cb_config.use_secureos = true;
Marshall Dawsondbae6322019-03-04 10:31:03 -07001337 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001338 case AMDFW_OPT_INSTANCE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001339 instance = strtoul(optarg, &tmp, 16);
1340 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001341 case AMDFW_OPT_LOAD_MP2FW:
Zheng Baoba3af5e2021-11-04 18:56:47 +08001342 cb_config.load_mp2_fw = true;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001343 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001344 case AMDFW_OPT_NVRAM:
Marshall Dawsondbae6322019-03-04 10:31:03 -07001345 register_fw_filename(AMD_FW_PSP_NVRAM, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001346 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001347 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001348 case AMDFW_OPT_FUSE:
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001349 register_fw_fuse(optarg);
1350 fuse_defined = 1;
1351 sub = 0;
1352 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001353 case AMDFW_OPT_APCB:
Zheng Bao5caca942020-12-04 16:39:38 +08001354 if ((instance & 0xF0) == 0)
1355 register_bdt_data(AMD_BIOS_APCB, sub, instance & 0xF, optarg);
1356 else
1357 register_bdt_data(AMD_BIOS_APCB_BK, sub,
1358 instance & 0xF, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001359 sub = instance = 0;
1360 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001361 case AMDFW_OPT_APOBBASE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001362 /* APOB destination */
1363 register_fw_addr(AMD_BIOS_APOB, 0, optarg, 0);
1364 sub = instance = 0;
1365 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001366 case AMDFW_OPT_APOB_NVBASE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001367 /* APOB NV source */
1368 register_fw_addr(AMD_BIOS_APOB_NV, optarg, 0, 0);
1369 sub = instance = 0;
1370 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001371 case AMDFW_OPT_APOB_NVSIZE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001372 /* APOB NV size */
1373 register_fw_addr(AMD_BIOS_APOB_NV, 0, 0, optarg);
1374 sub = instance = 0;
1375 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001376 case AMDFW_OPT_BIOSBIN:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001377 register_bdt_data(AMD_BIOS_BIN, sub, instance, optarg);
1378 sub = instance = 0;
1379 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001380 case AMDFW_OPT_BIOSBIN_SOURCE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001381 /* BIOS source */
1382 register_fw_addr(AMD_BIOS_BIN, optarg, 0, 0);
1383 sub = instance = 0;
1384 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001385 case AMDFW_OPT_BIOSBIN_DEST:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001386 /* BIOS destination */
1387 register_fw_addr(AMD_BIOS_BIN, 0, optarg, 0);
1388 sub = instance = 0;
1389 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001390 case AMDFW_OPT_BIOS_UNCOMP_SIZE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001391 /* BIOS destination size */
1392 register_fw_addr(AMD_BIOS_BIN, 0, 0, optarg);
1393 sub = instance = 0;
1394 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001395 case AMDFW_OPT_UCODE:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001396 register_bdt_data(AMD_BIOS_UCODE, sub,
1397 instance, optarg);
1398 sub = instance = 0;
1399 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001400 case AMDFW_OPT_LOAD_S0I3:
Zheng Baoba3af5e2021-11-04 18:56:47 +08001401 cb_config.s0i3 = true;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001402 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001403 case AMDFW_OPT_WHITELIST:
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001404 register_fw_filename(AMD_FW_PSP_WHITELIST, sub, optarg);
1405 sub = instance = 0;
Zheng Baoba3af5e2021-11-04 18:56:47 +08001406 cb_config.have_whitelist = true;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001407 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001408 case AMDFW_OPT_VERSTAGE:
Martin Rothd3ce8c82019-07-13 20:13:07 -06001409 register_fw_filename(AMD_FW_PSP_VERSTAGE, sub, optarg);
1410 sub = instance = 0;
1411 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001412 case AMDFW_OPT_VERSTAGE_SIG:
Martin Rothb1f648f2020-09-01 09:36:59 -06001413 register_fw_filename(AMD_FW_VERSTAGE_SIG, sub, optarg);
1414 sub = instance = 0;
1415 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001416 case AMDFW_OPT_SOC_NAME:
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001417 soc_id = identify_platform(optarg);
1418 if (soc_id == PLATFORM_UNKNOWN) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001419 fprintf(stderr, "Error: Invalid SOC name specified\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001420 retval = 1;
1421 }
1422 sub = instance = 0;
1423 break;
1424 case LONGOPT_SPI_READ_MODE:
1425 efs_spi_readmode = strtoull(optarg, NULL, 16);
1426 sub = instance = 0;
1427 break;
1428 case LONGOPT_SPI_SPEED:
1429 efs_spi_speed = strtoull(optarg, NULL, 16);
1430 sub = instance = 0;
1431 break;
1432 case LONGOPT_SPI_MICRON_FLAG:
1433 efs_spi_micron_flag = strtoull(optarg, NULL, 16);
1434 sub = instance = 0;
1435 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001436 case AMDFW_OPT_OUTPUT:
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001437 output = optarg;
1438 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001439 case AMDFW_OPT_FLASHSIZE:
Marshall Dawson2794a862019-03-04 16:53:15 -07001440 ctx.rom_size = (uint32_t)strtoul(optarg, &tmp, 16);
Martin Roth60f15512016-11-08 09:55:01 -07001441 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08001442 fprintf(stderr, "Error: ROM size specified"
Martin Roth60f15512016-11-08 09:55:01 -07001443 " incorrectly (%s)\n\n", optarg);
Martin Roth31d95a22016-11-08 11:22:12 -07001444 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07001445 }
1446 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001447 case AMDFW_OPT_LOCATION:
Martin Roth0d3b1182017-10-03 14:16:04 -06001448 dir_location = (uint32_t)strtoul(optarg, &tmp, 16);
1449 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08001450 fprintf(stderr, "Error: Directory Location specified"
Martin Roth0d3b1182017-10-03 14:16:04 -06001451 " incorrectly (%s)\n\n", optarg);
1452 retval = 1;
1453 }
1454 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001455 case AMDFW_OPT_ANYWHERE:
Martin Roth37305e72020-04-07 14:16:39 -06001456 any_location = 1;
1457 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001458 case AMDFW_OPT_SHAREDMEM:
Martin Roth94554742020-04-14 14:59:36 -06001459 /* shared memory destination */
1460 register_fw_addr(AMD_BIOS_PSP_SHARED_MEM, 0, optarg, 0);
1461 sub = instance = 0;
1462 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001463 case AMDFW_OPT_SHAREDMEM_SIZE:
Martin Roth94554742020-04-14 14:59:36 -06001464 /* shared memory size */
1465 register_fw_addr(AMD_BIOS_PSP_SHARED_MEM, NULL, NULL, optarg);
1466 sub = instance = 0;
1467 break;
Martin Roth0d3b1182017-10-03 14:16:04 -06001468
Zheng Bao806892a2021-04-27 17:21:54 +08001469 case AMDFW_OPT_CONFIG:
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001470 config = optarg;
1471 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001472 case AMDFW_OPT_DEBUG:
Zheng Bao9e908072020-10-28 11:39:13 +08001473 debug = 1;
1474 break;
Zheng Bao806892a2021-04-27 17:21:54 +08001475 case AMDFW_OPT_HELP:
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001476 usage();
Martin Roth31d95a22016-11-08 11:22:12 -07001477 return 0;
Zheng Bao806892a2021-04-27 17:21:54 +08001478 case AMDFW_OPT_LIST_DEPEND:
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001479 list_deps = 1;
1480 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001481 default:
1482 break;
1483 }
1484 }
1485
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001486 if (config) {
1487 config_handle = fopen(config, "r");
1488 if (config_handle == NULL) {
1489 fprintf(stderr, "Can not open file %s for reading: %s\n",
1490 config, strerror(errno));
1491 exit(1);
1492 }
1493 if (process_config(config_handle, &cb_config, list_deps) == 0) {
1494 fprintf(stderr, "Configuration file %s parsing error\n", config);
1495 fclose(config_handle);
1496 exit(1);
1497 }
1498 fclose(config_handle);
1499 }
Zheng Bao9e908072020-10-28 11:39:13 +08001500 /* For debug. */
1501 if (debug) {
1502 dump_psp_firmwares(amd_psp_fw_table);
1503 dump_bdt_firmwares(amd_bios_table);
1504 }
1505
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001506 if (!fuse_defined)
1507 register_fw_fuse(DEFAULT_SOFT_FUSE_CHAIN);
1508
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001509 if (!output && !list_deps) {
1510 fprintf(stderr, "Error: Output value is not specified.\n\n");
Martin Roth31d95a22016-11-08 11:22:12 -07001511 retval = 1;
1512 }
1513
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001514 if ((ctx.rom_size % 1024 != 0) && !list_deps) {
1515 fprintf(stderr, "Error: ROM Size (%d bytes) should be a multiple of"
Marshall Dawson2794a862019-03-04 16:53:15 -07001516 " 1024 bytes.\n\n", ctx.rom_size);
Martin Roth31d95a22016-11-08 11:22:12 -07001517 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07001518 }
1519
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001520 if ((ctx.rom_size < MIN_ROM_KB * 1024) && !list_deps) {
1521 fprintf(stderr, "Error: ROM Size (%dKB) must be at least %dKB.\n\n",
Marshall Dawson2794a862019-03-04 16:53:15 -07001522 ctx.rom_size / 1024, MIN_ROM_KB);
Martin Roth31d95a22016-11-08 11:22:12 -07001523 retval = 1;
1524 }
1525
1526 if (retval) {
1527 usage();
1528 return retval;
Martin Roth60f15512016-11-08 09:55:01 -07001529 }
1530
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001531 if (list_deps) {
1532 return retval;
1533 }
1534
Marshall Dawson2794a862019-03-04 16:53:15 -07001535 printf(" AMDFWTOOL Using ROM size of %dKB\n", ctx.rom_size / 1024);
Martin Roth60f15512016-11-08 09:55:01 -07001536
Marshall Dawson2794a862019-03-04 16:53:15 -07001537 rom_base_address = 0xFFFFFFFF - ctx.rom_size + 1;
Martin Roth0d3b1182017-10-03 14:16:04 -06001538 if (dir_location && (dir_location < rom_base_address)) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001539 fprintf(stderr, "Error: Directory location outside of ROM.\n\n");
Martin Roth0d3b1182017-10-03 14:16:04 -06001540 return 1;
1541 }
1542
Martin Roth37305e72020-04-07 14:16:39 -06001543 if (any_location) {
1544 if (dir_location & 0x3f) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001545 fprintf(stderr, "Error: Invalid Directory location.\n");
1546 fprintf(stderr, " Valid locations are 64-byte aligned\n");
Martin Roth37305e72020-04-07 14:16:39 -06001547 return 1;
1548 }
1549 } else {
1550 switch (dir_location) {
1551 case 0: /* Fall through */
1552 case 0xFFFA0000: /* Fall through */
1553 case 0xFFF20000: /* Fall through */
1554 case 0xFFE20000: /* Fall through */
1555 case 0xFFC20000: /* Fall through */
1556 case 0xFF820000: /* Fall through */
1557 case 0xFF020000: /* Fall through */
1558 break;
1559 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001560 fprintf(stderr, "Error: Invalid Directory location.\n");
1561 fprintf(stderr, " Valid locations are 0xFFFA0000, 0xFFF20000,\n");
1562 fprintf(stderr, " 0xFFE20000, 0xFFC20000, 0xFF820000, 0xFF020000\n");
Martin Roth37305e72020-04-07 14:16:39 -06001563 return 1;
1564 }
Martin Roth0d3b1182017-10-03 14:16:04 -06001565 }
Marshall Dawson2794a862019-03-04 16:53:15 -07001566 ctx.rom = malloc(ctx.rom_size);
1567 if (!ctx.rom) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001568 fprintf(stderr, "Error: Failed to allocate memory\n");
Martin Roth31d95a22016-11-08 11:22:12 -07001569 return 1;
Marshall Dawson2794a862019-03-04 16:53:15 -07001570 }
1571 memset(ctx.rom, 0xFF, ctx.rom_size);
Martin Roth60f15512016-11-08 09:55:01 -07001572
Martin Roth0d3b1182017-10-03 14:16:04 -06001573 if (dir_location)
Marshall Dawson2794a862019-03-04 16:53:15 -07001574 romsig_offset = ctx.current = dir_location - rom_base_address;
Martin Roth0d3b1182017-10-03 14:16:04 -06001575 else
Marshall Dawson2794a862019-03-04 16:53:15 -07001576 romsig_offset = ctx.current = AMD_ROMSIG_OFFSET;
Kangheui Won275ade92021-07-14 02:42:43 +00001577 printf(" AMDFWTOOL Using firmware directory location of 0x%08x\n",
1578 RUN_CURRENT(ctx));
Martin Roth0d3b1182017-10-03 14:16:04 -06001579
Marshall Dawson2794a862019-03-04 16:53:15 -07001580 amd_romsig = BUFF_OFFSET(ctx, romsig_offset);
Marshall Dawson239286c2019-02-23 16:42:46 -07001581 amd_romsig->signature = EMBEDDED_FW_SIGNATURE;
1582 amd_romsig->imc_entry = 0;
1583 amd_romsig->gec_entry = 0;
1584 amd_romsig->xhci_entry = 0;
Martin Roth60f15512016-11-08 09:55:01 -07001585
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001586 if (soc_id != PLATFORM_UNKNOWN) {
1587 retval = set_efs_table(soc_id, amd_romsig, efs_spi_readmode,
1588 efs_spi_speed, efs_spi_micron_flag);
1589 if (retval) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001590 fprintf(stderr, "ERROR: Failed to initialize EFS table!\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001591 return retval;
1592 }
1593 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08001594 fprintf(stderr, "WARNING: No SOC name specified.\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001595 }
1596
Marshall Dawson2794a862019-03-04 16:53:15 -07001597 integrate_firmwares(&ctx, amd_romsig, amd_fw_table);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001598
Patrick Georgi900a2542020-02-17 16:52:40 +01001599 ctx.current = ALIGN(ctx.current, 0x10000U); /* TODO: is it necessary? */
Marshall Dawson2794a862019-03-04 16:53:15 -07001600
Zheng Bao481661e2021-08-20 14:47:46 +08001601 if (cb_config.multi_level) {
Marshall Dawson24f73d42019-04-01 10:48:43 -06001602 /* Do 2nd PSP directory followed by 1st */
Zheng Bao481661e2021-08-20 14:47:46 +08001603 psp_directory_table *pspdir2 = new_psp_dir(&ctx, cb_config.multi_level);
Zheng Baoedd1e362021-11-04 17:47:07 +08001604 integrate_psp_firmwares(&ctx, pspdir2, NULL,
Zheng Bao20795892021-08-20 14:58:22 +08001605 amd_psp_fw_table, PSPL2_COOKIE, &cb_config);
Zheng Bao481661e2021-08-20 14:47:46 +08001606 pspdir = new_psp_dir(&ctx, cb_config.multi_level);
Marshall Dawson24f73d42019-04-01 10:48:43 -06001607 integrate_psp_firmwares(&ctx, pspdir, pspdir2,
Zheng Bao20795892021-08-20 14:58:22 +08001608 amd_psp_fw_table, PSP_COOKIE, &cb_config);
Marshall Dawson24f73d42019-04-01 10:48:43 -06001609 } else {
1610 /* flat: PSP 1 cookie and no pointer to 2nd table */
Zheng Bao481661e2021-08-20 14:47:46 +08001611 pspdir = new_psp_dir(&ctx, cb_config.multi_level);
Zheng Baoedd1e362021-11-04 17:47:07 +08001612 integrate_psp_firmwares(&ctx, pspdir, NULL,
Zheng Bao20795892021-08-20 14:58:22 +08001613 amd_psp_fw_table, PSP_COOKIE, &cb_config);
Marshall Dawson24f73d42019-04-01 10:48:43 -06001614 }
Marshall Dawson2794a862019-03-04 16:53:15 -07001615
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001616 if (comboable)
Felix Heldad68b072021-10-18 14:00:35 +02001617 amd_romsig->combo_psp_directory = BUFF_TO_RUN(ctx, pspdir);
Marshall Dawson67d868d2019-02-28 11:43:40 -07001618 else
Felix Heldad68b072021-10-18 14:00:35 +02001619 amd_romsig->psp_directory = BUFF_TO_RUN(ctx, pspdir);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001620
zbaoc3a08a92016-03-02 14:47:27 +08001621#if PSP_COMBO
Marshall Dawson2794a862019-03-04 16:53:15 -07001622 psp_combo_directory *combo_dir = new_combo_dir(&ctx);
Felix Heldad68b072021-10-18 14:00:35 +02001623 amd_romsig->combo_psp_directory = BUFF_TO_RUN(ctx, combo_dir);
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001624 /* 0 -Compare PSP ID, 1 -Compare chip family ID */
1625 combo_dir->entries[0].id_sel = 0;
Zheng Baoeb0404e2021-10-14 15:09:09 +08001626 combo_dir->entries[0].id = get_psp_id(soc_id);
Marshall Dawson2794a862019-03-04 16:53:15 -07001627 combo_dir->entries[0].lvl2_addr = BUFF_TO_RUN(ctx, pspdir);
Zheng Bao4fcc9f22015-11-20 12:29:04 +08001628
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001629 combo_dir->header.lookup = 1;
Zheng Baoec5a5d72021-06-15 14:41:37 +08001630 fill_dir_header(combo_dir, 1, PSP2_COOKIE, &ctx);
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001631#endif
Zheng Bao4fcc9f22015-11-20 12:29:04 +08001632
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001633 if (have_bios_tables(amd_bios_table)) {
1634 bios_directory_table *biosdir;
Zheng Bao481661e2021-08-20 14:47:46 +08001635 if (cb_config.multi_level) {
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001636 /* Do 2nd level BIOS directory followed by 1st */
1637 bios_directory_table *biosdir2 =
Zheng Bao481661e2021-08-20 14:47:46 +08001638 new_bios_dir(&ctx, cb_config.multi_level);
Zheng Baoedd1e362021-11-04 17:47:07 +08001639 integrate_bios_firmwares(&ctx, biosdir2, NULL,
Zheng Bao20795892021-08-20 14:58:22 +08001640 amd_bios_table, BDT2_COOKIE, &cb_config);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001641
Zheng Bao481661e2021-08-20 14:47:46 +08001642 biosdir = new_bios_dir(&ctx, cb_config.multi_level);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001643 integrate_bios_firmwares(&ctx, biosdir, biosdir2,
Zheng Bao20795892021-08-20 14:58:22 +08001644 amd_bios_table, BDT1_COOKIE, &cb_config);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001645 } else {
1646 /* flat: BDT1 cookie and no pointer to 2nd table */
Zheng Bao481661e2021-08-20 14:47:46 +08001647 biosdir = new_bios_dir(&ctx, cb_config.multi_level);
Zheng Baoedd1e362021-11-04 17:47:07 +08001648 integrate_bios_firmwares(&ctx, biosdir, NULL,
Zheng Bao20795892021-08-20 14:58:22 +08001649 amd_bios_table, BDT1_COOKIE, &cb_config);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001650 }
Zheng Baobf29a0d2020-12-03 23:00:48 +08001651 switch (soc_id) {
1652 case PLATFORM_RENOIR:
1653 case PLATFORM_LUCIENNE:
1654 case PLATFORM_CEZANNE:
1655 amd_romsig->bios3_entry = BUFF_TO_RUN(ctx, biosdir);
1656 break;
Zheng Bao535ec532021-08-12 16:30:19 +08001657 case PLATFORM_MENDOCINO:
1658 break;
Zheng Baobf29a0d2020-12-03 23:00:48 +08001659 case PLATFORM_STONEYRIDGE:
1660 case PLATFORM_RAVEN:
1661 case PLATFORM_PICASSO:
1662 default:
1663 amd_romsig->bios1_entry = BUFF_TO_RUN(ctx, biosdir);
1664 break;
1665 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001666 }
1667
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001668 /* Free the filename. */
1669 free_psp_firmware_filenames(amd_psp_fw_table);
1670 free_bdt_firmware_filenames(amd_bios_table);
1671
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001672 targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666);
Martin Roth31d95a22016-11-08 11:22:12 -07001673 if (targetfd >= 0) {
Zheng Bao47396912020-09-29 17:33:17 +08001674 ssize_t bytes;
1675 bytes = write(targetfd, amd_romsig, ctx.current - romsig_offset);
1676 if (bytes != ctx.current - romsig_offset) {
1677 fprintf(stderr, "Error: Writing to file %s failed\n", output);
1678 retval = 1;
1679 }
Martin Roth31d95a22016-11-08 11:22:12 -07001680 close(targetfd);
1681 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08001682 fprintf(stderr, "Error: could not open file: %s\n", output);
Martin Roth31d95a22016-11-08 11:22:12 -07001683 retval = 1;
1684 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001685
Martin Roth31d95a22016-11-08 11:22:12 -07001686 free(rom);
1687 return retval;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001688}