diff options
-rw-r--r-- | Makefile.inc | 8 | ||||
-rw-r--r-- | util/amdfwtool/Makefile | 36 | ||||
-rw-r--r-- | util/amdfwtool/amdfwtool.c | 534 |
3 files changed, 574 insertions, 4 deletions
diff --git a/Makefile.inc b/Makefile.inc index b85a2cba8f..f5326baa91 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -290,7 +290,7 @@ CFLAGS_common += -Os endif additional-dirs := $(objutil)/cbfstool $(objutil)/romcc $(objutil)/ifdtool \ - $(objutil)/ifdfake $(objutil)/options $(objutil)/fletcher \ + $(objutil)/ifdfake $(objutil)/options $(objutil)/amdfwtool \ $(objutil)/cbootimage $(objutil)/bimgtool ####################################################################### @@ -348,10 +348,10 @@ $(IFDFAKE): $(top)/util/ifdfake/ifdfake.c @printf " HOSTCC $(subst $(obj)/,,$(@))\n" $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -FLETCHER:=$(objutil)/fletcher/fletcher -$(FLETCHER): $(top)/util/fletcher/fletcher.c +AMDFWTOOL:=$(objutil)/amdfwtool/amdfwtool +$(AMDFWTOOL): $(top)/util/amdfwtool/amdfwtool.c @printf " HOSTCC $(subst $(obj)/,,$(@))\n" - $(HOSTCC) $(HOSTCFLAGS) -o $@ $< + $(HOSTCC) $(HOSTCFLAGS) -DCONFIG_ROM_SIZE=$(CONFIG_ROM_SIZE) -o $@ $< CBOOTIMAGE:=$(objutil)/cbootimage/cbootimage diff --git a/util/amdfwtool/Makefile b/util/amdfwtool/Makefile new file mode 100644 index 0000000000..f252066d23 --- /dev/null +++ b/util/amdfwtool/Makefile @@ -0,0 +1,36 @@ +#***************************************************************************** +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Advanced Micro Devices, Inc. nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +#***************************************************************************** +HOSTCC ?= cc + +amdfwtool_exe : amdfwtool.c + $(HOSTCC) amdfwtool.c -o amdfwtool + +amdfwtool : amdfwtool_exe + +clean: + @rm -f amdfwtool.o amdfwtool amdfwtool.exe diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c new file mode 100644 index 0000000000..f09041109e --- /dev/null +++ b/util/amdfwtool/amdfwtool.c @@ -0,0 +1,534 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * ROMSIG At ROMBASE + 0x20000: + * +------------+---------------+----------------+------------+ + * | 0x55AA55AA |EC ROM Address |GEC ROM Address |USB3 ROM | + * +------------+---------------+----------------+------------+ + * | PSPDIR ADDR|PSP2DIR ADDR | + * +------------+---------------+ + * EC ROM should be 64K aligned. + * + * PSP directory + * +------------+---------------+----------------+------------+ + * | 'PSP$' | Fletcher | Count | Reserved | + * +------------+---------------+----------------+------------+ + * | 0 | size | Base address | Reserved | Pubkey + * +------------+---------------+----------------+------------+ + * | 1 | size | Base address | Reserved | Bootloader + * +------------+---------------+----------------+------------+ + * | 8 | size | Base address | Reserved | Smu Firmware + * +------------+---------------+----------------+------------+ + * | 3 | size | Base address | Reserved | Recovery Firmware + * +------------+---------------+----------------+------------+ + * | | + * | | + * | Other PSP Firmware | + * | | + * | | + * +------------+---------------+----------------+------------+ + */ + + +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +#ifndef CONFIG_ROM_SIZE +#define CONFIG_ROM_SIZE 0x400000 +#endif + +#define ROM_BASE_ADDRESS (0xFFFFFFFF - CONFIG_ROM_SIZE + 1) +#define AMD_ROMSIG_OFFSET 0x20000 + +#define ALIGN(val, by) (((val) + (by)-1)&~((by)-1)) + +/* + Reserved for future. + TODO: PSP2 is for Combo BIOS, which is the idea that one image supports 2 + kinds of APU. +*/ +#define PSP2 1 + +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; + +/* + * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3. + * The checksum field of the passed PDU does not need to be reset to zero. + * + * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of + * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an + * alternative to cyclical redundancy checks because it provides error- + * detection properties similar to cyclical redundancy checks but at the + * cost of a simple summation technique. Its characteristics were first + * published in IEEE Transactions on Communications in January 1982. One + * version has been adopted by ISO for use in the class-4 transport layer + * of the network protocol. + * + * This program expects: + * stdin: The input file to compute a checksum for. The input file + * not be longer than 256 bytes. + * stdout: Copied from the input file with the Fletcher's Checksum + * inserted 8 bytes after the beginning of the file. + * stderr: Used to print out error messages. + */ +uint32_t fletcher32 (const uint16_t *pptr, int length) +{ + uint32_t c0; + uint32_t c1; + uint32_t checksum; + int index; + + c0 = 0xFFFF; + c1 = 0xFFFF; + + for (index = 0; index < length; index++) { + /* + * Ignore the contents of the checksum field. + */ + c0 += *(pptr++); + c1 += c0; + if ((index % 360) == 0) { + c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow + c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow + } + } + + c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow + c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow + checksum = (c1 << 16) | c0; + + return checksum; +} + +void usage() +{ + printf("Create AMD Firmware combination\n"); +} + +typedef enum _amd_fw_type { + AMD_FW_PSP_PUBKEY = 0, + AMD_FW_PSP_BOOTLOADER = 1, + AMD_FW_PSP_SMU_FIRMWARE = 8, + AMD_FW_PSP_RECOVERY = 3, + AMD_FW_PSP_RTM_PUBKEY = 5, + AMD_FW_PSP_SECURED_OS = 2, + AMD_FW_PSP_NVRAM = 4, + AMD_FW_PSP_SECURED_DEBUG = 9, + AMD_FW_PSP_TRUSTLETS = 12, + AMD_FW_PSP_TRUSTLETKEY = 13, + AMD_FW_PSP_SMU_FIRMWARE2 = 18, + AMD_PSP_FUSE_CHAIN = 11, + AMD_FW_PSP_SMUSCS = 95, + + AMD_FW_IMC, + AMD_FW_GEC, + AMD_FW_XHCI, +} amd_fw_type; + +typedef struct _amd_fw_entry { + amd_fw_type type; + char *filename; +} amd_fw_entry; + +amd_fw_entry amd_psp_fw_table[] = { + { .type = AMD_FW_PSP_PUBKEY }, + { .type = AMD_FW_PSP_BOOTLOADER }, + { .type = AMD_FW_PSP_SMU_FIRMWARE }, + { .type = AMD_FW_PSP_RECOVERY }, + { .type = AMD_FW_PSP_RTM_PUBKEY }, + { .type = AMD_FW_PSP_SECURED_OS }, + { .type = AMD_FW_PSP_NVRAM }, + { .type = AMD_FW_PSP_SECURED_DEBUG }, + { .type = AMD_FW_PSP_TRUSTLETS }, + { .type = AMD_FW_PSP_TRUSTLETKEY }, + { .type = AMD_FW_PSP_SMU_FIRMWARE2 }, + { .type = AMD_FW_PSP_SMUSCS }, + { .type = AMD_PSP_FUSE_CHAIN }, +}; + +#if PSP2 +amd_fw_entry amd_psp2_fw_table[] = { + { .type = AMD_FW_PSP_PUBKEY }, + { .type = AMD_FW_PSP_BOOTLOADER }, + { .type = AMD_FW_PSP_SMU_FIRMWARE }, + { .type = AMD_FW_PSP_RECOVERY }, + { .type = AMD_FW_PSP_RTM_PUBKEY }, + { .type = AMD_FW_PSP_SECURED_OS }, + { .type = AMD_FW_PSP_NVRAM }, + { .type = AMD_FW_PSP_SECURED_DEBUG }, + { .type = AMD_FW_PSP_TRUSTLETS }, + { .type = AMD_FW_PSP_TRUSTLETKEY }, + { .type = AMD_FW_PSP_SMU_FIRMWARE2 }, + { .type = AMD_FW_PSP_SMUSCS }, + { .type = AMD_PSP_FUSE_CHAIN }, +}; +#endif + +amd_fw_entry amd_fw_table[] = { + { .type = AMD_FW_XHCI }, + { .type = AMD_FW_IMC }, + { .type = AMD_FW_GEC }, +}; + +void fill_psp_head(uint32_t *pspdir, int count) +{ + pspdir[0] = 1347637284; /* 'PSP$' */ + pspdir[2] = count; /* size */ + pspdir[3] = 0; + pspdir[1] = fletcher32((uint16_t *)&pspdir[1], (count *16 + 16)/2 - 2); +} + +uint32_t integerate_one_fw(void *base, uint32_t pos, uint32_t *romsig, int i) +{ + int fd; + struct stat fd_stat; + + if (amd_fw_table[i].filename != NULL) { + fd = open (amd_fw_table[i].filename, O_RDONLY); + fstat(fd, &fd_stat); + + switch (amd_fw_table[i].type) { + case AMD_FW_IMC: + pos = ALIGN(pos, 0x10000); + romsig[1] = pos + ROM_BASE_ADDRESS; + break; + case AMD_FW_GEC: + romsig[2] = pos + ROM_BASE_ADDRESS; + break; + case AMD_FW_XHCI: + romsig[3] = pos + ROM_BASE_ADDRESS; + break; + default: + /* Error */ + break; + } + + read (fd, base+pos, fd_stat.st_size); + + pos += fd_stat.st_size; + pos = ALIGN(pos, 0x100); + close (fd); + } + + return pos; +} + +uint32_t integerate_one_psp(void *base, uint32_t pos, uint32_t *pspdir, int i) +{ + int fd; + struct stat fd_stat; + + if (amd_psp_fw_table[i].type == AMD_PSP_FUSE_CHAIN) { + pspdir[4+4*i+0] = amd_psp_fw_table[i].type; + pspdir[4+4*i+1] = 0xFFFFFFFF; + pspdir[4+4*i+2] = 1; + pspdir[4+4*i+3] = 0; + } else if (amd_psp_fw_table[i].filename != NULL) { + pspdir[4+4*i+0] = amd_psp_fw_table[i].type; + + fd = open (amd_psp_fw_table[i].filename, O_RDONLY); + fstat(fd, &fd_stat); + pspdir[4+4*i+1] = fd_stat.st_size; + + pspdir[4+4*i+2] = pos + ROM_BASE_ADDRESS; + pspdir[4+4*i+3] = 0; + + read (fd, base+pos, fd_stat.st_size); + + pos += fd_stat.st_size; + pos = ALIGN(pos, 0x100); + close (fd); + } else { + /* This APU doesn't have this firmware. */ + } + + return pos; +} + +static const char *optstring = "x:i:g:p:b:s:r:k:o:n:d:t:u:w:m:h"; +static struct option long_options[] = { + {"xhci", required_argument, 0, 'x' }, + {"imc", required_argument, 0, 'i' }, + {"gec", required_argument, 0, 'g' }, + /* PSP */ + {"pubkey", required_argument, 0, 'p' }, + {"bootloader", required_argument, 0, 'b' }, + {"smufirmware", required_argument, 0, 's' }, + {"recovery", required_argument, 0, 'r' }, + {"rtmpubkey", required_argument, 0, 'k' }, + {"secureos", required_argument, 0, 'c' }, + {"nvram", required_argument, 0, 'n' }, + {"securedebug", required_argument, 0, 'd' }, + {"trustlets", required_argument, 0, 't' }, + {"trustletkey", required_argument, 0, 'u' }, + {"smufirmware2", required_argument, 0, 'w' }, + {"smuscs", required_argument, 0, 'm' }, + + /* TODO: PSP2 */ +#if PSP2 + {"pubkey2", required_argument, 0, 'P' }, + {"bootloader2", required_argument, 0, 'B' }, + {"smufirmware2", required_argument, 0, 'S' }, + {"recovery2", required_argument, 0, 'R' }, + {"rtmpubkey2", required_argument, 0, 'K' }, + {"secureos2", required_argument, 0, 'C' }, + {"nvram2", required_argument, 0, 'N' }, + {"securedebug2", required_argument, 0, 'D' }, + {"trustlets2", required_argument, 0, 'T' }, + {"trustletkey2", required_argument, 0, 'U' }, + {"smufirmware2_2",required_argument, 0, 'W' }, + {"smuscs2", required_argument, 0, 'M' }, +#endif + + {"output", required_argument, 0, 'o' }, + {"help", no_argument, 0, 'h' }, + + {NULL, 0, 0, 0 } +}; + +void register_fw_filename(amd_fw_type type, char filename[], int pspflag) +{ + int i; + + for (i = 0; i < sizeof(amd_fw_table)/sizeof(amd_fw_entry); i++) { + if (amd_fw_table[i].type == type) { + amd_fw_table[i].filename = filename; + return; + } + } + + if (pspflag == 1) { + for (i = 0; i < sizeof(amd_psp_fw_table)/sizeof(amd_fw_entry); i++) { + if (amd_psp_fw_table[i].type == type) { + amd_psp_fw_table[i].filename = filename; + return; + } + } + } + +#if PSP2 + if (pspflag == 2) { + for (i = 0; i < sizeof(amd_psp2_fw_table)/sizeof(amd_fw_entry); i++) { + if (amd_psp2_fw_table[i].type == type) { + amd_psp2_fw_table[i].filename = filename; + return; + } + } + } +#endif +} + +int main(int argc, char **argv) +{ + int c, count, pspflag = 0; +#if PSP2 + int psp2flag = 0; +#endif + void *rom = NULL; + uint32_t current; + uint32_t *amd_romsig, *pspdir; + + int targetfd; + char *output; + + rom = malloc(CONFIG_ROM_SIZE); + memset (rom, 0xFF, CONFIG_ROM_SIZE); + if (!rom) { + return 1; + } + + current = AMD_ROMSIG_OFFSET; + amd_romsig = rom + AMD_ROMSIG_OFFSET; + amd_romsig[0] = 0x55AA55AA; /* romsig */ + + current += 0x20; /* size of ROMSIG */ + + while (1) { + int optindex = 0; + + c = getopt_long(argc, argv, optstring, long_options, &optindex); + + if (c == -1) + break; + + switch (c) { + case 'x': + register_fw_filename(AMD_FW_XHCI, optarg, 0); + break; + case 'i': + register_fw_filename(AMD_FW_IMC, optarg, 0); + break; + case 'g': + register_fw_filename(AMD_FW_GEC, optarg, 0); + break; + case 'p': + register_fw_filename(AMD_FW_PSP_PUBKEY, optarg, 1); + pspflag = 1; + break; + case 'b': + register_fw_filename(AMD_FW_PSP_BOOTLOADER, optarg, 1); + pspflag = 1; + break; + case 's': + register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE, optarg, 1); + pspflag = 1; + break; + case 'r': + register_fw_filename(AMD_FW_PSP_RECOVERY, optarg, 1); + pspflag = 1; + break; + case 'k': + register_fw_filename(AMD_FW_PSP_RTM_PUBKEY, optarg, 1); + pspflag = 1; + break; + case 'c': + register_fw_filename(AMD_FW_PSP_SECURED_OS, optarg, 1); + pspflag = 1; + break; + case 'n': + register_fw_filename(AMD_FW_PSP_NVRAM, optarg, 1); + pspflag = 1; + break; + case 'd': + register_fw_filename(AMD_FW_PSP_SECURED_DEBUG, optarg, 1); + pspflag = 1; + break; + case 't': + register_fw_filename(AMD_FW_PSP_TRUSTLETS, optarg, 1); + pspflag = 1; + break; + case 'u': + register_fw_filename(AMD_FW_PSP_TRUSTLETKEY, optarg, 1); + pspflag = 1; + break; + case 'w': + register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE2, optarg, 1); + pspflag = 1; + break; + case 'm': + register_fw_filename(AMD_FW_PSP_SMUSCS, optarg, 1); + pspflag = 1; + break; +#if PSP2 + case 'P': + register_fw_filename(AMD_FW_PSP_PUBKEY, optarg, 2); + psp2flag = 1; + break; + case 'B': + register_fw_filename(AMD_FW_PSP_BOOTLOADER, optarg, 2); + psp2flag = 1; + break; + case 'S': + register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE, optarg, 2); + psp2flag = 1; + break; + case 'R': + register_fw_filename(AMD_FW_PSP_RECOVERY, optarg, 2); + psp2flag = 1; + break; + case 'K': + register_fw_filename(AMD_FW_PSP_RTM_PUBKEY, optarg, 2); + psp2flag = 1; + break; + case 'C': + register_fw_filename(AMD_FW_PSP_SECURED_OS, optarg, 2); + psp2flag = 1; + break; + case 'N': + register_fw_filename(AMD_FW_PSP_NVRAM, optarg, 2); + psp2flag = 1; + break; + case 'D': + register_fw_filename(AMD_FW_PSP_SECURED_DEBUG, optarg, 2); + psp2flag = 1; + break; + case 'T': + register_fw_filename(AMD_FW_PSP_TRUSTLETS, optarg, 2); + psp2flag = 1; + break; + case 'U': + register_fw_filename(AMD_FW_PSP_TRUSTLETKEY, optarg, 2); + psp2flag = 1; + break; + case 'W': + register_fw_filename(AMD_FW_PSP_SMU_FIRMWARE2, optarg, 2); + psp2flag = 1; + break; + case 'M': + register_fw_filename(AMD_FW_PSP_SMUSCS, optarg, 2); + psp2flag = 1; + break; +#endif + case 'o': + output = optarg; + break; + case 'h': + usage(); + return 1; + default: + break; + } + } + + current = ALIGN(current, 0x100); + for (count = 0; count < sizeof(amd_fw_table) / sizeof(amd_fw_entry); count ++) { + current = integerate_one_fw(rom, current, amd_romsig, count); + } + + if (pspflag == 1) { + current = ALIGN(current, 0x10000); + pspdir = rom + current; + amd_romsig[4] = current + ROM_BASE_ADDRESS; + + current += 0x200; /* Conservative size of pspdir */ + for (count = 0; count < sizeof(amd_psp_fw_table) / sizeof(amd_fw_entry); count ++) { + current = integerate_one_psp(rom, current, pspdir, count); + } + + fill_psp_head(pspdir, count); + +#if PSP2 + if (psp2flag == 1) { + current = ALIGN(current, 0x10000); + pspdir = rom + current; + amd_romsig[5] = current + ROM_BASE_ADDRESS; + current += 0x200; /* Conservative size of pspdir */ + + for (count = 0; count < sizeof(amd_psp2_fw_table) / sizeof(amd_fw_entry); count ++) { + current = integerate_one_psp(rom, current, pspdir, count); + } + + fill_psp_head(pspdir, count); + } +#endif + } + + targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666); + write(targetfd, amd_romsig, current - AMD_ROMSIG_OFFSET); + close(targetfd); + free(rom); + + return 0; +} |