The StartupVector member of ACPI_CPU_DATA points to low level assembly
code that starts out in real mode, and is the boot code that gets run on
each AP in response to an INIT-Start-up-Start-up IPI sequence.

Importantly, *each* one of PiSmmCpuDxeSmm and CpuMpDxe (from
Quark_EDKII_v1.1.0/IA32FamilyCpuBasePkg/) has its own, private startup
vector implementation. They are similar, and are located in the respective
"IA32/MpFuncs.S" files (named RendezvousFunnelProcStart()).

With regard to the communication from CpuMpDxe to PiSmmCpuDxeSmm,
PiSmmCpuDxeSmm does not reuse CpuMpDxe's startup vector on the S3 resume
path (which would be unsafe anyway, unless the startup vector itself were
saved in SMRAM). PiSmmCpuDxeSmm only reuses (and overwrites) the reserved
memory *buffer* underneath ACPI_CPU_DATA.StartupVector that CpuMpDxe
allocated.

Therefore in this patch we only cover the allocation in our CpuS3DataDxe
driver; we can ignore everything else that CpuMpDxe would otherwise do
with its own startup vector.

PiSmmCpuDxeSmm silently assumes that its startup vector (plus the BSP-AP
communication structure that follows it directly) are not larger than the
same pair from CpuMpDxe. Because our CpuS3DataDxe driver has no such
things to key the allocation size off of, we allocate a single page (which
in practice is already larger than the original pair from CpuMpDxe).
PiSmmCpuDxeSmm should assert or enforce that this page is sufficient for
PiSmmCpuDxeSmm's startup vector and BSP-AP communication area.

The code added to CpuS3DataDxe is a little awkward; it looks like this
because it is built from positionally correct snippets (modified as
necessary) lifted from CpuMpDxe, preserving the original control flow:

  entry point (MultiProcessorInitialize() vs. CpuS3DataInitialize())
    ProcessorConfiguration()
      WakeupAPAndCollectBist()
        PrepareAPStartupVector()
          AllocateStartupVector()
            // allocates mStartupVector

  SmmConfigurationEventNotify()
    SaveCpuS3Data()
      // sets ACPI_CPU_DATA.StartupVector to mStartupVector

  ReAllocateMemoryForAP() -- optionally, if CSM is present
    // reallocates mStartupVector from legacy region
    // re-sets ACPI_CPU_DATA.StartupVector to mStartupVector

The CpuS3DataDxe subdirectory is supposed to be diffable against the
original CpuMpDxe.

(In fact the original CpuMpDxe has a bug; it *only* sets
mAcpiCpuData->StartupVector to mStartupVector when the Legacy BIOS
Protocol (ie. CSM) is present, and the startup vector is relocated into
the E or F segment.)

Starting with this patch, CpuS3DataDxe grows arch-specific dependencies,
and therefore OVMF will build for Ia32 only, when -D SMM_REQUIRE is
specified.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---

Notes:
    v2:
    - Drop the ASSERT() that v1 added to QuarkPort/PiSmmCpuDxeSmm, about the
      size of the area pre-allocated by CpuS3DataDxe. Instead, spell out
      this idea in the commit message; with Mike we've agreed that
      UefiCpuPkg/PiSmmCpuDxeSmm will verify or enforce this in the future
      somehow.

 OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf               |   6 ++
 OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h                          |  16 +++
 OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h                     |  42 ++++++++
 OvmfPkg/QuarkPort/CpuS3DataDxe/{Cpu.h => IA32/ArchSpecific.c} |  34 +++----
 OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c                     | 107 
++++++++++++++++++++
 OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c              |  63 
++++++++++++
 6 files changed, 251 insertions(+), 17 deletions(-)

diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf 
b/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf
index efb71d4..be362d8 100644
--- a/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf
+++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf
@@ -56,13 +56,17 @@ [Sources]
   Cpu.h
 
 [Sources.Ia32]
+  IA32/ArchSpecific.c
 
 [Packages]
   MdePkg/MdePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   UefiBootServicesTableLib
+  MemoryAllocationLib
   UefiDriverEntryPoint
   BaseMemoryLib
   UefiLib
@@ -72,6 +76,7 @@ [LibraryClasses]
 [Guids]
 
 [Protocols]
+  gEfiLegacyBiosProtocolGuid                    ## SOMETIMES_CONSUMES
   gEfiSmmConfigurationProtocolGuid              # PROTOCOL ALWAYS_CONSUMED
 
 [FeaturePcd]
@@ -80,6 +85,7 @@ [FixedPcd]
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize
 
 [Depex]
   TRUE
diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h 
b/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h
index ca4816b..62faa0b 100644
--- a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h
+++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h
@@ -40,6 +40,22 @@
 
 #include "MpCommon.h"
 
+extern EFI_PHYSICAL_ADDRESS        mStartupVector;
+
+extern ACPI_CPU_DATA               *mAcpiCpuData;
+
+/**
+  Wakes up APs for the first time to count their number and collect BIST data.
+
+  This function wakes up APs for the first time to count their number and
+  collect BIST data.
+
+**/
+VOID
+WakeupAPAndCollectBist (
+  VOID
+  );
+
 /**
   Prepare ACPI NVS memory below 4G memory for use of S3 resume.
   
diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h 
b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h
index ec8a4a1..beb30f4 100644
--- a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h
+++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h
@@ -42,14 +42,40 @@
 
 #include <AcpiCpuData.h>
 
+#include <Protocol/LegacyBios.h>
 #include <Protocol/SmmConfiguration.h>
 
 #include <Library/DebugLib.h>
 #include <Library/UefiLib.h>
 #include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 
 /**
+  Allocates startup vector for APs.
+
+  This function allocates Startup vector for APs.
+
+  @param  Size  The size of startup vector.
+
+**/
+VOID
+AllocateStartupVector (
+  UINTN   Size
+  );
+
+/**
+  Prepares Startup Vector for APs.
+
+  This function prepares Startup Vector for APs.
+
+**/
+VOID
+PrepareAPStartupVector (
+  VOID
+  );
+
+/**
   Allocate EfiACPIMemoryNVS below 4G memory address.
 
   This function allocates EfiACPIMemoryNVS below 4G memory address.
@@ -64,4 +90,20 @@ AllocateAcpiNvsMemoryBelow4G (
   IN   UINTN   Size
   );
 
+/**
+  Protocol notification that is fired when LegacyBios protocol is installed.
+
+  Re-allocate a wakeup buffer from E/F segment because the previous wakeup
+  buffer under 640K won't be preserved by the legacy OS.
+
+  @param  Event                 The triggered event.
+  @param  Context               Context for this event.
+**/
+VOID
+EFIAPI
+ReAllocateMemoryForAP (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
 #endif
diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h 
b/OvmfPkg/QuarkPort/CpuS3DataDxe/IA32/ArchSpecific.c
similarity index 76%
copy from OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h
copy to OvmfPkg/QuarkPort/CpuS3DataDxe/IA32/ArchSpecific.c
index ca4816b..8bf991b 100644
--- a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h
+++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/IA32/ArchSpecific.c
@@ -1,6 +1,6 @@
 /** @file
 
-  Include file for CPU DXE Module
+  Memory Operation Functions for IA32 Architecture.
 
   Copyright (C) 2015, Red Hat, Inc.
   Copyright (c) 2013-2015 Intel Corporation.
@@ -31,27 +31,27 @@
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-  Module Name:  Cpu.h
+  Module Name:  ArchSpecific.c
 
 **/
 
-#ifndef _CPU_DXE_H_
-#define _CPU_DXE_H_
-
-#include "MpCommon.h"
+#include "Cpu.h"
+#include "MpService.h"
 
 /**
-  Prepare ACPI NVS memory below 4G memory for use of S3 resume.
-  
-  This function allocates ACPI NVS memory below 4G memory for use of S3 resume,
-  and saves data into the memory region.
+  Prepares Startup Vector for APs.
+
+  This function prepares Startup Vector for APs.
 
-  @param  Context   The Context save the info.
-  
 **/
 VOID
-SaveCpuS3Data (
-  VOID    *Context
-  );
-
-#endif
+PrepareAPStartupVector (
+  VOID
+  )
+{
+  //
+  // Allocate a 4K-aligned region under 1M for startup vector for AP.
+  // The region contains AP startup code and exchange data between BSP and AP.
+  //
+  AllocateStartupVector (SIZE_4KB);
+}
diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c 
b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c
index 6f6ddb9..6f06628 100644
--- a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c
+++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c
@@ -36,6 +36,113 @@
 **/
 
 #include "MpService.h"
+#include "Cpu.h"
+
+UINTN                 mStartupVectorSize;
+
+/**
+  Allocates startup vector for APs.
+
+  This function allocates Startup vector for APs.
+
+  @param  Size  The size of startup vector.
+
+**/
+VOID
+AllocateStartupVector (
+  UINTN   Size
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_PHYSICAL_ADDRESS                  StartAddress;
+
+  mStartupVectorSize = Size;
+  Status = EFI_NOT_FOUND;
+
+  //
+  // Allocate wakeup buffer below 640K. Don't touch legacy region.
+  // Leave some room immediately below 640K in for CSM module.
+  // PcdEbdaReservedMemorySize has been required to be a multiple of 4KB.
+  //
+  StartAddress = 0xA0000 - PcdGet32 (PcdEbdaReservedMemorySize) -
+                 (EFI_SIZE_TO_PAGES (Size) * EFI_PAGE_SIZE);
+  for (mStartupVector = StartAddress;
+       mStartupVector >= 0x2000;
+       mStartupVector -= (EFI_SIZE_TO_PAGES (Size) * EFI_PAGE_SIZE)) {
+
+    //
+    // If finally no CSM in the platform, this wakeup buffer is to be used in
+    // S3 boot path.
+    //
+    Status = gBS->AllocatePages (
+                    AllocateAddress,
+                    EfiReservedMemoryType,
+                    EFI_SIZE_TO_PAGES (Size),
+                    &mStartupVector
+                    );
+
+    if (!EFI_ERROR (Status)) {
+      break;
+    }
+  }
+
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  Protocol notification that is fired when LegacyBios protocol is installed.
+
+  Re-allocate a wakeup buffer from E/F segment because the previous wakeup
+  buffer under 640K won't be preserved by the legacy OS.
+
+  @param  Event                 The triggered event.
+  @param  Context               Context for this event.
+**/
+VOID
+EFIAPI
+ReAllocateMemoryForAP (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EFI_LEGACY_BIOS_PROTOCOL   *LegacyBios;
+  VOID                       *LegacyRegion;
+  EFI_STATUS                 Status;
+
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL,
+                  (VOID **)&LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return ;
+  }
+
+  //
+  // Allocate 4K aligned bytes from either 0xE0000 or 0xF0000.
+  // Note some CSM16 does not satisfy alignment request, so allocate a buffer
+  // of 2*4K and adjust the base address myself.
+  //
+  Status = LegacyBios->GetLegacyRegion (
+                         LegacyBios,
+                         0x2000,
+                         0,
+                         0x1000,
+                         &LegacyRegion
+                         );
+  ASSERT_EFI_ERROR (Status);
+
+  if ((((UINTN)LegacyRegion) & 0xfff) != 0) {
+    LegacyRegion =
+      (VOID *)(UINTN)((((UINTN)LegacyRegion) + 0xfff) & ~((UINTN)0xfff));
+  }
+
+  //
+  // Free original wakeup buffer
+  //
+  FreePages ((VOID *)(UINTN)mStartupVector,
+    EFI_SIZE_TO_PAGES (mStartupVectorSize));
+
+  mStartupVector = (EFI_PHYSICAL_ADDRESS)(UINTN)LegacyRegion;
+  mAcpiCpuData->StartupVector = mStartupVector;
+}
 
 /**
   Allocate EfiACPIMemoryNVS below 4G memory address.
diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c 
b/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c
index 2b5c319..9ad98ff 100644
--- a/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c
+++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c
@@ -37,6 +37,7 @@
 #include "MpService.h"
 #include "Cpu.h"
 
+EFI_PHYSICAL_ADDRESS                mStartupVector;
 ACPI_CPU_DATA                       *mAcpiCpuData;
 EFI_EVENT                           mSmmConfigurationNotificationEvent;
 EFI_HANDLE                          mImageHandle;
@@ -60,6 +61,7 @@ SmmConfigurationEventNotify (
   )
 {
   EFI_STATUS    Status;
+  VOID  *Registration;
   EFI_SMM_CONFIGURATION_PROTOCOL  *SmmConfiguration;
 
   //
@@ -75,6 +77,40 @@ SmmConfigurationEventNotify (
   // Save CPU S3 data
   //
   SaveCpuS3Data (mImageHandle);
+
+  //
+  // Setup notification on Legacy BIOS Protocol to reallocate AP wakeup
+  //
+  EfiCreateProtocolNotifyEvent (
+    &gEfiLegacyBiosProtocolGuid,
+    TPL_CALLBACK,
+    ReAllocateMemoryForAP,
+    NULL,
+    &Registration
+    );
+}
+
+/**
+  First phase MP initialization before SMM initialization.
+  
+  @retval EFI_SUCCESS      First phase MP initialization was done successfully.
+  @retval EFI_UNSUPPORTED  There is legacy APIC ID conflict and can't be
+                           rsolved in xAPIC mode.
+
+**/
+EFI_STATUS
+ProcessorConfiguration (
+  VOID
+  )
+{
+  //
+  // Wakeup APs for the first time, BSP stalls for arbitrary
+  // time for APs' completion. BSP then collects the number
+  // and BIST information of APs.
+  //
+  WakeupAPAndCollectBist ();
+
+  return EFI_SUCCESS;
 }
 
 /**
@@ -96,9 +132,17 @@ CpuS3DataInitialize (
   IN EFI_SYSTEM_TABLE                      *SystemTable
   )
 {
+  EFI_STATUS  Status;
   VOID        *Registration;
 
   mImageHandle = ImageHandle;
+  //
+  // Configure processors with three-phase architecture
+  //
+  Status = ProcessorConfiguration ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
 
   //
   // Install notification callback on SMM Configuration Protocol
@@ -115,6 +159,24 @@ CpuS3DataInitialize (
 }
 
 /**
+  Wakes up APs for the first time to count their number and collect BIST data.
+
+  This function wakes up APs for the first time to count their number and
+  collect BIST data.
+
+**/
+VOID
+WakeupAPAndCollectBist (
+  VOID
+  )
+{
+  //
+  // Prepare code and data for APs' startup vector
+  //
+  PrepareAPStartupVector ();
+}
+
+/**
   Prepare ACPI NVS memory below 4G memory for use of S3 resume.
   
   This function allocates ACPI NVS memory below 4G memory for use of S3 resume,
@@ -139,6 +201,7 @@ SaveCpuS3Data (
   // Set the value for CPU data
   //
   mAcpiCpuData                 = &(MpCpuSavedData->AcpiCpuData);
+  mAcpiCpuData->StartupVector  = mStartupVector;
 
   //
   // Set the base address of CPU S3 data to PcdCpuS3DataAddress
-- 
1.8.3.1


_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to