Newer
Older
AMI-Aptio-BIOS-Reversed / ServerMgmtSetup / ServerMgmtSetup.c
@Ajax Dong Ajax Dong 2 days ago 14 KB Init
/**
 * ServerMgmtSetup.c - Server Management Setup Module
 *
 * UEFI HII driver for Lenovo server management configuration.
 * Provides BIOS setup forms for BMC LAN, DNS, NCSI, FRU, SOL,
 * IPMI user management, and SEL viewing.
 *
 * Source: AMI IPMI Framework (AmiIpmiPkg)
 * Platform: Lenovo HR650X (Neon City)
 */

#include "ServerMgmtSetup.h"

//
// Global State
//
EFI_HANDLE                  gImageHandle       = NULL;
EFI_SYSTEM_TABLE           *gSystemTable       = NULL;
EFI_BOOT_SERVICES          *gBootServices      = NULL;
EFI_RUNTIME_SERVICES       *gRuntimeServices   = NULL;
EFI_HII_DATABASE_PROTOCOL  *gHiiDatabase       = NULL;
EFI_HII_STRING_PROTOCOL    *gHiiString         = NULL;
EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting = NULL;
VOID                       *gHiiConfigAccess   = NULL;
VOID                       *gFormBrowser2      = NULL;
VOID                       *gIpmiTransport     = NULL;
EFI_HANDLE                  gImageHandleRaw    = NULL;
EFI_SYSTEM_TABLE           *gST                = NULL;
EFI_BOOT_SERVICES          *gBS                = NULL;
EFI_RUNTIME_SERVICES       *gRT                = NULL;
VOID                       *gDxeIpmiTransport  = NULL;
VOID                       *gHiiConfigRouting2 = NULL;
UINT8                       gSelDelInitDone    = 0;
UINT64                      gCurrentFormContext = 0;
UINT8                       gBmcMaxUsers       = 0;
UINT8                       gBmcLanKey         = 0;
UINT8                       gBmcUserCount      = 0;

extern HII_CALLBACK_ENTRY mCallbackTable[];

/**
 * _ModuleEntryPoint - UEFI module entry point
 */
EFI_STATUS
EFIAPI
ModuleEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  UefiBootServicesTableLibConstructor();
  return ServerMgmtSetupEntry(ImageHandle, SystemTable);
}

/**
 * UefiBootServicesTableLibConstructor - Initialize global service pointers
 */
VOID
UefiBootServicesTableLibConstructor (
  VOID
  )
{
  EFI_STATUS Status;

  gImageHandleRaw = ImageHandle;
  ASSERT(gImageHandleRaw != NULL);
  gST = SystemTable;
  ASSERT(gST != NULL);
  gBS = SystemTable->BootServices;
  ASSERT(gBS != NULL);
  gRT = SystemTable->RuntimeServices;
  ASSERT(gRT != NULL);

  Status = gBS->LocateProtocol(
    &gEfiHiiDatabaseProtocolGuid, NULL, (VOID**)&gHiiDatabase);
  ASSERT_EFI_ERROR(Status);

  Status = gBS->LocateProtocol(
    &gEfiHiiStringProtocolGuid, NULL, (VOID**)&gHiiString);
  ASSERT_EFI_ERROR(Status);

  Status = gBS->LocateProtocol(
    &gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID**)&gHiiConfigRouting);
  ASSERT_EFI_ERROR(Status);

  gBS->LocateProtocol(&gEfiHiiConfigAccessProtocolGuid,  NULL, &gHiiConfigAccess);
  gBS->LocateProtocol(&gEfiFormBrowser2ProtocolGuid,     NULL, &gFormBrowser2);
  gBS->LocateProtocol(&gEfiDxeIpmiTransportProtocolGuid, NULL, &gIpmiTransport);
}

/**
 * ServerMgmtSetupEntry - Register HII form and install driver handle
 */
EFI_STATUS
EFIAPI
ServerMgmtSetupEntry (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_HII_HANDLE  HiiHandle;
  EFI_HANDLE      DriverHandle;
  UINTN           BufferSize;
  EFI_STATUS      Status;

  if (gSystemTable == NULL) {
    gSystemTable = (UINTN)SystemTable;
    gBootServices = (UINTN)SystemTable->BootServices;
    gRuntimeServices = (UINTN)SystemTable->RuntimeServices;
  }
  gImageHandle = ImageHandle;

  BufferSize = sizeof(mServerSetupFormData);
  Status = gRT->GetVariable(
    L"ServerSetup", &mServerSetupFormGuid,
    NULL, &BufferSize, &mServerSetupFormData);

  if (Status == EFI_NOT_FOUND) {
    HiiInitDelayed(0, 0);
    Status = gBS->InstallProtocolInterface(
      &DriverHandle, &gEfiHiiConfigAccessProtocolGuid,
      EFI_NATIVE_INTERFACE, &mConfigAccessProtocol);
    if (Status >= 0) {
      gBS->InstallProtocolInterface(
        (UINT32*)GuidData,
        EFI_NATIVE_INTERFACE,
        &mConfigAccessProtocol);
    }
  } else {
    HiiInitDelayed(0, 0);
  }
  return EFI_SUCCESS;
}

/**
 * HiiCallbackRouter - Route HII callbacks to form/question handlers
 */
EFI_STATUS
EFIAPI
HiiCallbackRouter (
  IN     CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
  IN     EFI_BROWSER_ACTION                   Action,
  IN     EFI_QUESTION_ID                      QuestionId,
  IN     EFI_FORM_ID                          FormId,
  IN     VOID                                 *CallbackData,
  OUT    EFI_BROWSER_ACTION_REQUEST           *HandleResult
  )
{
  HII_CALLBACK_ENTRY *Entry;
  EFI_STATUS          Status;

  gCurrentFormContext = (UINTN)&Action;
  Status = EFI_UNSUPPORTED;

  if (mCallbackTable != NULL) {
    Entry = &mCallbackTable[0];
    while (Entry->Handler != NULL) {
      if (Entry->FormId == FormId && Entry->QuestionId == QuestionId) {
        Status = Entry->Handler(
          (EFI_HANDLE)gHiiConfigAccess,
          Action, QuestionId, FormId,
          CallbackData, HandleResult);
        if (Status != EFI_UNSUPPORTED) break;
      }
      Entry++;
    }
  }
  gCurrentFormContext = 0;
  return Status;
}

/**
 * HiiInitDelayed - Locate HII protocols and initialize SEL deletion support
 */
VOID
HiiInitDelayed (
  IN EFI_HANDLE ImageHandle OPTIONAL
  )
{
  if (gHiiDatabase == NULL)
    gBS->LocateProtocol(&gEfiHiiDatabaseProtocolGuid, NULL, (VOID**)&gHiiDatabase);
  if (gHiiString == NULL)
    gBS->LocateProtocol(&gEfiHiiStringProtocolGuid, NULL, (VOID**)&gHiiString);

  if ((gHiiDatabase != NULL) && (gHiiString != NULL)) {
    if (ImageHandle != NULL) gBS->FreePool(ImageHandle);
    if (!gSelDelInitDone) {
      gSelDelInitDone = TRUE;
      InitSelDelSupport();
    }
  }
}

/**
 * GetBmcLanConfiguration - Read BMC LAN configuration via IPMI
 */
EFI_STATUS
GetBmcLanConfiguration (
  OUT BMC_LAN_CONFIGURATION *LanConfigBuffer
  )
{
  return InternalIpmiSendCommand(
    IPMI_NETFN_APP | IPMI_LUN_0,
    IPMI_APP_GET_LAN_CONFIG,
    LanConfigBuffer, sizeof(*LanConfigBuffer));
}

/**
 * SetBmcLanConfiguration - Write BMC LAN configuration via IPMI
 */
EFI_STATUS
SetBmcLanConfiguration (
  IN BMC_LAN_CONFIGURATION *LanConfigBuffer
  )
{
  return InternalIpmiSendCommand(
    IPMI_NETFN_APP | IPMI_LUN_0,
    IPMI_APP_SET_LAN_CONFIG,
    LanConfigBuffer, sizeof(*LanConfigBuffer));
}

/**
 * SetBmcLanInterfaceState - Set BMC LAN interface state via IPMI
 */
EFI_STATUS
SetBmcLanInterfaceState (
  IN BOOLEAN Enable
  )
{
  UINT8 Command[2];
  Command[0] = IPMI_LAN_SET_INTERFACE_ENABLE;
  Command[1] = Enable ? 1 : 0;
  return InternalIpmiSendCommand(
    IPMI_NETFN_TRANSPORT | IPMI_LUN_0,
    IPMI_TRANSPORT_SET_LAN_CONFIG,
    Command, sizeof(Command));
}

/**
 * GetBmcDnsConfiguration - Retrieve DNS configuration from BMC
 */
EFI_STATUS
GetBmcDnsConfiguration (
  OUT BMC_DNS_CONFIGURATION *DnsConfigBuffer
  )
{
  return InternalIpmiSendCommand(
    IPMI_NETFN_TRANSPORT | IPMI_LUN_0,
    IPMI_TRANSPORT_GET_DNS_CONFIG,
    DnsConfigBuffer, sizeof(*DnsConfigBuffer));
}

/**
 * SetBmcDnsConfiguration - Configure BMC DNS via IPMI
 */
EFI_STATUS
SetBmcDnsConfiguration (
  IN BMC_DNS_CONFIGURATION *DnsConfigBuffer
  )
{
  return InternalIpmiSendCommand(
    IPMI_NETFN_TRANSPORT | IPMI_LUN_0,
    IPMI_TRANSPORT_SET_DNS_CONFIG,
    DnsConfigBuffer, sizeof(*DnsConfigBuffer));
}

/**
 * SendBmcCommand - Generic BMC IPMI command send/receive
 */
EFI_STATUS
SendBmcCommand (
  IN  UINT8   NetFn,
  IN  UINT8   Command,
  IN  UINT8   *RequestData,
  IN  UINT32  RequestSize,
  OUT UINT8   *ResponseData,
  IN  OUT UINT32 *ResponseSize
  )
{
  return InternalProcessBmcCommand(
    NetFn, Command,
    RequestData, RequestSize,
    ResponseData, ResponseSize);
}

/**
 * UpdateHiiString - Write a string value to the HII form
 */
VOID
UpdateHiiString (
  IN EFI_FORM_ID FormId,
  IN EFI_STRING_ID StringId
  )
{
  gHiiConfigRouting2->UpdateString(
    gHiiConfigRouting2, 0, FormId, StringId, L"Setup");
}

/**
 * ZeroMemoryBios - Clear a memory buffer
 */
VOID
ZeroMemoryBios (
  IN VOID   *Buffer,
  IN UINTN  Size
  )
{
  UINT8 *Ptr = (UINT8 *)Buffer;
  while (Size--) *Ptr++ = 0;
}

/**
 * SetNcsiSwitchCmd - Send NCSI switch IPMI command to BMC
 */
EFI_STATUS
SetNcsiSwitchCmd (
  IN UINT8 Selector
  )
{
  UINT8 NcsiCommand[8];
  NcsiCommand[0] = 0;
  NcsiCommand[1] = 0x01;
  NcsiCommand[2] = Selector;
  return InternalIpmiSendCommand(
    IPMI_NETFN_OEM | IPMI_LUN_0,
    IPMI_OEM_NCSI_SWITCH,
    NcsiCommand, sizeof(NcsiCommand));
}

/**
 * BmcDnsConfigCallback - BMC DNS configuration handler (10004)
 */
EFI_STATUS
BmcDnsConfigCallback (
  IN UINT64    a1,
  IN UINT64    a2,
  IN UINT64    a3,
  IN UINT16    a4
  )
{
  UINT8   DnsBuffer[581];
  UINT8   Ipv6Buffer[581];
  UINTN   bufferSize;
  UINT32  IpAddressParts;
  CHAR8   IpStr[32];

  ZeroMem(DnsBuffer, sizeof(DnsBuffer));
  ZeroMem(Ipv6Buffer, sizeof(Ipv6Buffer));
  bufferSize = sizeof(DnsBuffer);

  if ((a4 - 10006) > 2) return EFI_INVALID_PARAMETER;

  if (gCurrentFormContext + 8 != 1) {
    LoadFormData(&bufferSize, DnsBuffer,
      SETUP_DATA_GUID, L"SetupBmcDnsConfig");

    switch (a4) {
      case 0x2716: case 0x2717: case 0x2718:
        ValidateAndStoreIpAddress(IpBuffer1, IpResult, &IpAddressParts);
        CopyIpAddressOctets(IpResult, (UINT8 *)&IpAddressParts, 4);
        FormatIpDisplayString(IpBuffer2, L"%d.%d.%d.%d", ...);
        break;
    }

    if (CheckHexStringInput(IpBuffer1, IpResult, &IpAddressParts) >= 0
        && *(UINT16 *)IpResult == 0) {
      ValidateIpOctets();
    }

    SaveFormData(bufferSize, DnsBuffer,
      SETUP_DATA_GUID, L"SetupBmcDnsConfig");
  }
  return EFI_SUCCESS;
}

/**
 * AddNewBmcUserCb - Add a new BMC user via IPMI (Callback 10063)
 */
EFI_STATUS
AddNewBmcUserCb (
  IN UINT64    a1,
  IN UINT64    a2,
  IN UINT64    a3,
  IN UINT16    ActionId
  )
{
  UINT8   NewUserId;
  CHAR8   UserName[17];
  UINT8   Buffer[892];
  UINT8   PasswordHash[18];
  UINT8   StateBuffer[180];

  ZeroMem(Buffer, sizeof(Buffer));

  if (ActionId != 10063) return EFI_INVALID_PARAMETER;
  if (gCurrentFormContext + 8 != 1) return EFI_SUCCESS;

  *(UINT64 *)(Buffer + 2) = 0x10000;
  *(UINT32 *)Buffer = 0x140012;
  *(UINT64 *)(Buffer + 16) = (UINT64)(Buffer + 72);

  gHiiConfigRouting2->SetString(Buffer + 32, 360, ...);

  WideStrToMultiByte(gBmcNewUserBuffer, gBmcUserNameBuffer);
  if (StrLen(gBmcUserNameBuffer) == 0 || StrLen(gBmcUserNameBuffer) > 20) {
    UpdateHiiString(394);
    ZeroBuffer(gBmcNewUserBuffer, 21);
    return EFI_INVALID_PARAMETER;
  }

  gBmcLanKey = GetLanKey();
  if (SendIpmiCommand(3, gBmcNewUserBuffer) >= 0) {
    for (Index = 0; Index < gBmcMaxUsers; Index++) {
      if (CheckUserNameExists(gBmcUserNameList[Index],
                              gBmcUserNameTemp)) break;
    }
    if (Index < gBmcMaxUsers) {
      EncodePassword();
      SendBmcAddUser();
      UpdateHiiString(397);
      ClearBuffer(gBmcLanKey);
      ClearBuffer(PasswordBuffer);
      RefreshUserList(a1);
      return EFI_SUCCESS;
    }
  }
  UpdateHiiString(Index >= gBmcMaxUsers ? 396 : 395);
  return EFI_INVALID_PARAMETER;
}

/**
 * WideStrCmp - Wide string comparison
 */
BOOLEAN
WideStrCmp (
  IN CONST CHAR16 *Str1,
  IN CONST CHAR16 *Str2
  )
{
  while (*Str1 != L'\0' && *Str2 != L'\0') {
    if (*Str1 != *Str2) return FALSE;
    Str1++; Str2++;
  }
  return (*Str1 == L'\0' && *Str2 == L'\0');
}

/**
 * WideStrToMultiByte - Convert wide string to ASCII
 */
VOID
WideStrToMultiByte (
  IN  CONST CHAR16 *WideStr,
  OUT CHAR8        *MultiStr
  )
{
  while (*WideStr != L'\0') *MultiStr++ = (CHAR8)*WideStr++;
  *MultiStr = '\0';
}

/**
 * MultiByteToWideStr - Convert ASCII to wide string
 */
VOID
MultiByteToWideStr (
  IN  CONST CHAR8  *MultiStr,
  OUT CHAR16       *WideStr
  )
{
  while (*MultiStr != '\0') *WideStr++ = (CHAR16)*MultiStr++;
  *WideStr = L'\0';
}

/**
 * AmiConvertHexStringToInt - Parse hex string to integer
 */
EFI_STATUS
AmiConvertHexStringToInt (
  IN  CONST CHAR8   *HexStr,
  OUT UINT64        *Value,
  IN  UINTN         MaxLen
  )
{
  UINTN  Index;
  UINT64 Result = 0;

  for (Index = 0; Index < MaxLen && HexStr[Index] != '\0'; Index++) {
    if (!IsHexChar(HexStr[Index])) return EFI_INVALID_PARAMETER;
    Result = (Result << 4) | HexCharToInt(HexStr[Index]);
  }
  *Value = Result;
  return EFI_SUCCESS;
}

/**
 * IsHexChar - Check if character is valid hex digit
 */
BOOLEAN
IsHexChar (
  IN CHAR8 Char
  )
{
  return ((Char >= '0' && Char <= '9') ||
          (Char >= 'A' && Char <= 'F') ||
          (Char >= 'a' && Char <= 'f'));
}

/**
 * HexCharToInt - Convert hex character to integer value
 */
UINT8
HexCharToInt (
  IN CHAR8 Char
  )
{
  if (Char >= '0' && Char <= '9') return Char - '0';
  Char = ConvertToUppercase(Char);
  return Char - 'A' + 10;
}

/**
 * ConvertToUppercase - Convert ASCII char to uppercase
 */
CHAR8
ConvertToUppercase (
  IN CHAR8 Char
  )
{
  if (Char >= 'a' && Char <= 'z') return Char - ('a' - 'A');
  return Char;
}

/**
 * DebugPrintFormat - Debug serial print with format string
 */
VOID
DebugPrintFormat (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Format,
  ...
  )
{
  VA_LIST Marker;
  VA_START(Marker, Format);
  AsciiVSPrint(Format, Marker);
  VA_END(Marker);
}

/**
 * AssertDeadloop - ASSERT failure handler with deadloop
 */
VOID
AssertDeadloop (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Message
  )
{
  DEBUG((EFI_D_ERROR, "\nASSERT %a(%d): %a\n",
         FileName, (UINTN)LineNumber, Message));
  CpuDeadLoop();
}

/**
 * CopyIpAddressOctets - Copy IP address octets from 32-bit value
 */
VOID
CopyIpAddressOctets (
  OUT UINT8   *Dest,
  IN  UINT32  *Source,
  IN  UINTN   OctetCount
  )
{
  UINTN Index;
  for (Index = 0; Index < OctetCount; Index++)
    Dest[Index] = (UINT8)(*Source >> (Index * 8));
}

/**
 * StringLen - Get ASCII string length
 */
UINTN
StringLen (
  IN CONST CHAR8 *String
  )
{
  UINTN Length = 0;
  while (String[Length] != '\0') Length++;
  return Length;
}

/**
 * AsciiStrCmp - Compare two ASCII strings
 */
BOOLEAN
AsciiStrCmp (
  IN CONST CHAR8 *Str1,
  IN CONST CHAR8 *Str2
  )
{
  while (*Str1 != '\0' && *Str2 != '\0') {
    if (*Str1 != *Str2) return FALSE;
    Str1++; Str2++;
  }
  return (*Str1 == '\0' && *Str2 == '\0');
}

/**
 * IsNumericChar - Check if character is numeric
 */
BOOLEAN
IsNumericChar (
  IN CHAR8 Char
  )
{
  return (Char >= '0' && Char <= '9');
}

/**
 * ValidateHexString - Validate hex string format
 */
BOOLEAN
ValidateHexString (
  IN CONST CHAR8 *HexStr
  )
{
  while (*HexStr != '\0') {
    if (!IsHexChar(*HexStr)) return FALSE;
    HexStr++;
  }
  return TRUE;
}