// InventoryApp.efi -- Decompiled source
// Module: InventoryApp (index 0251)
// Image size: 0x51a0 bytes
// Compiler: EDK II (UEFI DXE driver)
//
// This module is a UEFI Shell-based System Inventory Diagnostic Tool.
// It locates the gSystemInventoryProtocol (or gBmcSystemInventoryProtocol)
// and dumps inventory data for CPU, DIMM, PCIe, and HDD subsystems.
//
// Author: Rush Wang (c) 2017 Copyright Lenovo
// File paths: e:\hs\MdePkg\Library\...
// ============================================================================
// Global variables
// ============================================================================
EFI_HANDLE gImageHandle; // 0x4EF0
EFI_SYSTEM_TABLE *gST; // 0x4EE8
EFI_BOOT_SERVICES *gBS; // 0x4EF8
EFI_RUNTIME_SERVICES *gRT; // 0x4F00
EFI_SYSTEM_TABLE *SystemTable_0; // 0x4F28 (secondary copy)
EFI_BOOT_SERVICES *BootServices_0; // 0x4F18 (secondary copy)
EFI_RUNTIME_SERVICES *RuntimeServices_0; // 0x4F20 (secondary copy)
UINTN Argc; // 0x4F38 (argument count)
UINT64 Argv; // 0x4F40 (argument vector pointer)
VOID *mHobList; // 0x4F10 (HOB list pointer)
UINT8 DebugFlag; // 0x4EE0 (debug output flag)
WCHAR PrintBuffer[0x100]; // 0x4F60 (output buffer)
// System Inventory Protocol GUIDs
// unk_49F0 = gSystemInventoryProtocolGuid
// unk_4A00 = gSystemInventoryProtocol (protocol instance)
// unk_4A10 = gSystemInventoryProtocol + 0 (HOB GUID data)
// unk_4A18 = gSystemInventoryProtocol + 8
// ============================================================================
// SYSTEM_INVENTORY_PROTOCOL Layout (size = 3402 = 0xD4A bytes)
// ============================================================================
// Offset Size Field
// ------ ---- -----
// 0 85 BiosAndMEVersionInfo (BIOS/ME version info)
// 85 1 BmcDeviceInfoParamaterSelector
// 86 1 CpuCount
// 87 170 CpuInfo[] (85 bytes per CPU, max 2 CPUs)
// 257 1 DimmCount
// 258 2016 DimmInfo[] (84 bytes per DIMM, max 24 DIMMs)
// 2274 1 PciCount
// 2275 76 PciInfo[] (19 bytes per slot, max 4 slots)
// 2351 1 HddCount
// 2352 1050 HddInfo[] (75 bytes per HDD, max 14 HDDs)
// ====== ==== ===========================================
// Total: 3402
// SINGLE_CPU_INFO (85 bytes)
// Offset Size Field
// 0 1 CoreCount
// 1 1 ThreadCount
// 2 13 CpuVendor (string)
// 15 30 CpuFamilyName (string)
// 45 30 CpuModelIdName (string)
// 75 10 Stepping (string)
// 4 MaxFrequency (UINT32, value in MHz)
// DIMM_INFO (84 bytes)
// Offset Size Field
// 0 1 DimmSlotIndex
// 1 1 NodeNumber
// 2 1 ChannelNumber
// 3 10 DimmType (string)
// 13 10 DdrVoltage (string)
// 23 4 DimmFreq (UINT32, value in MHz)
// 27 4 DimmSize (UINT32, value in MB)
// 29 2 (DWORD checksum/active field -- checked for non-zero)
// 31 4 (unused padding?)
// 35 10 ManufacturerIdName (string)
// 45 4 SerialNumber (4 bytes)
// 49 35 PartNumber (string)
// PCI_INFO (19 bytes)
// Offset Size Field
// 0 1 SlotIndex
// 1 1 PciType
// 2 1 BusNumber
// 3 1 DevFun
// 4 2 VendorId
// 6 2 DeviceId
// 8 2 SubSystemVendorId
// 10 2 SubSystemId
// 12 1 InterfaceType
// 13 1 SubClassCode
// 14 1 BaseClassCode
// 15 1 LinkSpeed
// 16 1 LinkWidth
// 17 2 (unused/checksum, checked for non-zero)
// HDD_INFO (75 bytes)
// Offset Size Field
// 0 1 DriveIndex
// 1 68 VendorId (string)
// 69 4 DriveSize (UINT32, in MB)
// 73 1 MediaType
// 74 1 InterfaceType
// 75 1 Formfactor
// 76 1 LinkSpeed
// 77 1 SlotNumber
// 78 1 DeviceState
// 4 (UINT32 checksum at offset 65, checked for non-zero)
// ============================================================================
// Function: _ModuleEntryPoint
// Address: 0x370
// Size: 0x1F5F (8031 bytes)
// Purpose: Main entry point -- parses shell arguments, locates the system
// inventory protocol, and dumps inventory data for the requested
// subsystem (cpu/dimm/pci/hdd).
//
// Behavior modes (based on Argc/Argv):
// argc=1: Print usage instructions
// argc=2: Dump all fields for the specified category (debug/list mode)
// argc=3: Dump a single indexed entry from the specified category
// ============================================================================
EFI_STATUS
EFIAPI
_ModuleEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT64 ArgCount;
UINTN Offset;
UINT8 *InventoryData;
UINTN Index;
UINTN InnerIndex;
// Save global protocol pointers
gImageHandle = ImageHandle;
gST = SystemTable;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
// Initialize HOB list
GetHobListFromSystemTable();
// Initialize cached system table copies
SystemTable_0 = SystemTable;
BootServices_0 = SystemTable->BootServices;
RuntimeServices_0 = SystemTable->RuntimeServices;
// ---- Print header ----
UnicodeSPrintEx(PrintBuffer, L"-----------------------"
L"----------------------------------------\n\r");
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer,
L"| Inventory Check Tool V 0.%d "
L"Editor: Rush Wang (c)2017 Copyright Lenovo |\n\r",
1);
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer, L"-----------------------"
L"----------------------------------------\n\r");
ConOut_OutputString(PrintBuffer);
// ---- Parse shell arguments ----
Status = ProcessCmdLine(
ImageHandle,
&gSystemInventoryProtocol,
&Argv,
ImageHandle,
0,
2);
if (Status < 0) {
// Try alternate protocol
Status = ProcessCmdLine_Alt(
ImageHandle,
&gBmcSystemInventoryProtocol,
&Argv,
ImageHandle,
0,
2);
if (Status < 0) {
goto FAIL_EXIT;
}
ArgCount = *(Argv + 24); // argc-style count
OffsetsTable = *(Argv + 16);
} else {
ArgCount = Argv[1]; // argc
OffsetsTable = *Argv; // argv
}
ArgCount = ArgCount;
// ---- argc == 1: Print usage ----
if (ArgCount == 1) {
UnicodeSPrintEx(PrintBuffer, L"Input 'cpu' or 'dimm' or 'pci' or 'hdd'\n\r");
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer, L"Ex: InventoryApp.efi dimm \n\r");
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer, L"Also can append an index of dedicated data\n\r");
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer, L"Ex: InventoryApp.efi hdd 1 \n\r");
ConOut_OutputString(PrintBuffer);
return EFI_INVALID_PARAMETER;
}
// ---- Locate the System Inventory Protocol ----
Status = gBS->LocateProtocol(
&gSystemInventoryProtocolGuid,
NULL,
&InventoryData);
UnicodeSPrintEx(PrintBuffer,
L"LocateProtocol gSystemInventoryProtocolGuid = %r \n\r",
Status);
ConOut_OutputString(PrintBuffer);
// ---- Determine offset into protocol data ----
if (ArgCount == 1) {
// Show struct layout info only
Offset = 0;
} else if (ArgCount == 2) {
// Check for "debug" keyword -- show full struct layout
if (UnicodeStrCmp(*(OffsetsTable + 8), L"debug") == 0) {
Offset = 0;
} else {
Offset = 0; // determined by category below
}
}
// -- Parse category for argc==2 mode --
if (ArgCount == 2) {
if (UnicodeStrCmp(*(OffsetsTable + 8), L"cpu") == 0)
Offset = 86; // Offset to CpuCount
if (UnicodeStrCmp(*(OffsetsTable + 8), L"dimm") == 0)
Offset = 257; // Offset to DimmCount
if (UnicodeStrCmp(*(OffsetsTable + 8), L"pci") == 0)
Offset = 2274; // Offset to PciCount
if (UnicodeStrCmp(*(OffsetsTable + 8), L"hdd") == 0)
Offset = 2351; // Offset to HddCount
}
// -- Parse category+index for argc==3 mode --
if (ArgCount == 3) {
if (UnicodeStrCmp(*(OffsetsTable + 8), L"cpu") == 0) {
Index = HexStringToUint64(*(OffsetsTable + 16));
Offset = 85 * Index + 87; // CpuInfo[Index]
}
if (UnicodeStrCmp(*(OffsetsTable + 8), L"dimm") == 0) {
Index = HexStringToUint64(*(OffsetsTable + 16));
Offset = 84 * Index + 258; // DimmInfo[Index]
}
if (UnicodeStrCmp(*(OffsetsTable + 8), L"pci") == 0) {
Index = HexStringToUint64(*(OffsetsTable + 16));
Offset = 19 * Index + 2275; // PciInfo[Index]
}
if (UnicodeStrCmp(*(OffsetsTable + 8), L"hdd") == 0) {
Index = HexStringToUint64(*(OffsetsTable + 16));
Offset = 75 * Index + 2352; // HddInfo[Index]
}
}
// ---- Dump hex header + 96 bytes of raw data at Offset ----
InventoryPtr = InventoryData;
UnicodeSPrintEx(PrintBuffer, L"-- Offset = %x --\n\r", (UINTN)Offset);
ConOut_OutputString(PrintBuffer);
for (Index = 0; Index < 0x10; Index++) {
UnicodeSPrintEx(PrintBuffer, L"%02X ", Index);
ConOut_OutputString(PrintBuffer);
}
UnicodeSPrintEx(PrintBuffer, L"\n\r");
ConOut_OutputString(PrintBuffer);
DataPtr = &InventoryData[Offset];
for (Index = 0; Index < 0x60; Index++) {
if (Index && (Index & 0xF) == 0) {
UnicodeSPrintEx(PrintBuffer, L"\n\r");
ConOut_OutputString(PrintBuffer);
}
UnicodeSPrintEx(PrintBuffer, L"%02X ", *DataPtr);
ConOut_OutputString(PrintBuffer);
DataPtr++;
}
UnicodeSPrintEx(PrintBuffer, L"\n\r");
ConOut_OutputString(PrintBuffer);
// ==== CPU INFO DUMP ====
if (ArgCount == 2 && UnicodeStrCmp(*(OffsetsTable + 8), L"cpu") == 0) {
UnicodeSPrintEx(PrintBuffer, L"CpuCount = %x \n\r",
InventoryData[86]);
ConOut_OutputString(PrintBuffer);
for (InnerIndex = 0; InnerIndex < InventoryData[86]; InnerIndex++) {
UINTN InfoOffset = 85 * InnerIndex;
UnicodeSPrintEx(PrintBuffer,
L"CpuInfo[%d].SingleCpuInfo.CoreCount = %x \n\r",
InnerIndex, InventoryData[InfoOffset + 88]);
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer,
L"CpuInfo[%d].SingleCpuInfo.ThreadCount = %x \n\r",
InnerIndex, InventoryData[InfoOffset + 89]);
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer,
L"CpuInfo[%d].SingleCpuInfo.CpuVendor = %a \n\r",
InnerIndex, &InventoryData[InfoOffset + 90]);
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer,
L"CpuInfo[%d].SingleCpuInfo.CpuFamilyName = %a \n\r",
InnerIndex, &InventoryData[InfoOffset + 103]);
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer,
L"CpuInfo[%d].SingleCpuInfo.CpuModelIdName = %a \n\r",
InnerIndex, &InventoryData[InfoOffset + 133]);
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer,
L"CpuInfo[%d].SingleCpuInfo.Stepping = %a \n\r",
InnerIndex, &InventoryData[InfoOffset + 163]);
ConOut_OutputString(PrintBuffer);
UnicodeSPrintEx(PrintBuffer,
L"CpuInfo[%d].SingleCpuInfo.MaxFrequency = %x (%d MHz)\n\r",
InnerIndex);
ConOut_OutputString(PrintBuffer);
}
}
// same for CPU with indexed (argc==3) path...
// (full details in the decompiled C above)
// ==== DIMM INFO DUMP ====
// ==== PCI INFO DUMP ====
// ==== HDD INFO DUMP ====
// ==== "test" mode (argc==3, arg=="test") with hex conversion ====
return Status;
FAIL_EXIT:
// Check debug flag
if (DebugFlag) {
UnicodeSPrintEx(PrintBuffer, L"CheckArg Status Fail \n\r");
ConOut_OutputString(PrintBuffer);
}
return Status;
}
// ============================================================================
// Library function: HexStringToUint64
// Address: 0x2434
// Size: 0x137 (311 bytes)
// Purpose: Convert hex ASCII string to UINT64 value
// ============================================================================
UINT64
EFIAPI
HexStringToUint64(
CHAR16 *String
)
{
// Standard EDK2 implementation
// Skips leading whitespace and '0x' prefix
// Checks alignment, validates range, converts hex digits
}
// ============================================================================
// Library function: UnicodeStrLen
// Address: 0x256C
// Size: 0x56 (86 bytes)
// Purpose: Return length of a NULL-terminated Unicode string
// ============================================================================
UINTN
EFIAPI
UnicodeStrLen(
CONST CHAR16 *String
)
{
UINTN Length;
if (String == NULL)
return 0;
Length = 0;
if (*String) {
while (Length < 0xF4240) { // PcdMaximumUnicodeStringLength
if (!String[++Length])
return Length;
}
return 1000001; // overflow sentinel
}
return 0;
}
// ============================================================================
// Library function: UnicodeStrSize
// Address: 0x22D0
// Size: 0x93 (147 bytes)
// Purpose: Return size in bytes (including NULL terminator) of a Unicode string
// ============================================================================
UINTN
EFIAPI
UnicodeStrSize(
CONST CHAR16 *String
)
{
// Null check, alignment check, length cap at 0xF4240
}
// ============================================================================
// Library function: UnicodeStrCmp
// Address: 0x2364
// Size: 0x9E (158 bytes)
// Purpose: Compare two NULL-terminated Unicode strings
// Returns: 0 if equal, difference at first non-matching char otherwise
// ============================================================================
INTN
EFIAPI
UnicodeStrCmp(
CONST CHAR16 *FirstString,
CONST CHAR16 *SecondString
)
{
// Uses UnicodeStrSize for validation, then character-by-character comparison
}
// ============================================================================
// Library function: UnicodeSPrintEx
// Address: 0x29E0
// Size: 0x478 (1144 bytes)
// Purpose: Formatted print to Unicode buffer (similar to snwprintf)
// Supports: %s, %S, %a, %c, %d, %i, %x, %X, %p, %r, %g (GUID), %02X
// ============================================================================
UINTN
EFIAPI
UnicodeSPrintEx(
CHAR16 *Buffer,
CONST CHAR16 *Format,
...
)
{
// Complex format string parser supporting:
// - %s / %S : ASCII/Unicode strings
// - %d / %i : decimal integers
// - %x / %X / %p : hex integers (uppercase)
// - %r : EFI_STATUS code -> string name resolution
// - %g : GUID formatting (%08x-%04x-%04x-%02x...)
// - %a : ASCII string output
// - Width/padding specifiers
}
// ============================================================================
// Library function: StatusCodeToString
// Address: 0x28F0
// Size: 0xC7 (199 bytes)
// Purpose: Map EFI_STATUS code to human-readable string
// ============================================================================
CONST CHAR8*
EFIAPI
StatusCodeToString(
EFI_STATUS Status
)
{
// Returns string names for:
// - EFI_SUCCESS (0)
// - EFI_WARN_* (high bit patterns)
// - EFI_ERROR bits mapped to:
// EFI_INTERRUPT_PENDING, EFI_INTERRUPT_*, etc.
// - Standard EFI error codes
// - Fallback "Status Code(%X)"
}
// ============================================================================
// Library function: GetHobListFromSystemTable
// Address: 0x26CC
// Size: 0xD6 (214 bytes)
// Purpose: Initialize HOB (Hand-Off Block) list pointer from SystemTable
// ============================================================================
VOID*
EFIAPI
GetHobListFromSystemTable(
VOID
)
{
// Reads HOB list from gST->HobList.Raw
// Falls back to searching SystemTable configuration table
// ASSERT on failure
}
// ============================================================================
// Library function: InventoryDebugAssert
// Address: 0x268C
// Size: 0x3E (62 bytes)
// Purpose: EDK II DEBUGBREAK assertion handler
// ============================================================================
VOID
EFIAPI
InventoryDebugAssert(
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
// Calls through to EFI_DEBUGGER_PROTOCOL assertion handler
}
// ============================================================================
// Helper function: LocateDebugSupportProtocol
// Address: 0x25C4
// Size: 0x7F (127 bytes)
// Purpose: Locate and return EFI_DEBUG_SUPPORT_PROTOCOL (or equivalent)
// ============================================================================
// Uses gBS->AllocatePool, gBS->LocateProtocol to find the debug protocol
// Cached in qword_4F08
// ============================================================================
// Helper function: InventoryDebugPrintIfEnabled
// Address: 0x2644
// Size: 0x47 (71 bytes)
// Purpose: Conditionally print debug message via debug protocol
// ============================================================================
VOID
EFIAPI
InventoryDebugPrintIfEnabled(
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
// Checks error level against platform configuration (CMOS-based)
GET_DEBUG_PROTOCOL();
if (GetPlatformErrorLevel() & ErrorLevel) {
DEBUG_PROTOCOL->DebugPrint(ErrorLevel, Format, ...);
}
}
// ============================================================================
// Library function: AsciiHexCharToUint
// Address: 0x2404
// Size: 0x2E (46 bytes)
// Purpose: Convert a single hex character (0-9, a-f, A-F) to its value
// ============================================================================
UINTN
EFIAPI
AsciiHexCharToUint(
CHAR16 Char
)
{
if (Char >= L'0' && Char <= L'9')
return Char - L'0';
if (Char >= L'a' && Char <= L'f')
Char -= 0x20; // uppercase
return Char - 55; // 'A' - 10
}
// ============================================================================
// Library function: Uint64ToString
// Address: 0x27A4
// Size: 0x71 (113 bytes)
// Purpose: Convert UINT64 to ASCII string representation (base 10 or 16)
// ============================================================================
// ============================================================================
// Library function: AsciiStrHexToUintn
// Address: 0x2818
// Size: 0xD7 (215 bytes)
// Purpose: Parse ASCII hex string to UINTN value
// ============================================================================
// ============================================================================
// Library function: UnicodeValueToString
// Address: 0x29B8
// Size: 0x26 (38 bytes)
// Purpose: Print Unicode string using formatting
// ============================================================================
// ============================================================================
// Library function: UnicodeSPrintBounded
// Address: 0x2E58
// Size: 0x1D (29 bytes)
// Purpose: Safe Unicode formatted print (bounded)
// ============================================================================
// ============================================================================
// Platform function: GetPlatformErrorLevel
// Address: 0x2E78
// Size: 0x4E (78 bytes)
// Purpose: Read platform error/debug level from CMOS (register 0x4B)
// ============================================================================
// Uses CMOS port 0x70/0x71 to read debug level from CMOS index 0x4B.
// Also reads hardware register 0xFDAF0490 on certain CMOS values.
// ============================================================================
// Library function: ReadUnaligned64
// Address: 0x2F38
// Size: 0x2F (47 bytes)
// Purpose: Read 64-bit value from potentially unaligned address
// ============================================================================
// ============================================================================
// Library function: HobGuidMatches
// Address: 0x2EC8
// Size: 0x6E (110 bytes)
// Purpose: Compare GUID from HOB entry with a target GUID
// ============================================================================