Newer
Older
AMI-Aptio-BIOS-Reversed / GenericElog / GenericElog.c
@Ajax Dong Ajax Dong 2 days ago 23 KB Init
/**
 * GenericElog.efi - Generic Event Log Driver for HR650X BIOS
 *
 * Source: HR650X_3647_AJAX_BIOS_ORIGINAL.pe_structured/pe_files/0119_GenericElog_ed8309653316/GenericElog.efi
 * MD5: 505105199f916015a6ce128e8f6215fd
 * SHA256: ed83096533163eb95940b41647b5dc6d8e7d33fc2627d97879f818df94daead9
 */

#include "GenericElog.h"

//
// External GUID declarations (from .rdata section)
//
extern EFI_GUID gEfiGenericElogProtocolGuid;
extern EFI_GUID gEfiRedirElogProtocolGuid;
extern EFI_GUID gEfiGenericElogProtocolGuid_DevicePath;

//
// Globals
//
STATIC EFI_HANDLE                  gImageHandle           = NULL;
STATIC EFI_SYSTEM_TABLE            *gSystemTable          = NULL;
STATIC EFI_BOOT_SERVICES           *gBootServices         = NULL;
STATIC EFI_RUNTIME_SERVICES        *gRuntimeServices      = NULL;
STATIC EFI_RUNTIME_SERVICES        *gRuntimeServicesCopy  = NULL;
STATIC EFI_BOOT_SERVICES           *gBootServicesCopy     = NULL;

//
// The local structure that holds redirect-protocol pointers
// and the function dispatch table.
//
STATIC VOID                        *gElogLocalStructure   = NULL;

//
// Debug / assertion output handle
//
STATIC VOID                        *gDebugOutputHandle    = NULL;

//
// HOB list pointer (discovered during init)
//
STATIC VOID                        *gHobList              = NULL;

//
// Helper: ZeroMemory wrapper (originally sub_1000)
//
STATIC
VOID *
EFIAPI
InternalZeroMem (
  IN VOID   *Buffer,
  IN UINTN  Length
  )
{
  //
  // This is a simplified memset(0) for the given buffer.
  // The original implementation used 8-byte aligned stores
  // followed by a byte-wise tail.
  //
  ZeroMem (Buffer, Length);
  return Buffer;
}

//
// Helper: ASSERT-style debug print (originally sub_1834)
// Returns the debug output handle (if available).
//
STATIC
VOID *
EFIAPI
GetDebugOutputHandle (
  VOID
  )
{
  if (gDebugOutputHandle == NULL && gBootServicesCopy != NULL) {
    UINTN  PageCount;
    PageCount = (UINTN)gBootServicesCopy->CalculateTimerValue (31);
    gBootServicesCopy->Stall (PageCount);
    if (PageCount <= 16) {
      EFI_STATUS  Status;
      Status = gBootServicesCopy->LocateProtocol (
                                    &gEfiGenericElogProtocolGuid_DevicePath,
                                    NULL,
                                    &gDebugOutputHandle
                                    );
      if (EFI_ERROR (Status)) {
        gDebugOutputHandle = NULL;
      }
    }
  }
  return gDebugOutputHandle;
}

//
// Helper: Log a debug message (originally sub_18BC)
//
STATIC
EFI_STATUS
EFIAPI
DebugLog (
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  )
{
  EFI_STATUS  Status;
  VOID        *OutputHandle;
  UINT8       BiosDebugLevel;

  OutputHandle = GetDebugOutputHandle ();
  if (OutputHandle == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Read CMOS offset 0x4B to determine the current debug level.
  // If the debug level is <= 3, clamp it.
  //
  BiosDebugLevel = IoRead8 (0x70);
  IoWrite8 (0x70, (UINT8)(BiosDebugLevel & 0x80) | 0x4B);
  BiosDebugLevel = IoRead8 (0x71);
  if (BiosDebugLevel > 3) {
    BiosDebugLevel = 3;
  }

  if ((BiosDebugLevel - 1) <= MAX_UINT8 - 2) {
    //
    // Map BIOS debug level to EFI debug mask.
    //
    UINTN  DebugMask = 0x80000400;    // EFI_D_ERROR (default)
    if (BiosDebugLevel == 1) {
      DebugMask = 0x80000004;         // EFI_D_INFO
    }

    if ((DebugMask & ErrorLevel) != 0) {
      VA_LIST  Args;
      VA_START (Args, Format);
      Status = ((EFI_DEBUG_OUTPUT_PROTOCOL *)OutputHandle)->DebugPrint (
                                                             ErrorLevel,
                                                             Format,
                                                             Args
                                                             );
      VA_END (Args);
      return Status;
    }
  }

  return EFI_INVALID_PARAMETER;
}

//
// Helper: ASSERT-style fatal (originally sub_193C)
//
STATIC
VOID
EFIAPI
AssertFatal (
  IN CONST CHAR8 *FileName,
  IN UINTN       LineNumber,
  IN CONST CHAR8 *AssertText
  )
{
  EFI_STATUS          Status;
  VOID                *OutputHandle;

  OutputHandle = GetDebugOutputHandle ();
  if (OutputHandle != NULL) {
    ((EFI_DEBUG_OUTPUT_PROTOCOL *)OutputHandle)->DebugAssert (
                                                   FileName,
                                                   LineNumber,
                                                   AssertText
                                                   );
  }
}

//
// Boot-services-cleanup notification (originally sub_197C)
//
STATIC
VOID
EFIAPI
OnExitBootServices (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  gBootServicesCopy = NULL;
}

//
// Virtual-address-change notification (originally sub_1988)
//
STATIC
VOID
EFIAPI
OnVirtualAddressChange (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  if (gDebugOutputHandle != NULL) {
    gRuntimeServices->ConvertPointer (0, (VOID **)&gDebugOutputHandle);
  }
}

//
// Allocate zeroed pool (originally sub_19B0)
//
STATIC
VOID *
EFIAPI
AllocateZeroedPool (
  IN UINTN  AllocationSize
  )
{
  VOID        *Buffer;
  EFI_STATUS  Status;

  Status = gBootServices->AllocatePool (
                            EfiBootServicesData,
                            AllocationSize,
                            &Buffer
                            );
  if (EFI_ERROR (Status)) {
    return NULL;
  }
  ZeroMem (Buffer, AllocationSize);
  return Buffer;
}

//
// Free pool with ASSERT (originally sub_19E8)
//
STATIC
EFI_STATUS
EFIAPI
FreePoolOrAssert (
  IN VOID  *Buffer
  )
{
  EFI_STATUS  Status;

  Status = gBootServices->FreePool (Buffer);
  if (EFI_ERROR (Status)) {
    DebugLog (
      EFI_D_ERROR,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      Status
      );
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiMemoryAllocationLib\\MemoryAllocationLib.c",
      819,
      "!EFI_ERROR (Status)"
      );
  }
  return Status;
}

//
// Create a notification event and register for protocol callbacks
// (originally sub_1A2C)
//
STATIC
VOID *
EFIAPI
CreateProtocolNotifyEvent (
  IN EFI_GUID               *ProtocolGuid,
  IN EFI_TPL                NotifyTpl,
  IN EFI_EVENT_NOTIFY       NotifyFunction,
  IN VOID                   *Registration OPTIONAL
  )
{
  EFI_STATUS  Status;
  VOID        *RegistrationLocal;

  if (Registration == NULL) {
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiLib\\UefiLib.c",
      154,
      "Registration != ((void *) 0)"
      );
  }

  Status = gBootServices->CreateEvent (
                            EVT_NOTIFY_SIGNAL,
                            NotifyTpl,
                            NotifyFunction,
                            NULL,
                            &RegistrationLocal
                            );
  if (EFI_ERROR (Status)) {
    DebugLog (EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiLib\\UefiLib.c",
      167,
      "!EFI_ERROR (Status)"
      );
  }

  Status = gBootServices->RegisterProtocolNotify (
                            ProtocolGuid,
                            RegistrationLocal,
                            Registration
                            );
  if (EFI_ERROR (Status)) {
    DebugLog (EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiLib\\UefiLib.c",
      179,
      "!EFI_ERROR (Status)"
      );
  }

  return RegistrationLocal;
}

//
// Discover HOB list from the System Table (originally sub_1B18)
//
STATIC
VOID *
EFIAPI
GetHobList (
  VOID
  )
{
  UINTN       Index;
  UINTN       Offset;

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

  gHobList = NULL;

  if (gSystemTable->NumberOfTableEntries > 0) {
    Offset = 0;
    for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
      if (CompareGuid (
            (EFI_GUID *)((UINT8 *)gSystemTable->ConfigurationTable + Offset),
            &gEfiGenericElogProtocolGuid
            ))
      {
        gHobList = *(VOID **)((UINT8 *)gSystemTable->ConfigurationTable + Offset + 16);
        break;
      }
      Offset += sizeof (EFI_CONFIGURATION_TABLE);
    }
  }

  if (gHobList == NULL) {
    DebugLog (EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND);
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      54,
      "!EFI_ERROR (Status)"
      );
  }

  if (gHobList == NULL) {
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      55,
      "mHobList != ((void *) 0)"
      );
  }

  return gHobList;
}

//
// GUID comparison helper (originally sub_1BF0)
//
STATIC
BOOLEAN
EFIAPI
CompareGuidPair (
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  )
{
  //
  // Compare two GUIDs by reading them as 64-bit halves.
  //
  EFI_GUID  LocalGuid1;
  EFI_GUID  LocalGuid2;

  LocalGuid1 = *(EFI_GUID *)Guid1;
  LocalGuid2 = *(EFI_GUID *)Guid2;

  return CompareGuid (&LocalGuid1, &LocalGuid2);
}

//
// Read unaligned UINT64 (originally sub_1C60)
//
STATIC
UINT64
EFIAPI
ReadUnaligned64 (
  IN VOID  *Buffer
  )
{
  if (Buffer == NULL) {
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      "Buffer != ((void *) 0)"
      );
  }
  return *(UINT64 *)Buffer;
}

// =========================================================================
// Virtual-address-change handler (originally sub_1364)
//
// Converts pointers in the gElogLocalStructure for runtime.
// =========================================================================
STATIC
VOID
EFIAPI
ElogVirtualAddressChangeEvent (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  UINT8   Count;
  UINT8   Index;

  //
  // Convert each redirect handle pointer in the array
  // (8 bytes per pointer, 4 fields per handle: base, +8, +16, +24).
  //
  Count = *(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET);
  for (Index = 0; Index < Count; Index++) {
    gRuntimeServices->ConvertPointer (
                       0,
                       (VOID **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET + 8 * Index)
                       );
    gRuntimeServices->ConvertPointer (
                       0,
                       (VOID **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET + 8 * Index + 8)
                       );
    gRuntimeServices->ConvertPointer (
                       0,
                       (VOID **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET + 8 * Index + 16)
                       );
    gRuntimeServices->ConvertPointer (
                       0,
                       (VOID **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET + 8 * Index + 24)
                       );
    gRuntimeServices->ConvertPointer (
                       0,
                       (VOID **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET + 8 * Index)
                       );
  }

  //
  // Convert the structure's base pointers.
  //
  gRuntimeServices->ConvertPointer (0, (VOID **)&gElogLocalStructure + 8);
  gRuntimeServices->ConvertPointer (0, (VOID **)&gElogLocalStructure + 16);
  gRuntimeServices->ConvertPointer (0, (VOID **)&gElogLocalStructure + 24);
}

// =========================================================================
// Enumerate redirect protocols (originally sub_146C)
//
// Locates all handles that publish gEfiRedirElogProtocolGuid and stores
// up to ELOG_MAX_REDIRECTS of them in gElogLocalStructure.
// =========================================================================
STATIC
VOID
EFIAPI
EnumerateRedirectProtocols (
  VOID
  )
{
  EFI_STATUS           Status;
  UINTN                HandleCount;
  EFI_HANDLE           *HandleBuffer;
  UINTN                Index;
  EFI_REDIR_ELOG_PROTOCOL  *RedirElog;

  //
  // Reset the redirect count.
  //
  *(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET) = 0;
  InternalZeroMem (
    (UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET,
    0x28
    );

  Status = gBootServices->LocateHandleBuffer (
                            ByProtocol,
                            &gEfiRedirElogProtocolGuid,
                            NULL,
                            &HandleCount,
                            &HandleBuffer
                            );
  DebugLog (
    EFI_D_INFO,
    " LocateHandleBuffer: gEfiRedirElogProtocolGuid Status: %r NumberOfRedirects: %x \n",
    Status,
    HandleCount
    );

  if (!EFI_ERROR (Status)) {
    if (HandleCount <= ELOG_MAX_REDIRECTS) {
      while (HandleCount > 0) {
        HandleCount--;
        Status = gBootServices->HandleProtocol (
                                  HandleBuffer[HandleCount],
                                  &gEfiRedirElogProtocolGuid,
                                  (VOID **)&RedirElog
                                  );
        if (!EFI_ERROR (Status) && RedirElog != NULL) {
          ((EFI_REDIR_ELOG_PROTOCOL **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET))
            [ELOG_MAX_REDIRECTS - HandleCount - 1] = RedirElog;
          (*(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET))++;
        }
      }
    }
  }

  if (HandleBuffer != NULL) {
    FreePoolOrAssert (HandleBuffer);
  }
}

// =========================================================================
// GenericElogWriteEvent - dispatch to redirect handlers (originally sub_1550)
// =========================================================================
EFI_STATUS
EFIAPI
GenericElogWriteEvent (
  IN  UINT8                  *EventLogEntry,
  IN  UINT64                 EventLogLength,
  IN  UINT8                  LogType,
  IN  UINT64                 *Attributes,
  IN  UINT64                 *Policy,
  OUT UINT64                 *EventLogEntryAddress
  )
{
  UINT8       Index;
  EFI_STATUS  Status;

  //
  // Maximum log type check.
  //
  if (LogType >= ELOG_MAX_REDIRECTS) {
    return EFI_INVALID_PARAMETER;
  }

  Status = EFI_NOT_FOUND;
  if (*(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET) != 0) {
    for (Index = 0; Index < *(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET); Index++) {
      Status = ((EFI_REDIR_ELOG_PROTOCOL **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET))[Index]
        ->WriteEvent (
           EventLogEntry,
           EventLogLength,
           LogType,
           Attributes,
           Policy,
           EventLogEntryAddress
           );
      if (Status != EFI_NOT_FOUND) {
        break;
      }
    }
  }

  return Status;
}

// =========================================================================
// GenericElogReadEvent - dispatch to redirect handlers (originally sub_160C)
// =========================================================================
EFI_STATUS
EFIAPI
GenericElogReadEvent (
  IN  UINT8                  *EventLogEntry,
  IN  UINT64                 EventLogLength,
  IN  UINT8                  LogType,
  IN  UINT64                 *Attributes
  )
{
  UINT8       Index;
  EFI_STATUS  Status;

  if (LogType >= ELOG_MAX_REDIRECTS) {
    return EFI_INVALID_PARAMETER;
  }

  if (*(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET) == 0) {
    return EFI_NOT_FOUND;
  }

  for (Index = 0; Index < *(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET); Index++) {
    Status = ((EFI_REDIR_ELOG_PROTOCOL **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET))[Index]
      ->ReadEvent (
         EventLogEntry,
         EventLogLength,
         LogType,
         Attributes
         );
    if (Status != EFI_NOT_FOUND) {
      return Status;
    }
  }

  return EFI_NOT_FOUND;
}

// =========================================================================
// GenericElogGetStatus - dispatch to redirect handlers (originally sub_16B0)
// =========================================================================
EFI_STATUS
EFIAPI
GenericElogGetStatus (
  IN  UINT8                  LogType,
  OUT UINT64                 *Status
  )
{
  UINT8       Index;
  EFI_STATUS  Result;

  if (LogType >= ELOG_MAX_REDIRECTS) {
    return EFI_INVALID_PARAMETER;
  }

  if (*(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET) == 0) {
    return EFI_NOT_FOUND;
  }

  for (Index = 0; Index < *(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET); Index++) {
    Result = ((EFI_REDIR_ELOG_PROTOCOL **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET))[Index]
      ->GetStatus (
         LogType,
         Status
         );
    if (Result != EFI_NOT_FOUND) {
      return Result;
    }
  }

  return EFI_NOT_FOUND;
}

// =========================================================================
// GenericElogSetStatus - dispatch to redirect handlers (originally sub_1738)
// =========================================================================
EFI_STATUS
EFIAPI
GenericElogSetStatus (
  IN  UINT8                  LogType,
  IN  UINT64                 Status
  )
{
  UINT8       Index;
  EFI_STATUS  Result;

  if (LogType >= ELOG_MAX_REDIRECTS) {
    return EFI_INVALID_PARAMETER;
  }

  if (*(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET) == 0) {
    return EFI_NOT_FOUND;
  }

  for (Index = 0; Index < *(UINT8 *)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_COUNT_OFFSET); Index++) {
    Result = ((EFI_REDIR_ELOG_PROTOCOL **)((UINT8 *)gElogLocalStructure + ELOG_STRUCT_REDIR_ARRAY_OFFSET))[Index]
      ->SetStatus (
         LogType,
         Status
         );
    if (Result != EFI_NOT_FOUND) {
      return Result;
    }
  }

  return EFI_NOT_FOUND;
}

// =========================================================================
// Module initialization (originally sub_1108)
//
// Saves ImageHandle / SystemTable / BootServices / RuntimeServices,
// creates the exit-boot-services event and the virtual-address-change
// event, then discovers the HOB list.
// =========================================================================
STATIC
EFI_STATUS
EFIAPI
ElogDriverInit (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  //
  // Save globals.
  //
  gImageHandle = ImageHandle;
  if (gImageHandle == NULL) {
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      "gImageHandle != ((void *) 0)"
      );
  }

  gSystemTable = SystemTable;
  if (gSystemTable == NULL) {
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      57,
      "gST != ((void *) 0)"
      );
  }

  gBootServices = SystemTable->BootServices;
  if (gBootServices == NULL) {
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      63,
      "gBS != ((void *) 0)"
      );
  }

  gRuntimeServices = SystemTable->RuntimeServices;
  if (gRuntimeServices == NULL) {
    AssertFatal (
      "e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
      47,
      "gRT != ((void *) 0)"
      );
  }

  //
  // Save copies for runtime conversion.
  //
  gRuntimeServicesCopy = gRuntimeServices;
  gBootServicesCopy    = gBootServices;

  //
  // Create ExitBootServices notification that clears the BS copy.
  //
  gBootServices->CreateEvent (
                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
                  TPL_NOTIFY,
                  OnExitBootServices,
                  NULL
                  );

  //
  // Create protocol notification for the GenericElog protocol,
  // which triggers redirect-protocol enumeration.
  //
  gBootServices->CreateEvent (
                  EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  EnumerateRedirectProtocols,
                  NULL
                  );

  //
  // Create VirtualAddressChange notification to convert pointers.
  //
  gBootServices->CreateEvent (
                  EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
                  TPL_NOTIFY,
                  ElogVirtualAddressChangeEvent,
                  NULL
                  );

  //
  // Discover the HOB list.
  //
  return (EFI_STATUS)GetHobList ();
}

// =========================================================================
// Module entry point (originally ModuleEntryPoint at 0x10C4)
//
// See GenericElogEntryPoint in the header.
// =========================================================================
EFI_STATUS
EFIAPI
GenericElogEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;

  //
  // Stage 1: Save globals, create events, discover HOBs.
  //
  ElogDriverInit (ImageHandle, SystemTable);

  //
  // Stage 2: Allocate the local structure, set up the protocol dispatch,
  // install the GenericElog protocol, enumerate redirects, and register
  // the virtual-address-change event handler.
  //
  Status = (EFI_STATUS)(UINTN)ElogDriverMain ();
  if (EFI_ERROR (Status)) {
    //
    // Clean up resources on failure.
    //
    if (gBootServicesCopy != NULL) {
      gBootServicesCopy->CloseEvent ((EFI_EVENT)gBootServicesCopy);
    }
    if (gBootServicesCopy != NULL) {
      gBootServicesCopy->CloseEvent ((EFI_EVENT)gBootServicesCopy);
    }
  }

  return Status;
}

// =========================================================================
// Driver main (originally sub_1210)
//
// Allocates the gElogLocalStructure, fills in the dispatch table,
// installs the GenericElog protocol, enumerates redirect handlers,
// creates the virtual-address-change event, and registers the
// notification event for the RedirElog protocol.
// =========================================================================
STATIC
EFI_STATUS
EFIAPI
ElogDriverMain (
  VOID
  )
{
  EFI_STATUS                   Status;
  VOID                         *Registration;
  EFI_GENERIC_ELOG_PROTOCOL    *GenericElog;
  //
  // The dispatch function pointers are embedded in the local structure.
  //

  //
  // Allocate the local structure (0x49 bytes).
  //
  gElogLocalStructure = AllocateZeroedPool (0x49);
  if (gElogLocalStructure == NULL) {
    DebugLog (
      EFI_D_ERROR,
      "Failed to allocate memory for gElogLocalStructure! \n"
      );
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Fill in the dispatch table at the beginning of the structure.
  //
  *(VOID **)((UINT8 *)gElogLocalStructure + 0)  = GenericElogWriteEvent;
  *(VOID **)((UINT8 *)gElogLocalStructure + 8)  = GenericElogReadEvent;
  *(VOID **)((UINT8 *)gElogLocalStructure + 16) = GenericElogGetStatus;
  *(VOID **)((UINT8 *)gElogLocalStructure + 24) = GenericElogSetStatus;

  //
  // Install the GenericElog protocol.
  //
  Status = gBootServices->InstallProtocolInterface (
                            &gImageHandle,
                            &gEfiGenericElogProtocolGuid,
                            EFI_NATIVE_INTERFACE,
                            gElogLocalStructure
                            );
  DebugLog (
    EFI_D_INFO,
    "gEfiGenericElogProtocolGuid protocol  status %r\n",
    Status
    );

  if (!EFI_ERROR (Status)) {
    //
    // Enumerate existing redirect protocols and register for new ones.
    //
    Registration = CreateProtocolNotifyEvent (
                     &gEfiRedirElogProtocolGuid,
                     EnumerateRedirectProtocols,
                     &Registration
                     );
    DebugLog (
      EFI_D_INFO,
      "Create Notification event for RedirElogProtocol GUID...RedirElogNotifyEvent: %x \n",
      Registration
      );

    //
    // Create the VirtualAddressChange event.
    //
    gBootServices->CreateEvent (
                    EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
                    TPL_NOTIFY,
                    OnVirtualAddressChange,
                    NULL
                    );

    return EFI_SUCCESS;
  } else {
    FreePoolOrAssert (gElogLocalStructure);
    gElogLocalStructure = NULL;
  }

  return Status;
}