Newer
Older
AMI-Aptio-BIOS-Reversed / InventoryApp / InventoryApp.c
@Ajax Dong Ajax Dong 2 days ago 20 KB Init
// 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
    GetHobList();

    // Initialize cached system table copies
    SystemTable_0      = SystemTable;
    BootServices_0     = SystemTable->BootServices;
    RuntimeServices_0  = SystemTable->RuntimeServices;

    // ---- Print header ----
    SPrintf(PrintBuffer, L"-----------------------"
                        L"----------------------------------------\n\r");
    ConOut_OutputString(PrintBuffer);

    SPrintf(PrintBuffer,
        L"| Inventory Check Tool    V 0.%d    "
        L"Editor: Rush Wang (c)2017 Copyright Lenovo |\n\r",
        1);
    ConOut_OutputString(PrintBuffer);

    SPrintf(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) {
        SPrintf(PrintBuffer, L"Input 'cpu' or 'dimm' or 'pci' or 'hdd'\n\r");
        ConOut_OutputString(PrintBuffer);

        SPrintf(PrintBuffer, L"Ex: InventoryApp.efi dimm \n\r");
        ConOut_OutputString(PrintBuffer);

        SPrintf(PrintBuffer, L"Also can append an index of dedicated data\n\r");
        ConOut_OutputString(PrintBuffer);

        SPrintf(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);

    SPrintf(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 (StrCmp(*(OffsetsTable + 8), L"debug") == 0) {
            Offset = 0;
        } else {
            Offset = 0;  // determined by category below
        }
    }

    // -- Parse category for argc==2 mode --
    if (ArgCount == 2) {
        if (StrCmp(*(OffsetsTable + 8), L"cpu") == 0)
            Offset = 86;    // Offset to CpuCount
        if (StrCmp(*(OffsetsTable + 8), L"dimm") == 0)
            Offset = 257;   // Offset to DimmCount
        if (StrCmp(*(OffsetsTable + 8), L"pci") == 0)
            Offset = 2274;  // Offset to PciCount
        if (StrCmp(*(OffsetsTable + 8), L"hdd") == 0)
            Offset = 2351;  // Offset to HddCount
    }

    // -- Parse category+index for argc==3 mode --
    if (ArgCount == 3) {
        if (StrCmp(*(OffsetsTable + 8), L"cpu") == 0) {
            Index  = StrHexToUint64(*(OffsetsTable + 16));
            Offset = 85 * Index + 87;  // CpuInfo[Index]
        }
        if (StrCmp(*(OffsetsTable + 8), L"dimm") == 0) {
            Index  = StrHexToUint64(*(OffsetsTable + 16));
            Offset = 84 * Index + 258;  // DimmInfo[Index]
        }
        if (StrCmp(*(OffsetsTable + 8), L"pci") == 0) {
            Index  = StrHexToUint64(*(OffsetsTable + 16));
            Offset = 19 * Index + 2275;  // PciInfo[Index]
        }
        if (StrCmp(*(OffsetsTable + 8), L"hdd") == 0) {
            Index  = StrHexToUint64(*(OffsetsTable + 16));
            Offset = 75 * Index + 2352;  // HddInfo[Index]
        }
    }

    // ---- Dump hex header + 96 bytes of raw data at Offset ----
    InventoryPtr = InventoryData;
    SPrintf(PrintBuffer, L"-- Offset = %x --\n\r", (UINTN)Offset);
    ConOut_OutputString(PrintBuffer);

    for (Index = 0; Index < 0x10; Index++) {
        SPrintf(PrintBuffer, L"%02X ", Index);
        ConOut_OutputString(PrintBuffer);
    }
    SPrintf(PrintBuffer, L"\n\r");
    ConOut_OutputString(PrintBuffer);

    DataPtr = &InventoryData[Offset];
    for (Index = 0; Index < 0x60; Index++) {
        if (Index && (Index & 0xF) == 0) {
            SPrintf(PrintBuffer, L"\n\r");
            ConOut_OutputString(PrintBuffer);
        }
        SPrintf(PrintBuffer, L"%02X ", *DataPtr);
        ConOut_OutputString(PrintBuffer);
        DataPtr++;
    }
    SPrintf(PrintBuffer, L"\n\r");
    ConOut_OutputString(PrintBuffer);

    // ==== CPU INFO DUMP ====
    if (ArgCount == 2 && StrCmp(*(OffsetsTable + 8), L"cpu") == 0) {
        SPrintf(PrintBuffer, L"CpuCount = %x \n\r",
                InventoryData[86]);
        ConOut_OutputString(PrintBuffer);

        for (InnerIndex = 0; InnerIndex < InventoryData[86]; InnerIndex++) {
            UINTN InfoOffset = 85 * InnerIndex;
            SPrintf(PrintBuffer,
                L"CpuInfo[%d].SingleCpuInfo.CoreCount = %x \n\r",
                InnerIndex, InventoryData[InfoOffset + 88]);
            ConOut_OutputString(PrintBuffer);

            SPrintf(PrintBuffer,
                L"CpuInfo[%d].SingleCpuInfo.ThreadCount = %x \n\r",
                InnerIndex, InventoryData[InfoOffset + 89]);
            ConOut_OutputString(PrintBuffer);

            SPrintf(PrintBuffer,
                L"CpuInfo[%d].SingleCpuInfo.CpuVendor = %a \n\r",
                InnerIndex, &InventoryData[InfoOffset + 90]);
            ConOut_OutputString(PrintBuffer);

            SPrintf(PrintBuffer,
                L"CpuInfo[%d].SingleCpuInfo.CpuFamilyName = %a \n\r",
                InnerIndex, &InventoryData[InfoOffset + 103]);
            ConOut_OutputString(PrintBuffer);

            SPrintf(PrintBuffer,
                L"CpuInfo[%d].SingleCpuInfo.CpuModelIdName = %a \n\r",
                InnerIndex, &InventoryData[InfoOffset + 133]);
            ConOut_OutputString(PrintBuffer);

            SPrintf(PrintBuffer,
                L"CpuInfo[%d].SingleCpuInfo.Stepping = %a \n\r",
                InnerIndex, &InventoryData[InfoOffset + 163]);
            ConOut_OutputString(PrintBuffer);

            SPrintf(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) {
        SPrintf(PrintBuffer, L"CheckArg Status Fail \n\r");
        ConOut_OutputString(PrintBuffer);
    }
    return Status;
}

// ============================================================================
// Library function: AsciiStrHexToUint64 (sub_2434)
// Address: 0x2434
// Size: 0x137 (311 bytes)
// Purpose: Convert hex ASCII string to UINT64 value
// ============================================================================
UINT64
EFIAPI
AsciiStrHexToUint64(
    CHAR16 *String
    )
{
    // Standard EDK2 implementation
    // Skips leading whitespace and '0x' prefix
    // Checks alignment, validates range, converts hex digits
}

// ============================================================================
// Library function: StrLen (sub_256C)
// Address: 0x256C
// Size: 0x56 (86 bytes)
// Purpose: Return length of a NULL-terminated Unicode string
// ============================================================================
UINTN
EFIAPI
StrLen(
    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: StrSize (sub_22D0)
// Address: 0x22D0
// Size: 0x93 (147 bytes)
// Purpose: Return size in bytes (including NULL terminator) of a Unicode string
// ============================================================================
UINTN
EFIAPI
StrSize(
    CONST CHAR16 *String
    )
{
    // Null check, alignment check, length cap at 0xF4240
}

// ============================================================================
// Library function: StrCmp (sub_2364)
// 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
StrCmp(
    CONST CHAR16 *FirstString,
    CONST CHAR16 *SecondString
    )
{
    // Uses StrSize for validation, then character-by-character comparison
}

// ============================================================================
// Library function: SPrintf / UnicodeBSPrint (sub_29E0)
// 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
SPrintf(
    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 (sub_28F0)
// 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: GetHobList (sub_26CC)
// Address: 0x26CC
// Size: 0xD6 (214 bytes)
// Purpose: Initialize HOB (Hand-Off Block) list pointer from SystemTable
// ============================================================================
VOID*
EFIAPI
GetHobList(
    VOID
    )
{
    // Reads HOB list from gST->HobList.Raw
    // Falls back to searching SystemTable configuration table
    // ASSERT on failure
}

// ============================================================================
// Library function: DebugAssert (sub_268C)
// Address: 0x268C
// Size: 0x3E (62 bytes)
// Purpose: EDK II DEBUGBREAK assertion handler
// ============================================================================
VOID
EFIAPI
DebugAssert(
    IN CONST CHAR8  *FileName,
    IN UINTN         LineNumber,
    IN CONST CHAR8  *Description
    )
{
    // Calls through to EFI_DEBUGGER_PROTOCOL assertion handler
}

// ============================================================================
// Helper function: GetDebugProtocol (sub_25C4)
// 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: DebugPrint (sub_2644)
// Address: 0x2644
// Size: 0x47 (71 bytes)
// Purpose: Conditionally print debug message via debug protocol
// ============================================================================
VOID
EFIAPI
DebugPrint(
    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: HexCharToUint (sub_2404)
// Address: 0x2404
// Size: 0x2E (46 bytes)
// Purpose: Convert a single hex character (0-9, a-f, A-F) to its value
// ============================================================================
UINTN
EFIAPI
HexCharToUint(
    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 (sub_27A4)
// Address: 0x27A4
// Size: 0x71 (113 bytes)
// Purpose: Convert UINT64 to ASCII string representation (base 10 or 16)
// ============================================================================

// ============================================================================
// Library function: AsciiStrHexToUintn (sub_2818)
// Address: 0x2818
// Size: 0xD7 (215 bytes)
// Purpose: Parse ASCII hex string to UINTN value
// ============================================================================

// ============================================================================
// Library function: UnicodeValueToString (sub_29B8)
// Address: 0x29B8
// Size: 0x26 (38 bytes)
// Purpose: Print Unicode string using formatting
// ============================================================================

// ============================================================================
// Library function: UnicodeSPrint (sub_2E58)
// Address: 0x2E58
// Size: 0x1D (29 bytes)
// Purpose: Safe Unicode formatted print (bounded)
// ============================================================================

// ============================================================================
// Platform function: GetPlatformErrorLevel (sub_2E78)
// 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 (sub_2F38)
// Address: 0x2F38
// Size: 0x2F (47 bytes)
// Purpose: Read 64-bit value from potentially unaligned address
// ============================================================================

// ============================================================================
// Library function: HobGuidMatch (sub_2EC8)
// Address: 0x2EC8
// Size: 0x6E (110 bytes)
// Purpose: Compare GUID from HOB entry with a target GUID
// ============================================================================