blob: 9cf6a4f8c0ad2a0812e95c9fabada979cdef325e [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>
60
61#include "amdfwtool.h"
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080062
Martin Roth60f15512016-11-08 09:55:01 -070063#define AMD_ROMSIG_OFFSET 0x20000
64#define MIN_ROM_KB 256
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080065
Martin Rothcd15bc82016-11-08 11:34:02 -070066#define ALIGN(val, by) (((val) + (by) - 1) & ~((by) - 1))
Marshall Dawson7c1e1422019-04-11 09:44:43 -060067#define _MAX(A, B) (((A) > (B)) ? (A) : (B))
68#define ERASE_ALIGNMENT 0x1000U
Marshall Dawson2794a862019-03-04 16:53:15 -070069#define TABLE_ALIGNMENT 0x1000U
70#define BLOB_ALIGNMENT 0x100U
Marshall Dawson24f73d42019-04-01 10:48:43 -060071#define TABLE_ERASE_ALIGNMENT _MAX(TABLE_ALIGNMENT, ERASE_ALIGNMENT)
Marshall Dawson7c1e1422019-04-11 09:44:43 -060072#define BLOB_ERASE_ALIGNMENT _MAX(BLOB_ALIGNMENT, ERASE_ALIGNMENT)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080073
Marshall Dawsonef79fcc2019-04-01 10:16:41 -060074#define DEFAULT_SOFT_FUSE_CHAIN "0x1"
75
Marshall Dawson239286c2019-02-23 16:42:46 -070076#define EMBEDDED_FW_SIGNATURE 0x55aa55aa
Marshall Dawson24f73d42019-04-01 10:48:43 -060077#define PSP_COOKIE 0x50535024 /* 'PSP$' */
78#define PSPL2_COOKIE 0x324c5024 /* '2LP$' */
79#define PSP2_COOKIE 0x50535032 /* 'PSP2' */
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -060080#define BDT1_COOKIE 0x44484224 /* 'DHB$ */
81#define BDT2_COOKIE 0x324c4224 /* '2LB$ */
Marshall Dawson239286c2019-02-23 16:42:46 -070082
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080083/*
Marshall Dawson0e02ce82019-03-04 16:50:37 -070084 * Beginning with Family 15h Models 70h-7F, a.k.a Stoney Ridge, the PSP
85 * can support an optional "combo" implementation. If the PSP sees the
86 * PSP2 cookie, it interprets the table as a roadmap to additional PSP
87 * tables. Using this, support for multiple product generations may be
88 * built into one image. If the PSP$ cookie is found, the table is a
89 * normal directory table.
90 *
91 * Modern generations supporting the combo directories require the
92 * pointer to be at offset 0x14 of the Embedded Firmware Structure,
93 * regardless of the type of directory used. The --combo-capable
94 * argument enforces this placement.
95 *
96 * TODO: Future work may require fully implementing the PSP_COMBO feature.
zbaoc3b0b722016-02-19 13:47:31 +080097 */
Marshall Dawson0e02ce82019-03-04 16:50:37 -070098#define PSP_COMBO 0
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080099
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800100/*
101 * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
102 * The checksum field of the passed PDU does not need to be reset to zero.
103 *
104 * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of
105 * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an
106 * alternative to cyclical redundancy checks because it provides error-
107 * detection properties similar to cyclical redundancy checks but at the
108 * cost of a simple summation technique. Its characteristics were first
109 * published in IEEE Transactions on Communications in January 1982. One
110 * version has been adopted by ISO for use in the class-4 transport layer
111 * of the network protocol.
112 *
113 * This program expects:
114 * stdin: The input file to compute a checksum for. The input file
115 * not be longer than 256 bytes.
116 * stdout: Copied from the input file with the Fletcher's Checksum
117 * inserted 8 bytes after the beginning of the file.
118 * stderr: Used to print out error messages.
119 */
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700120static uint32_t fletcher32(const void *data, int length)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800121{
122 uint32_t c0;
123 uint32_t c1;
124 uint32_t checksum;
125 int index;
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700126 const uint16_t *pptr = data;
127
128 length /= 2;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800129
130 c0 = 0xFFFF;
131 c1 = 0xFFFF;
132
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600133 while (length) {
134 index = length >= 359 ? 359 : length;
135 length -= index;
136 do {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800137 c0 += *(pptr++);
138 c1 += c0;
Marshall Dawsonb85ddc52019-07-23 07:24:30 -0600139 } while (--index);
140 c0 = (c0 & 0xFFFF) + (c0 >> 16);
141 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800142 }
143
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700144 /* Sums[0,1] mod 64K + overflow */
145 c0 = (c0 & 0xFFFF) + (c0 >> 16);
146 c1 = (c1 & 0xFFFF) + (c1 >> 16);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800147 checksum = (c1 << 16) | c0;
148
149 return checksum;
150}
151
Martin Roth8806f7f2016-11-08 10:44:18 -0700152static void usage(void)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800153{
Martin Roth0e940622016-11-08 10:37:53 -0700154 printf("amdfwtool: Create AMD Firmware combination\n");
155 printf("Usage: amdfwtool [options] -f <size> -o <filename>\n");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600156 printf("-x | --xhci <FILE> Add XHCI blob\n");
157 printf("-i | --imc <FILE> Add IMC blob\n");
158 printf("-g | --gec <FILE> Add GEC blob\n");
Martin Roth0e940622016-11-08 10:37:53 -0700159
160 printf("\nPSP options:\n");
Marshall Dawson67d868d2019-02-28 11:43:40 -0700161 printf("-A | --combo-capable Place PSP directory pointer at Embedded Firmware\n");
162 printf(" offset able to support combo directory\n");
Marshall Dawson24f73d42019-04-01 10:48:43 -0600163 printf("-M | --multilevel Generate primary and secondary tables\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800164 printf("-n | --nvram <FILE> Add nvram binary\n");
165 printf("-T | --soft-fuse Set soft fuse\n");
166 printf("-U | --token-unlock Set token unlock\n");
167 printf("-W | --whitelist Set if there is a whitelist\n");
168 printf("-S | --use-pspsecureos Set if psp secure OS is needed\n");
169 printf("-p | --load-mp2-fw Set if load MP2 firmware\n");
170 printf("-L | --load-s0i3 Set if load s0i3 firmware\n");
Martin Rothd3ce8c82019-07-13 20:13:07 -0600171 printf("-Z | --verstage <FILE> Add verstage\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800172 printf("-E | --verstage_sig Add verstage signature");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600173 printf("\nBIOS options:\n");
174 printf("-I | --instance <number> Sets instance field for the next BIOS firmware\n");
175 printf("-a | --apcb <FILE> Add AGESA PSP customization block\n");
176 printf("-Q | --apob-base <HEX_VAL> Destination for AGESA PSP output block\n");
177 printf("-F | --apob-nv-base <HEX_VAL> Location of S3 resume data\n");
178 printf("-H | --apob-nv-size <HEX_VAL> Size of S3 resume data\n");
Martin Rothec933132019-07-13 20:03:34 -0600179 printf("-O | --ucode <FILE> Add microcode patch\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600180 printf("-V | --bios-bin <FILE> Add compressed image; auto source address\n");
181 printf("-e | --bios-bin-src <HEX_VAL> Address in flash of source if -V not used\n");
182 printf("-v | --bios-bin-dest <HEX_VAL> Destination for uncompressed BIOS\n");
183 printf("-j | --bios-uncomp-size <HEX> Uncompressed size of BIOS image\n");
Martin Roth0e940622016-11-08 10:37:53 -0700184 printf("\n-o | --output <filename> output filename\n");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600185 printf("-f | --flashsize <HEX_VAL> ROM size in bytes\n");
186 printf(" size must be larger than %dKB\n",
Martin Roth0e940622016-11-08 10:37:53 -0700187 MIN_ROM_KB);
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600188 printf(" and must a multiple of 1024\n");
Martin Roth0d3b1182017-10-03 14:16:04 -0600189 printf("-l | --location Location of Directory\n");
Martin Roth37305e72020-04-07 14:16:39 -0600190 printf("-q | --anywhere Use any 64-byte aligned addr for Directory\n");
Martin Roth94554742020-04-14 14:59:36 -0600191 printf("-R | --sharedmem Location of PSP/FW shared memory\n");
192 printf("-P | --sharedmem-size Maximum size of the PSP/FW shared memory area\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500193 printf("-C | --soc-name <socname> Specify SOC name. Supported names are\n");
194 printf(" Stoneyridge, Raven, Picasso, Renoir or Lucienne");
Marshall Dawsonf4b9b412017-03-17 16:30:51 -0600195 printf("-h | --help show this help\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500196 printf("\nEmbedded Firmware Structure options used by the PSP:\n");
197 printf("--spi-speed <HEX_VAL> SPI fast speed to place in EFS Table\n");
198 printf(" 0x0 66.66Mhz\n");
199 printf(" 0x1 33.33MHz\n");
200 printf(" 0x2 22.22MHz\n");
201 printf(" 0x3 16.66MHz\n");
202 printf(" 0x4 100MHz\n");
203 printf(" 0x5 800KHz\n");
204 printf("--spi-read-mode <HEX_VAL> SPI read mode to place in EFS Table\n");
205 printf(" 0x0 Normal Read (up to 33M)\n");
206 printf(" 0x1 Reserved\n");
207 printf(" 0x2 Dual IO (1-1-2)\n");
208 printf(" 0x3 Quad IO (1-1-4)\n");
209 printf(" 0x4 Dual IO (1-2-2)\n");
210 printf(" 0x5 Quad IO (1-4-4)\n");
211 printf(" 0x6 Normal Read (up to 66M)\n");
212 printf(" 0x7 Fast Read\n");
213 printf("--spi-micron-flag <HEX_VAL> Micron SPI part support for RV and later SOC\n");
214 printf(" 0x0 Micron parts are not used\n");
215 printf(" 0x1 Micron parts are always used\n");
216 printf(" 0x2 Micron parts optional, this option is only\n");
217 printf(" supported with RN/LCN SOC\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800218 printf("-c | --config <config file> Config file\n");
Zheng Bao9e908072020-10-28 11:39:13 +0800219 printf("-d | --debug Print debug message\n");
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800220 printf("-D | --depend List out the firmware files\n");
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800221}
222
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800223amd_fw_entry amd_psp_fw_table[] = {
Marshall Dawson24f73d42019-04-01 10:48:43 -0600224 { .type = AMD_FW_PSP_PUBKEY, .level = PSP_BOTH },
225 { .type = AMD_FW_PSP_BOOTLOADER, .level = PSP_BOTH },
226 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 0, .level = PSP_BOTH },
227 { .type = AMD_FW_PSP_RECOVERY, .level = PSP_LVL1 },
228 { .type = AMD_FW_PSP_RTM_PUBKEY, .level = PSP_BOTH },
229 { .type = AMD_FW_PSP_SECURED_OS, .level = PSP_LVL2 },
230 { .type = AMD_FW_PSP_NVRAM, .level = PSP_LVL2 },
231 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 2, .level = PSP_BOTH },
232 { .type = AMD_FW_PSP_SECURED_DEBUG, .level = PSP_LVL2 },
233 { .type = AMD_FW_PSP_TRUSTLETS, .level = PSP_LVL2 },
234 { .type = AMD_FW_PSP_TRUSTLETKEY, .level = PSP_LVL2 },
235 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 2, .level = PSP_BOTH },
236 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
237 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
238 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .level = PSP_BOTH },
239 { .type = AMD_FW_PSP_SMUSCS, .level = PSP_BOTH },
240 { .type = AMD_PSP_FUSE_CHAIN, .level = PSP_LVL2 },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600241 { .type = AMD_DEBUG_UNLOCK, .level = PSP_LVL2 },
242 { .type = AMD_WRAPPED_IKEK, .level = PSP_BOTH },
243 { .type = AMD_TOKEN_UNLOCK, .level = PSP_BOTH },
244 { .type = AMD_SEC_GASKET, .subprog = 2, .level = PSP_BOTH },
245 { .type = AMD_SEC_GASKET, .subprog = 1, .level = PSP_BOTH },
246 { .type = AMD_MP2_FW, .subprog = 2, .level = PSP_LVL2 },
247 { .type = AMD_MP2_FW, .subprog = 1, .level = PSP_LVL2 },
248 { .type = AMD_DRIVER_ENTRIES, .level = PSP_LVL2 },
249 { .type = AMD_S0I3_DRIVER, .level = PSP_LVL2 },
250 { .type = AMD_ABL0, .level = PSP_BOTH },
251 { .type = AMD_ABL1, .level = PSP_BOTH },
252 { .type = AMD_ABL2, .level = PSP_BOTH },
253 { .type = AMD_ABL3, .level = PSP_BOTH },
254 { .type = AMD_ABL4, .level = PSP_BOTH },
255 { .type = AMD_ABL5, .level = PSP_BOTH },
256 { .type = AMD_ABL6, .level = PSP_BOTH },
257 { .type = AMD_ABL7, .level = PSP_BOTH },
Marshall Dawson24f73d42019-04-01 10:48:43 -0600258 { .type = AMD_FW_PSP_SMU_FIRMWARE, .subprog = 1, .level = PSP_BOTH },
259 { .type = AMD_FW_PSP_SMU_FIRMWARE2, .subprog = 1, .level = PSP_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600260 { .type = AMD_FW_PSP_WHITELIST, .level = PSP_LVL2 },
Martin Rothd3ce8c82019-07-13 20:13:07 -0600261 { .type = AMD_FW_PSP_VERSTAGE, .level = PSP_BOTH },
Martin Rothb1f648f2020-09-01 09:36:59 -0600262 { .type = AMD_FW_VERSTAGE_SIG, .level = PSP_BOTH },
zbaoc3a08a92016-03-02 14:47:27 +0800263 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800264};
265
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800266amd_fw_entry amd_fw_table[] = {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800267 { .type = AMD_FW_XHCI },
268 { .type = AMD_FW_IMC },
269 { .type = AMD_FW_GEC },
zbaoc3a08a92016-03-02 14:47:27 +0800270 { .type = AMD_FW_INVALID },
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800271};
272
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800273amd_bios_entry amd_bios_table[] = {
Marshall Dawson0581bf62019-09-25 11:03:53 -0600274 { .type = AMD_BIOS_APCB, .inst = 0, .level = BDT_BOTH },
275 { .type = AMD_BIOS_APCB, .inst = 1, .level = BDT_BOTH },
276 { .type = AMD_BIOS_APCB, .inst = 2, .level = BDT_BOTH },
277 { .type = AMD_BIOS_APCB, .inst = 3, .level = BDT_BOTH },
278 { .type = AMD_BIOS_APCB, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700279 { .type = AMD_BIOS_APCB, .inst = 5, .level = BDT_BOTH },
280 { .type = AMD_BIOS_APCB, .inst = 6, .level = BDT_BOTH },
281 { .type = AMD_BIOS_APCB, .inst = 7, .level = BDT_BOTH },
282 { .type = AMD_BIOS_APCB, .inst = 8, .level = BDT_BOTH },
283 { .type = AMD_BIOS_APCB, .inst = 9, .level = BDT_BOTH },
284 { .type = AMD_BIOS_APCB, .inst = 10, .level = BDT_BOTH },
285 { .type = AMD_BIOS_APCB, .inst = 11, .level = BDT_BOTH },
286 { .type = AMD_BIOS_APCB, .inst = 12, .level = BDT_BOTH },
287 { .type = AMD_BIOS_APCB, .inst = 13, .level = BDT_BOTH },
288 { .type = AMD_BIOS_APCB, .inst = 14, .level = BDT_BOTH },
289 { .type = AMD_BIOS_APCB, .inst = 15, .level = BDT_BOTH },
Marshall Dawson2dd3b5c2020-01-03 17:57:48 -0700290 { .type = AMD_BIOS_APCB_BK, .inst = 0, .level = BDT_BOTH },
291 { .type = AMD_BIOS_APCB_BK, .inst = 1, .level = BDT_BOTH },
292 { .type = AMD_BIOS_APCB_BK, .inst = 2, .level = BDT_BOTH },
293 { .type = AMD_BIOS_APCB_BK, .inst = 3, .level = BDT_BOTH },
294 { .type = AMD_BIOS_APCB_BK, .inst = 4, .level = BDT_BOTH },
Rob Barnes18fd26c2020-03-03 10:35:02 -0700295 { .type = AMD_BIOS_APCB_BK, .inst = 5, .level = BDT_BOTH },
296 { .type = AMD_BIOS_APCB_BK, .inst = 6, .level = BDT_BOTH },
297 { .type = AMD_BIOS_APCB_BK, .inst = 7, .level = BDT_BOTH },
298 { .type = AMD_BIOS_APCB_BK, .inst = 8, .level = BDT_BOTH },
299 { .type = AMD_BIOS_APCB_BK, .inst = 9, .level = BDT_BOTH },
300 { .type = AMD_BIOS_APCB_BK, .inst = 10, .level = BDT_BOTH },
301 { .type = AMD_BIOS_APCB_BK, .inst = 11, .level = BDT_BOTH },
302 { .type = AMD_BIOS_APCB_BK, .inst = 12, .level = BDT_BOTH },
303 { .type = AMD_BIOS_APCB_BK, .inst = 13, .level = BDT_BOTH },
304 { .type = AMD_BIOS_APCB_BK, .inst = 14, .level = BDT_BOTH },
305 { .type = AMD_BIOS_APCB_BK, .inst = 15, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600306 { .type = AMD_BIOS_APOB, .level = BDT_BOTH },
307 { .type = AMD_BIOS_BIN,
308 .reset = 1, .copy = 1, .zlib = 1, .level = BDT_BOTH },
309 { .type = AMD_BIOS_APOB_NV, .level = BDT_LVL2 },
310 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 0, .level = BDT_BOTH },
311 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 0, .level = BDT_BOTH },
312 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 0, .level = BDT_BOTH },
313 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 0, .level = BDT_BOTH },
314 { .type = AMD_BIOS_PMUI, .inst = 1, .subpr = 1, .level = BDT_BOTH },
315 { .type = AMD_BIOS_PMUD, .inst = 1, .subpr = 1, .level = BDT_BOTH },
316 { .type = AMD_BIOS_PMUI, .inst = 4, .subpr = 1, .level = BDT_BOTH },
317 { .type = AMD_BIOS_PMUD, .inst = 4, .subpr = 1, .level = BDT_BOTH },
318 { .type = AMD_BIOS_UCODE, .inst = 0, .level = BDT_LVL2 },
319 { .type = AMD_BIOS_UCODE, .inst = 1, .level = BDT_LVL2 },
320 { .type = AMD_BIOS_UCODE, .inst = 2, .level = BDT_LVL2 },
321 { .type = AMD_BIOS_MP2_CFG, .level = BDT_LVL2 },
Martin Roth94554742020-04-14 14:59:36 -0600322 { .type = AMD_BIOS_PSP_SHARED_MEM, .inst = 0, .level = BDT_BOTH },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600323 { .type = AMD_BIOS_INVALID },
324};
325
Marshall Dawson239286c2019-02-23 16:42:46 -0700326typedef struct _embedded_firmware {
327 uint32_t signature; /* 0x55aa55aa */
328 uint32_t imc_entry;
329 uint32_t gec_entry;
330 uint32_t xhci_entry;
331 uint32_t psp_entry;
332 uint32_t comboable;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600333 uint32_t bios0_entry; /* todo: add way to select correct entry */
334 uint32_t bios1_entry;
Marshall Dawson94f24922019-09-28 08:49:09 -0600335 uint32_t bios2_entry;
Matt Papageorgebe4376c2020-06-15 11:18:15 -0500336 uint32_t second_gen_efs;
337 uint32_t bios3_entry;
338 uint32_t reserved_2Ch;
339 uint32_t promontory_fw_ptr;
340 uint32_t lp_promontory_fw_ptr;
341 uint32_t reserved_38h;
342 uint32_t reserved_3Ch;
343 uint8_t spi_readmode_f15_mod_60_6f;
344 uint8_t fast_speed_new_f15_mod_60_6f;
345 uint8_t reserved_42h;
346 uint8_t spi_readmode_f17_mod_00_2f;
347 uint8_t spi_fastspeed_f17_mod_00_2f;
348 uint8_t qpr_dummy_cycle_f17_mod_00_2f;
349 uint8_t reserved_46h;
350 uint8_t spi_readmode_f17_mod_30_3f;
351 uint8_t spi_fastspeed_f17_mod_30_3f;
352 uint8_t micron_detect_f17_mod_30_3f;
353 uint8_t reserved_4Ah;
354 uint8_t reserved_4Bh;
355 uint32_t reserved_4Ch;
Marshall Dawson239286c2019-02-23 16:42:46 -0700356} __attribute__((packed, aligned(16))) embedded_firmware;
357
358typedef struct _psp_directory_header {
359 uint32_t cookie;
360 uint32_t checksum;
361 uint32_t num_entries;
362 uint32_t reserved;
363} __attribute__((packed, aligned(16))) psp_directory_header;
364
365typedef struct _psp_directory_entry {
Marshall Dawsondbae6322019-03-04 10:31:03 -0700366 uint8_t type;
367 uint8_t subprog;
368 uint16_t rsvd;
Marshall Dawson239286c2019-02-23 16:42:46 -0700369 uint32_t size;
370 uint64_t addr; /* or a value in some cases */
371} __attribute__((packed)) psp_directory_entry;
372
373typedef struct _psp_directory_table {
374 psp_directory_header header;
375 psp_directory_entry entries[];
376} __attribute__((packed)) psp_directory_table;
377
Marshall Dawson2794a862019-03-04 16:53:15 -0700378#define MAX_PSP_ENTRIES 0x1f
379
Marshall Dawson239286c2019-02-23 16:42:46 -0700380typedef struct _psp_combo_header {
381 uint32_t cookie;
382 uint32_t checksum;
383 uint32_t num_entries;
384 uint32_t lookup;
385 uint64_t reserved[2];
386} __attribute__((packed, aligned(16))) psp_combo_header;
387
388typedef struct _psp_combo_entry {
389 uint32_t id_sel;
390 uint32_t id;
391 uint64_t lvl2_addr;
392} __attribute__((packed)) psp_combo_entry;
393
394typedef struct _psp_combo_directory {
395 psp_combo_header header;
396 psp_combo_entry entries[];
397} __attribute__((packed)) psp_combo_directory;
398
Marshall Dawson2794a862019-03-04 16:53:15 -0700399#define MAX_COMBO_ENTRIES 1
400
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600401typedef struct _bios_directory_hdr {
402 uint32_t cookie;
403 uint32_t checksum;
404 uint32_t num_entries;
405 uint32_t reserved;
406} __attribute__((packed, aligned(16))) bios_directory_hdr;
407
408typedef struct _bios_directory_entry {
409 uint8_t type;
410 uint8_t region_type;
411 int reset:1;
412 int copy:1;
413 int ro:1;
414 int compressed:1;
415 int inst:4;
416 uint8_t subprog; /* b[7:3] reserved */
417 uint32_t size;
418 uint64_t source;
419 uint64_t dest;
420} __attribute__((packed)) bios_directory_entry;
421
422typedef struct _bios_directory_table {
423 bios_directory_hdr header;
424 bios_directory_entry entries[];
425} bios_directory_table;
426
Martin Roth94554742020-04-14 14:59:36 -0600427#define MAX_BIOS_ENTRIES 0x2f
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600428
Marshall Dawson2794a862019-03-04 16:53:15 -0700429typedef struct _context {
430 char *rom; /* target buffer, size of flash device */
431 uint32_t rom_size; /* size of flash device */
432 uint32_t current; /* pointer within flash & proxy buffer */
433} context;
434
435#define RUN_BASE(ctx) (0xFFFFFFFF - (ctx).rom_size + 1)
436#define RUN_OFFSET(ctx, offset) (RUN_BASE(ctx) + (offset))
437#define RUN_CURRENT(ctx) RUN_OFFSET((ctx), (ctx).current)
438#define BUFF_OFFSET(ctx, offset) ((void *)((ctx).rom + (offset)))
439#define BUFF_CURRENT(ctx) BUFF_OFFSET((ctx), (ctx).current)
440#define BUFF_TO_RUN(ctx, ptr) RUN_OFFSET((ctx), ((char *)(ptr) - (ctx).rom))
441#define BUFF_ROOM(ctx) ((ctx).rom_size - (ctx).current)
442
Marshall Dawson24f73d42019-04-01 10:48:43 -0600443static void *new_psp_dir(context *ctx, int multi)
Marshall Dawson2794a862019-03-04 16:53:15 -0700444{
445 void *ptr;
446
Marshall Dawson24f73d42019-04-01 10:48:43 -0600447 /*
448 * Force both onto boundary when multi. Primary table is after
449 * updatable table, so alignment ensures primary can stay intact
450 * if secondary is reprogrammed.
451 */
452 if (multi)
453 ctx->current = ALIGN(ctx->current, TABLE_ERASE_ALIGNMENT);
454 else
455 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
456
Marshall Dawson2794a862019-03-04 16:53:15 -0700457 ptr = BUFF_CURRENT(*ctx);
458 ctx->current += sizeof(psp_directory_header)
459 + MAX_PSP_ENTRIES * sizeof(psp_directory_entry);
460 return ptr;
461}
462
Martin Rothec933132019-07-13 20:03:34 -0600463#if PSP_COMBO
Marshall Dawson2794a862019-03-04 16:53:15 -0700464static void *new_combo_dir(context *ctx)
465{
466 void *ptr;
467
468 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
469 ptr = BUFF_CURRENT(*ctx);
470 ctx->current += sizeof(psp_combo_header)
471 + MAX_COMBO_ENTRIES * sizeof(psp_combo_entry);
472 return ptr;
473}
Martin Rothec933132019-07-13 20:03:34 -0600474#endif
Marshall Dawson2794a862019-03-04 16:53:15 -0700475
Marshall Dawsona378c222019-03-04 16:52:07 -0700476static void fill_dir_header(void *directory, uint32_t count, uint32_t cookie)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800477{
Marshall Dawson24f73d42019-04-01 10:48:43 -0600478 psp_combo_directory *cdir = directory;
479 psp_directory_table *dir = directory;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600480 bios_directory_table *bdir = directory;
Marshall Dawson24f73d42019-04-01 10:48:43 -0600481
482 if (!count)
483 return;
484
485 switch (cookie) {
486 case PSP2_COOKIE:
Marshall Dawsona378c222019-03-04 16:52:07 -0700487 /* caller is responsible for lookup mode */
Marshall Dawsona378c222019-03-04 16:52:07 -0700488 cdir->header.cookie = cookie;
489 cdir->header.num_entries = count;
490 cdir->header.reserved[0] = 0;
491 cdir->header.reserved[1] = 0;
492 /* checksum everything that comes after the Checksum field */
493 cdir->header.checksum = fletcher32(&cdir->header.num_entries,
494 count * sizeof(psp_combo_entry)
495 + sizeof(cdir->header.num_entries)
496 + sizeof(cdir->header.lookup)
497 + 2 * sizeof(cdir->header.reserved[0]));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600498 break;
499 case PSP_COOKIE:
500 case PSPL2_COOKIE:
Marshall Dawsona378c222019-03-04 16:52:07 -0700501 dir->header.cookie = cookie;
502 dir->header.num_entries = count;
503 dir->header.reserved = 0;
504 /* checksum everything that comes after the Checksum field */
505 dir->header.checksum = fletcher32(&dir->header.num_entries,
Marshall Dawson8a45a4d2019-02-24 07:18:44 -0700506 count * sizeof(psp_directory_entry)
Marshall Dawsona378c222019-03-04 16:52:07 -0700507 + sizeof(dir->header.num_entries)
508 + sizeof(dir->header.reserved));
Marshall Dawson24f73d42019-04-01 10:48:43 -0600509 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600510 case BDT1_COOKIE:
511 case BDT2_COOKIE:
512 bdir->header.cookie = cookie;
513 bdir->header.num_entries = count;
514 bdir->header.reserved = 0;
515 /* checksum everything that comes after the Checksum field */
516 bdir->header.checksum = fletcher32(&bdir->header.num_entries,
517 count * sizeof(bios_directory_entry)
518 + sizeof(bdir->header.num_entries)
519 + sizeof(bdir->header.reserved));
520 break;
Marshall Dawsona378c222019-03-04 16:52:07 -0700521 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800522}
523
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700524static ssize_t copy_blob(void *dest, const char *src_file, size_t room)
525{
526 int fd;
527 struct stat fd_stat;
528 ssize_t bytes;
529
530 fd = open(src_file, O_RDONLY);
531 if (fd < 0) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800532 fprintf(stderr, "Error opening file: %s: %s\n",
Eric Peersaf505672020-03-05 16:04:15 -0700533 src_file, strerror(errno));
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700534 return -1;
535 }
536
537 if (fstat(fd, &fd_stat)) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800538 fprintf(stderr, "fstat error: %s\n", strerror(errno));
Jacob Garber967f8622019-07-02 10:35:10 -0600539 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700540 return -2;
541 }
542
Zheng Bao6d402ac2020-10-01 16:16:30 +0800543 if ((size_t)fd_stat.st_size > room) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800544 fprintf(stderr, "Error: %s will not fit. Exiting.\n", src_file);
Jacob Garber967f8622019-07-02 10:35:10 -0600545 close(fd);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700546 return -3;
547 }
548
549 bytes = read(fd, dest, (size_t)fd_stat.st_size);
550 close(fd);
551 if (bytes != (ssize_t)fd_stat.st_size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800552 fprintf(stderr, "Error while reading %s\n", src_file);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700553 return -4;
554 }
555
556 return bytes;
557}
558
Marshall Dawson2794a862019-03-04 16:53:15 -0700559static void integrate_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -0700560 embedded_firmware *romsig,
Marshall Dawson2794a862019-03-04 16:53:15 -0700561 amd_fw_entry *fw_table)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800562{
Richard Spiegel137484d2018-01-17 10:23:19 -0700563 ssize_t bytes;
Zheng Bao6d402ac2020-10-01 16:16:30 +0800564 uint32_t i;
Marshall Dawson2794a862019-03-04 16:53:15 -0700565
566 ctx->current += sizeof(embedded_firmware);
567 ctx->current = ALIGN(ctx->current, BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800568
Martin Rothcd15bc82016-11-08 11:34:02 -0700569 for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
zbaoc3a08a92016-03-02 14:47:27 +0800570 if (fw_table[i].filename != NULL) {
zbaoc3a08a92016-03-02 14:47:27 +0800571 switch (fw_table[i].type) {
572 case AMD_FW_IMC:
Marshall Dawson2794a862019-03-04 16:53:15 -0700573 ctx->current = ALIGN(ctx->current, 0x10000U);
574 romsig->imc_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800575 break;
576 case AMD_FW_GEC:
Marshall Dawson2794a862019-03-04 16:53:15 -0700577 romsig->gec_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800578 break;
579 case AMD_FW_XHCI:
Marshall Dawson2794a862019-03-04 16:53:15 -0700580 romsig->xhci_entry = RUN_CURRENT(*ctx);
zbaoc3a08a92016-03-02 14:47:27 +0800581 break;
582 default:
583 /* Error */
584 break;
585 }
586
Marshall Dawson2794a862019-03-04 16:53:15 -0700587 bytes = copy_blob(BUFF_CURRENT(*ctx),
588 fw_table[i].filename, BUFF_ROOM(*ctx));
Marshall Dawson02bd7732019-03-13 14:43:17 -0600589 if (bytes < 0) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700590 free(ctx->rom);
Martin Roth60f15512016-11-08 09:55:01 -0700591 exit(1);
592 }
593
Marshall Dawson2794a862019-03-04 16:53:15 -0700594 ctx->current = ALIGN(ctx->current + bytes,
595 BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800596 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800597 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800598}
599
Zheng Bao9e908072020-10-28 11:39:13 +0800600/* For debugging */
601static void dump_psp_firmwares(amd_fw_entry *fw_table)
602{
603 amd_fw_entry *index;
604
605 printf("PSP firmware components:");
606 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
607 if (index->filename)
608 printf(" filename=%s\n", index->filename);
609 }
610}
611
612static void dump_bdt_firmwares(amd_bios_entry *fw_table)
613{
614 amd_bios_entry *index;
615
616 printf("BIOS Directory Table (BDT) components:");
617 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
618 if (index->filename)
619 printf(" filename=%s\n", index->filename);
620 }
621}
622
Zheng Baoc5e28ab2020-10-28 11:38:09 +0800623static void free_psp_firmware_filenames(amd_fw_entry *fw_table)
624{
625 amd_fw_entry *index;
626
627 for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
628 if (index->filename &&
629 index->type != AMD_FW_VERSTAGE_SIG &&
630 index->type != AMD_FW_PSP_VERSTAGE &&
631 index->type != AMD_FW_PSP_WHITELIST) {
632 free(index->filename);
633 }
634 }
635}
636
637static void free_bdt_firmware_filenames(amd_bios_entry *fw_table)
638{
639 amd_bios_entry *index;
640
641 for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
642 if (index->filename &&
643 index->type != AMD_BIOS_APCB &&
644 index->type != AMD_BIOS_BIN &&
645 index->type != AMD_BIOS_APCB_BK)
646 free(index->filename);
647 }
648}
649
Marshall Dawson2794a862019-03-04 16:53:15 -0700650static void integrate_psp_firmwares(context *ctx,
Marshall Dawson239286c2019-02-23 16:42:46 -0700651 psp_directory_table *pspdir,
Marshall Dawson24f73d42019-04-01 10:48:43 -0600652 psp_directory_table *pspdir2,
653 amd_fw_entry *fw_table,
654 uint32_t cookie)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800655{
Richard Spiegel137484d2018-01-17 10:23:19 -0700656 ssize_t bytes;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700657 unsigned int i, count;
Marshall Dawson24f73d42019-04-01 10:48:43 -0600658 int level;
659
660 /* This function can create a primary table, a secondary table, or a
661 * flattened table which contains all applicable types. These if-else
662 * statements infer what the caller intended. If a 2nd-level cookie
663 * is passed, clearly a 2nd-level table is intended. However, a
664 * 1st-level cookie may indicate level 1 or flattened. If the caller
665 * passes a pointer to a 2nd-level table, then assume not flat.
666 */
667 if (cookie == PSPL2_COOKIE)
668 level = PSP_LVL2;
669 else if (pspdir2)
670 level = PSP_LVL1;
671 else
672 level = PSP_BOTH;
Marshall Dawson2794a862019-03-04 16:53:15 -0700673
674 ctx->current = ALIGN(ctx->current, BLOB_ALIGNMENT);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800675
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700676 for (i = 0, count = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
Marshall Dawson24f73d42019-04-01 10:48:43 -0600677 if (!(fw_table[i].level & level))
678 continue;
679
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600680 if (fw_table[i].type == AMD_TOKEN_UNLOCK) {
681 if (!fw_table[i].other)
682 continue;
683 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
684 pspdir->entries[count].type = fw_table[i].type;
685 pspdir->entries[count].size = 4096; /* TODO: doc? */
686 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
687 pspdir->entries[count].subprog = fw_table[i].subprog;
688 pspdir->entries[count].rsvd = 0;
689 ctx->current = ALIGN(ctx->current + 4096, 0x100U);
690 count++;
691 } else if (fw_table[i].type == AMD_PSP_FUSE_CHAIN) {
Marshall Dawson239286c2019-02-23 16:42:46 -0700692 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -0700693 pspdir->entries[count].subprog = fw_table[i].subprog;
694 pspdir->entries[count].rsvd = 0;
Marshall Dawson239286c2019-02-23 16:42:46 -0700695 pspdir->entries[count].size = 0xFFFFFFFF;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -0600696 pspdir->entries[count].addr = fw_table[i].other;
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700697 count++;
Marshall Dawson7c1e1422019-04-11 09:44:43 -0600698 } else if (fw_table[i].type == AMD_FW_PSP_NVRAM) {
699 if (fw_table[i].filename == NULL)
700 continue;
701 /* TODO: Add a way to reserve for NVRAM without
702 * requiring a filename. This isn't a feature used
703 * by coreboot systems, so priority is very low.
704 */
705 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
706 bytes = copy_blob(BUFF_CURRENT(*ctx),
707 fw_table[i].filename, BUFF_ROOM(*ctx));
708 if (bytes <= 0) {
709 free(ctx->rom);
710 exit(1);
711 }
712
713 pspdir->entries[count].type = fw_table[i].type;
714 pspdir->entries[count].subprog = fw_table[i].subprog;
715 pspdir->entries[count].rsvd = 0;
716 pspdir->entries[count].size = ALIGN(bytes,
717 ERASE_ALIGNMENT);
718 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
719
720 ctx->current = ALIGN(ctx->current + bytes,
721 BLOB_ERASE_ALIGNMENT);
722 count++;
zbaoc3a08a92016-03-02 14:47:27 +0800723 } else if (fw_table[i].filename != NULL) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700724 bytes = copy_blob(BUFF_CURRENT(*ctx),
725 fw_table[i].filename, BUFF_ROOM(*ctx));
Marshall Dawson02bd7732019-03-13 14:43:17 -0600726 if (bytes < 0) {
Marshall Dawson2794a862019-03-04 16:53:15 -0700727 free(ctx->rom);
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700728 exit(1);
729 }
730
Marshall Dawson239286c2019-02-23 16:42:46 -0700731 pspdir->entries[count].type = fw_table[i].type;
Marshall Dawsondbae6322019-03-04 10:31:03 -0700732 pspdir->entries[count].subprog = fw_table[i].subprog;
733 pspdir->entries[count].rsvd = 0;
Marshall Dawson8e0dca02019-02-27 18:40:49 -0700734 pspdir->entries[count].size = (uint32_t)bytes;
Marshall Dawson2794a862019-03-04 16:53:15 -0700735 pspdir->entries[count].addr = RUN_CURRENT(*ctx);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800736
Marshall Dawson2794a862019-03-04 16:53:15 -0700737 ctx->current = ALIGN(ctx->current + bytes,
738 BLOB_ALIGNMENT);
Marshall Dawsonc38c0c92019-02-23 16:41:35 -0700739 count++;
zbaoc3a08a92016-03-02 14:47:27 +0800740 } else {
741 /* This APU doesn't have this firmware. */
742 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800743 }
Marshall Dawson2794a862019-03-04 16:53:15 -0700744
Marshall Dawson24f73d42019-04-01 10:48:43 -0600745 if (pspdir2) {
746 pspdir->entries[count].type = AMD_FW_L2_PTR;
747 pspdir->entries[count].subprog = 0;
748 pspdir->entries[count].rsvd = 0;
749 pspdir->entries[count].size = sizeof(pspdir2->header)
750 + pspdir2->header.num_entries
751 * sizeof(psp_directory_entry);
752
753 pspdir->entries[count].addr = BUFF_TO_RUN(*ctx, pspdir2);
754 count++;
755 }
756
Marshall Dawson2794a862019-03-04 16:53:15 -0700757 if (count > MAX_PSP_ENTRIES) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800758 fprintf(stderr, "Error: PSP entries exceed max allowed items\n");
Marshall Dawson2794a862019-03-04 16:53:15 -0700759 free(ctx->rom);
760 exit(1);
761 }
762
Marshall Dawson24f73d42019-04-01 10:48:43 -0600763 fill_dir_header(pspdir, count, cookie);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800764}
765
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600766static void *new_bios_dir(context *ctx, int multi)
767{
768 void *ptr;
769
770 /*
771 * Force both onto boundary when multi. Primary table is after
772 * updatable table, so alignment ensures primary can stay intact
773 * if secondary is reprogrammed.
774 */
775 if (multi)
776 ctx->current = ALIGN(ctx->current, TABLE_ERASE_ALIGNMENT);
777 else
778 ctx->current = ALIGN(ctx->current, TABLE_ALIGNMENT);
779 ptr = BUFF_CURRENT(*ctx);
780 ctx->current += sizeof(bios_directory_hdr)
781 + MAX_BIOS_ENTRIES * sizeof(bios_directory_entry);
782 return ptr;
783}
784
785static int locate_bdt2_bios(bios_directory_table *level2,
786 uint64_t *source, uint32_t *size)
787{
Zheng Bao6d402ac2020-10-01 16:16:30 +0800788 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600789
790 *source = 0;
791 *size = 0;
792 if (!level2)
793 return 0;
794
795 for (i = 0 ; i < level2->header.num_entries ; i++) {
796 if (level2->entries[i].type == AMD_BIOS_BIN) {
797 *source = level2->entries[i].source;
798 *size = level2->entries[i].size;
799 return 1;
800 }
801 }
802 return 0;
803}
804
805static int have_bios_tables(amd_bios_entry *table)
806{
807 int i;
808
809 for (i = 0 ; table[i].type != AMD_BIOS_INVALID; i++) {
810 if (table[i].level & BDT_LVL1 && table[i].filename)
811 return 1;
812 }
813 return 0;
814}
815
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700816static int find_bios_entry(amd_bios_type type)
817{
818 int i;
819
820 for (i = 0; amd_bios_table[i].type != AMD_BIOS_INVALID; i++) {
821 if (amd_bios_table[i].type == type)
822 return i;
823 }
824 return -1;
825}
826
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600827static void integrate_bios_firmwares(context *ctx,
828 bios_directory_table *biosdir,
829 bios_directory_table *biosdir2,
830 amd_bios_entry *fw_table,
831 uint32_t cookie)
832{
833 ssize_t bytes;
Martin Rothec933132019-07-13 20:03:34 -0600834 unsigned int i, count;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600835 int level;
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700836 int apob_idx;
Martin Rotheca423b2020-09-01 10:54:11 -0600837 uint32_t size;
838 uint64_t source;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600839
840 /* This function can create a primary table, a secondary table, or a
841 * flattened table which contains all applicable types. These if-else
842 * statements infer what the caller intended. If a 2nd-level cookie
843 * is passed, clearly a 2nd-level table is intended. However, a
844 * 1st-level cookie may indicate level 1 or flattened. If the caller
845 * passes a pointer to a 2nd-level table, then assume not flat.
846 */
847 if (cookie == BDT2_COOKIE)
848 level = BDT_LVL2;
849 else if (biosdir2)
850 level = BDT_LVL1;
851 else
852 level = BDT_BOTH;
853
854 ctx->current = ALIGN(ctx->current, BLOB_ALIGNMENT);
855
856 for (i = 0, count = 0; fw_table[i].type != AMD_BIOS_INVALID; i++) {
857 if (!(fw_table[i].level & level))
858 continue;
859 if (fw_table[i].filename == NULL && (
860 fw_table[i].type != AMD_BIOS_APOB &&
861 fw_table[i].type != AMD_BIOS_APOB_NV &&
862 fw_table[i].type != AMD_BIOS_L2_PTR &&
Martin Roth94554742020-04-14 14:59:36 -0600863 fw_table[i].type != AMD_BIOS_BIN &&
864 fw_table[i].type != AMD_BIOS_PSP_SHARED_MEM))
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600865 continue;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600866
867 /* BIOS Directory items may have additional requirements */
868
Martin Roth48dd9fe2020-07-29 16:32:25 -0600869 /* Check APOB_NV requirements */
870 if (fw_table[i].type == AMD_BIOS_APOB_NV) {
871 if (!fw_table[i].size && !fw_table[i].src)
872 continue; /* APOB_NV not used */
873 if (fw_table[i].src && !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800874 fprintf(stderr, "Error: APOB NV address provided, but no size\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600875 free(ctx->rom);
876 exit(1);
877 }
Martin Roth48dd9fe2020-07-29 16:32:25 -0600878 /* If the APOB isn't used, APOB_NV isn't used either */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700879 apob_idx = find_bios_entry(AMD_BIOS_APOB);
Martin Roth48dd9fe2020-07-29 16:32:25 -0600880 if (apob_idx < 0 || !fw_table[apob_idx].dest)
881 continue; /* APOV NV not supported */
Marshall Dawsonc4a8c482020-01-21 17:17:59 -0700882 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600883
884 /* APOB_DATA needs destination */
885 if (fw_table[i].type == AMD_BIOS_APOB && !fw_table[i].dest) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800886 fprintf(stderr, "Error: APOB destination not provided\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600887 free(ctx->rom);
888 exit(1);
889 }
890
891 /* BIOS binary must have destination and uncompressed size. If
892 * no filename given, then user must provide a source address.
893 */
894 if (fw_table[i].type == AMD_BIOS_BIN) {
895 if (!fw_table[i].dest || !fw_table[i].size) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800896 fprintf(stderr, "Error: BIOS binary destination and uncompressed size are required\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600897 free(ctx->rom);
898 exit(1);
899 }
900 if (!fw_table[i].filename && !fw_table[i].src) {
Zheng Bao77a2c672020-10-01 17:05:43 +0800901 fprintf(stderr, "Error: BIOS binary assumed outside amdfw.rom but no source address given\n");
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600902 free(ctx->rom);
903 exit(1);
904 }
905 }
906
Martin Roth94554742020-04-14 14:59:36 -0600907 /* PSP_SHARED_MEM needs a destination and size */
908 if (fw_table[i].type == AMD_BIOS_PSP_SHARED_MEM &&
909 (!fw_table[i].dest || !fw_table[i].size))
910 continue;
911
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600912 biosdir->entries[count].type = fw_table[i].type;
913 biosdir->entries[count].region_type = fw_table[i].region_type;
914 biosdir->entries[count].dest = fw_table[i].dest ?
915 fw_table[i].dest : (uint64_t)-1;
916 biosdir->entries[count].reset = fw_table[i].reset;
917 biosdir->entries[count].copy = fw_table[i].copy;
918 biosdir->entries[count].ro = fw_table[i].ro;
919 biosdir->entries[count].compressed = fw_table[i].zlib;
920 biosdir->entries[count].inst = fw_table[i].inst;
921 biosdir->entries[count].subprog = fw_table[i].subpr;
922
923 switch (fw_table[i].type) {
924 case AMD_BIOS_APOB:
925 biosdir->entries[count].size = fw_table[i].size;
926 biosdir->entries[count].source = fw_table[i].src;
927 break;
928 case AMD_BIOS_APOB_NV:
929 if (fw_table[i].src) {
930 /* If source is given, use that and its size */
931 biosdir->entries[count].source = fw_table[i].src;
932 biosdir->entries[count].size = fw_table[i].size;
933 } else {
934 /* Else reserve size bytes within amdfw.rom */
935 ctx->current = ALIGN(ctx->current, ERASE_ALIGNMENT);
936 biosdir->entries[count].source = RUN_CURRENT(*ctx);
937 biosdir->entries[count].size = ALIGN(
938 fw_table[i].size, ERASE_ALIGNMENT);
939 memset(BUFF_CURRENT(*ctx), 0xff,
940 biosdir->entries[count].size);
941 ctx->current = ctx->current
942 + biosdir->entries[count].size;
943 }
944 break;
945 case AMD_BIOS_BIN:
946 /* Don't make a 2nd copy, point to the same one */
Martin Rotheca423b2020-09-01 10:54:11 -0600947 if (level == BDT_LVL1 && locate_bdt2_bios(biosdir2, &source, &size)) {
948 biosdir->entries[count].source = source;
949 biosdir->entries[count].size = size;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600950 break;
Martin Rotheca423b2020-09-01 10:54:11 -0600951 }
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600952
953 /* level 2, or level 1 and no copy found in level 2 */
954 biosdir->entries[count].source = fw_table[i].src;
955 biosdir->entries[count].dest = fw_table[i].dest;
956 biosdir->entries[count].size = fw_table[i].size;
957
958 if (!fw_table[i].filename)
959 break;
960
961 bytes = copy_blob(BUFF_CURRENT(*ctx),
962 fw_table[i].filename, BUFF_ROOM(*ctx));
963 if (bytes <= 0) {
964 free(ctx->rom);
965 exit(1);
966 }
967
968 biosdir->entries[count].source = RUN_CURRENT(*ctx);
969
970 ctx->current = ALIGN(ctx->current + bytes, 0x100U);
971 break;
Martin Roth94554742020-04-14 14:59:36 -0600972 case AMD_BIOS_PSP_SHARED_MEM:
973 biosdir->entries[count].dest = fw_table[i].dest;
974 biosdir->entries[count].size = fw_table[i].size;
975 break;
976
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -0600977 default: /* everything else is copied from input */
978 if (fw_table[i].type == AMD_BIOS_APCB ||
979 fw_table[i].type == AMD_BIOS_APCB_BK)
980 ctx->current = ALIGN(
981 ctx->current, ERASE_ALIGNMENT);
982
983 bytes = copy_blob(BUFF_CURRENT(*ctx),
984 fw_table[i].filename, BUFF_ROOM(*ctx));
985 if (bytes <= 0) {
986 free(ctx->rom);
987 exit(1);
988 }
989
990 biosdir->entries[count].size = (uint32_t)bytes;
991 biosdir->entries[count].source = RUN_CURRENT(*ctx);
992
993 ctx->current = ALIGN(ctx->current + bytes, 0x100U);
994 break;
995 }
996
997 count++;
998 }
999
1000 if (biosdir2) {
1001 biosdir->entries[count].type = AMD_BIOS_L2_PTR;
1002 biosdir->entries[count].size =
1003 + MAX_BIOS_ENTRIES
1004 * sizeof(bios_directory_entry);
1005 biosdir->entries[count].source =
1006 BUFF_TO_RUN(*ctx, biosdir2);
1007 biosdir->entries[count].subprog = 0;
1008 biosdir->entries[count].inst = 0;
1009 biosdir->entries[count].copy = 0;
1010 biosdir->entries[count].compressed = 0;
1011 biosdir->entries[count].dest = -1;
1012 biosdir->entries[count].reset = 0;
1013 biosdir->entries[count].ro = 0;
1014 count++;
1015 }
1016
1017 if (count > MAX_BIOS_ENTRIES) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001018 fprintf(stderr, "Error: BIOS entries (%d) exceeds max allowed items "
Rob Barnes18fd26c2020-03-03 10:35:02 -07001019 "(%d)\n", count, MAX_BIOS_ENTRIES);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001020 free(ctx->rom);
1021 exit(1);
1022 }
1023
1024 fill_dir_header(biosdir, count, cookie);
1025}
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001026
1027enum {
1028 /* begin after ASCII characters */
1029 LONGOPT_SPI_READ_MODE = 256,
1030 LONGOPT_SPI_SPEED = 257,
1031 LONGOPT_SPI_MICRON_FLAG = 258,
1032};
1033
Zheng Bao9e908072020-10-28 11:39:13 +08001034/* Unused values: BGJKNXYbkmprstuwyz*/
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001035static 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 +08001036 "H:o:f:l:hZ:qR:C:c:E:dD";
Marc Jones90099b62016-09-20 21:05:45 -06001037
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001038static struct option long_options[] = {
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001039 {"xhci", required_argument, 0, 'x' },
1040 {"imc", required_argument, 0, 'i' },
1041 {"gec", required_argument, 0, 'g' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001042 /* PSP Directory Table items */
Marshall Dawson67d868d2019-02-28 11:43:40 -07001043 {"combo-capable", no_argument, 0, 'A' },
Marshall Dawson24f73d42019-04-01 10:48:43 -06001044 {"multilevel", no_argument, 0, 'M' },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001045 {"nvram", required_argument, 0, 'n' },
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001046 {"soft-fuse", required_argument, 0, 'T' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001047 {"token-unlock", no_argument, 0, 'U' },
1048 {"whitelist", required_argument, 0, 'W' },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001049 {"use-pspsecureos", no_argument, 0, 'S' },
1050 {"load-mp2-fw", no_argument, 0, 'p' },
1051 {"load-s0i3", no_argument, 0, 'L' },
Martin Rothd3ce8c82019-07-13 20:13:07 -06001052 {"verstage", required_argument, 0, 'Z' },
Martin Rothb1f648f2020-09-01 09:36:59 -06001053 {"verstage_sig", required_argument, 0, 'E' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001054 /* BIOS Directory Table items */
1055 {"instance", required_argument, 0, 'I' },
1056 {"apcb", required_argument, 0, 'a' },
1057 {"apob-base", required_argument, 0, 'Q' },
1058 {"bios-bin", required_argument, 0, 'V' },
1059 {"bios-bin-src", required_argument, 0, 'e' },
1060 {"bios-bin-dest", required_argument, 0, 'v' },
1061 {"bios-uncomp-size", required_argument, 0, 'j' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001062 {"ucode", required_argument, 0, 'O' },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001063 {"apob-nv-base", required_argument, 0, 'F' },
1064 {"apob-nv-size", required_argument, 0, 'H' },
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001065 /* Embedded Firmware Structure items*/
1066 {"spi-read-mode", required_argument, 0, LONGOPT_SPI_READ_MODE },
1067 {"spi-speed", required_argument, 0, LONGOPT_SPI_SPEED },
1068 {"spi-micron-flag", required_argument, 0, LONGOPT_SPI_MICRON_FLAG },
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001069 /* other */
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001070 {"output", required_argument, 0, 'o' },
1071 {"flashsize", required_argument, 0, 'f' },
Martin Roth0d3b1182017-10-03 14:16:04 -06001072 {"location", required_argument, 0, 'l' },
Martin Roth37305e72020-04-07 14:16:39 -06001073 {"anywhere", no_argument, 0, 'q' },
Martin Roth94554742020-04-14 14:59:36 -06001074 {"sharedmem", required_argument, 0, 'R' },
1075 {"sharedmem-size", required_argument, 0, 'P' },
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001076 {"soc-name", required_argument, 0, 'C' },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001077
1078 {"config", required_argument, 0, 'c' },
Zheng Bao9e908072020-10-28 11:39:13 +08001079 {"debug", no_argument, 0, 'd' },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001080 {"help", no_argument, 0, 'h' },
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001081 {"depend", no_argument, 0, 'D' },
Marshall Dawsonf4b9b412017-03-17 16:30:51 -06001082 {NULL, 0, 0, 0 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001083};
1084
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001085void register_fw_fuse(char *str)
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001086{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001087 uint32_t i;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001088
1089 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1090 if (amd_psp_fw_table[i].type != AMD_PSP_FUSE_CHAIN)
1091 continue;
1092
1093 amd_psp_fw_table[i].other = strtoull(str, NULL, 16);
1094 return;
1095 }
1096}
1097
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001098static void register_fw_token_unlock(void)
1099{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001100 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001101
1102 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
1103 if (amd_psp_fw_table[i].type != AMD_TOKEN_UNLOCK)
1104 continue;
1105
1106 amd_psp_fw_table[i].other = 1;
1107 return;
1108 }
1109}
1110
Marshall Dawsondbae6322019-03-04 10:31:03 -07001111static void register_fw_filename(amd_fw_type type, uint8_t sub, char filename[])
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001112{
Martin Roth8806f7f2016-11-08 10:44:18 -07001113 unsigned int i;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001114
Martin Rothcd15bc82016-11-08 11:34:02 -07001115 for (i = 0; i < sizeof(amd_fw_table) / sizeof(amd_fw_entry); i++) {
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001116 if (amd_fw_table[i].type == type) {
1117 amd_fw_table[i].filename = filename;
1118 return;
1119 }
1120 }
1121
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001122 for (i = 0; i < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); i++) {
Marshall Dawsondbae6322019-03-04 10:31:03 -07001123 if (amd_psp_fw_table[i].type != type)
1124 continue;
1125
1126 if (amd_psp_fw_table[i].subprog == sub) {
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001127 amd_psp_fw_table[i].filename = filename;
1128 return;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001129 }
1130 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001131}
1132
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001133static void register_bdt_data(amd_bios_type type, int sub, int ins, char name[])
1134{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001135 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001136
1137 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
1138 if (amd_bios_table[i].type == type
1139 && amd_bios_table[i].inst == ins
1140 && amd_bios_table[i].subpr == sub) {
1141 amd_bios_table[i].filename = name;
1142 return;
1143 }
1144 }
1145}
1146
Martin Rothec933132019-07-13 20:03:34 -06001147static void register_fw_addr(amd_bios_type type, char *src_str,
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001148 char *dst_str, char *size_str)
1149{
Zheng Bao6d402ac2020-10-01 16:16:30 +08001150 uint32_t i;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001151 for (i = 0; i < sizeof(amd_bios_table) / sizeof(amd_bios_entry); i++) {
1152 if (amd_bios_table[i].type != type)
1153 continue;
1154
1155 if (src_str)
1156 amd_bios_table[i].src = strtoull(src_str, NULL, 16);
1157 if (dst_str)
1158 amd_bios_table[i].dest = strtoull(dst_str, NULL, 16);
1159 if (size_str)
1160 amd_bios_table[i].size = strtoul(size_str, NULL, 16);
1161
1162 return;
1163 }
1164}
1165
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001166enum platform {
1167 PLATFORM_UNKNOWN,
1168 PLATFORM_STONEYRIDGE,
1169 PLATFORM_RAVEN,
1170 PLATFORM_PICASSO,
1171 PLATFORM_RENOIR,
1172 PLATFORM_LUCIENNE,
1173};
1174
1175static int set_efs_table(uint8_t soc_id, embedded_firmware *amd_romsig,
1176 uint8_t efs_spi_readmode, uint8_t efs_spi_speed,
1177 uint8_t efs_spi_micron_flag)
1178{
1179 if ((efs_spi_readmode == 0xFF) || (efs_spi_speed == 0xFF)) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001180 fprintf(stderr, "Error: EFS read mode and SPI speed must be set\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001181 return 1;
1182 }
1183 switch (soc_id) {
1184 case PLATFORM_STONEYRIDGE:
1185 amd_romsig->second_gen_efs = 0;
1186 amd_romsig->spi_readmode_f15_mod_60_6f = efs_spi_readmode;
1187 amd_romsig->fast_speed_new_f15_mod_60_6f = efs_spi_speed;
1188 break;
1189 case PLATFORM_RAVEN:
1190 case PLATFORM_PICASSO:
1191 amd_romsig->second_gen_efs = 0;
1192 amd_romsig->spi_readmode_f17_mod_00_2f = efs_spi_readmode;
1193 amd_romsig->spi_fastspeed_f17_mod_00_2f = efs_spi_speed;
1194 switch (efs_spi_micron_flag) {
1195 case 0:
1196 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xff;
1197 break;
1198 case 1:
1199 amd_romsig->qpr_dummy_cycle_f17_mod_00_2f = 0xa;
1200 break;
1201 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001202 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001203 return 1;
1204 }
1205 break;
1206 case PLATFORM_RENOIR:
1207 case PLATFORM_LUCIENNE:
1208 amd_romsig->second_gen_efs = 1;
1209 amd_romsig->spi_readmode_f17_mod_30_3f = efs_spi_readmode;
1210 amd_romsig->spi_fastspeed_f17_mod_30_3f = efs_spi_speed;
1211 switch (efs_spi_micron_flag) {
1212 case 0:
1213 amd_romsig->micron_detect_f17_mod_30_3f = 0xff;
1214 break;
1215 case 1:
1216 amd_romsig->micron_detect_f17_mod_30_3f = 0xaa;
1217 break;
1218 case 2:
1219 amd_romsig->micron_detect_f17_mod_30_3f = 0x55;
1220 break;
1221 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001222 fprintf(stderr, "Error: EFS Micron flag must be correctly set.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001223 return 1;
1224 }
1225 break;
1226 case PLATFORM_UNKNOWN:
1227 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001228 fprintf(stderr, "Error: Invalid SOC name.\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001229 return 1;
1230 }
1231 return 0;
1232}
1233
1234static int identify_platform(char *soc_name)
1235{
1236 if (!strcasecmp(soc_name, "Stoneyridge"))
1237 return PLATFORM_STONEYRIDGE;
1238 else if (!strcasecmp(soc_name, "Raven"))
1239 return PLATFORM_RAVEN;
1240 else if (!strcasecmp(soc_name, "Picasso"))
1241 return PLATFORM_PICASSO;
1242 else if (!strcasecmp(soc_name, "Renoir"))
1243 return PLATFORM_RENOIR;
1244 else if (!strcasecmp(soc_name, "Lucienne"))
1245 return PLATFORM_LUCIENNE;
1246 else
1247 return PLATFORM_UNKNOWN;
1248
1249}
1250
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001251int main(int argc, char **argv)
1252{
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001253 int c;
Martin Roth31d95a22016-11-08 11:22:12 -07001254 int retval = 0;
Martin Roth60f15512016-11-08 09:55:01 -07001255 char *tmp;
Martin Roth8806f7f2016-11-08 10:44:18 -07001256 char *rom = NULL;
Marshall Dawson239286c2019-02-23 16:42:46 -07001257 embedded_firmware *amd_romsig;
1258 psp_directory_table *pspdir;
Marshall Dawson67d868d2019-02-28 11:43:40 -07001259 int comboable = 0;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001260 int fuse_defined = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001261 int targetfd;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001262 char *output = NULL, *config = NULL;
1263 FILE *config_handle;
Zheng Bao9c8ce3e2020-09-28 10:36:29 +08001264 context ctx = { 0 };
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001265 /* Values cleared after each firmware or parameter, regardless if N/A */
1266 uint8_t sub = 0, instance = 0;
Martin Roth0d3b1182017-10-03 14:16:04 -06001267 uint32_t dir_location = 0;
Martin Roth37305e72020-04-07 14:16:39 -06001268 bool any_location = 0;
Martin Roth0d3b1182017-10-03 14:16:04 -06001269 uint32_t romsig_offset;
Martin Roth60f15512016-11-08 09:55:01 -07001270 uint32_t rom_base_address;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001271 uint8_t soc_id = PLATFORM_UNKNOWN;
1272 uint8_t efs_spi_readmode = 0xff;
1273 uint8_t efs_spi_speed = 0xff;
1274 uint8_t efs_spi_micron_flag = 0xff;
1275
Marshall Dawson24f73d42019-04-01 10:48:43 -06001276 int multi = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001277 amd_cb_config cb_config;
Zheng Bao9e908072020-10-28 11:39:13 +08001278 int debug = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001279 int list_deps = 0;
1280
1281 cb_config.have_whitelist = 0;
1282 cb_config.unlock_secure = 0;
1283 cb_config.use_secureos = 0;
1284 cb_config.load_mp2_fw = 0;
1285 cb_config.s0i3 = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001286
1287 while (1) {
1288 int optindex = 0;
1289
1290 c = getopt_long(argc, argv, optstring, long_options, &optindex);
1291
1292 if (c == -1)
1293 break;
1294
1295 switch (c) {
1296 case 'x':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001297 register_fw_filename(AMD_FW_XHCI, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001298 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001299 break;
1300 case 'i':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001301 register_fw_filename(AMD_FW_IMC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001302 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001303 break;
1304 case 'g':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001305 register_fw_filename(AMD_FW_GEC, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001306 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001307 break;
Marshall Dawson67d868d2019-02-28 11:43:40 -07001308 case 'A':
1309 comboable = 1;
1310 break;
Marshall Dawson24f73d42019-04-01 10:48:43 -06001311 case 'M':
1312 multi = 1;
1313 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001314 case 'U':
1315 register_fw_token_unlock();
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001316 cb_config.unlock_secure = 1;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001317 sub = instance = 0;
1318 break;
Marshall Dawsondbae6322019-03-04 10:31:03 -07001319 case 'S':
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001320 cb_config.use_secureos = 1;
Marshall Dawsondbae6322019-03-04 10:31:03 -07001321 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001322 case 'I':
1323 instance = strtoul(optarg, &tmp, 16);
1324 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001325 case 'p':
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001326 cb_config.load_mp2_fw = 1;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001327 break;
1328 case 'n':
Marshall Dawsondbae6322019-03-04 10:31:03 -07001329 register_fw_filename(AMD_FW_PSP_NVRAM, sub, optarg);
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001330 sub = instance = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001331 break;
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001332 case 'T':
1333 register_fw_fuse(optarg);
1334 fuse_defined = 1;
1335 sub = 0;
1336 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001337 case 'a':
1338 register_bdt_data(AMD_BIOS_APCB, sub, instance, optarg);
1339 register_bdt_data(AMD_BIOS_APCB_BK, sub,
1340 instance, optarg);
1341 sub = instance = 0;
1342 break;
1343 case 'Q':
1344 /* APOB destination */
1345 register_fw_addr(AMD_BIOS_APOB, 0, optarg, 0);
1346 sub = instance = 0;
1347 break;
1348 case 'F':
1349 /* APOB NV source */
1350 register_fw_addr(AMD_BIOS_APOB_NV, optarg, 0, 0);
1351 sub = instance = 0;
1352 break;
1353 case 'H':
1354 /* APOB NV size */
1355 register_fw_addr(AMD_BIOS_APOB_NV, 0, 0, optarg);
1356 sub = instance = 0;
1357 break;
1358 case 'V':
1359 register_bdt_data(AMD_BIOS_BIN, sub, instance, optarg);
1360 sub = instance = 0;
1361 break;
1362 case 'e':
1363 /* BIOS source */
1364 register_fw_addr(AMD_BIOS_BIN, optarg, 0, 0);
1365 sub = instance = 0;
1366 break;
1367 case 'v':
1368 /* BIOS destination */
1369 register_fw_addr(AMD_BIOS_BIN, 0, optarg, 0);
1370 sub = instance = 0;
1371 break;
1372 case 'j':
1373 /* BIOS destination size */
1374 register_fw_addr(AMD_BIOS_BIN, 0, 0, optarg);
1375 sub = instance = 0;
1376 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001377 case 'O':
1378 register_bdt_data(AMD_BIOS_UCODE, sub,
1379 instance, optarg);
1380 sub = instance = 0;
1381 break;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001382 case 'L':
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001383 cb_config.s0i3 = 1;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001384 break;
1385 case 'W':
1386 register_fw_filename(AMD_FW_PSP_WHITELIST, sub, optarg);
1387 sub = instance = 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001388 cb_config.have_whitelist = 1;
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001389 break;
Martin Rothd3ce8c82019-07-13 20:13:07 -06001390 case 'Z':
1391 register_fw_filename(AMD_FW_PSP_VERSTAGE, sub, optarg);
1392 sub = instance = 0;
1393 break;
Martin Rothb1f648f2020-09-01 09:36:59 -06001394 case 'E':
1395 register_fw_filename(AMD_FW_VERSTAGE_SIG, sub, optarg);
1396 sub = instance = 0;
1397 break;
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001398 case 'C':
1399 soc_id = identify_platform(optarg);
1400 if (soc_id == PLATFORM_UNKNOWN) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001401 fprintf(stderr, "Error: Invalid SOC name specified\n\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001402 retval = 1;
1403 }
1404 sub = instance = 0;
1405 break;
1406 case LONGOPT_SPI_READ_MODE:
1407 efs_spi_readmode = strtoull(optarg, NULL, 16);
1408 sub = instance = 0;
1409 break;
1410 case LONGOPT_SPI_SPEED:
1411 efs_spi_speed = strtoull(optarg, NULL, 16);
1412 sub = instance = 0;
1413 break;
1414 case LONGOPT_SPI_MICRON_FLAG:
1415 efs_spi_micron_flag = strtoull(optarg, NULL, 16);
1416 sub = instance = 0;
1417 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001418 case 'o':
1419 output = optarg;
1420 break;
Martin Roth60f15512016-11-08 09:55:01 -07001421 case 'f':
Marshall Dawson2794a862019-03-04 16:53:15 -07001422 ctx.rom_size = (uint32_t)strtoul(optarg, &tmp, 16);
Martin Roth60f15512016-11-08 09:55:01 -07001423 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08001424 fprintf(stderr, "Error: ROM size specified"
Martin Roth60f15512016-11-08 09:55:01 -07001425 " incorrectly (%s)\n\n", optarg);
Martin Roth31d95a22016-11-08 11:22:12 -07001426 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07001427 }
1428 break;
Martin Roth0d3b1182017-10-03 14:16:04 -06001429 case 'l':
1430 dir_location = (uint32_t)strtoul(optarg, &tmp, 16);
1431 if (*tmp != '\0') {
Zheng Bao77a2c672020-10-01 17:05:43 +08001432 fprintf(stderr, "Error: Directory Location specified"
Martin Roth0d3b1182017-10-03 14:16:04 -06001433 " incorrectly (%s)\n\n", optarg);
1434 retval = 1;
1435 }
1436 break;
Martin Roth37305e72020-04-07 14:16:39 -06001437 case 'q':
1438 any_location = 1;
1439 break;
Martin Roth94554742020-04-14 14:59:36 -06001440 case 'R':
1441 /* shared memory destination */
1442 register_fw_addr(AMD_BIOS_PSP_SHARED_MEM, 0, optarg, 0);
1443 sub = instance = 0;
1444 break;
1445 case 'P':
1446 /* shared memory size */
1447 register_fw_addr(AMD_BIOS_PSP_SHARED_MEM, NULL, NULL, optarg);
1448 sub = instance = 0;
1449 break;
Martin Roth0d3b1182017-10-03 14:16:04 -06001450
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001451 case 'c':
1452 config = optarg;
1453 break;
Zheng Bao9e908072020-10-28 11:39:13 +08001454 case 'd':
1455 debug = 1;
1456 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001457 case 'h':
1458 usage();
Martin Roth31d95a22016-11-08 11:22:12 -07001459 return 0;
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001460 case 'D':
1461 list_deps = 1;
1462 break;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001463 default:
1464 break;
1465 }
1466 }
1467
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001468 if (config) {
1469 config_handle = fopen(config, "r");
1470 if (config_handle == NULL) {
1471 fprintf(stderr, "Can not open file %s for reading: %s\n",
1472 config, strerror(errno));
1473 exit(1);
1474 }
1475 if (process_config(config_handle, &cb_config, list_deps) == 0) {
1476 fprintf(stderr, "Configuration file %s parsing error\n", config);
1477 fclose(config_handle);
1478 exit(1);
1479 }
1480 fclose(config_handle);
1481 }
Zheng Bao9e908072020-10-28 11:39:13 +08001482 /* For debug. */
1483 if (debug) {
1484 dump_psp_firmwares(amd_psp_fw_table);
1485 dump_bdt_firmwares(amd_bios_table);
1486 }
1487
Marshall Dawsonef79fcc2019-04-01 10:16:41 -06001488 if (!fuse_defined)
1489 register_fw_fuse(DEFAULT_SOFT_FUSE_CHAIN);
1490
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001491 if (!output && !list_deps) {
1492 fprintf(stderr, "Error: Output value is not specified.\n\n");
Martin Roth31d95a22016-11-08 11:22:12 -07001493 retval = 1;
1494 }
1495
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001496 if ((ctx.rom_size % 1024 != 0) && !list_deps) {
1497 fprintf(stderr, "Error: ROM Size (%d bytes) should be a multiple of"
Marshall Dawson2794a862019-03-04 16:53:15 -07001498 " 1024 bytes.\n\n", ctx.rom_size);
Martin Roth31d95a22016-11-08 11:22:12 -07001499 retval = 1;
Martin Roth60f15512016-11-08 09:55:01 -07001500 }
1501
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001502 if ((ctx.rom_size < MIN_ROM_KB * 1024) && !list_deps) {
1503 fprintf(stderr, "Error: ROM Size (%dKB) must be at least %dKB.\n\n",
Marshall Dawson2794a862019-03-04 16:53:15 -07001504 ctx.rom_size / 1024, MIN_ROM_KB);
Martin Roth31d95a22016-11-08 11:22:12 -07001505 retval = 1;
1506 }
1507
1508 if (retval) {
1509 usage();
1510 return retval;
Martin Roth60f15512016-11-08 09:55:01 -07001511 }
1512
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001513 if (list_deps) {
1514 return retval;
1515 }
1516
Marshall Dawson2794a862019-03-04 16:53:15 -07001517 printf(" AMDFWTOOL Using ROM size of %dKB\n", ctx.rom_size / 1024);
Martin Roth60f15512016-11-08 09:55:01 -07001518
Marshall Dawson2794a862019-03-04 16:53:15 -07001519 rom_base_address = 0xFFFFFFFF - ctx.rom_size + 1;
Martin Roth0d3b1182017-10-03 14:16:04 -06001520 if (dir_location && (dir_location < rom_base_address)) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001521 fprintf(stderr, "Error: Directory location outside of ROM.\n\n");
Martin Roth0d3b1182017-10-03 14:16:04 -06001522 return 1;
1523 }
1524
Martin Roth37305e72020-04-07 14:16:39 -06001525 if (any_location) {
1526 if (dir_location & 0x3f) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001527 fprintf(stderr, "Error: Invalid Directory location.\n");
1528 fprintf(stderr, " Valid locations are 64-byte aligned\n");
Martin Roth37305e72020-04-07 14:16:39 -06001529 return 1;
1530 }
1531 } else {
1532 switch (dir_location) {
1533 case 0: /* Fall through */
1534 case 0xFFFA0000: /* Fall through */
1535 case 0xFFF20000: /* Fall through */
1536 case 0xFFE20000: /* Fall through */
1537 case 0xFFC20000: /* Fall through */
1538 case 0xFF820000: /* Fall through */
1539 case 0xFF020000: /* Fall through */
1540 break;
1541 default:
Zheng Bao77a2c672020-10-01 17:05:43 +08001542 fprintf(stderr, "Error: Invalid Directory location.\n");
1543 fprintf(stderr, " Valid locations are 0xFFFA0000, 0xFFF20000,\n");
1544 fprintf(stderr, " 0xFFE20000, 0xFFC20000, 0xFF820000, 0xFF020000\n");
Martin Roth37305e72020-04-07 14:16:39 -06001545 return 1;
1546 }
Martin Roth0d3b1182017-10-03 14:16:04 -06001547 }
1548
Marshall Dawson2794a862019-03-04 16:53:15 -07001549 ctx.rom = malloc(ctx.rom_size);
1550 if (!ctx.rom) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001551 fprintf(stderr, "Error: Failed to allocate memory\n");
Martin Roth31d95a22016-11-08 11:22:12 -07001552 return 1;
Marshall Dawson2794a862019-03-04 16:53:15 -07001553 }
1554 memset(ctx.rom, 0xFF, ctx.rom_size);
Martin Roth60f15512016-11-08 09:55:01 -07001555
Martin Roth0d3b1182017-10-03 14:16:04 -06001556 if (dir_location)
Marshall Dawson2794a862019-03-04 16:53:15 -07001557 romsig_offset = ctx.current = dir_location - rom_base_address;
Martin Roth0d3b1182017-10-03 14:16:04 -06001558 else
Marshall Dawson2794a862019-03-04 16:53:15 -07001559 romsig_offset = ctx.current = AMD_ROMSIG_OFFSET;
1560 printf(" AMDFWTOOL Using firmware directory location of 0x%08x\n",
1561 RUN_CURRENT(ctx));
Martin Roth0d3b1182017-10-03 14:16:04 -06001562
Marshall Dawson2794a862019-03-04 16:53:15 -07001563 amd_romsig = BUFF_OFFSET(ctx, romsig_offset);
Marshall Dawson239286c2019-02-23 16:42:46 -07001564 amd_romsig->signature = EMBEDDED_FW_SIGNATURE;
1565 amd_romsig->imc_entry = 0;
1566 amd_romsig->gec_entry = 0;
1567 amd_romsig->xhci_entry = 0;
Martin Roth60f15512016-11-08 09:55:01 -07001568
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001569 if (soc_id != PLATFORM_UNKNOWN) {
1570 retval = set_efs_table(soc_id, amd_romsig, efs_spi_readmode,
1571 efs_spi_speed, efs_spi_micron_flag);
1572 if (retval) {
Zheng Bao77a2c672020-10-01 17:05:43 +08001573 fprintf(stderr, "ERROR: Failed to initialize EFS table!\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001574 return retval;
1575 }
1576 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08001577 fprintf(stderr, "WARNING: No SOC name specified.\n");
Matt Papageorgebe4376c2020-06-15 11:18:15 -05001578 }
1579
Marshall Dawson2794a862019-03-04 16:53:15 -07001580 integrate_firmwares(&ctx, amd_romsig, amd_fw_table);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001581
Patrick Georgi900a2542020-02-17 16:52:40 +01001582 ctx.current = ALIGN(ctx.current, 0x10000U); /* TODO: is it necessary? */
Marshall Dawson2794a862019-03-04 16:53:15 -07001583
Marshall Dawson24f73d42019-04-01 10:48:43 -06001584 if (multi) {
1585 /* Do 2nd PSP directory followed by 1st */
1586 psp_directory_table *pspdir2 = new_psp_dir(&ctx, multi);
1587 integrate_psp_firmwares(&ctx, pspdir2, 0,
1588 amd_psp_fw_table, PSPL2_COOKIE);
1589
1590 pspdir = new_psp_dir(&ctx, multi);
1591 integrate_psp_firmwares(&ctx, pspdir, pspdir2,
1592 amd_psp_fw_table, PSP_COOKIE);
1593 } else {
1594 /* flat: PSP 1 cookie and no pointer to 2nd table */
1595 pspdir = new_psp_dir(&ctx, multi);
1596 integrate_psp_firmwares(&ctx, pspdir, 0,
1597 amd_psp_fw_table, PSP_COOKIE);
1598 }
Marshall Dawson2794a862019-03-04 16:53:15 -07001599
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001600 if (comboable)
Marshall Dawson2794a862019-03-04 16:53:15 -07001601 amd_romsig->comboable = BUFF_TO_RUN(ctx, pspdir);
Marshall Dawson67d868d2019-02-28 11:43:40 -07001602 else
Marshall Dawson2794a862019-03-04 16:53:15 -07001603 amd_romsig->psp_entry = BUFF_TO_RUN(ctx, pspdir);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001604
zbaoc3a08a92016-03-02 14:47:27 +08001605#if PSP_COMBO
Marshall Dawson2794a862019-03-04 16:53:15 -07001606 psp_combo_directory *combo_dir = new_combo_dir(&ctx);
1607 amd_romsig->comboable = BUFF_TO_RUN(ctx, combo_dir);
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001608 /* 0 -Compare PSP ID, 1 -Compare chip family ID */
1609 combo_dir->entries[0].id_sel = 0;
1610 /* TODO: PSP ID. Documentation is needed. */
1611 combo_dir->entries[0].id = 0x10220B00;
Marshall Dawson2794a862019-03-04 16:53:15 -07001612 combo_dir->entries[0].lvl2_addr = BUFF_TO_RUN(ctx, pspdir);
Zheng Bao4fcc9f22015-11-20 12:29:04 +08001613
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001614 combo_dir->header.lookup = 1;
Marshall Dawsona378c222019-03-04 16:52:07 -07001615 fill_dir_header(combo_dir, 1, PSP2_COOKIE);
Marshall Dawson0e02ce82019-03-04 16:50:37 -07001616#endif
Zheng Bao4fcc9f22015-11-20 12:29:04 +08001617
Marshall Dawsonce2b2ba2019-03-19 14:45:31 -06001618 if (have_bios_tables(amd_bios_table)) {
1619 bios_directory_table *biosdir;
1620 if (multi) {
1621 /* Do 2nd level BIOS directory followed by 1st */
1622 bios_directory_table *biosdir2 =
1623 new_bios_dir(&ctx, multi);
1624 integrate_bios_firmwares(&ctx, biosdir2, 0,
1625 amd_bios_table, BDT2_COOKIE);
1626
1627 biosdir = new_bios_dir(&ctx, multi);
1628 integrate_bios_firmwares(&ctx, biosdir, biosdir2,
1629 amd_bios_table, BDT1_COOKIE);
1630 } else {
1631 /* flat: BDT1 cookie and no pointer to 2nd table */
1632 biosdir = new_bios_dir(&ctx, multi);
1633 integrate_bios_firmwares(&ctx, biosdir, 0,
1634 amd_bios_table, BDT1_COOKIE);
1635 }
1636 amd_romsig->bios1_entry = BUFF_TO_RUN(ctx, biosdir);
1637 }
1638
Zheng Baoc5e28ab2020-10-28 11:38:09 +08001639 /* Free the filename. */
1640 free_psp_firmware_filenames(amd_psp_fw_table);
1641 free_bdt_firmware_filenames(amd_bios_table);
1642
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001643 targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666);
Martin Roth31d95a22016-11-08 11:22:12 -07001644 if (targetfd >= 0) {
Zheng Bao47396912020-09-29 17:33:17 +08001645 ssize_t bytes;
1646 bytes = write(targetfd, amd_romsig, ctx.current - romsig_offset);
1647 if (bytes != ctx.current - romsig_offset) {
1648 fprintf(stderr, "Error: Writing to file %s failed\n", output);
1649 retval = 1;
1650 }
Martin Roth31d95a22016-11-08 11:22:12 -07001651 close(targetfd);
1652 } else {
Zheng Bao77a2c672020-10-01 17:05:43 +08001653 fprintf(stderr, "Error: could not open file: %s\n", output);
Martin Roth31d95a22016-11-08 11:22:12 -07001654 retval = 1;
1655 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001656
Martin Roth31d95a22016-11-08 11:22:12 -07001657 free(rom);
1658 return retval;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001659}