1
0
Fork 0
mirror of https://github.com/LongSoft/UEFITool.git synced 2025-05-31 23:38:22 -04:00

Add AMD firmware parser

Based on the open source AMDFWTOOL available here:
https://github.com/coreboot/coreboot/tree/main/util/amdfwtool

TODO:
- Merge duplicated regions
  There can be multiple L2 directory tables, for A/B recovery or
  to support different SoC SKUs. They point to the same regions,
  causing the same area to be shown multiple times in the parsed
  image.
- Better quirks support
  PSP hardcodes certain sizes and address types for some files.
  The parser might thus fail, even though it works on real hardware.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
This commit is contained in:
Patrick Rudolph 2025-01-29 08:40:38 +01:00
parent 3aefe281c4
commit 432340352c
12 changed files with 1366 additions and 11 deletions

View file

@ -19,6 +19,7 @@ SET(PROJECT_SOURCES
../common/nvramparser.cpp
../common/meparser.cpp
../common/ffsparser.cpp
../common/ffsparser_amd.cpp
../common/ffsparser_intel.cpp
../common/fitparser.cpp
../common/ffsreport.cpp

View file

@ -17,6 +17,7 @@ SET(PROJECT_SOURCES
../common/nvram.cpp
../common/nvramparser.cpp
../common/ffsparser.cpp
../common/ffsparser_amd.cpp
../common/ffsparser_intel.cpp
../common/fitparser.cpp
../common/peimage.cpp

View file

@ -48,6 +48,7 @@ SET(PROJECT_SOURCES
../common/utility.cpp
../common/ffsbuilder.cpp
../common/ffsparser.cpp
../common/ffsparser_amd.cpp
../common/ffsparser_intel.cpp
../common/ffsreport.cpp
../common/treeitem.cpp

View file

@ -109,6 +109,7 @@ SOURCES += uefitool_main.cpp \
../common/utility.cpp \
../common/ffsbuilder.cpp \
../common/ffsparser.cpp \
../common/ffsparser_amd.cpp \
../common/ffsparser_intel.cpp \
../common/ffsreport.cpp \
../common/treeitem.cpp \

258
common/amd_descriptor.h Normal file
View file

@ -0,0 +1,258 @@
/* amd_descriptor.h
Copyright (c) 2025 Patrick Rudolph. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef AMD_DESCRIPTOR_H
#define AMD_DESCRIPTOR_H
#include "basetypes.h"
#include "ustring.h"
#include "ubytearray.h"
// Make sure we use right packing rules
#pragma pack(push,1)
typedef enum AMD_ADDR_MODE_ {
AMD_ADDR_PHYSICAL = 0, /* Physical address */
AMD_ADDR_REL_BIOS, /* Relative to beginning of image */
AMD_ADDR_REL_TAB, /* Relative to table */
AMD_ADDR_REL_SLOT, /* Relative to slot */
} AMD_ADDR_MODE;
/* An address can be relative to the image/file start but it can also be the address when
* the image is mapped at 0xff000000. Used to ensure that we only attempt to read within
* the limits of the file. */
#define SPI_ROM_BASE 0xff000000
#define FILE_REL_MASK 0xffffff
// Embedded firmware descriptor
typedef struct AMD_EMBEDDED_FIRMWARE_ {
UINT32 Signature; // 0x55aa55aa
UINT32 IMC_Entry; // Pointer to IMC blob
UINT32 GEC_Entry; // Pointer to GEC blob
UINT32 xHCI_Entry; // Pointer to xHCI blob
UINT32 PSP_Directory; // Use New_PSP_Directory when 0xffffffff
UINT32 New_PSP_Directory; // Could be upper 32-bit of PSP_Directory
UINT32 BIOS0_Entry; // Unused?
UINT32 BIOS1_Entry; // Used by EFS1.0
// Might be a BIOS directory or Combo directory table
UINT32 BIOS2_Entry; // Unused?
UINT32 Efs_Generation; // only used after RAVEN/PICASSO
// EFS 1.0
// PLATFORM_CARRIZO 15h (60-6fh)
// PLATFORM_STONEYRIDGE 15h (60-6fh)
// PLATFORM_RAVEN 17h (00-0fh)
// PLATFORM_PICASSO 17h (10-2fh)
// EFS 2.0
// PLATFORM_RENOIR 17h (10-1fh)
// PLATFORM_LUCIENNE 17h (60-6fh)
// PLATFORM_CEZANNE 19h (50-5fh)
// PLATFORM_MENDOCINO 17h (A0-Afh)
// PLATFORM_PHOENIX 19h (70-7fh)
// PLATFORM_GLINDA 17h
// PLATFORM_GENOA 19h
UINT32 BIOS3_Entry; // only used when not using A/B recovery
// Might be a BIOS directory or Combo directory table
UINT32 Reserved_0;
UINT32 Promontory_FW_PTR;
UINT32 Reserved_1[6];
} AMD_EMBEDDED_FIRMWARE;
#define AMD_EFS_GEN1 0xFFFFFFFFUL
// PSP directory header
typedef struct AMD_PSP_DIRECTORY_HEADER_ {
UINT32 Cookie; // 0x50535024
UINT32 Checksum;
UINT32 Num_Entries;
UINT32 Additional_Info_Fields;
} AMD_PSP_DIRECTORY_HEADER;
typedef struct AMD_PSP_DIRECTORY_ENTRY_ {
UINT8 Type;
UINT8 SubProg;
UINT16 Flags;
UINT32 Size;
UINT64 Address_AddressMode;
} AMD_PSP_DIRECTORY_ENTRY;
// PSP combo directory header
typedef struct AMD_PSP_COMBO_DIRECTORY_HEADER_ {
UINT32 Cookie; // 0x50535032
UINT32 Checksum;
UINT32 Num_Entries;
UINT32 Lookup;
UINT64 Reserved[2];
} AMD_PSP_COMBO_DIRECTORY_HEADER;
typedef struct AMD_PSP_COMBO_ENTRY_ {
UINT32 Id_Sel;
UINT32 Id;
UINT64 Lvl2_Address;
} AMD_PSP_COMBO_ENTRY;
typedef enum AMD_BIOS_TYPE_ {
AMD_BIOS_SIG = 0x07,
AMD_BIOS_APCB = 0x60,
AMD_BIOS_APOB = 0x61,
AMD_BIOS_BIN = 0x62,
AMD_BIOS_APOB_NV = 0x63,
AMD_BIOS_PMUI = 0x64,
AMD_BIOS_PMUD = 0x65,
AMD_BIOS_UCODE = 0x66,
AMD_BIOS_APCB_BK = 0x68,
AMD_BIOS_EARLY_VGA = 0x69,
AMD_BIOS_MP2_CFG = 0x6a,
AMD_BIOS_PSP_SHARED_MEM = 0x6b,
AMD_BIOS_L2_PTR = 0x70,
AMD_BIOS_INVALID,
AMD_BIOS_SKIP
} AMD_BIOS_TYPE;
typedef enum AMD_FW_TYPE_ {
AMD_FW_PSP_PUBKEY = 0x00,
AMD_FW_PSP_BOOTLOADER = 0x01,
AMD_FW_PSP_SECURED_OS = 0x02,
AMD_FW_PSP_RECOVERY = 0x03,
AMD_FW_PSP_NVRAM = 0x04,
AMD_FW_RTM_PUBKEY = 0x05,
AMD_FW_PSP_SMU_FIRMWARE = 0x08,
AMD_FW_PSP_SECURED_DEBUG = 0x09,
AMD_FW_ABL_PUBKEY = 0x0a,
AMD_PSP_FUSE_CHAIN = 0x0b,
AMD_FW_PSP_TRUSTLETS = 0x0c,
AMD_FW_PSP_TRUSTLETKEY = 0x0d,
AMD_FW_PSP_SMU_FIRMWARE2 = 0x12,
AMD_DEBUG_UNLOCK = 0x13,
AMD_FW_PSP_TEEIPKEY = 0x15,
AMD_BOOT_DRIVER = 0x1b,
AMD_SOC_DRIVER = 0x1c,
AMD_DEBUG_DRIVER = 0x1d,
AMD_INTERFACE_DRIVER = 0x1f,
AMD_HW_IPCFG = 0x20,
AMD_WRAPPED_IKEK = 0x21,
AMD_TOKEN_UNLOCK = 0x22,
AMD_SEC_GASKET = 0x24,
AMD_MP2_FW = 0x25,
AMD_DRIVER_ENTRIES = 0x28,
AMD_FW_KVM_IMAGE = 0x29,
AMD_FW_MP5 = 0x2a,
AMD_S0I3_DRIVER = 0x2d,
AMD_ABL0 = 0x30,
AMD_ABL1 = 0x31,
AMD_ABL2 = 0x32,
AMD_ABL3 = 0x33,
AMD_ABL4 = 0x34,
AMD_ABL5 = 0x35,
AMD_ABL6 = 0x36,
AMD_ABL7 = 0x37,
AMD_SEV_DATA = 0x38,
AMD_SEV_CODE = 0x39,
AMD_FW_PSP_WHITELIST = 0x3a,
AMD_VBIOS_BTLOADER = 0x3c,
AMD_FW_L2_PTR = 0x40,
AMD_FW_DXIO = 0x42,
AMD_FW_USB_PHY = 0x44,
AMD_FW_TOS_SEC_POLICY = 0x45,
AMD_FW_DRTM_TA = 0x47,
AMD_FW_RECOVERYAB_A = 0x48,
AMD_FW_RECOVERYAB_B = 0x4A,
AMD_FW_BIOS_TABLE = 0x49,
AMD_FW_KEYDB_BL = 0x50,
AMD_FW_KEYDB_TOS = 0x51,
AMD_FW_PSP_VERSTAGE = 0x52,
AMD_FW_VERSTAGE_SIG = 0x53,
AMD_RPMC_NVRAM = 0x54,
AMD_FW_SPL = 0x55,
AMD_FW_DMCU_ERAM = 0x58,
AMD_FW_DMCU_ISR = 0x59,
AMD_FW_MSMU = 0x5a,
AMD_FW_SPIROM_CFG = 0x5c,
AMD_FW_MPIO = 0x5d,
AMD_FW_TPMLITE = 0x5f, /* family 17h & 19h */
AMD_FW_PSP_SMUSCS = 0x5f, /* family 15h & 16h */
AMD_FW_DMCUB = 0x71,
AMD_FW_PSP_BOOTLOADER_AB = 0x73,
AMD_RIB = 0x76,
AMD_FW_AMF_SRAM = 0x85,
AMD_FW_AMF_DRAM = 0x86,
AMD_FW_MFD_MPM = 0x87,
AMD_FW_AMF_WLAN = 0x88,
AMD_FW_AMF_MFD = 0x89,
AMD_FW_MPDMA_TF = 0x8c,
AMD_TA_IKEK = 0x8d,
AMD_FW_MPCCX = 0x90,
AMD_FW_GMI3_PHY = 0x91,
AMD_FW_MPDMA_PM = 0x92,
AMD_FW_LSDMA = 0x94,
AMD_FW_C20_MP = 0x95,
AMD_FW_FCFG_TABLE = 0x98,
AMD_FW_MINIMSMU = 0x9a,
AMD_FW_GFXIMU_0 = 0x9b,
AMD_FW_GFXIMU_1 = 0x9c,
AMD_FW_GFXIMU_2 = 0x9d,
AMD_FW_SRAM_FW_EXT = 0x9d,
AMD_FW_UMSMU = 0xa2,
AMD_FW_S3IMG = 0xa0,
AMD_FW_USBDP = 0xa4,
AMD_FW_USBSS = 0xa5,
AMD_FW_USB4 = 0xa6,
AMD_FW_IMC = 0x200, /* Large enough to be larger than the top BHD entry type. */
AMD_FW_GEC,
AMD_FW_XHCI,
AMD_FW_INVALID, /* Real last one to detect the last entry in table. */
AMD_FW_SKIP /* This is for non-applicable options. */
} AMD_FW_TYPE;
#define AMD_MAX_PSP_ENTRIES 0xff
typedef struct AMD_ISH_DIRECTORY_TABLE_ {
UINT32 Checksum;
UINT32 Boot_Priority;
UINT32 Update_Retry_Count;
UINT8 Glitch_Retry_Count;
UINT8 Glitch_Higherbits_Reserved[3];
UINT32 Pl2_location;
UINT32 Psp_Id;
UINT32 Slot_Max_Size;
UINT32 Reserved;
} AMD_ISH_DIRECTORY_TABLE;
// BIOS directory header
typedef struct AMD_BIOS_DIRECTORY_HEADER_ {
UINT32 Cookie; // 0x44484224
UINT32 Checksum;
UINT32 Num_Entries;
UINT32 Additional_Info_Fields;
} AMD_BIOS_DIRECTORY_HEADER;
typedef struct AMD_BIOS_DIRECTORY_ENTRY_ {
UINT8 Type;
UINT8 RegionType;
UINT16 Flags;
UINT32 Size;
UINT64 Address_AddressMode;
UINT64 Destination;
} AMD_BIOS_DIRECTORY_ENTRY;
#define AMD_MAX_BIOS_ENTRIES 0x2f
// AMD signatures
#define AMD_EMBEDDED_FIRMWARE_SIGNATURE 0x55aa55aa
#define AMD_PSP_DIRECTORY_HEADER_SIGNATURE 0x50535024
#define AMD_PSPL2_DIRECTORY_HEADER_SIGNATURE 0x324c5024
#define AMD_BIOS_HEADER_SIGNATURE 0x44484224
#define AMD_BHDL2_HEADER_SIGNATURE 0x324c4224
#define AMD_PSP_COMBO_DIRECTORY_HEADER_SIGNATURE 0x50535032
#define AMD_PSP_BHD2_DIRECTORY_HEADER_SIGNATURE 0x44484232
#define AMD_EMBEDDED_FIRMWARE_OFFSET 0x20000
#endif // AMD_DESCRIPTOR_H

View file

@ -114,7 +114,12 @@ USTATUS FfsParser::performFirstPass(const UByteArray & buffer, UModelIndex & ind
if (buffer.isEmpty()) {
return U_INVALID_PARAMETER;
}
// Try parsing as AMD image
if (U_SUCCESS == parseAMDImage(buffer, 0, UModelIndex(), index)) {
return U_SUCCESS;
}
// Try parsing as UEFI Capsule
if (U_SUCCESS == parseCapsule(buffer, 0, UModelIndex(), index)) {
return U_SUCCESS;

View file

@ -128,6 +128,29 @@ private:
USTATUS parseCapsule(const UByteArray & capsule, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
// AMD specific
USTATUS parseAMDImage(const UByteArray & amdImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseEFTable(const UByteArray & amdImage, const UINT32 efOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS extractTable(const UByteArray & amdImage, const UINT32 offset, UByteArray & table);
USTATUS decodePSPTableAny(const UByteArray & amdImage, const UINT32 offset, const UModelIndex & parent, UModelIndex & index);
USTATUS isValidTable(const UByteArray & amdImage, const UINT32 offset);
USTATUS isSupportedCookie(const UByteArray & amdImage, const UINT32 offset);
USTATUS parsePSPDir(const UINT32 offset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseComboDir(const UINT32 pspOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseBiosDir(const UINT32 imageOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS insertRegion(UINT32 imageOffset, const UINT32 size, const UString name, UINT8 type, UINT8 subType, const UModelIndex & parent, UModelIndex & index);
USTATUS findByRange(const UINT32 offset, const UINT32 size, const UModelIndex & index, UModelIndex & found);
USTATUS parseISH(const UByteArray & fileImage, const UModelIndex & parent, UModelIndex & index);
USTATUS amdRelativeOffset(const UModelIndex& pspRegionIndex, const UINT64 addr, const UINT64 mode, UINT64 & outaddr);
UString pspFileName(const UINT8 type, const UINT8 subtype);
UINT32 fletcher32(const UByteArray &Image);
USTATUS decompressBios(UModelIndex& parent);
USTATUS insertDirectoryFile(const UINT32 imageOffset, const UINT32 size, const UString name, const UModelIndex & parent, UModelIndex & index);
// Intel specific
USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseBpdtRegion(const UByteArray & region, const UINT32 localOffset, const UINT32 sbpdtOffsetFixup, const UModelIndex & parent, UModelIndex & index);

1030
common/ffsparser_amd.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@ uefitoolcommon = static_library('uefitoolcommon',
'meparser.cpp',
'fitparser.cpp',
'ffsparser.cpp',
'ffsparser_amd.cpp',
'ffsparser_intel.cpp',
'ffsreport.cpp',
'peimage.cpp',

View file

@ -1,11 +1,11 @@
/* types.cpp
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
@ -18,6 +18,7 @@
UString regionTypeToUString(const UINT8 type)
{
switch (type) {
// Intel specific
case Subtypes::DescriptorRegion: return UString("Descriptor");
case Subtypes::BiosRegion: return UString("BIOS");
case Subtypes::MeRegion: return UString("ME");
@ -34,8 +35,12 @@ UString regionTypeToUString(const UINT8 type)
case Subtypes::Reserved1Region: return UString("Reserved1");
case Subtypes::Reserved2Region: return UString("Reserved2");
case Subtypes::PttRegion: return UString("PTT");
// AMD specific
case Subtypes::PspL1DirectoryRegion:return UString("PSP L1 Directory");
case Subtypes::PspL2DirectoryRegion:return UString("PSP L2 Directory");
case Subtypes::PspDirectoryFile: return UString("PSP Directory File");
};
return usprintf("Unknown %02Xh", type);
}
@ -83,8 +88,10 @@ UString itemTypeToUString(const UINT8 type)
case Types::CpdExtension: return UString("CPD extension");
case Types::CpdSpiEntry: return UString("CPD SPI entry");
case Types::StartupApDataEntry: return UString("Startup AP data");
case Types::DirectoryTable: return UString("AMD Directory Table");
case Types::DirectoryTableEntry: return UString("AMD Directory Entry");
}
return usprintf("Unknown %02Xh", type);
}
@ -94,6 +101,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
case Types::Image:
if (subtype == Subtypes::IntelImage) return UString("Intel");
else if (subtype == Subtypes::UefiImage) return UString("UEFI");
else if (subtype == Subtypes::AmdImage) return UString("AMD");
break;
case Types::Padding:
if (subtype == Subtypes::ZeroPadding) return UString("Empty (0x00)");
@ -172,8 +180,20 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
case Types::StartupApDataEntry:
if (subtype == Subtypes::x86128kStartupApDataEntry) return UString("X86 128K");
break;
case Types::DirectoryTable:
if (subtype == Subtypes::PSPDirectory) return UString("PSP Directory Table");
if (subtype == Subtypes::ComboDirectory) return UString("Combo Directory Table");
if (subtype == Subtypes::BiosDirectory) return UString("BIOS Directory Table");
if (subtype == Subtypes::ISHDirectory) return UString("ISH Directory Table");
break;
case Types::DirectoryTableEntry:
if (subtype == Subtypes::PSPDirectory) return UString("PSP Directory");
if (subtype == Subtypes::ComboDirectory) return UString("Combo Directory");
if (subtype == Subtypes::BiosDirectory) return UString("BIOS Directory");
break;
}
return UString();
}
@ -190,7 +210,7 @@ UString compressionTypeToUString(const UINT8 algorithm)
case COMPRESSION_ALGORITHM_GZIP: return UString("GZip");
case COMPRESSION_ALGORITHM_ZLIB: return UString("Zlib");
}
return usprintf("Unknown %02Xh", algorithm);
}
@ -205,7 +225,7 @@ UString actionTypeToUString(const UINT8 action)
case Actions::Rebuild: return UString("Rebuild");
case Actions::Rebase: return UString("Rebase");
}
return usprintf("Unknown %02Xh", action);
}
@ -235,7 +255,7 @@ UString fitEntryTypeToUString(const UINT8 type)
case INTEL_FIT_TYPE_JMP_DEBUG_POLICY: return UString("JMP Debug Policy");
case INTEL_FIT_TYPE_EMPTY: return UString("Empty");
}
return usprintf("Unknown %02Xh", (type & 0x7F));
}
@ -249,7 +269,7 @@ UString hashTypeToUString(const UINT16 algorithm_id)
case TCG_HASH_ALGORITHM_ID_NULL: return UString("NULL");
case TCG_HASH_ALGORITHM_ID_SM3: return UString("SM3");
}
return usprintf("Unknown %04Xh", algorithm_id);
}

View file

@ -75,6 +75,8 @@ namespace Types {
CpdExtension,
CpdSpiEntry,
StartupApDataEntry,
DirectoryTable,
DirectoryTableEntry,
};
}
@ -82,6 +84,7 @@ namespace Subtypes {
enum ImageSubtypes{
IntelImage = 90,
UefiImage,
AmdImage,
};
enum CapsuleSubtypes {
@ -116,6 +119,9 @@ namespace Subtypes {
Reserved1Region,
Reserved2Region,
PttRegion,
PspL1DirectoryRegion,
PspL2DirectoryRegion,
PspDirectoryFile,
};
enum PaddingSubtypes {
@ -144,7 +150,14 @@ namespace Subtypes {
InvalidSysFEntry = 150,
NormalSysFEntry,
};
enum DirectorySubtypes {
PSPDirectory = 150,
ComboDirectory,
BiosDirectory,
ISHDirectory,
};
enum EvsaEntrySubtypes {
InvalidEvsaEntry = 160,
UnknownEvsaEntry,

View file

@ -19,6 +19,7 @@ SET(PROJECT_SOURCES
../common/nvramparser.cpp
../common/meparser.cpp
../common/ffsparser.cpp
../common/ffsparser_amd.cpp
../common/ffsparser_intel.cpp
../common/fitparser.cpp
../common/peimage.cpp