From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001
From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com>
Date: Tue, 10 Oct 2023 14:33:42 +0000
Subject: Add submodule dependency files

Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
---
 .../Acpi/BootScriptExecutorDxe/ScriptExecute.c     | 497 +++++++++++++++++++++
 1 file changed, 497 insertions(+)
 create mode 100644 roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c

(limited to 'roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c')

diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c
new file mode 100644
index 000000000..b2ae9ec3a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c
@@ -0,0 +1,497 @@
+/** @file
+  This is the code for Boot Script Executer module.
+
+  This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory
+  in the entry point. The functionality is to interpret and restore the S3 boot script
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ScriptExecute.h"
+
+EFI_GUID              mBootScriptExecutorImageGuid = {
+  0x9a8d3433, 0x9fe8, 0x42b6, { 0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b }
+};
+
+BOOLEAN               mPage1GSupport = FALSE;
+UINT64                mAddressEncMask = 0;
+
+/**
+  Entry function of Boot script exector. This function will be executed in
+  S3 boot path.
+  This function should not return, because it is invoked by switch stack.
+
+  @param  AcpiS3Context    a pointer to a structure of ACPI_S3_CONTEXT
+  @param  PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE
+
+  @retval EFI_INVALID_PARAMETER - OS waking vector not found
+  @retval EFI_UNSUPPORTED - something wrong when we resume to OS
+**/
+EFI_STATUS
+EFIAPI
+S3BootScriptExecutorEntryFunction (
+  IN ACPI_S3_CONTEXT       *AcpiS3Context,
+  IN PEI_S3_RESUME_STATE   *PeiS3ResumeState
+  )
+{
+  EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
+  EFI_STATUS                                    Status;
+  UINTN                                         TempStackTop;
+  UINTN                                         TempStack[0x10];
+  UINTN                                         AsmTransferControl16Address;
+  IA32_DESCRIPTOR                               IdtDescriptor;
+
+  //
+  // Disable interrupt of Debug timer, since new IDT table cannot handle it.
+  //
+  SaveAndSetDebugTimerInterrupt (FALSE);
+
+  AsmReadIdtr (&IdtDescriptor);
+  //
+  // Restore IDT for debug
+  //
+  SetIdtEntry (AcpiS3Context);
+
+  //
+  // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer.
+  //
+  InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL);
+
+  //
+  // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL
+  // for that parameter.
+  //
+  Status = S3BootScriptExecute ();
+
+  //
+  // If invalid script table or opcode in S3 boot script table.
+  //
+  ASSERT_EFI_ERROR (Status);
+
+  if (EFI_ERROR (Status)) {
+    CpuDeadLoop ();
+    return Status;
+  }
+
+  AsmWbinvd ();
+
+  //
+  // Get ACPI Table Address
+  //
+  Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
+
+  //
+  // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.
+  //
+  if (PeiS3ResumeState != 0) {
+    //
+    // Need report status back to S3ResumePeim.
+    // If boot script execution is failed, S3ResumePeim wil report the error status code.
+    //
+    PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;
+    if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+      //
+      // X64 S3 Resume
+      //
+      DEBUG ((DEBUG_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
+      PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32;
+
+      if ((Facs != NULL) &&
+          (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) &&
+          (Facs->FirmwareWakingVector != 0) ) {
+        //
+        // more step needed - because relative address is handled differently between X64 and IA32.
+        //
+        AsmTransferControl16Address = (UINTN)AsmTransferControl16;
+        AsmFixAddress16 = (UINT32)AsmTransferControl16Address;
+        AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12));
+      }
+
+      AsmDisablePaging64 (
+        PeiS3ResumeState->ReturnCs,
+        (UINT32)PeiS3ResumeState->ReturnEntryPoint,
+        (UINT32)(UINTN)AcpiS3Context,
+        (UINT32)(UINTN)PeiS3ResumeState,
+        (UINT32)PeiS3ResumeState->ReturnStackPointer
+        );
+    } else {
+      //
+      // IA32 S3 Resume
+      //
+      DEBUG ((DEBUG_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
+      PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl;
+
+      SwitchStack (
+        (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,
+        (VOID *)(UINTN)AcpiS3Context,
+        (VOID *)(UINTN)PeiS3ResumeState,
+        (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer
+        );
+    }
+
+    //
+    // Never run to here
+    //
+    CpuDeadLoop();
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly
+  //
+  if (Facs->XFirmwareWakingVector != 0) {
+    //
+    // Switch to native waking vector
+    //
+    TempStackTop = (UINTN)&TempStack + sizeof(TempStack);
+    if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
+        ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
+        ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
+      //
+      // X64 long mode waking vector
+      //
+      DEBUG ((DEBUG_INFO, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
+      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+        SwitchStack (
+          (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
+          NULL,
+          NULL,
+          (VOID *)(UINTN)TempStackTop
+          );
+      } else {
+        // Unsupported for 32bit DXE, 64bit OS vector
+        DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));
+        ASSERT (FALSE);
+      }
+    } else {
+      //
+      // IA32 protected mode waking vector (Page disabled)
+      //
+      DEBUG ((DEBUG_INFO, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
+      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+        AsmDisablePaging64 (
+          0x10,
+          (UINT32)Facs->XFirmwareWakingVector,
+          0,
+          0,
+          (UINT32)TempStackTop
+          );
+      } else {
+        SwitchStack (
+          (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
+          NULL,
+          NULL,
+          (VOID *)(UINTN)TempStackTop
+          );
+      }
+    }
+  } else {
+    //
+    // 16bit Realmode waking vector
+    //
+    DEBUG ((DEBUG_INFO, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));
+    AsmTransferControl (Facs->FirmwareWakingVector, 0x0);
+  }
+
+  //
+  // Never run to here
+  //
+  CpuDeadLoop();
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Register image to memory profile.
+
+  @param FileName       File name of the image.
+  @param ImageBase      Image base address.
+  @param ImageSize      Image size.
+  @param FileType       File type of the image.
+
+**/
+VOID
+RegisterMemoryProfileImage (
+  IN EFI_GUID                       *FileName,
+  IN PHYSICAL_ADDRESS               ImageBase,
+  IN UINT64                         ImageSize,
+  IN EFI_FV_FILETYPE                FileType
+  )
+{
+  EFI_STATUS                        Status;
+  EDKII_MEMORY_PROFILE_PROTOCOL     *ProfileProtocol;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+  UINT8                             TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
+
+  if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) {
+
+    FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
+    Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
+    if (!EFI_ERROR (Status)) {
+      EfiInitializeFwVolDevicepathNode (FilePath, FileName);
+      SetDevicePathEndNode (FilePath + 1);
+
+      Status = ProfileProtocol->RegisterImage (
+                                  ProfileProtocol,
+                                  (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
+                                  ImageBase,
+                                  ImageSize,
+                                  FileType
+                                  );
+    }
+  }
+}
+
+/**
+  This is the Event notification function to reload BootScriptExecutor image
+  to RESERVED mem and save it to LockBox.
+
+  @param    Event   Pointer to this event
+  @param    Context Event handler private data
+ **/
+VOID
+EFIAPI
+ReadyToLockEventNotify (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EFI_STATUS                                    Status;
+  VOID                                          *Interface;
+  UINT8                                         *Buffer;
+  UINTN                                         BufferSize;
+  EFI_HANDLE                                    NewImageHandle;
+  UINTN                                         Pages;
+  EFI_PHYSICAL_ADDRESS                          FfsBuffer;
+  PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR               MemDesc;
+
+  Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  //
+  // A workaround: Here we install a dummy handle
+  //
+  NewImageHandle = NULL;
+  Status = gBS->InstallProtocolInterface (
+                  &NewImageHandle,
+                  &gEfiCallerIdGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Reload BootScriptExecutor image itself to RESERVED mem
+  //
+  Status = GetSectionFromAnyFv  (
+             &gEfiCallerIdGuid,
+             EFI_SECTION_PE32,
+             0,
+             (VOID **) &Buffer,
+             &BufferSize
+             );
+  ASSERT_EFI_ERROR (Status);
+  ImageContext.Handle    = Buffer;
+  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+  //
+  // Get information about the image being loaded
+  //
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);
+  ASSERT_EFI_ERROR (Status);
+  if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+    Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
+  } else {
+    Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
+  }
+  FfsBuffer = 0xFFFFFFFF;
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiReservedMemoryType,
+                  Pages,
+                  &FfsBuffer
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Make sure that the buffer can be used to store code.
+  //
+  Status = gDS->GetMemorySpaceDescriptor (FfsBuffer, &MemDesc);
+  if (!EFI_ERROR (Status) && (MemDesc.Attributes & EFI_MEMORY_XP) != 0) {
+    gDS->SetMemorySpaceAttributes (
+           FfsBuffer,
+           EFI_PAGES_TO_SIZE (Pages),
+           MemDesc.Attributes & (~EFI_MEMORY_XP)
+           );
+  }
+
+  ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
+  //
+  // Align buffer on section boundary
+  //
+  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+  //
+  // Load the image to our new buffer
+  //
+  Status = PeCoffLoaderLoadImage (&ImageContext);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Relocate the image in our new buffer
+  //
+  Status = PeCoffLoaderRelocateImage (&ImageContext);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
+  //
+  gBS->FreePool (Buffer);
+
+  //
+  // Flush the instruction cache so the image data is written before we execute it
+  //
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+  RegisterMemoryProfileImage (
+    &gEfiCallerIdGuid,
+    ImageContext.ImageAddress,
+    ImageContext.ImageSize,
+    EFI_FV_FILETYPE_DRIVER
+    );
+
+  Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Additional step for BootScript integrity
+  // Save BootScriptExecutor image
+  //
+  Status = SaveLockBox (
+             &mBootScriptExecutorImageGuid,
+             (VOID *)(UINTN)ImageContext.ImageAddress,
+             (UINTN)ImageContext.ImageSize
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+  ASSERT_EFI_ERROR (Status);
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Entrypoint of Boot script exector driver, this function will be executed in
+  normal boot phase and invoked by DXE dispatch.
+
+  @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 is executed successfully.
+  @retval other             Some error occurs when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+BootScriptExecutorEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  UINTN                                         BufferSize;
+  UINTN                                         Pages;
+  BOOT_SCRIPT_EXECUTOR_VARIABLE                 *EfiBootScriptExecutorVariable;
+  EFI_PHYSICAL_ADDRESS                          BootScriptExecutorBuffer;
+  EFI_STATUS                                    Status;
+  VOID                                          *DevicePath;
+  EFI_EVENT                                     ReadyToLockEvent;
+  VOID                                          *Registration;
+  UINT32                                        RegEax;
+  UINT32                                        RegEdx;
+
+  if (!PcdGetBool (PcdAcpiS3Enable)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Make sure AddressEncMask is contained to smallest supported address field.
+  //
+  mAddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+  //
+  // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry
+  // point is loaded by DXE code which is the first time loaded. or else, it is already
+  // be reloaded be itself.This is a work-around
+  //
+  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);
+  if (EFI_ERROR (Status)) {
+      //
+      // Create ReadyToLock event to reload BootScriptExecutor image
+      // to RESERVED mem and save it to LockBox.
+      //
+      ReadyToLockEvent = EfiCreateProtocolNotifyEvent  (
+                           &gEfiDxeSmmReadyToLockProtocolGuid,
+                           TPL_NOTIFY,
+                           ReadyToLockEventNotify,
+                           NULL,
+                           &Registration
+                           );
+      ASSERT (ReadyToLockEvent != NULL);
+    } else {
+      //
+      // the entry point is invoked after reloading. following code only run in RESERVED mem
+      //
+      if (PcdGetBool(PcdUse1GPageTable)) {
+        AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+        if (RegEax >= 0x80000001) {
+          AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+          if ((RegEdx & BIT26) != 0) {
+            mPage1GSupport = TRUE;
+          }
+        }
+      }
+
+      BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE);
+
+      BootScriptExecutorBuffer = 0xFFFFFFFF;
+      Pages = EFI_SIZE_TO_PAGES(BufferSize);
+      Status = gBS->AllocatePages (
+                      AllocateMaxAddress,
+                      EfiReservedMemoryType,
+                      Pages,
+                      &BootScriptExecutorBuffer
+                      );
+      ASSERT_EFI_ERROR (Status);
+
+      EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer;
+      EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ;
+
+      Status = SaveLockBox (
+                 &gEfiBootScriptExecutorVariableGuid,
+                 &BootScriptExecutorBuffer,
+                 sizeof(BootScriptExecutorBuffer)
+                 );
+      ASSERT_EFI_ERROR (Status);
+
+      //
+      // Additional step for BootScript integrity
+      // Save BootScriptExecutor context
+      //
+      Status = SaveLockBox (
+                 &gEfiBootScriptExecutorContextGuid,
+                 EfiBootScriptExecutorVariable,
+                 sizeof(*EfiBootScriptExecutorVariable)
+                 );
+      ASSERT_EFI_ERROR (Status);
+
+      Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+      ASSERT_EFI_ERROR (Status);
+    }
+
+    return EFI_SUCCESS;
+}
+
-- 
cgit