/** @file
AddressTranslationDsmMemRas - Purley Platform RAS Address Translation DSM Driver (SMM)
This driver is an SMM driver that provides Address Translation DSM (Direct Memory Store)
error reporting functionality. It registers an SMI handler to handle memory error
log queries from the OS, and installs a patched SSDT to expose the ACPI
interface for Address Translation DSM.
Source: PurleyPlatPkg\Ras\AddressTranslationDsm\AddressTranslationDsm.c
Copyright (c) Lenovo. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "AddressTranslationDsmMemRas.h"
//
// Global variables
//
EFI_HANDLE *gImageHandle = NULL;
EFI_SYSTEM_TABLE *gSystemTable = NULL;
EFI_BOOT_SERVICES *gBootServices = NULL;
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
EFI_SMM_SYSTEM_TABLE2 *gSmst = NULL;
EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL;
MEMRAS_PROTOCOL *mMemRas = NULL;
//
// SMI communication buffer (0x100 bytes allocated via AllocatePool)
//
ADDRESS_TRANSLATION_DSM_COMMUNICATION_BUFFER *mCommunicationBuffer = NULL;
//
// SMRAM ranges for memory allocation tracking
//
EFI_SMRAM_DESCRIPTOR *mSmramRanges = NULL;
UINTN mSmramRangeCount = 0;
//
// Module status tracking
//
EFI_STATUS mModuleStatus = EFI_SUCCESS;
//
// Protocol GUIDs (platform-specific)
//
EFI_GUID gMemRasProtocolGuid = { 0x6D7E4A32, 0x9A73, 0x46BA, { 0x94, 0xA1, 0x5F, 0x2F, 0x25, 0xEF, 0x3E, 0x29 } };
EFI_GUID gAddressTranslationDsmSsdtFileGuid = { 0xFFE06BDD, 0x6107, 0x46A6, { 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C } };
/**
Initialize UEFI Boot Services Library globals and locate SMM protocols.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@return The number of SMRAM ranges.
**/
UINTN
EFIAPI
UefiBootServicesTableLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
UINTN SmramSize;
gImageHandle = ImageHandle;
ASSERT (ImageHandle != NULL);
gSystemTable = SystemTable;
ASSERT (SystemTable != NULL);
gBootServices = SystemTable->BootServices;
ASSERT (gBootServices != NULL);
gRuntimeServices = SystemTable->RuntimeServices;
ASSERT (gRuntimeServices != NULL);
//
// Locate SMM Base2 protocol to get SMM System Table
//
Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&gSmst);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
ASSERT (gSmst != NULL);
//
// Get SMM Access2 protocol for SMRAM discovery
//
Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
//
// Query SMRAM capabilities (expected to return EFI_BUFFER_TOO_SMALL initially)
//
Status = SmmAccess->GetCapabilities (SmmAccess, &SmramSize, NULL);
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
//
// Allocate SMRAM ranges descriptor
//
mSmramRanges = (EFI_SMRAM_DESCRIPTOR *)SmramAllocatePool (SmramSize);
ASSERT (mSmramRanges != NULL);
Status = SmmAccess->GetCapabilities (SmmAccess, &SmramSize, mSmramRanges);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
//
// Each descriptor is 0x20 (32) bytes
//
mSmramRangeCount = SmramSize >> 5;
return mSmramRangeCount;
}
/**
DEBUG print wrapper. Checks CMOS debug level to determine whether
to output the debug message.
@param ErrorLevel The error level mask.
@param Format Format string.
@param ... Variable arguments.
**/
VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
EFI_SMM_CPU_PROTOCOL *SmmCpu;
UINT8 DebugLevel;
UINTN DebugMask;
SmmCpu = GetSmmCpuProtocol ();
if (SmmCpu == NULL) {
return;
}
//
// Check CMOS debug level at offset 0x4C
//
DebugLevel = IoRead8 (0x70);
IoWrite8 (0x70, DebugLevel & 0x80 | 0x4C);
DebugLevel = IoRead8 (0x71);
if (DebugLevel > 3) {
if (DebugLevel == 0) {
DebugLevel = (MmioRead8 (0xFDAF0490) & 2) | 1;
}
}
switch (DebugLevel) {
case 1:
DebugMask = EFI_D_ERROR;
break;
case 2:
DebugMask = EFI_D_WARN;
break;
case 3:
default:
DebugMask = EFI_D_INFO;
break;
}
if ((DebugMask & ErrorLevel) != 0) {
SmmCpu->DebugPrint (ErrorLevel, Format, VA_LIST);
}
}
/**
Debug ASSERT wrapper that calls SMM_CPU_PROTOCOL for assertion handling.
@param FileName The file name of the assertion.
@param LineNumber The line number of the assertion.
@param Description The assertion description.
**/
VOID
EFIAPI
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
EFI_SMM_CPU_PROTOCOL *SmmCpu;
SmmCpu = GetSmmCpuProtocol ();
if (SmmCpu != NULL) {
SmmCpu->DebugAssert (FileName, LineNumber, Description);
}
}
/**
Retrieve the EFI_SMM_CPU_PROTOCOL via SMM Services Table.
Uses a cached pointer after first lookup.
@return The SMM_CPU_PROTOCOL interface, or NULL if not found.
**/
EFI_SMM_CPU_PROTOCOL *
GetSmmCpuProtocol (
VOID
)
{
if (mSmmCpu == NULL) {
if (EFI_ERROR (gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **)&mSmmCpu))) {
mSmmCpu = NULL;
}
}
return mSmmCpu;
}
/**
Check if an address falls within any known SMRAM range.
@param Address The address to check.
@return TRUE if the address is in SMRAM. FALSE otherwise.
**/
BOOLEAN
IsAddressInSmram (
IN EFI_PHYSICAL_ADDRESS Address
)
{
UINTN Index;
if (mSmramRangeCount == 0) {
return FALSE;
}
for (Index = 0; Index < mSmramRangeCount; Index++) {
if (Address >= mSmramRanges[Index].CpuStart &&
Address < mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize) {
return TRUE;
}
}
return FALSE;
}
/**
Free memory allocated from either SMRAM or boot services,
selecting the appropriate free function based on address location.
@param Buffer Pointer to the buffer to free.
**/
VOID
FreeMemory (
IN VOID *Buffer
)
{
EFI_STATUS Status;
if (Buffer == NULL) {
return;
}
if (IsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer)) {
Status = gSmst->SmmFreePool (Buffer);
} else {
Status = gBootServices->FreePool (Buffer);
}
ASSERT_EFI_ERROR (Status);
}
/**
Save execution context to a jump buffer (SetJump equivalent).
Preserves non-volatile general-purpose registers, MXCSR, and XMM6-XMM15.
@param JumpBuffer The jump buffer to save context to.
@return 0 when called directly.
**/
UINTN
EFIAPI
SetJump (
IN BASE_LIBRARY_JUMP_BUFFER *JumpBuffer
)
{
ASSERT (JumpBuffer != NULL);
ASSERT (((UINTN)JumpBuffer & (8 - 1)) == 0);
SaveContext (JumpBuffer);
//
// Save non-volatile GPRs
//
JumpBuffer->Rbx = (UINT64)__Rbx;
JumpBuffer->Rbp = (UINT64)__Rbp;
JumpBuffer->Rdi = (UINT64)__Rdi;
JumpBuffer->Rsi = (UINT64)__Rsi;
JumpBuffer->R12 = (UINT64)__R12;
JumpBuffer->R13 = (UINT64)__R13;
JumpBuffer->R14 = (UINT64)__R14;
JumpBuffer->R15 = (UINT64)__R15;
JumpBuffer->Rip = (UINT64)__Rip;
JumpBuffer->MxCsr = _mm_getcsr ();
JumpBuffer->Xmm6 = __Xmm6;
JumpBuffer->Xmm7 = __Xmm7;
JumpBuffer->Xmm8 = __Xmm8;
JumpBuffer->Xmm9 = __Xmm9;
JumpBuffer->Xmm10 = __Xmm10;
JumpBuffer->Xmm11 = __Xmm11;
JumpBuffer->Xmm12 = __Xmm12;
JumpBuffer->Xmm13 = __Xmm13;
JumpBuffer->Xmm14 = __Xmm14;
JumpBuffer->Xmm15 = __Xmm15;
return JumpBuffer->Rip ();
}
/**
Restore execution context from a jump buffer (LongJump equivalent).
Restores non-volatile registers and jumps to the saved RIP.
@param JumpBuffer The jump buffer to restore context from.
@param Value The value to return from SetJump.
**/
VOID
EFIAPI
LongJump (
IN BASE_LIBRARY_JUMP_BUFFER *JumpBuffer,
IN UINTN Value
)
{
_mm_setcsr (JumpBuffer->MxCsr);
__ReturnFromJumpBuffer (JumpBuffer, Value);
}
/**
Entry point for Address Translation DSM. This function:
1. Locates the MemRas protocol
2. Allocates a communication buffer for OS/SMM data exchange
3. Registers the SW SMI handler
4. Installs the SSDT ACPI table
@return EFI_STATUS indicating success or failure.
**/
EFI_STATUS
AddressTranslationDsmEntry (
VOID
)
{
EFI_STATUS Status;
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Enter AddressTranslationDsmEntry\n"));
//
// Locate MemRas protocol
//
Status = gSmst->SmmLocateProtocol (&gMemRasProtocolGuid, NULL, (VOID **)&mMemRas);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
goto Exit;
}
//
// Allocate communication buffer (sizeof = 0x100 bytes)
//
Status = gBootServices->AllocatePool (
EfiBootServicesData,
sizeof (ADDRESS_TRANSLATION_DSM_COMMUNICATION_BUFFER),
(VOID **)&mCommunicationBuffer
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
goto Exit;
}
//
// Register SW SMI handler
//
Status = RegisterSwSmi ();
if (EFI_ERROR (Status)) {
goto Exit;
}
//
// Install patched SSDT
//
Status = InstallSsdt ();
Exit:
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Exit AddressTranslationDsmEntry: %r\n", Status));
return Status;
}
/**
Register a Software SMI handler that dispatches Address Translation DSM commands.
The handler is triggered by SW_SMI_COMMAND_VALUE (0x97).
@return EFI_STATUS.
**/
EFI_STATUS
RegisterSwSmi (
VOID
)
{
EFI_STATUS Status;
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
EFI_HANDLE SwHandle;
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Enter RegisterSwSmi\n"));
//
// Locate SMM SW Dispatch2 protocol
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmSwDispatch2ProtocolGuid,
NULL,
(VOID **)&SwDispatch
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
goto Exit;
}
//
// Register SMI handler with input value 0x97 (151)
//
SwContext.SwSmiInputValue = SW_SMI_COMMAND_VALUE;
ASSERT (SwContext.SwSmiInputValue < SwDispatch->MaximumSwiValue);
Status = SwDispatch->Register (SwDispatch, SwSmiHandler, &SwContext, &SwHandle);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
ASSERT (SwDispatch->MaximumSwiValue <= MAX_UINT32);
//
// Store the SW SMI input value in the communication header
//
mCommunicationBuffer->SwSmiInputValue = SwContext.SwSmiInputValue;
//
// If already registered, treat as unsupported
//
if (Status == EFI_ALREADY_STARTED) {
Status = EFI_UNSUPPORTED;
}
Exit:
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Exit RegisterSwSmi: %r\n", Status));
return Status;
}
/**
SMI handler for Address Translation DSM.
Dispatches GET_ERROR_LOG and CLEAR_ERROR_LOG commands from the OS.
Command 2 (GET_ERROR_LOG): Calls mMemRas->GetErrorLog() to retrieve
memory error information and stores it in the communication buffer.
Command 3 (CLEAR_ERROR_LOG): Calls mMemRas->ClearErrorLog() to
clear memory error records.
@param DispatchHandle SMI dispatch handle.
@param Context Optional SMI context.
@return EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
SwSmiHandler (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *Context OPTIONAL
)
{
ADDRESS_TRANSLATION_DSM_COMMUNICATION_BUFFER Buffer;
ADDRESS_TRANSLATION_DSM_COMMUNICATION_BUFFER *CommBuffer;
EFI_STATUS Status;
//
// Check MemRas protocol availability
//
if (mMemRas == NULL) {
ASSERT (mMemRas != NULL);
if (mMemRas == NULL) {
return EFI_UNSUPPORTED;
}
}
//
// Clear stack buffer
//
ZeroMem (&Buffer, sizeof (Buffer));
CommBuffer = mCommunicationBuffer;
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Enter SwSmiHandler\n"));
//
// Set status to "in progress" (2)
//
CommBuffer->Status = COMMAND_STATUS_IN_PROGRESS;
//
// Command: GET_ERROR_LOG (2)
//
if (CommBuffer->Command == COMMAND_GET_ERROR_LOG) {
Status = mMemRas->GetErrorLog (
(VOID *)(UINTN)CommBuffer->Address0,
&Buffer
);
CommBuffer->Status = (Status < 0) ? COMMAND_STATUS_ERROR : COMMAND_STATUS_SUCCESS;
}
//
// Command: CLEAR_ERROR_LOG (3)
//
if (CommBuffer->Command == COMMAND_CLEAR_ERROR_LOG) {
//
// Copy input data from communication buffer
//
CopyMem (&Buffer, (VOID *)(UINTN)CommBuffer->Address0, sizeof (Buffer));
Status = mMemRas->ClearErrorLog (&Buffer);
CommBuffer->Status = (Status < 0) ? COMMAND_STATUS_ERROR : COMMAND_STATUS_SUCCESS;
}
//
// If command succeeded, copy results back with sentinel handling.
// Fields are conditionally written: if the output field value equals the
// sentinel (-1 for QWORD/DWORD, 0xFF for BYTE), the original value is preserved.
//
if (CommBuffer->Status == COMMAND_STATUS_SUCCESS) {
CommBuffer->Address0 = (Buffer.Address0 != (UINT64)-1) ? Buffer.Address0 : (UINT64)-1;
CommBuffer->Address1 = (Buffer.Address1 != (UINT64)-1) ? Buffer.Address1 : (UINT64)-1;
CommBuffer->Address2 = (Buffer.Address2 != (UINT64)-1) ? Buffer.Address2 : (UINT64)-1;
CommBuffer->Address3 = (Buffer.Address3 != (UINT64)-1) ? Buffer.Address3 : (UINT64)-1;
CommBuffer->Byte0 = (Buffer.Byte0 != 0xFF) ? Buffer.Byte0 : (UINT8)-1;
CommBuffer->Byte1 = (Buffer.Byte1 != 0xFF) ? Buffer.Byte1 : (UINT8)-1;
CommBuffer->Byte2 = (Buffer.Byte2 != 0xFF) ? Buffer.Byte2 : (UINT8)-1;
CommBuffer->Byte3 = (Buffer.Byte3 != 0xFF) ? Buffer.Byte3 : (UINT8)-1;
CommBuffer->Byte4 = (Buffer.Byte4 != 0xFF) ? Buffer.Byte4 : (UINT8)-1;
CommBuffer->Byte5 = (Buffer.Byte5 != 0xFF) ? Buffer.Byte5 : (UINT8)-1;
CommBuffer->Byte6 = (Buffer.Byte6 != 0xFF) ? Buffer.Byte6 : (UINT8)-1;
CommBuffer->Byte7 = (Buffer.Byte7 != 0xFF) ? Buffer.Byte7 : (UINT8)-1;
CommBuffer->Byte8 = (Buffer.Byte8 != 0xFF) ? Buffer.Byte8 : (UINT8)-1;
CommBuffer->Byte9 = (Buffer.Byte9 != 0xFF) ? Buffer.Byte9 : (UINT8)-1;
CommBuffer->Byte10 = (Buffer.Byte10 != 0xFF) ? Buffer.Byte10 : (UINT8)-1;
CommBuffer->Byte11 = (Buffer.Byte11 != 0xFF) ? Buffer.Byte11 : (UINT8)-1;
CommBuffer->Byte12 = (Buffer.Byte12 != 0xFF) ? Buffer.Byte12 : (UINT8)-1;
CommBuffer->Byte13 = (Buffer.Byte13 != 0xFF) ? Buffer.Byte13 : (UINT8)-1;
CommBuffer->Byte14 = (Buffer.Byte14 != 0xFF) ? Buffer.Byte14 : (UINT8)-1;
CommBuffer->Byte15 = (Buffer.Byte15 != 0xFF) ? Buffer.Byte15 : (UINT8)-1;
CommBuffer->Byte16 = (Buffer.Byte16 != 0xFF) ? Buffer.Byte16 : (UINT8)-1;
CommBuffer->Byte17 = (Buffer.Byte17 != 0xFF) ? Buffer.Byte17 : (UINT8)-1;
CommBuffer->Byte18 = (Buffer.Byte18 != 0xFF) ? Buffer.Byte18 : (UINT8)-1;
CommBuffer->Byte19 = (Buffer.Byte19 != 0xFF) ? Buffer.Byte19 : (UINT8)-1;
CommBuffer->Byte20 = (Buffer.Byte20 != 0xFF) ? Buffer.Byte20 : (UINT8)-1;
CommBuffer->Qword5 = (Buffer.Qword5 != (UINT64)-1) ? Buffer.Qword5 : (UINT64)-1;
CommBuffer->Qword6 = (Buffer.Qword6 != (UINT64)-1) ? Buffer.Qword6 : (UINT64)-1;
CommBuffer->Qword7 = (Buffer.Qword7 != (UINT64)-1) ? Buffer.Qword7 : (UINT64)-1;
CommBuffer->Qword8 = (Buffer.Qword8 != (UINT64)-1) ? Buffer.Qword8 : (UINT64)-1;
CommBuffer->Dword3 = (Buffer.Dword3 != (UINT32)-1) ? Buffer.Dword3 : (UINT32)-1;
CommBuffer->Dword4 = (Buffer.Dword4 != (UINT32)-1) ? Buffer.Dword4 : (UINT32)-1;
}
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Exit SwSmiHandler\n"));
return EFI_SUCCESS;
}
/**
Install a patched SSDT ACPI table for Address Translation DSM.
Reads the SSDT raw data from firmware volume and patches the
ADDRESS_TRANSLATION_DSM_SSDT_SIGNATURE signature offset with
the communication buffer address.
@return EFI_STATUS.
**/
EFI_STATUS
InstallSsdt (
VOID
)
{
EFI_STATUS Status;
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
VOID *SsdtData;
UINTN SsdtSize;
UINT8 *Data;
UINTN Offset;
UINTN EndOffset;
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Enter InstallSsdt\n"));
//
// Locate ACPI Table protocol
//
Status = gBootServices->LocateProtocol (
&gEfiAcpiTableProtocolGuid,
NULL,
(VOID **)&AcpiTable
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
goto Exit;
}
//
// Read SSDT firmware file by GUID from Firmware Volume
//
Status = GetSectionFromFv (
&gAddressTranslationDsmSsdtFileGuid,
&SsdtData,
&SsdtSize
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
goto Exit;
}
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Enter PatchSsdt\n"));
//
// Search for the SSDT signature pattern to patch.
// Pattern: ExtOpPrefix (0x5B), OpRegion/CreateField (0x80), "BUFF" signature,
// 0x00, 0x0C (DWordConst), <4-byte address>, 0x0C (DWordConst)
//
Offset = (UINTN)SsdtData + 36;
EndOffset = (UINTN)SsdtData + *(UINT32 *)((UINTN)SsdtData + 4) + (UINTN)SsdtData - 16;
while (Offset < EndOffset) {
Data = (UINT8 *)Offset;
if (Data[0] == 0x5B && // ExtOpPrefix
Data[1] == 0x80 && // CreateField/OpRegion
*(UINT32 *)&Data[2] == 0x46465542 && // "BUFF"
Data[6] == 0x00 &&
Data[7] == 0x0C && // DWordConst
Data[12] == 0x0C) { // DWordConst
//
// Patch the buffer address to point to the communication buffer
//
*(UINT32 *)&Data[8] = (UINT32)(UINTN)mCommunicationBuffer;
*(UINT32 *)&Data[13] = sizeof (ADDRESS_TRANSLATION_DSM_COMMUNICATION_BUFFER);
break;
}
Offset++;
}
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Exit PatchSsdt: %r\n", Status));
if (Status < 0) {
ASSERT_EFI_ERROR (Status);
return Status;
}
//
// Install the SSDT ACPI table
//
{
UINTN TableKey = 0;
Status = AcpiTable->InstallAcpiTable (
AcpiTable,
SsdtData,
SsdtSize,
&TableKey
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
}
DEBUG ((EFI_D_INFO, "[AddressTranslationDsm] Exit InstallSsdt: %r\n", Status));
Exit:
return Status;
}
/**
Read a section from Firmware Volume by GUID.
@param[in] FileGuid The GUID identifying the file in FV.
@param[out] Buffer Pointer to receive the buffer.
@param[out] Size Pointer to receive the size.
@return EFI_STATUS.
**/
EFI_STATUS
GetSectionFromFv (
IN EFI_GUID *FileGuid,
OUT VOID **Buffer,
OUT UINTN *Size
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
VOID *FvInstance;
//
// Locate firmware volume protocol by image handle
//
if (gImageHandle == NULL) {
ASSERT (gImageHandle != NULL);
return EFI_UNSUPPORTED;
}
Status = gBS->OpenProtocol (
gImageHandle,
&gEfiFirmwareVolume2ProtocolGuid,
&FvInstance,
gImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
return Status;
}
*Buffer = 0;
*Size = 0;
//
// Read the raw file section
//
Status = FvProtocol->ReadSection (
FvInstance,
FileGuid,
EFI_SECTION_RAW,
0,
Buffer,
Size
);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (*Buffer != NULL);
ASSERT (*Size != 0);
return EFI_SUCCESS;
}
/**
Module entry point.
Attempts to initialize and start the Address Translation DSM driver.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@return EFI_STATUS.
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
//
// Initialize boot services and SMM globals
//
UefiBootServicesTableLibConstructor (ImageHandle, SystemTable);
//
// Set module status to EFI_SUCCESS initially
//
mModuleStatus = 0x8000000000000001uLL;
//
// Attempt to initialize with SetJump for error recovery
//
if (SetJump (&JumpBuffer) == 0) {
Status = AddressTranslationDsmEntry ();
//
// Update module status if needed
//
if (Status >= 0 || mModuleStatus < 0) {
mModuleStatus = Status;
}
}
LongJump (&JumpBuffer, -1);
//
// Check final status and free memory if failed
//
Status = mModuleStatus;
if (Status < 0) {
FreeMemory (mCommunicationBuffer);
}
return Status;
}