blob: 644e904f50d6b4de03207f51b96e630aaf8218e3 [file] [log] [blame]
Zheng Baof080cd52023-03-22 12:50:36 +08001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <fcntl.h>
4#include <errno.h>
5#include <limits.h>
6#include <openssl/sha.h>
7#include <stdio.h>
8#include <sys/stat.h>
9#include <unistd.h>
10#include <string.h>
11#include <stdlib.h>
12
13#include "amdfwtool.h"
14
15/* Defines related to hashing signed binaries */
16enum hash_header_ver {
17 HASH_HDR_V1 = 1,
18};
19/* Signature ID enums are defined by PSP based on the algorithm used. */
20enum signature_id {
21 SIG_ID_RSA2048,
22 SIG_ID_RSA4096 = 2,
23};
24#define HASH_FILE_SUFFIX ".hash"
25
26static uint16_t get_psp_fw_type(enum platform soc_id, struct amd_fw_header *header)
27{
28 switch (soc_id) {
29 case PLATFORM_MENDOCINO:
30 case PLATFORM_PHOENIX:
31 case PLATFORM_GLINDA:
32 /* Fallback to fw_type if fw_id is not populated, which serves the same
33 purpose on older SoCs. */
34 return header->fw_id ? header->fw_id : header->fw_type;
35 default:
36 return header->fw_type;
37 }
38}
39
40static int add_single_sha(amd_fw_entry_hash *entry, void *buf, enum platform soc_id)
41{
42 uint8_t hash[SHA384_DIGEST_LENGTH];
43 struct amd_fw_header *header = (struct amd_fw_header *)buf;
44 /* Include only signed part for hash calculation. */
45 size_t len = header->fw_size_signed + sizeof(struct amd_fw_header);
46 uint8_t *body = (uint8_t *)buf;
47
48 if (len > header->size_total)
49 return -1;
50
51 if (header->sig_id == SIG_ID_RSA4096) {
52 SHA384(body, len, hash);
53 entry->sha_len = SHA384_DIGEST_LENGTH;
54 } else if (header->sig_id == SIG_ID_RSA2048) {
55 SHA256(body, len, hash);
56 entry->sha_len = SHA256_DIGEST_LENGTH;
57 } else {
58 fprintf(stderr, "%s: Unknown signature id: 0x%08x\n",
59 __func__, header->sig_id);
60 return -1;
61 }
62
63 memcpy(entry->sha, hash, entry->sha_len);
64 entry->fw_id = get_psp_fw_type(soc_id, header);
65 entry->subtype = header->fw_subtype;
66
67 return 0;
68}
69
70static int get_num_binaries(void *buf, size_t buf_size)
71{
72 struct amd_fw_header *header = (struct amd_fw_header *)buf;
73 size_t total_len = 0;
74 int num_binaries = 0;
75
76 while (total_len < buf_size) {
77 num_binaries++;
78 total_len += header->size_total;
79 header = (struct amd_fw_header *)(buf + total_len);
80 }
81
82 if (total_len != buf_size) {
83 fprintf(stderr, "Malformed binary\n");
84 return -1;
85 }
86 return num_binaries;
87}
88
89static int add_sha(amd_fw_entry *entry, void *buf, size_t buf_size, enum platform soc_id)
90{
91 struct amd_fw_header *header = (struct amd_fw_header *)buf;
92 /* Include only signed part for hash calculation. */
93 size_t total_len = 0;
94 int num_binaries = get_num_binaries(buf, buf_size);
95
96 if (num_binaries <= 0)
97 return num_binaries;
98
99 entry->hash_entries = malloc(num_binaries * sizeof(amd_fw_entry_hash));
100 if (!entry->hash_entries) {
101 fprintf(stderr, "Error allocating memory to add FW hash\n");
102 return -1;
103 }
104 entry->num_hash_entries = num_binaries;
105
106 /* Iterate through each binary */
107 for (int i = 0; i < num_binaries; i++) {
108 if (add_single_sha(&entry->hash_entries[i], buf + total_len, soc_id)) {
109 free(entry->hash_entries);
110 return -1;
111 }
112 total_len += header->size_total;
113 header = (struct amd_fw_header *)(buf + total_len);
114 }
115
116 return 0;
117}
118
119static void write_one_psp_firmware_hash_entry(int fd, amd_fw_entry_hash *entry)
120{
121 uint16_t type = entry->fw_id;
122 uint16_t subtype = entry->subtype;
123
124 write_or_fail(fd, &type, sizeof(type));
125 write_or_fail(fd, &subtype, sizeof(subtype));
126 write_or_fail(fd, entry->sha, entry->sha_len);
127}
128
129static void write_psp_firmware_hash(const char *filename,
130 amd_fw_entry *fw_table)
131{
132 struct psp_fw_hash_table hash_header = {0};
133 int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
134
135 if (fd < 0) {
136 fprintf(stderr, "Error opening file: %s: %s\n",
137 filename, strerror(errno));
138 exit(-1);
139 }
140
141 hash_header.version = HASH_HDR_V1;
142 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
143 for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
144 if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) {
145 hash_header.no_of_entries_256++;
146 } else if (fw_table[i].hash_entries[j].sha_len ==
147 SHA384_DIGEST_LENGTH) {
148 hash_header.no_of_entries_384++;
149 } else if (fw_table[i].hash_entries[j].sha_len) {
150 fprintf(stderr, "%s: Error invalid sha_len %d\n",
151 __func__, fw_table[i].hash_entries[j].sha_len);
152 exit(-1);
153 }
154 }
155 }
156
157 write_or_fail(fd, &hash_header, sizeof(hash_header));
158
159 /* Add all the SHA256 hash entries first followed by SHA384 entries. PSP verstage
160 processes the table in that order. Mixing and matching SHA256 and SHA384 entries
161 will cause the hash verification failure at run-time. */
162 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
163 for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
164 if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH)
165 write_one_psp_firmware_hash_entry(fd,
166 &fw_table[i].hash_entries[j]);
167 }
168 }
169
170 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
171 for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
172 if (fw_table[i].hash_entries[j].sha_len == SHA384_DIGEST_LENGTH)
173 write_one_psp_firmware_hash_entry(fd,
174 &fw_table[i].hash_entries[j]);
175 }
176 }
177
178 close(fd);
179 for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
180 if (!fw_table[i].num_hash_entries || !fw_table[i].hash_entries)
181 continue;
182
183 free(fw_table[i].hash_entries);
184 fw_table[i].hash_entries = NULL;
185 fw_table[i].num_hash_entries = 0;
186 }
187}
188
189/**
190 * process_signed_psp_firmwares() - Process the signed PSP binaries to keep them separate
191 * @signed_rom: Output file path grouping all the signed PSP binaries.
192 * @fw_table: Table of all the PSP firmware entries/binaries to be processed.
193 * @signed_start_addr: Offset of the FMAP section, within the flash device, to hold
194 * the signed PSP binaries.
195 * @soc_id: SoC ID of the PSP binaries.
196 */
197void process_signed_psp_firmwares(const char *signed_rom,
198 amd_fw_entry *fw_table,
199 uint64_t signed_start_addr,
200 enum platform soc_id)
201{
202 unsigned int i;
203 int fd;
204 int signed_rom_fd;
205 ssize_t bytes, align_bytes;
206 uint8_t *buf;
207 char *signed_rom_hash;
208 size_t signed_rom_hash_strlen;
209 struct amd_fw_header header;
210 struct stat fd_stat;
211 /* Every blob in amdfw*.rom has to start at address aligned to 0x100. Prepare an
212 alignment data with 0xff to pad the blobs and meet the alignment requirement. */
213 uint8_t align_data[BLOB_ALIGNMENT - 1];
214
215 memset(align_data, 0xff, sizeof(align_data));
216 signed_rom_fd = open(signed_rom, O_RDWR | O_CREAT | O_TRUNC,
217 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
218 if (signed_rom_fd < 0) {
219 fprintf(stderr, "Error opening file: %s: %s\n",
220 signed_rom, strerror(errno));
221 return;
222 }
223
224 for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
225 fw_table[i].num_hash_entries = 0;
226 fw_table[i].hash_entries = NULL;
227
228 if (!(fw_table[i].filename) || fw_table[i].skip_hashing)
229 continue;
230
231 memset(&header, 0, sizeof(header));
232
233 fd = open(fw_table[i].filename, O_RDONLY);
234 if (fd < 0) {
235 /* Keep the file along with set of unsigned PSP binaries & continue. */
236 fprintf(stderr, "Error opening file: %s: %s\n",
237 fw_table[i].filename, strerror(errno));
238 continue;
239 }
240
241 if (fstat(fd, &fd_stat)) {
242 /* Keep the file along with set of unsigned PSP binaries & continue. */
243 fprintf(stderr, "fstat error: %s\n", strerror(errno));
244 close(fd);
245 continue;
246 }
247
248 bytes = read_from_file_to_buf(fd, &header, sizeof(struct amd_fw_header));
249 if (bytes != (ssize_t)sizeof(struct amd_fw_header)) {
250 /* Keep the file along with set of unsigned PSP binaries & continue. */
251 fprintf(stderr, "%s: Error reading header from %s\n",
252 __func__, fw_table[i].filename);
253 close(fd);
254 continue;
255 }
256
257 /* If firmware header looks like invalid, assume it's not signed */
258 if (!header.fw_type && !header.fw_id) {
259 fprintf(stderr, "%s: Invalid FWID for %s\n",
260 __func__, fw_table[i].filename);
261 close(fd);
262 continue;
263 }
264
265
266 /* PSP binary is not signed and should not be part of signed PSP binaries
267 set. */
268 if (header.sig_opt != 1) {
269 close(fd);
270 continue;
271 }
272
273 buf = malloc(fd_stat.st_size);
274 if (!buf) {
275 /* Keep the file along with set of unsigned PSP binaries & continue. */
276 fprintf(stderr, "%s: failed to allocate memory with size %lld\n",
277 __func__, (long long)fd_stat.st_size);
278 close(fd);
279 continue;
280 }
281
282 lseek(fd, SEEK_SET, 0);
283 bytes = read_from_file_to_buf(fd, buf, fd_stat.st_size);
284 if (bytes != fd_stat.st_size) {
285 /* Keep the file along with set of unsigned PSP binaries & continue. */
286 fprintf(stderr, "%s: failed to read %s\n",
287 __func__, fw_table[i].filename);
288 free(buf);
289 close(fd);
290 continue;
291 }
292
293 bytes = write_from_buf_to_file(signed_rom_fd, buf, fd_stat.st_size);
294 if (bytes != fd_stat.st_size) {
295 /* Keep the file along with set of unsigned PSP binaries & continue. */
296 fprintf(stderr, "%s: failed to write %s\n",
297 __func__, fw_table[i].filename);
298 free(buf);
299 close(fd);
300 continue;
301 }
302
303 /* Write Blob alignment bytes */
304 align_bytes = 0;
305 if (fd_stat.st_size & (BLOB_ALIGNMENT - 1)) {
306 align_bytes = BLOB_ALIGNMENT -
307 (fd_stat.st_size & (BLOB_ALIGNMENT - 1));
308 bytes = write_from_buf_to_file(signed_rom_fd, align_data, align_bytes);
309 if (bytes != align_bytes) {
310 fprintf(stderr, "%s: failed to write alignment data for %s\n",
311 __func__, fw_table[i].filename);
312 lseek(signed_rom_fd, SEEK_CUR, -fd_stat.st_size);
313 free(buf);
314 close(fd);
315 continue;
316 }
317 }
318
319 if (add_sha(&fw_table[i], buf, fd_stat.st_size, soc_id))
320 exit(-1);
321
322 /* File is successfully processed and is part of signed PSP binaries set. */
323 fw_table[i].fw_id = get_psp_fw_type(soc_id, &header);
324 fw_table[i].addr_signed = signed_start_addr;
325 fw_table[i].file_size = (uint32_t)fd_stat.st_size;
326
327 signed_start_addr += fd_stat.st_size + align_bytes;
328
329 free(buf);
330 close(fd);
331 }
332
333 close(signed_rom_fd);
334
335 /* signed_rom file name + ".hash" + '\0' */
336 signed_rom_hash_strlen = strlen(signed_rom) + strlen(HASH_FILE_SUFFIX) + 1;
337 signed_rom_hash = malloc(signed_rom_hash_strlen);
338 if (!signed_rom_hash) {
339 fprintf(stderr, "malloc(%lu) failed\n", signed_rom_hash_strlen);
340 exit(-1);
341 }
342 strcpy(signed_rom_hash, signed_rom);
343 strcat(signed_rom_hash, HASH_FILE_SUFFIX);
344 write_psp_firmware_hash(signed_rom_hash, fw_table);
345 free(signed_rom_hash);
346}