/**
* 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;
}