Newer
Older
AMI-Aptio-BIOS-Reversed / LenovoServerPkg / SmbiosType39 / SmbiosType39.c
@Ajax Dong Ajax Dong 2 days ago 30 KB Full restructure
/** @file
  SmbiosType39.efi

  UEFI DXE driver that installs SMBIOS Type 39 (Power Supply) records.

  This driver communicates with the Management Engine (ME) via the HECI
  protocol to retrieve power supply information for up to two power supply
  bays. For each detected bay, it queries the ME for the device name,
  manufacturer, serial number, asset tag, model part number, revision level,
  max power capacity, and presence/status. The collected data is assembled
  into SMBIOS Type 39 (Power Supply) structures and installed via the
  SMBIOS protocol.

  Copyright (c) Lenovo Corporation.
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "SmbiosType39.h"

//
// Global data
//
EFI_HANDLE                gImageHandle  = NULL;
EFI_SYSTEM_TABLE          *gST          = NULL;
EFI_BOOT_SERVICES         *gBS          = NULL;
EFI_RUNTIME_SERVICES      *gRT          = NULL;
EFI_SMBIOS_PROTOCOL       *gSmbios      = NULL;
EFI_HECI_PROTOCOL         *gHeci        = NULL;
VOID                       *gPcd        = NULL;
VOID                       *gMmPciBase  = NULL;
EFI_EVENT                  gRegistrationEvent = NULL;

//
// GUID definitions (referenced from global data section)
//
extern EFI_GUID  gEfiSmbiosProtocolGuid;
extern EFI_GUID  gEfiHeciProtocolGuid;
extern EFI_GUID  gEfiDxeServicesTableGuid;
extern EFI_GUID  gEfiPcdProtocolGuid;
extern EFI_GUID  gEfiMmPciBaseGuid;

//
// HECI command message for power supply queries
//
#pragma pack(1)
typedef struct {
  UINT16  GroupId;         // 0x8A0A = HECI_GROUP_ID << 8 | 0x0A
  UINT8   Command;         // HECI command byte
  UINT8   Reserved;
  UINT32  Param;           // Parameter data (varies per command)
} HECI_POWER_SUPPLY_REQUEST;

typedef struct {
  UINT16  GroupId;
  UINT8   Command;
  UINT8   Reserved;
  UINT32  Param1;
  UINT16  Param2;
} HECI_POWER_SUPPLY_REQUEST_EXT;
#pragma pack()

//
// HECI command template: GroupId = 0x8A0A
//
#define HECI_POWER_SUPPLY_GROUP_ID    0x8A0A
#define HECI_CMD_DEVICE_NAME          0x9A
#define HECI_CMD_MANUFACTURER         0x99
#define HECI_CMD_SERIAL_NUMBER        0x62  // (0x9E -> -98 signed)
#define HECI_CMD_ASSET_TAG            0x61  // (0xF1 -> -15 signed, but command field is 0x61)

#define HECI_CMD_MODEL_PART_NUMBER    0x9B  // (-101 signed)
#define HECI_CMD_REVISION_LEVEL       0xA7  // (-89 signed)
#define HECI_CMD_MAX_POWER_CAPACITY   0x78  // (120)
#define HECI_CMD_POWER_SUPPLY_STATUS  0x78  // (120, same as max capacity but different param)

//
// ME FWS (Firmware Status) register bits
//
#define ME_FWS_CURRENT_STATE_MASK     0x0F

/**
  ZeroMem implementation - fills a buffer with zeros.

  @param[out] Buffer  Pointer to the buffer to zero.
  @param[in]  Length  Number of bytes to zero.

  @return Buffer.
**/
VOID *
EFIAPI
InternalZeroMem (
  OUT VOID   *Buffer,
  IN  UINTN  Length
  )
{
  //
  // Zero out 8 bytes at a time, then remaining bytes
  //
  ZeroMem (Buffer, Length);
  return Buffer;
}

/**
  Reads a 64-bit value from memory (unaligned-safe).

  @param[in] Buffer  Pointer to the memory location.

  @return The 64-bit value read.
**/
UINT64
EFIAPI
InternalReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  ASSERT (Buffer != NULL);
  return *(UINT64 *)Buffer;
}

/**
  Returns the length of a null-terminated ASCII string.

  @param[in] String  A pointer to the null-terminated ASCII string.

  @return The number of ASCII characters in String excluding the null terminator.
**/
UINTN
EFIAPI
AsciiStrLen (
  IN CONST CHAR8  *String
  )
{
  UINTN  Length;

  ASSERT (String != NULL);

  Length = 0;
  while (*String != '\0') {
    if (Length >= 0xF4240) {
      ASSERT (FALSE);  // PcdMaximumAsciiStringLength exceeded
    }
    String++;
    Length++;
  }

  return Length;
}

/**
  Returns the length of a null-terminated Unicode string.

  @param[in] String  A pointer to the null-terminated Unicode string.

  @return The number of Unicode characters in String excluding the null terminator.
**/
UINTN
EFIAPI
StrLen (
  IN CONST CHAR16  *String
  )
{
  UINTN  Length;

  ASSERT (String != NULL);
  ASSERT (((UINTN)String & 0x00000001) == 0);

  Length = 0;
  while (*String != L'\0') {
    if (Length >= 0xF4240) {
      ASSERT (FALSE);  // PcdMaximumUnicodeStringLength exceeded
    }
    String++;
    Length++;
  }

  return Length;
}

/**
  Converts a null-terminated ASCII string to a null-terminated Unicode string.

  @param[in]  Source      A pointer to the ASCII string.
  @param[out] Destination A pointer to the destination Unicode buffer.

  @return Destination.
**/
CHAR16 *
EFIAPI
AsciiStrToUnicodeStr (
  IN CONST CHAR8   *Source,
  OUT CHAR16       *Destination
  )
{
  CHAR16  *Dest;

  ASSERT (Destination != NULL);
  ASSERT (AsciiStrSize (Source) != 0);
  //
  // Ensure buffers do not overlap in a way that would cause corruption
  //
  ASSERT ((UINTN)((CHAR8 *)Destination - Source) > AsciiStrLen (Source));
  ASSERT ((UINTN)(Source - (CHAR8 *)Destination) >= (AsciiStrSize (Source) * sizeof (CHAR16)));

  Dest = Destination;
  while (*Source != '\0') {
    *(Dest++) = (CHAR16)(UINT8)*(Source++);
  }
  *Dest = L'\0';

  ASSERT (StrSize (Destination) != 0);

  return Destination;
}

/**
  Copies one ASCII string to another (with overlap safety checks).

  @param[out] Destination  A pointer to the destination buffer.
  @param[in]  Source       A pointer to the source string.

  @return Destination.
**/
CHAR8 *
EFIAPI
AsciiStrCpyS (
  OUT CHAR8        *Destination,
  IN CONST CHAR8   *Source
  )
{
  CHAR8  *Dest;

  ASSERT (Destination != NULL);
  ASSERT ((UINTN)(Destination - Source) > AsciiStrLen (Source));
  ASSERT ((UINTN)(Source - Destination) > AsciiStrLen (Source));

  Dest = Destination;
  while (*Source != '\0') {
    *(Dest++) = *(Source++);
  }
  *Dest = '\0';

  return Destination;
}

/**
  Copies an ASCII string from a source buffer to destination, stopping after
  a specified number of characters and appending a null terminator.

  @param[out] Destination  Pointer to the destination buffer.
  @param[in]  Source       Pointer to the source buffer.
  @param[in]  Length       Maximum number of characters to copy.

  @return Destination.
**/
CHAR8 *
EFIAPI
InternalStrnCpyAscii (
  OUT CHAR8   *Destination,
  IN  CHAR8   *Source,
  IN  UINTN   Length
  )
{
  UINTN  Index;

  Index = 0;
  if (Length > 0) {
    do {
      Destination[Index] = Source[Index];
      Index++;
    } while (Index < Length);
  }
  Destination[Index] = '\0';

  return Destination;
}

/**
  Locates a configuration table by GUID in the UEFI System Table.

  @param[in]  TableGuid  GUID of the table to locate.
  @param[out] Table      On successful return, points to the table.

  @retval EFI_SUCCESS        The table was found.
  @retval EFI_NOT_FOUND      The table was not found.
**/
EFI_STATUS
EFIAPI
EfiGetSystemConfigurationTable (
  IN  EFI_GUID  *TableGuid,
  OUT VOID      **Table
  )
{
  UINTN  Index;
  UINTN  NumberOfTableEntries;

  ASSERT (TableGuid != NULL);
  ASSERT (Table != NULL);

  *Table = NULL;

  NumberOfTableEntries = gST->NumberOfTableEntries;
  if (NumberOfTableEntries == 0) {
    return EFI_NOT_FOUND;
  }

  for (Index = 0; Index < NumberOfTableEntries; Index++) {
    if (CompareGuid (TableGuid, &gST->ConfigurationTable[Index].VendorGuid)) {
      *Table = (VOID *)gST->ConfigurationTable[Index].VendorTable;
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

/**
  Sends a HECI power supply command and retrieves the response.

  This function constructs a HECI command message with the appropriate
  group ID and command byte, sends it via the HECI protocol, and returns
  the response length and data.

  @param[in]  HeciProtocol  Pointer to the HECI protocol instance.
  @param[in]  Command       HECI command byte.
  @param[in]  SupplyBay     Power supply bay index (0 or 1).
  @param[out] DataBuffer    Buffer to receive response data.
  @param[in]  BufferSize    Size of the data buffer.
  @param[out] DataLength    On output, length of data returned by ME.

  @retval EFI_SUCCESS       Command succeeded and data was returned.
  @retval Others            HECI communication failed.
**/
EFI_STATUS
SendHeciPowerSupplyCommand (
  IN  EFI_HECI_PROTOCOL  *HeciProtocol,
  IN  UINT8              Command,
  IN  UINT8              SupplyBay,
  OUT VOID               *DataBuffer,
  IN  UINTN              BufferSize,
  OUT UINTN              *DataLength
  )
{
  HECI_POWER_SUPPLY_REQUEST  Request;
  UINT8                      Response[64];
  UINTN                      ResponseLength;
  UINT8                      *DataPtr;
  UINTN                      CopyLength;

  //
  // Build the HECI request header
  //
  Request.GroupId  = HECI_POWER_SUPPLY_GROUP_ID;   // 0x8A0A
  Request.Command  = Command;
  Request.Reserved = 0;
  Request.Param    = SupplyBay;  // supply bay index in low byte

  DEBUG ((
    DEBUG_INFO,
    "pHeciProtocol->SendwACK (%x)\n",
    Command
    ));

  //
  // Send the command via HECI with the default buffer size
  //
  ResponseLength = sizeof (Response);
  Status         = HeciProtocol->SendwACK (
                                  0,
                                  &Request,
                                  sizeof (Request),
                                  &ResponseLength,
                                  0,
                                  32
                                  );

  DEBUG ((
    DEBUG_INFO,
    "pHeciProtocol->SendwACK Status: %r, HeciMsg[1]=%x, HeciMsg[2]=%x\n",
    Status,
    Request.Command,
    SupplyBay
    ));

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Check response: if HeciMsg[1] is non-zero but not 0xA3, no data available
  //
  if (Response[1] != 0) {
    if (Response[1] != 0xA3) {
      return EFI_DEVICE_ERROR;
    }
  }

  //
  // Response[2] contains the data length (SupplyBay response)
  //
  *DataLength = Response[2];
  if (*DataLength == 0) {
    return EFI_NOT_FOUND;
  }

  //
  // Copy the returned data to the caller's buffer
  //
  DataPtr  = &Response[3];
  CopyLength = MIN (*DataLength, BufferSize);
  CopyMem (DataBuffer, DataPtr, CopyLength);

  return EFI_SUCCESS;
}

/**
  Retrieves the HOB list pointer from the UEFI System Table.

  The HOB list is needed for DXE services initialization. This function
  looks up the gEfiDxeServicesTableGuid in the system configuration table
  and caches the pointer.

**/
VOID
GetHobList (
  VOID
  )
{
  EFI_STATUS  Status;

  if (gMmPciBase == NULL) {
    Status = EfiGetSystemConfigurationTable (
               &gEfiDxeServicesTableGuid,
               &gMmPciBase
               );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "\nASSERT_EFI_ERROR (Status = %r)\n",
        Status
        ));
      ASSERT_EFI_ERROR (FALSE);
    }
    if (gMmPciBase == NULL) {
      ASSERT (gMmPciBase != NULL);
    }
  }
}

/**
  Retrieves the SMBIOS protocol from the UEFI protocol database.

  @return Pointer to the EFI_SMBIOS_PROTOCOL instance, or NULL if not found.
**/
EFI_SMBIOS_PROTOCOL *
GetSmbiosProtocol (
  VOID
  )
{
  EFI_STATUS  Status;

  if (gSmbios == NULL) {
    Status = gBS->LocateProtocol (
                    &gEfiSmbiosProtocolGuid,
                    NULL,
                    (VOID **)&gSmbios
                    );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "\nASSERT_EFI_ERROR (Status = %r)\n",
        Status
        ));
      ASSERT_EFI_ERROR (FALSE);
    }
  }

  return gSmbios;
}

/**
  Retrieves the HECI protocol from the UEFI protocol database.

  @return Pointer to the EFI_HECI_PROTOCOL instance, or NULL if not found.
**/
EFI_HECI_PROTOCOL *
GetHeciProtocol (
  VOID
  )
{
  EFI_STATUS  Status;

  if (gHeci == NULL) {
    Status = gBS->LocateProtocol (
                    &gEfiHeciProtocolGuid,
                    NULL,
                    (VOID **)&gHeci
                    );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "\nASSERT_EFI_ERROR (Status = %r)\n",
        Status
        ));
      ASSERT_EFI_ERROR (FALSE);
    }
  }

  return gHeci;
}

/**
  Retrieves the PCD protocol from the UEFI protocol database.

  @return Pointer to the PCD protocol, or NULL if not found.
**/
VOID *
GetPcdProtocol (
  VOID
  )
{
  EFI_STATUS  Status;
  UINTN       Pages;
  VOID        *Pcd;

  if (gPcd != NULL) {
    return gPcd;
  }

  //
  // Allocate 31 pages for PCD protocol usage
  //
  Pages = EFI_SIZE_TO_PAGES (31);
  gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, Pages, &Pages);
  if (Pages > 0x10) {
    //
    // Not enough pages - return NULL
    //
    return NULL;
  }

  //
  // Locate the PCD protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiPcdProtocolGuid,
                  NULL,
                  (VOID **)&gPcd
                  );
  if (EFI_ERROR (Status)) {
    gPcd = NULL;
  }

  return gPcd;
}

/**
  Returns a string description for a given power supply bay index.

  @param[in] SupplyBay  0 for Left/Inner Supply Bay, 1 for Right/Outer Supply Bay.

  @return Pointer to a static string describing the supply bay.
**/
CONST CHAR8 *
GetSupplyBayString (
  IN UINT8  SupplyBay
  )
{
  if (SupplyBay == 0) {
    return "Left/Inner Supply Bay";
  } else if (SupplyBay == 1) {
    return "Right/Outer Supply Bay";
  } else {
    return "INVALID";
  }
}

/**
  Frees a buffer allocated via gBS->AllocatePool.

  @param[in] Buffer  Pointer to the buffer to free.
**/
VOID
FreePoolOrBuffer (
  IN VOID  *Buffer
  )
{
  EFI_STATUS  Status;

  Status = gBS->FreePool (Buffer);
  if (EFI_ERROR (Status)) {
    DEBUG ((
      DEBUG_ERROR,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      Status
      ));
    ASSERT_EFI_ERROR (FALSE);
  }
}

/**
  Debug print routing function.

  This is a wrapper around the UEFI debug print functionality that checks
  the current debug level by reading CMOS/NVRAM and routes the output to
  the appropriate debug stream.

  @param[in] ErrorLevel  Debug error level.
  @param[in] Format      Format string.
  @param[in] ...         Variable arguments for the format string.
**/
VOID
EFIAPI
DebugPrint (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Format,
  ...
  )
{
  VOID    *DebugInfo;
  UINT8   CmosByte;
  UINT8   DebugLevel;
  UINT8   Port92Value;
  UINTN   Mask;

  DebugInfo = GetPcdProtocol ();
  if (DebugInfo == NULL) {
    return;
  }

  //
  // Read CMOS to determine current debug level
  //
  CmosByte     = IoRead8 (0x70);
  IoWrite8 (0x70, CmosByte & 0x80 | 0x4B);
  DebugLevel   = IoRead8 (0x71);

  //
  // Determine the error mask based on the debug level
  //
  if (DebugLevel > 3) {
    if (DebugLevel == 0) {
      Port92Value = *(volatile UINT8 *)0xFDAF0490;
      DebugLevel  = (Port92Value & 2) | 1;
    }
  }

  switch (DebugLevel) {
  case 1:
    Mask = DEBUG_ERROR;
    break;
  default:
    Mask = DEBUG_INIT | DEBUG_WARN | DEBUG_INFO;
    break;
  }

  if ((Mask & ErrorLevel) != 0) {
    DEBUG ((ErrorLevel, Format, ...));
  }
}

/**
  Installs SMBIOS Type 39 (Power Supply) structures.

  This function is the main callback that enumerates up to two power supply
  bays. For each bay, it communicates via HECI with the ME to retrieve:

    - Device Name
    - Manufacturer
    - Serial Number
    - Asset Tag
    - Model Part Number
    - Revision Level
    - Max Power Capacity
    - Power Supply Present/Status

  The collected data is assembled into an SMBIOS Type 39 record and added
  to the SMBIOS table.

  @param[in] Event    The event that triggered this callback.
  @param[in] Context  The driver image handle.

  @retval EFI_SUCCESS  The SMBIOS Type 39 structures were installed.
  @retval Others       An error occurred.
**/
EFI_STATUS
EFIAPI
InstallSmbiosType39Structure (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS           Status;
  UINTN                HeciStatus;
  UINTN                MeFwStatus;
  UINT8                CurrentMeState;
  EFI_HECI_PROTOCOL    *HeciProtocol;
  UINT8                SupplyBay;
  UINT8                NvRamVariable;
  UINT8                SupplyBayIncrement;
  UINTN                DataLen;
  CHAR8                DeviceName[64];
  CHAR8                Manufacturer[64];
  CHAR8                SerialNumber[64];
  CHAR8                AssetTag[64];
  CHAR8                ModelPartNumber[64];
  CHAR8                RevisionLevel[64];
  UINT16               MaxPowerCapacity;
  UINT16               PowerSupplyPresent;
  UINT16               PowerSupplyStatus;
  UINT16               PowerSupplyFlags;
  SMBIOS_TABLE_TYPE39  *SmbiosRecord;
  UINTN                StringBufferSize;
  CHAR8                *StringBuffer;
  CHAR8                *CurrentStringPtr;
  UINTN                TotalStringLength;
  CHAR16               UnicodeBuffer[256];
  UINTN                Index;
  UINTN                V2;

  //
  // Initialize the INVALID string length for fallback
  //
  V2 = AsciiStrLen ("INVALID");

  DEBUG ((DEBUG_INFO, "InstallSmbiosType39Structure entered\n"));

  //
  // Locate the SMBIOS protocol
  //
  SmbiosRecord = (SMBIOS_TABLE_TYPE39 *)(UINTN)GetSmbiosProtocol ();
  if (SmbiosRecord == NULL) {
    return EFI_UNSUPPORTED;
  }

  //
  // Close the notification event
  //
  Status = gBS->CloseEvent (Event);
  DEBUG ((DEBUG_INFO, "CloseEvent Status: %r\n", Status));

  //
  // Locate the HECI protocol
  //
  HeciProtocol = GetHeciProtocol ();
  if (HeciProtocol == NULL) {
    return EFI_UNSUPPORTED;
  }

  //
  // Check ME firmware status to determine if ME is in normal mode
  //
  NvRamVariable = 512;
  HeciStatus    = gMmPciBase->Read ((UINTN)&NvRamVariable, sizeof (NvRamVariable));
  if (HeciStatus != EFI_SUCCESS) {
    return HeciStatus;
  }

  CurrentMeState = MmPciRead8 (0) & ME_FWS_CURRENT_STATE_MASK;
  if (CurrentMeState != 5) {
    //
    // ME is not in S0/M0 normal operation state
    //
    DEBUG ((DEBUG_INFO, "MeFs1.Bits.CurrentState == %d\n", CurrentMeState));
    return EFI_DEVICE_ERROR;
  }

  //
  // Enumerate power supply bays (0 and 1)
  //
  SupplyBay         = 0;
  SupplyBayIncrement = 0;
  NvRamVariable     = 0;

  while (NvRamVariable < MAX_POWER_SUPPLY_COUNT) {
    ///
    /// Step 1: Get Device Name (command = 0x9A, -102 signed)
    ///
    DataLen = 0;
    Status  = SendHeciPowerSupplyCommand (
                HeciProtocol,
                HECI_CMD_DEVICE_NAME,
                SupplyBay,
                DeviceName,
                sizeof (DeviceName) - 1,
                &DataLen
                );
    if (EFI_ERROR (Status)) {
      //
      // Fallback: no device name available, use INVALID
      //
      AsciiStrCpyS (DeviceName, "INVALID");
    } else {
      DeviceName[DataLen] = '\0';
    }

    DEBUG ((DEBUG_INFO, "DeviceNameStr = %s\n", DeviceName));

    ///
    /// Step 2: Get Manufacturer (command = 0x99, -103 signed)
    ///
    DataLen = 0;
    Status  = SendHeciPowerSupplyCommand (
                HeciProtocol,
                HECI_CMD_MANUFACTURER,
                SupplyBay,
                Manufacturer,
                sizeof (Manufacturer) - 1,
                &DataLen
                );
    if (EFI_ERROR (Status)) {
      AsciiStrCpyS (Manufacturer, "INVALID");
    } else {
      Manufacturer[DataLen] = '\0';
    }

    DEBUG ((DEBUG_INFO, "ManufacturerStr = %s\n", Manufacturer));

    ///
    /// Step 3: Get Serial Number (command = 0x62, -98 signed as 0x9E)
    ///
    DataLen = 0;
    Status  = SendHeciPowerSupplyCommand (
                HeciProtocol,
                HECI_CMD_SERIAL_NUMBER,
                SupplyBay,
                SerialNumber,
                sizeof (SerialNumber) - 1,
                &DataLen
                );
    if (EFI_ERROR (Status)) {
      AsciiStrCpyS (SerialNumber, "INVALID");
    } else {
      SerialNumber[DataLen] = '\0';
    }

    DEBUG ((DEBUG_INFO, "SerialNumberStr = %s\n", SerialNumber));

    ///
    /// Step 4: Get Asset Tag (command = 0xF1, -15 signed)
    ///
    DataLen = 0;
    Status  = SendHeciPowerSupplyCommand (
                HeciProtocol,
                0xF1,          // Asset tag command
                SupplyBay,
                AssetTag,
                sizeof (AssetTag) - 1,
                &DataLen
                );
    if (EFI_ERROR (Status)) {
      AsciiStrCpyS (AssetTag, "INVALID");
    } else {
      AssetTag[DataLen] = '\0';
    }

    DEBUG ((DEBUG_INFO, "AssetTagNumberStr = %s\n", AssetTag));

    ///
    /// Step 5: Get Model Part Number (command = 0x9B, -101 signed)
    ///
    DataLen = 0;
    Status  = SendHeciPowerSupplyCommand (
                HeciProtocol,
                HECI_CMD_MODEL_PART_NUMBER,
                SupplyBay,
                ModelPartNumber,
                sizeof (ModelPartNumber) - 1,
                &DataLen
                );
    if (EFI_ERROR (Status)) {
      AsciiStrCpyS (ModelPartNumber, "INVALID");
    } else {
      ModelPartNumber[DataLen] = '\0';
    }

    DEBUG ((DEBUG_INFO, "ModelPartNumberStr = %s\n", ModelPartNumber));

    ///
    /// Step 6: Get Revision Level (command = 0xA7, -89 signed)
    ///
    DataLen = 0;
    Status  = SendHeciPowerSupplyCommand (
                HeciProtocol,
                HECI_CMD_REVISION_LEVEL,
                SupplyBay,
                RevisionLevel,
                sizeof (RevisionLevel) - 1,
                &DataLen
                );
    if (EFI_ERROR (Status)) {
      AsciiStrCpyS (RevisionLevel, "INVALID");
    } else {
      RevisionLevel[DataLen] = '\0';
    }

    DEBUG ((DEBUG_INFO, "RevisionLevelStr = %s\n", RevisionLevel));

    ///
    /// Step 7: Get Max Power Capacity
    ///
    {
      HECI_POWER_SUPPLY_REQUEST  CapRequest;
      UINT8                      CapResponse[64];
      UINTN                      CapResponseLen;
      UINT16                     RawCapacity;

      CapRequest.GroupId  = HECI_POWER_SUPPLY_GROUP_ID;
      CapRequest.Command  = HECI_CMD_MAX_POWER_CAPACITY;
      CapRequest.Reserved = 0;
      CapRequest.Param    = 0x01000001;  // Capacity request parameter

      CapResponseLen = sizeof (CapResponse);
      Status = HeciProtocol->SendwACK (
                               0,
                               &CapRequest,
                               sizeof (CapRequest),
                               &CapResponseLen,
                               0,
                               32
                               );

      DEBUG ((
        DEBUG_INFO,
        "pHeciProtocol->SendwACK Status: %r, HeciMsg[1]=%x, HeciMsg[2]=%x, HeciMsg[3]=%x\n",
        Status,
        CapResponse[1],
        SupplyBay,
        CapResponse[3]
        ));

      if (EFI_ERROR (Status) || CapResponse[1] != 0) {
        MaxPowerCapacity = POWER_SUPPLY_MAX_CAPACITY_DEFAULT;
      } else {
        RawCapacity = (UINT16)(CapResponse[2] | ((UINT16)CapResponse[3] << 8));
        switch (RawCapacity) {
        case 2323:
          MaxPowerCapacity = 550;
          break;
        case 2423:
          MaxPowerCapacity = 750;
          break;
        case 2598:
          MaxPowerCapacity = 1100;
          break;
        case 2848:
          MaxPowerCapacity = 1600;
          break;
        case 3048:
          MaxPowerCapacity = 2000;
          break;
        default:
          MaxPowerCapacity = POWER_SUPPLY_MAX_CAPACITY_DEFAULT;
          break;
        }
      }
    }

    DEBUG ((DEBUG_INFO, "MaxPowerCapacity = %d\n", MaxPowerCapacity));

    ///
    /// Step 8: Get Power Supply Present / Status
    ///
    {
      HECI_POWER_SUPPLY_REQUEST  PsuStatusRequest;
      UINT8                      PsuResponse[64];
      UINTN                      PsuResponseLen;

      PsuStatusRequest.GroupId  = HECI_POWER_SUPPLY_GROUP_ID;
      PsuStatusRequest.Command  = 0x78;           // Same as capacity command
      PsuStatusRequest.Reserved = 0;
      PsuStatusRequest.Param    = 0x01010078;     // Status request parameter

      PsuResponseLen = sizeof (PsuResponse);
      Status = HeciProtocol->SendwACK (
                               0,
                               &PsuStatusRequest,
                               sizeof (PsuStatusRequest),
                               &PsuResponseLen,
                               0,
                               32
                               );

      DEBUG ((
        DEBUG_INFO,
        "pHeciProtocol->SendwACK Status: %r, HeciMsg[1]=%x, HeciMsg[2]=%x\n",
        Status,
        PsuResponse[1],
        SupplyBay
        ));

      if (EFI_ERROR (Status) || PsuResponse[1] != 0) {
        PowerSupplyPresent = 0;
        PowerSupplyStatus  = 2;  // Status = Unknown
      } else {
        PowerSupplyPresent = 1;
        //
        // Determine power supply status based on response byte
        // If bit 1 of response[2] is clear -> status = 1 (Present, Unknown)
        // If bit 1 of response[2] is set   -> status = 3 (Present, Good)
        //
        PowerSupplyStatus = ((PsuResponse[2] & 0x02) != 0) ? 1 : 3;
      }
    }

    DEBUG ((
      DEBUG_INFO,
      "PowerSupplyPresent = %x, PowerSupplyStatus = %x\n",
      PowerSupplyPresent,
      PowerSupplyStatus
      ));

    ///
    /// Step 9: Allocate and build SMBIOS Type 39 record
    ///
    TotalStringLength = AsciiStrLen (DeviceName)
                      + AsciiStrLen (Manufacturer)
                      + AsciiStrLen (SerialNumber)
                      + AsciiStrLen (AssetTag)
                      + AsciiStrLen (ModelPartNumber)
                      + AsciiStrLen (RevisionLevel);

    StringBufferSize = TotalStringLength + 31;
    StringBuffer = AllocatePool (StringBufferSize);
    if (StringBuffer == NULL) {
      DEBUG ((DEBUG_ERROR, "Allocating Space for SmBios Type39Record fails...\n"));
      continue;
    }

    SmbiosRecord = AllocateZeroPool (StringBufferSize);
    if (SmbiosRecord == NULL) {
      DEBUG ((DEBUG_ERROR, "Allocating Space for SmBios Type39Record fails...\n"));
      FreePool (StringBuffer);
      continue;
    }

    //
    // Fill in the SMBIOS Type 39 record fields
    //
    SmbiosRecord->Hdr.Type   = SMBIOS_TYPE39_TYPE;
    SmbiosRecord->Hdr.Length = SMBIOS_TYPE39_LENGTH;
    SmbiosRecord->Hdr.Handle = SMBIOS_TYPE39_POWER_SUPPLY_HANDLE;

    //
    // Set power unit group (2 = "From the Mapping to the Power Unit Group")
    //
    SmbiosRecord->PowerUnitGroup       = 2;
    SmbiosRecord->NominalVoltage       = 7;       // Bits: Voltage=7, Location=0
    SmbiosRecord->MaxCapacity          = MaxPowerCapacity;

    //
    // Build the power supply status flags
    //
    // Bit 0   = Power Supply Present
    // Bits 6-7 = Power Supply Status (00=Unknown, 01=OK, 10=Non-critical, 11=Critical)
    //
    PowerSupplyFlags = (PowerSupplyPresent & 1) | ((PowerSupplyStatus & 7) << 6);
    SmbiosRecord->PowerSupplyCharacteristics = (UINT16)(0x0810 | (PowerSupplyFlags << 1));

    SmbiosRecord->HotReplaceSupported       = 0xFFFF;

    //
    // Now fill the string area.
    // Strings are packed as null-terminated ASCII after the fixed structure.
    //
    CurrentStringPtr = (CHAR8 *)(SmbiosRecord + 1);

    AsciiStrCpyS (CurrentStringPtr, GetSupplyBayString (SupplyBay));
    CurrentStringPtr += AsciiStrLen (GetSupplyBayString (SupplyBay)) + 1;

    AsciiStrCpyS (CurrentStringPtr, DeviceName);
    CurrentStringPtr += AsciiStrLen (DeviceName) + 1;

    AsciiStrCpyS (CurrentStringPtr, Manufacturer);
    CurrentStringPtr += AsciiStrLen (Manufacturer) + 1;

    AsciiStrCpyS (CurrentStringPtr, SerialNumber);
    CurrentStringPtr += AsciiStrLen (SerialNumber) + 1;

    AsciiStrCpyS (CurrentStringPtr, AssetTag);
    CurrentStringPtr += AsciiStrLen (AssetTag) + 1;

    AsciiStrCpyS (CurrentStringPtr, ModelPartNumber);
    CurrentStringPtr += AsciiStrLen (ModelPartNumber) + 1;

    AsciiStrCpyS (CurrentStringPtr, RevisionLevel);

    //
    // Step 10: Add the Type 39 record via SMBIOS protocol
    //
    {
      SMBIOS_HANDLE  SmbiosHandle;

      SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
      Status = gSmbios->Add (
                          gSmbios,
                          NULL,
                          &SmbiosHandle,
                          (EFI_SMBIOS_TABLE_HEADER *)SmbiosRecord
                          );

      DEBUG ((
        DEBUG_INFO,
        "SmbiosProtocol->Add Type39Record (%x)....  Status: %r\n",
        SupplyBay,
        Status
        ));
    }

    //
    // Cleanup allocated buffers
    //
    FreePool (StringBuffer);
    FreePool (SmbiosRecord);

    //
    // Move to the next supply bay
    //
    SupplyBayIncrement += 2;
    if (SupplyBayIncrement > 3) {
      DEBUG ((DEBUG_INFO, "InstallSmbiosType39Structure Exiting......\n"));
      return EFI_SUCCESS;
    }
  }

  DEBUG ((DEBUG_INFO, "InstallSmbiosType39Structure Exiting......\n"));
  return EFI_SUCCESS;
}

/**
  Entry point for the SmbiosType39 UEFI driver.

  This function initializes global variables (ImageHandle, SystemTable,
  BootServices, RuntimeServices), locates the DXE services table,
  PCD protocol, and registers a callback to install SMBIOS Type 39
  structures at the appropriate time.

  @param[in] ImageHandle  The firmware allocated handle for the EFI image.
  @param[in] SystemTable  A pointer to the EFI System Table.

  @retval EFI_SUCCESS           The entry point executed successfully.
  @retval EFI_NOT_FOUND         A required protocol was not found.
  @retval EFI_INVALID_PARAMETER A required global was NULL.
**/
EFI_STATUS
EFIAPI
SmbiosType39EntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;

  //
  // Initialize global variables
  //
  gImageHandle = ImageHandle;
  if (gImageHandle == NULL) {
    ASSERT (gImageHandle != NULL);
  }

  gST = SystemTable;
  if (gST == NULL) {
    ASSERT (gST != NULL);
  }

  gBS = SystemTable->BootServices;
  if (gBS == NULL) {
    ASSERT (gBS != NULL);
  }

  gRT = SystemTable->RuntimeServices;
  if (gRT == NULL) {
    ASSERT (gRT != NULL);
  }

  //
  // Initialize HOB list and PCD protocol
  //
  GetHobList ();
  GetPcdProtocol ();

  //
  // Look up the DXE Services Table via system configuration
  //
  Status = EfiGetSystemConfigurationTable (
             &gEfiDxeServicesTableGuid,
             &gMmPciBase
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((
      DEBUG_ERROR,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      Status
      ));
    ASSERT_EFI_ERROR (FALSE);
  }

  if (gMmPciBase == NULL) {
    DEBUG ((
      DEBUG_ERROR,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      Status
      ));
    ASSERT_EFI_ERROR (FALSE);
  }

  //
  // Look up the MM PCI base protocol (for MMIO PCI config access)
  //
  Status = gBS->LocateProtocol (
                  &gEfiMmPciBaseGuid,
                  NULL,
                  (VOID **)&gMmPciBase
                  );
  if (EFI_ERROR (Status)) {
    DEBUG ((
      DEBUG_ERROR,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      Status
      ));
    ASSERT_EFI_ERROR (FALSE);
  }

  ASSERT (gMmPciBase != NULL);

  //
  // Register a callback on the SMBIOS protocol installation
  // When SMBIOS protocol becomes available, InstallSmbiosType39Structure
  // will be called.
  //
  Status = gBS->CreateEvent (
                  EVT_NOTIFY_SIGNAL,
                  TPL_CALLBACK,
                  InstallSmbiosType39Structure,
                  ImageHandle,
                  &gRegistrationEvent
                  );
  if (EFI_ERROR (Status)) {
    Status = gBS->RegisterProtocolNotify (
                    &gEfiSmbiosProtocolGuid,
                    gRegistrationEvent,
                    &gRegistrationEvent
                    );
  }

  return EFI_SUCCESS;
}