blob: b08a9619641b573294ce52e3941ab795874da71d [file] [log] [blame]
Zheng Bao9c7ff7b2015-11-17 22:57:39 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2015 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16/*
17 * ROMSIG At ROMBASE + 0x20000:
18 * +------------+---------------+----------------+------------+
19 * | 0x55AA55AA |EC ROM Address |GEC ROM Address |USB3 ROM |
20 * +------------+---------------+----------------+------------+
21 * | PSPDIR ADDR|PSP2DIR ADDR |
22 * +------------+---------------+
23 * EC ROM should be 64K aligned.
24 *
Zheng Bao4fcc9f22015-11-20 12:29:04 +080025 * PSP directory (Where "PSPDIR ADDR" points)
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080026 * +------------+---------------+----------------+------------+
27 * | 'PSP$' | Fletcher | Count | Reserved |
28 * +------------+---------------+----------------+------------+
29 * | 0 | size | Base address | Reserved | Pubkey
30 * +------------+---------------+----------------+------------+
31 * | 1 | size | Base address | Reserved | Bootloader
32 * +------------+---------------+----------------+------------+
33 * | 8 | size | Base address | Reserved | Smu Firmware
34 * +------------+---------------+----------------+------------+
35 * | 3 | size | Base address | Reserved | Recovery Firmware
36 * +------------+---------------+----------------+------------+
37 * | |
38 * | |
39 * | Other PSP Firmware |
40 * | |
41 * | |
42 * +------------+---------------+----------------+------------+
Zheng Bao4fcc9f22015-11-20 12:29:04 +080043 *
44 * PSP2 directory
45 * +------------+---------------+----------------+------------+
46 * | 'PSP2' | Fletcher | Count | Reserved |
47 * +------------+---------------+----------------+------------+
48 * | 1 | PSP ID | PSPDIR ADDR | | 2nd PSP directory
49 * +------------+---------------+----------------+------------+
50 * | 2 | PSP ID | PSPDIR ADDR | | 3rd PSP directory
51 * +------------+---------------+----------------+------------+
52 * | |
53 * | Other PSP |
54 * | |
55 * +------------+---------------+----------------+------------+
56 *
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080057 */
58
Zheng Bao9c7ff7b2015-11-17 22:57:39 +080059#include <fcntl.h>
60#include <errno.h>
61#include <stdio.h>
62#include <sys/stat.h>
63#include <sys/types.h>
64#include <unistd.h>
65#include <string.h>
66#include <stdlib.h>
67#include <getopt.h>
68
69#ifndef CONFIG_ROM_SIZE
70#define CONFIG_ROM_SIZE 0x400000
71#endif
72
73#define ROM_BASE_ADDRESS (0xFFFFFFFF - CONFIG_ROM_SIZE + 1)
74#define AMD_ROMSIG_OFFSET 0x20000
75
76#define ALIGN(val, by) (((val) + (by)-1)&~((by)-1))
77
78/*
79 Reserved for future.
80 TODO: PSP2 is for Combo BIOS, which is the idea that one image supports 2
81 kinds of APU.
82*/
83#define PSP2 1
84
85typedef unsigned int uint32_t;
86typedef unsigned char uint8_t;
87typedef unsigned short uint16_t;
88
89/*
90 * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
91 * The checksum field of the passed PDU does not need to be reset to zero.
92 *
93 * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of
94 * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an
95 * alternative to cyclical redundancy checks because it provides error-
96 * detection properties similar to cyclical redundancy checks but at the
97 * cost of a simple summation technique. Its characteristics were first
98 * published in IEEE Transactions on Communications in January 1982. One
99 * version has been adopted by ISO for use in the class-4 transport layer
100 * of the network protocol.
101 *
102 * This program expects:
103 * stdin: The input file to compute a checksum for. The input file
104 * not be longer than 256 bytes.
105 * stdout: Copied from the input file with the Fletcher's Checksum
106 * inserted 8 bytes after the beginning of the file.
107 * stderr: Used to print out error messages.
108 */
109uint32_t fletcher32 (const uint16_t *pptr, int length)
110{
111 uint32_t c0;
112 uint32_t c1;
113 uint32_t checksum;
114 int index;
115
116 c0 = 0xFFFF;
117 c1 = 0xFFFF;
118
119 for (index = 0; index < length; index++) {
120 /*
121 * Ignore the contents of the checksum field.
122 */
123 c0 += *(pptr++);
124 c1 += c0;
125 if ((index % 360) == 0) {
126 c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow
127 c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow
128 }
129 }
130
131 c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow
132 c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow
133 checksum = (c1 << 16) | c0;
134
135 return checksum;
136}
137
138void usage()
139{
140 printf("Create AMD Firmware combination\n");
141}
142
143typedef enum _amd_fw_type {
144 AMD_FW_PSP_PUBKEY = 0,
145 AMD_FW_PSP_BOOTLOADER = 1,
146 AMD_FW_PSP_SMU_FIRMWARE = 8,
147 AMD_FW_PSP_RECOVERY = 3,
148 AMD_FW_PSP_RTM_PUBKEY = 5,
149 AMD_FW_PSP_SECURED_OS = 2,
150 AMD_FW_PSP_NVRAM = 4,
151 AMD_FW_PSP_SECURED_DEBUG = 9,
152 AMD_FW_PSP_TRUSTLETS = 12,
153 AMD_FW_PSP_TRUSTLETKEY = 13,
154 AMD_FW_PSP_SMU_FIRMWARE2 = 18,
155 AMD_PSP_FUSE_CHAIN = 11,
156 AMD_FW_PSP_SMUSCS = 95,
157
158 AMD_FW_IMC,
159 AMD_FW_GEC,
160 AMD_FW_XHCI,
161} amd_fw_type;
162
163typedef struct _amd_fw_entry {
164 amd_fw_type type;
165 char *filename;
166} amd_fw_entry;
167
168amd_fw_entry amd_psp_fw_table[] = {
169 { .type = AMD_FW_PSP_PUBKEY },
170 { .type = AMD_FW_PSP_BOOTLOADER },
171 { .type = AMD_FW_PSP_SMU_FIRMWARE },
172 { .type = AMD_FW_PSP_RECOVERY },
173 { .type = AMD_FW_PSP_RTM_PUBKEY },
174 { .type = AMD_FW_PSP_SECURED_OS },
175 { .type = AMD_FW_PSP_NVRAM },
176 { .type = AMD_FW_PSP_SECURED_DEBUG },
177 { .type = AMD_FW_PSP_TRUSTLETS },
178 { .type = AMD_FW_PSP_TRUSTLETKEY },
179 { .type = AMD_FW_PSP_SMU_FIRMWARE2 },
180 { .type = AMD_FW_PSP_SMUSCS },
181 { .type = AMD_PSP_FUSE_CHAIN },
182};
183
184#if PSP2
185amd_fw_entry amd_psp2_fw_table[] = {
186 { .type = AMD_FW_PSP_PUBKEY },
187 { .type = AMD_FW_PSP_BOOTLOADER },
188 { .type = AMD_FW_PSP_SMU_FIRMWARE },
189 { .type = AMD_FW_PSP_RECOVERY },
190 { .type = AMD_FW_PSP_RTM_PUBKEY },
191 { .type = AMD_FW_PSP_SECURED_OS },
192 { .type = AMD_FW_PSP_NVRAM },
193 { .type = AMD_FW_PSP_SECURED_DEBUG },
194 { .type = AMD_FW_PSP_TRUSTLETS },
195 { .type = AMD_FW_PSP_TRUSTLETKEY },
196 { .type = AMD_FW_PSP_SMU_FIRMWARE2 },
197 { .type = AMD_FW_PSP_SMUSCS },
198 { .type = AMD_PSP_FUSE_CHAIN },
199};
200#endif
201
202amd_fw_entry amd_fw_table[] = {
203 { .type = AMD_FW_XHCI },
204 { .type = AMD_FW_IMC },
205 { .type = AMD_FW_GEC },
206};
207
208void fill_psp_head(uint32_t *pspdir, int count)
209{
Zheng Bao4fcc9f22015-11-20 12:29:04 +0800210 pspdir[0] = 0x50535024; /* 'PSP$' */
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800211 pspdir[2] = count; /* size */
212 pspdir[3] = 0;
213 pspdir[1] = fletcher32((uint16_t *)&pspdir[1], (count *16 + 16)/2 - 2);
214}
215
216uint32_t integerate_one_fw(void *base, uint32_t pos, uint32_t *romsig, int i)
217{
218 int fd;
219 struct stat fd_stat;
220
221 if (amd_fw_table[i].filename != NULL) {
222 fd = open (amd_fw_table[i].filename, O_RDONLY);
223 fstat(fd, &fd_stat);
224
225 switch (amd_fw_table[i].type) {
226 case AMD_FW_IMC:
227 pos = ALIGN(pos, 0x10000);
228 romsig[1] = pos + ROM_BASE_ADDRESS;
229 break;
230 case AMD_FW_GEC:
231 romsig[2] = pos + ROM_BASE_ADDRESS;
232 break;
233 case AMD_FW_XHCI:
234 romsig[3] = pos + ROM_BASE_ADDRESS;
235 break;
236 default:
237 /* Error */
238 break;
239 }
240
241 read (fd, base+pos, fd_stat.st_size);
242
243 pos += fd_stat.st_size;
244 pos = ALIGN(pos, 0x100);
245 close (fd);
246 }
247
248 return pos;
249}
250
251uint32_t integerate_one_psp(void *base, uint32_t pos, uint32_t *pspdir, int i)
252{
253 int fd;
254 struct stat fd_stat;
255
256 if (amd_psp_fw_table[i].type == AMD_PSP_FUSE_CHAIN) {
257 pspdir[4+4*i+0] = amd_psp_fw_table[i].type;
258 pspdir[4+4*i+1] = 0xFFFFFFFF;
259 pspdir[4+4*i+2] = 1;
260 pspdir[4+4*i+3] = 0;
261 } else if (amd_psp_fw_table[i].filename != NULL) {
262 pspdir[4+4*i+0] = amd_psp_fw_table[i].type;
263
264 fd = open (amd_psp_fw_table[i].filename, O_RDONLY);
265 fstat(fd, &fd_stat);
266 pspdir[4+4*i+1] = fd_stat.st_size;
267
268 pspdir[4+4*i+2] = pos + ROM_BASE_ADDRESS;
269 pspdir[4+4*i+3] = 0;
270
271 read (fd, base+pos, fd_stat.st_size);
272
273 pos += fd_stat.st_size;
274 pos = ALIGN(pos, 0x100);
275 close (fd);
276 } else {
277 /* This APU doesn't have this firmware. */
278 }
279
280 return pos;
281}
282
283static const char *optstring = "x:i:g:p:b:s:r:k:o:n:d:t:u:w:m:h";
284static struct option long_options[] = {
285 {"xhci", required_argument, 0, 'x' },
286 {"imc", required_argument, 0, 'i' },
287 {"gec", required_argument, 0, 'g' },
288 /* PSP */
289 {"pubkey", required_argument, 0, 'p' },
290 {"bootloader", required_argument, 0, 'b' },
291 {"smufirmware", required_argument, 0, 's' },
292 {"recovery", required_argument, 0, 'r' },
293 {"rtmpubkey", required_argument, 0, 'k' },
294 {"secureos", required_argument, 0, 'c' },
295 {"nvram", required_argument, 0, 'n' },
296 {"securedebug", required_argument, 0, 'd' },
297 {"trustlets", required_argument, 0, 't' },
298 {"trustletkey", required_argument, 0, 'u' },
299 {"smufirmware2", required_argument, 0, 'w' },
300 {"smuscs", required_argument, 0, 'm' },
301
302 /* TODO: PSP2 */
303#if PSP2
304 {"pubkey2", required_argument, 0, 'P' },
305 {"bootloader2", required_argument, 0, 'B' },
306 {"smufirmware2", required_argument, 0, 'S' },
307 {"recovery2", required_argument, 0, 'R' },
308 {"rtmpubkey2", required_argument, 0, 'K' },
309 {"secureos2", required_argument, 0, 'C' },
310 {"nvram2", required_argument, 0, 'N' },
311 {"securedebug2", required_argument, 0, 'D' },
312 {"trustlets2", required_argument, 0, 'T' },
313 {"trustletkey2", required_argument, 0, 'U' },
314 {"smufirmware2_2",required_argument, 0, 'W' },
315 {"smuscs2", required_argument, 0, 'M' },
316#endif
317
318 {"output", required_argument, 0, 'o' },
319 {"help", no_argument, 0, 'h' },
320
321 {NULL, 0, 0, 0 }
322};
323
324void register_fw_filename(amd_fw_type type, char filename[], int pspflag)
325{
326 int i;
327
328 for (i = 0; i < sizeof(amd_fw_table)/sizeof(amd_fw_entry); i++) {
329 if (amd_fw_table[i].type == type) {
330 amd_fw_table[i].filename = filename;
331 return;
332 }
333 }
334
335 if (pspflag == 1) {
336 for (i = 0; i < sizeof(amd_psp_fw_table)/sizeof(amd_fw_entry); i++) {
337 if (amd_psp_fw_table[i].type == type) {
338 amd_psp_fw_table[i].filename = filename;
339 return;
340 }
341 }
342 }
343
344#if PSP2
345 if (pspflag == 2) {
346 for (i = 0; i < sizeof(amd_psp2_fw_table)/sizeof(amd_fw_entry); i++) {
347 if (amd_psp2_fw_table[i].type == type) {
348 amd_psp2_fw_table[i].filename = filename;
349 return;
350 }
351 }
352 }
353#endif
354}
355
356int main(int argc, char **argv)
357{
358 int c, count, pspflag = 0;
359#if PSP2
360 int psp2flag = 0;
Zheng Bao4fcc9f22015-11-20 12:29:04 +0800361 int psp2count;
362 uint32_t *psp2dir;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800363#endif
364 void *rom = NULL;
365 uint32_t current;
366 uint32_t *amd_romsig, *pspdir;
367
368 int targetfd;
369 char *output;
370
371 rom = malloc(CONFIG_ROM_SIZE);
372 memset (rom, 0xFF, CONFIG_ROM_SIZE);
373 if (!rom) {
374 return 1;
375 }
376
377 current = AMD_ROMSIG_OFFSET;
378 amd_romsig = rom + AMD_ROMSIG_OFFSET;
379 amd_romsig[0] = 0x55AA55AA; /* romsig */
zbao85f362e2015-12-07 05:17:23 -0500380 amd_romsig[1] = 0;
381 amd_romsig[2] = 0;
382 amd_romsig[3] = 0;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800383
384 current += 0x20; /* size of ROMSIG */
385
386 while (1) {
387 int optindex = 0;
388
389 c = getopt_long(argc, argv, optstring, long_options, &optindex);
390
391 if (c == -1)
392 break;
393
394 switch (c) {
395 case 'x':
396 register_fw_filename(AMD_FW_XHCI, optarg, 0);
397 break;
398 case 'i':
399 register_fw_filename(AMD_FW_IMC, optarg, 0);
400 break;
401 case 'g':
402 register_fw_filename(AMD_FW_GEC, optarg, 0);
403 break;
404 case 'p':
405 register_fw_filename(AMD_FW_PSP_PUBKEY, optarg, 1);
406 pspflag = 1;
407 break;
408 case 'b':
409 register_fw_filename(AMD_FW_PSP_BOOTLOADER, optarg, 1);
410 pspflag = 1;
411 break;
412 case 's':
413 register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE, optarg, 1);
414 pspflag = 1;
415 break;
416 case 'r':
417 register_fw_filename(AMD_FW_PSP_RECOVERY, optarg, 1);
418 pspflag = 1;
419 break;
420 case 'k':
421 register_fw_filename(AMD_FW_PSP_RTM_PUBKEY, optarg, 1);
422 pspflag = 1;
423 break;
424 case 'c':
425 register_fw_filename(AMD_FW_PSP_SECURED_OS, optarg, 1);
426 pspflag = 1;
427 break;
428 case 'n':
429 register_fw_filename(AMD_FW_PSP_NVRAM, optarg, 1);
430 pspflag = 1;
431 break;
432 case 'd':
433 register_fw_filename(AMD_FW_PSP_SECURED_DEBUG, optarg, 1);
434 pspflag = 1;
435 break;
436 case 't':
437 register_fw_filename(AMD_FW_PSP_TRUSTLETS, optarg, 1);
438 pspflag = 1;
439 break;
440 case 'u':
441 register_fw_filename(AMD_FW_PSP_TRUSTLETKEY, optarg, 1);
442 pspflag = 1;
443 break;
444 case 'w':
445 register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE2, optarg, 1);
446 pspflag = 1;
447 break;
448 case 'm':
449 register_fw_filename(AMD_FW_PSP_SMUSCS, optarg, 1);
450 pspflag = 1;
451 break;
452#if PSP2
453 case 'P':
454 register_fw_filename(AMD_FW_PSP_PUBKEY, optarg, 2);
455 psp2flag = 1;
456 break;
457 case 'B':
458 register_fw_filename(AMD_FW_PSP_BOOTLOADER, optarg, 2);
459 psp2flag = 1;
460 break;
461 case 'S':
462 register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE, optarg, 2);
463 psp2flag = 1;
464 break;
465 case 'R':
466 register_fw_filename(AMD_FW_PSP_RECOVERY, optarg, 2);
467 psp2flag = 1;
468 break;
469 case 'K':
470 register_fw_filename(AMD_FW_PSP_RTM_PUBKEY, optarg, 2);
471 psp2flag = 1;
472 break;
473 case 'C':
474 register_fw_filename(AMD_FW_PSP_SECURED_OS, optarg, 2);
475 psp2flag = 1;
476 break;
477 case 'N':
478 register_fw_filename(AMD_FW_PSP_NVRAM, optarg, 2);
479 psp2flag = 1;
480 break;
481 case 'D':
482 register_fw_filename(AMD_FW_PSP_SECURED_DEBUG, optarg, 2);
483 psp2flag = 1;
484 break;
485 case 'T':
486 register_fw_filename(AMD_FW_PSP_TRUSTLETS, optarg, 2);
487 psp2flag = 1;
488 break;
489 case 'U':
490 register_fw_filename(AMD_FW_PSP_TRUSTLETKEY, optarg, 2);
491 psp2flag = 1;
492 break;
493 case 'W':
494 register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE2, optarg, 2);
495 psp2flag = 1;
496 break;
497 case 'M':
498 register_fw_filename(AMD_FW_PSP_SMUSCS, optarg, 2);
499 psp2flag = 1;
500 break;
501#endif
502 case 'o':
503 output = optarg;
504 break;
505 case 'h':
506 usage();
507 return 1;
508 default:
509 break;
510 }
511 }
512
513 current = ALIGN(current, 0x100);
514 for (count = 0; count < sizeof(amd_fw_table) / sizeof(amd_fw_entry); count ++) {
515 current = integerate_one_fw(rom, current, amd_romsig, count);
516 }
517
518 if (pspflag == 1) {
519 current = ALIGN(current, 0x10000);
520 pspdir = rom + current;
521 amd_romsig[4] = current + ROM_BASE_ADDRESS;
522
523 current += 0x200; /* Conservative size of pspdir */
524 for (count = 0; count < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); count ++) {
525 current = integerate_one_psp(rom, current, pspdir, count);
526 }
527
528 fill_psp_head(pspdir, count);
529
530#if PSP2
531 if (psp2flag == 1) {
Zheng Bao4fcc9f22015-11-20 12:29:04 +0800532 current = ALIGN(current, 0x10000); /* PSP2 dir */
533 psp2dir = rom + current;
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800534 amd_romsig[5] = current + ROM_BASE_ADDRESS;
Zheng Bao4fcc9f22015-11-20 12:29:04 +0800535 current += 0x100; /* Add conservative size of psp2dir. */
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800536
Zheng Bao4fcc9f22015-11-20 12:29:04 +0800537 /* TODO: remove the hardcode. */
538 psp2count = 1; /* Start from 1. */
539 /* for (; psp2count <= PSP2COUNT; psp2count++, current=ALIGN(current, 0x100)) { */
540 psp2dir[psp2count*4 + 0] = psp2count; /* PSP Number */
541 psp2dir[psp2count*4 + 1] = 0x10220B00; /* TODO: PSP ID. Documentation is needed. */
542 psp2dir[psp2count*4 + 2] = current + ROM_BASE_ADDRESS;
543 pspdir = rom + current;
544 psp2dir[psp2count*4 + 3] = 0;
545
546 current += 0x200; /* Add conservative size of pspdir. Start of PSP entries. */
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800547 for (count = 0; count < sizeof(amd_psp2_fw_table) / sizeof(amd_fw_entry); count ++) {
548 current = integerate_one_psp(rom, current, pspdir, count);
549 }
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800550 fill_psp_head(pspdir, count);
Zheng Bao4fcc9f22015-11-20 12:29:04 +0800551 /* } */ /* End of loop */
552
553 /* fill the PSP2 head */
554 psp2dir[0] = 0x50535032; /* 'PSP2' */
555 psp2dir[2] = psp2count; /* Count */
556 psp2dir[3] = 0;
557 psp2dir[1] = fletcher32((uint16_t *)&psp2dir[1], (psp2count*16 + 16)/2 - 2);
Zheng Bao9c7ff7b2015-11-17 22:57:39 +0800558 }
559#endif
560 }
561
562 targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666);
563 write(targetfd, amd_romsig, current - AMD_ROMSIG_OFFSET);
564 close(targetfd);
565 free(rom);
566
567 return 0;
568}