[edk2-devel] [PATCH v5 33/36] OvmfPkg/LoongArchVirt: Support SEC phase

Chao Li posted 36 patches 2 years, 1 month ago
Only 35 patches received!
There is a newer version of this series
[edk2-devel] [PATCH v5 33/36] OvmfPkg/LoongArchVirt: Support SEC phase
Posted by Chao Li 2 years, 1 month ago
Add SEC code for LoongArch virtual machine.

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
 OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S | 183 +++++++
 OvmfPkg/LoongArchVirt/Sec/SecMain.c           | 507 ++++++++++++++++++
 OvmfPkg/LoongArchVirt/Sec/SecMain.inf         |  53 ++
 3 files changed, 743 insertions(+)
 create mode 100644 OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
 create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.c
 create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.inf

diff --git a/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
new file mode 100644
index 0000000000..145f8ffc59
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
@@ -0,0 +1,183 @@
+#------------------------------------------------------------------------------
+#
+# Start for Loongson LoongArch processor
+#
+# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#  @par Glossary:
+#    - CSR - CPU Status Register
+#    - EBASE - Exception Base Address
+#------------------------------------------------------------------------------
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include <Library/BaseMemoryLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include <Protocol/DebugSupport.h>
+
+#define BOOTCORE_ID 0
+
+//
+// For coding convenience, define the maximum valid
+// LoongArch exception.
+// Since UEFI V2.11, it will be present in DebugSupport.h.
+//
+#define MAX_LOONGARCH_EXCEPTION  64
+
+ASM_GLOBAL ASM_PFX(_ModuleEntryPoint)
+ASM_PFX(_ModuleEntryPoint):
+  /* Disable interrupt */
+  li.d     $t0, (1 << 2)
+  csrxchg  $zero, $t0, LOONGARCH_CSR_CRMD
+
+  /* Read physical cpu number id */
+  bl       GetApicId
+  li.d     $t0, BOOTCORE_ID  //0
+  bne      $a0, $t0, SlaveMain
+
+  /* Configure BSP reset ebase */
+  li.d     $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
+  bl       SetExceptionBaseAddress
+  move     $t1, $a0
+
+  /* Set BSP stack */
+  li.d     $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize)  # stack base
+  move     $sp, $t0
+  addi.d   $sp, $sp, -0x8
+
+  /* Construct SEC and PEI step exception environment */
+  la.pcrel $a1, ExceptionEntryStart
+  la.pcrel $t0, ExceptionEntryEnd
+  sub.d    $a2, $t0, $a1
+  li.w     $t0, (MAX_LOONGARCH_EXCEPTION +  MAX_LOONGARCH_INTERRUPT) * 512
+  bgeu     $a2, $t0, DeadLoop
+  move     $a0, $t1
+  bl       CopyMem
+
+CallEntry:
+  /* Call C function make sure parameter true */
+  li.d     $a0, FixedPcdGet64(PcdOvmfFdBaseAddress) # FW base
+  addi.d   $a1, $sp, 0x8
+  bl       SecCoreStartupWithStack
+# End of _ModuleEntryPoint
+
+ASM_PFX(ClearMailBox):
+  /* Clear mailbox */
+  li.d      $t1, LOONGARCH_IOCSR_MBUF3
+  iocsrwr.d $zero, $t1
+  li.d      $t1, LOONGARCH_IOCSR_MBUF2
+  iocsrwr.d $zero, $t1
+  li.d      $t1, LOONGARCH_IOCSR_MBUF1
+  iocsrwr.d $zero, $t1
+  li.d      $t1, LOONGARCH_IOCSR_MBUF0
+  iocsrwr.d $zero, $t1
+  jirl      $zero, $ra, 0
+# End of ClearMailBox
+
+ASM_PFX(EnableIPI):
+  /* Enable IPI interrupt */
+  li.d      $t1, (1 << 12)
+  csrxchg   $t1, $t1, LOONGARCH_CSR_ECFG
+
+  addi.d    $t2, $zero, -1
+  li.d      $t1, LOONGARCH_IOCSR_IPI_EN
+  iocsrwr.w $t2, $t1
+  jirl      $zero, $ra, 0
+# End of EeableIPI
+
+#/**
+#   Get APIC ID for every CPU.
+#
+#   @param   NULL
+#   @return  APICID
+#
+#   UINTN
+#   EFI_API
+#   GetApicId (
+#     VOID
+#     )
+#**/
+ASM_PFX(GetApicId):
+  csrrd $a0, LOONGARCH_CSR_CPUNUM
+  andi  $a0, $a0, 0x3ff
+  jirl  $zero, $ra, 0
+# End of GetApicId
+
+ASM_PFX(ApInitStack):
+  li.d   $t1, SIZE_1KB 
+  csrrd  $t0, LOONGARCH_CSR_TMID
+  mul.d  $t1, $t0, $t1
+  li.d   $t2, FixedPcdGet32(PcdCpuMaxLogicalProcessorNumber)
+  bgeu   $t0, $t2, DeadLoop
+  li.d   $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize) - SIZE_64KB
+  sub.d  $sp, $t0, $t1
+  addi.d $sp, $sp, -0x8
+  jirl   $zero, $ra, 0
+# End of ApInitStack
+
+ASM_PFX(SlaveMain):
+  /* Set AP exception handle in flash */
+  la.pcrel  $a0, ApException
+  bl        SetExceptionBaseAddress
+
+  /* Clean up local mail box and open INT */
+  bl        ClearMailBox
+  bl        EnableIPI
+  bl        EnableInterrupts
+
+WaitForWake:
+  /* Wait for wakeup */
+  bl        CpuSleep
+  li.d      $t1, LOONGARCH_IOCSR_MBUF0
+  iocsrrd.w $t2, $t1
+  beqz      $t2, WaitForWake
+
+  /* Disable global interrupt */
+  bl        DisableInterrupts
+
+  /* Disable IPI interrupt */
+  li.d      $t0, (1 << 12)
+  csrxchg   $zero, $t0, LOONGARCH_CSR_ECFG
+
+  /* Read mail buf and jump to specified entry */
+  li.d      $t1, LOONGARCH_IOCSR_MBUF0
+  iocsrrd.d $t0, $t1
+  li.d      $t1, LOONGARCH_IOCSR_MBUF3
+  iocsrrd.d $a1, $t1
+  bl        ClearMailBox
+  beqz      $a1, NoParameterCall
+
+  //
+  // If the parameters are not NULL, then calling happened in FW ENV.
+  // Set the EBASE to be the same as BSP.
+  //
+  li.d      $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
+  bl        SetExceptionBaseAddress
+
+  bl        ApInitStack
+  bl        GetApicId
+NoParameterCall:
+  move      $ra, $t0
+  jirl      $zero, $ra, 0x0
+# End of SlaveMain
+
+.align 12
+ASM_PFX(ApException):
+  csrrd     $t0, LOONGARCH_CSR_ESTAT
+  srli.d    $t0, $t0, 12
+  beqz      $t0, DeadLoop
+
+  li.d      $t0, LOONGARCH_IOCSR_IPI_STATUS
+  iocsrrd.w $t1, $t0
+  li.d      $t0, LOONGARCH_IOCSR_IPI_CLEAR
+  iocsrwr.w $t1, $t0
+  ertn
+# End of ApException
+
+ASM_PFX(DeadLoop):
+  b   DeadLoop
+# End of DeadLoop
+.end
diff --git a/OvmfPkg/LoongArchVirt/Sec/SecMain.c b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
new file mode 100644
index 0000000000..a7f4324811
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
@@ -0,0 +1,507 @@
+/** @file
+  Main SEC phase code.  Transitions to PEI.
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/PeimEntryPoint.h>
+
+#include <Ppi/TemporaryRamSupport.h>
+
+/**
+  temporary memory to permanent memory and do stack switching.
+
+  @param[in]  PeiServices     Pointer to the PEI Services Table.
+  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
+  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
+  @param[in]  CopySize   The size of memory that needs to be migrated.
+
+  @retval   EFI_SUCCESS  Migration successful.
+**/
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS    TemporaryMemoryBase,
+  IN EFI_PHYSICAL_ADDRESS    PermanentMemoryBase,
+  IN UINTN                   CopySize
+  );
+
+EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI  mTemporaryRamSupportPpi = {
+  TemporaryRamMigration
+};
+
+EFI_PEI_PPI_DESCRIPTOR  mPrivateDispatchTable[] = {
+  {
+    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+    &gEfiTemporaryRamSupportPpiGuid,
+    &mTemporaryRamSupportPpi
+  },
+};
+
+/**
+  Locates a section within a series of sections
+  with the specified section type.
+
+  The Instance parameter indicates which instance of the section
+  type to return. (0 is first instance, 1 is second...)
+
+  @param[in]   Sections        The sections to search
+  @param[in]   SizeOfSections  Total size of all sections
+  @param[in]   SectionType     The section type to locate
+  @param[in]   Instance        The section instance number
+  @param[out]  FoundSection    The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindFfsSectionInstance (
+  IN  VOID                       *Sections,
+  IN  UINTN                      SizeOfSections,
+  IN  EFI_SECTION_TYPE           SectionType,
+  IN  UINTN                      Instance,
+  OUT EFI_COMMON_SECTION_HEADER  **FoundSection
+  )
+{
+  EFI_PHYSICAL_ADDRESS       CurrentAddress;
+  UINT32                     Size;
+  EFI_PHYSICAL_ADDRESS       EndOfSections;
+  EFI_COMMON_SECTION_HEADER  *Section;
+  EFI_PHYSICAL_ADDRESS       EndOfSection;
+
+  //
+  // Loop through the FFS file sections within the PEI Core FFS file
+  //
+  EndOfSection  = (EFI_PHYSICAL_ADDRESS)(UINTN)Sections;
+  EndOfSections = EndOfSection + SizeOfSections;
+  for ( ; ; ) {
+    if (EndOfSection == EndOfSections) {
+      break;
+    }
+
+    CurrentAddress = (EndOfSection + 3) & ~(3ULL);
+    if (CurrentAddress >= EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
+
+    Size = SECTION_SIZE (Section);
+    if (Size < sizeof (*Section)) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    EndOfSection = CurrentAddress + Size;
+    if (EndOfSection > EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    //
+    // Look for the requested section type
+    //
+    if (Section->Type == SectionType) {
+      if (Instance == 0) {
+        *FoundSection = Section;
+        return EFI_SUCCESS;
+      } else {
+        Instance--;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Locates a section within a series of sections
+  with the specified section type.
+
+  @param[in]   Sections        The sections to search
+  @param[in]   SizeOfSections  Total size of all sections
+  @param[in]   SectionType     The section type to locate
+  @param[out]  FoundSection    The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindFfsSectionInSections (
+  IN  VOID                       *Sections,
+  IN  UINTN                      SizeOfSections,
+  IN  EFI_SECTION_TYPE           SectionType,
+  OUT EFI_COMMON_SECTION_HEADER  **FoundSection
+  )
+{
+  return FindFfsSectionInstance (
+           Sections,
+           SizeOfSections,
+           SectionType,
+           0,
+           FoundSection
+           );
+}
+
+/**
+  Locates a FFS file with the specified file type and a section
+  within that file with the specified section type.
+
+  @param[in]   Fv            The firmware volume to search
+  @param[in]   FileType      The file type to locate
+  @param[in]   SectionType   The section type to locate
+  @param[out]  FoundSection  The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindFfsFileAndSection (
+  IN  EFI_FIRMWARE_VOLUME_HEADER  *Fv,
+  IN  EFI_FV_FILETYPE             FileType,
+  IN  EFI_SECTION_TYPE            SectionType,
+  OUT EFI_COMMON_SECTION_HEADER   **FoundSection
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PHYSICAL_ADDRESS  CurrentAddress;
+  EFI_PHYSICAL_ADDRESS  EndOfFirmwareVolume;
+  EFI_FFS_FILE_HEADER   *File;
+  UINT32                Size;
+  EFI_PHYSICAL_ADDRESS  EndOfFile;
+
+  if (Fv->Signature != EFI_FVH_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  CurrentAddress      = (EFI_PHYSICAL_ADDRESS)(UINTN)Fv;
+  EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
+
+  //
+  // Loop through the FFS files in the Boot Firmware Volume
+  //
+  for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
+    CurrentAddress = (EndOfFile + 7) & ~(7ULL);
+    if (CurrentAddress > EndOfFirmwareVolume) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;
+    Size = *(UINT32 *)File->Size & 0xffffff;
+    if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    EndOfFile = CurrentAddress + Size;
+    if (EndOfFile > EndOfFirmwareVolume) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    //
+    // Look for the request file type
+    //
+    if (File->Type != FileType) {
+      continue;
+    }
+
+    Status = FindFfsSectionInSections (
+               (VOID *)(File + 1),
+               (UINTN)EndOfFile - (UINTN)(File + 1),
+               SectionType,
+               FoundSection
+               );
+    if (!EFI_ERROR (Status) ||
+        (Status == EFI_VOLUME_CORRUPTED))
+    {
+      return Status;
+    }
+  }
+}
+
+/**
+  Locates the PEI Core entry point address
+
+  @param[in]  Fv                 The firmware volume to search
+  @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindPeiCoreImageBaseInFv (
+  IN  EFI_FIRMWARE_VOLUME_HEADER  *Fv,
+  OUT  EFI_PHYSICAL_ADDRESS       *PeiCoreImageBase
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_COMMON_SECTION_HEADER  *Section;
+
+  Status = FindFfsFileAndSection (
+             Fv,
+             EFI_FV_FILETYPE_PEI_CORE,
+             EFI_SECTION_PE32,
+             &Section
+             );
+  if (EFI_ERROR (Status)) {
+    Status = FindFfsFileAndSection (
+               Fv,
+               EFI_FV_FILETYPE_PEI_CORE,
+               EFI_SECTION_TE,
+               &Section
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
+      return Status;
+    }
+  }
+
+  *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
+  return EFI_SUCCESS;
+}
+
+/**
+  Find and return Pei Core entry point.
+
+  It also find SEC and PEI Core file debug information. It will report them if
+  remote debug is enabled.
+**/
+VOID
+FindAndReportEntryPoints (
+  IN  EFI_FIRMWARE_VOLUME_HEADER  **BootFirmwareVolumePtr,
+  OUT EFI_PEI_CORE_ENTRY_POINT    *PeiCoreEntryPoint
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_PHYSICAL_ADDRESS          PeiCoreImageBase = 0;
+  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
+
+  Status = FindPeiCoreImageBaseInFv (*BootFirmwareVolumePtr, &PeiCoreImageBase);
+  ASSERT (Status == EFI_SUCCESS);
+
+  ZeroMem ((VOID *)&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+
+  //
+  // Report PEI Core debug information when remote debug is enabled
+  //
+  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
+  ImageContext.PdbPointer   = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
+  PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+  //
+  // Find PEI Core entry point
+  //
+  Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint);
+  if (EFI_ERROR (Status)) {
+    *PeiCoreEntryPoint = 0;
+  }
+
+  return;
+}
+
+/**
+  Find the peicore entry point and jump to the entry point to execute.
+
+  @param[in] Context    The first input parameter of InitializeDebugAgent().
+**/
+VOID
+EFIAPI
+SecStartupPhase2 (
+  IN VOID  *Context
+  )
+{
+  EFI_SEC_PEI_HAND_OFF        *SecCoreData;
+  EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
+  EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
+
+  SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
+
+  //
+  // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
+  // is enabled.
+  //
+  BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
+  FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
+  SecCoreData->BootFirmwareVolumeBase = BootFv;
+  SecCoreData->BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
+
+  DEBUG ((DEBUG_INFO, "Find Pei EntryPoint=%p\n", PeiCoreEntryPoint));
+
+  //
+  // Transfer the control to the PEI core
+  //
+  DEBUG ((DEBUG_INFO, "SecStartupPhase2 %p\n", PeiCoreEntryPoint));
+
+  (*PeiCoreEntryPoint)(SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
+
+  //
+  // If we get here then the PEI Core returned, which is not recoverable.
+  //
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
+
+/**
+  Entry point to the C language phase of SEC. initialize some temporary memory and set up the stack,
+  the control is transferred to this function.
+
+  @param[in]  BootFv   The pointer to the PEI FV in memory.
+  @param[in]  TopOfCurrentStack  Top of Current Stack.
+**/
+VOID
+EFIAPI
+SecCoreStartupWithStack (
+  IN EFI_FIRMWARE_VOLUME_HEADER  *BootFv,
+  IN VOID                        *TopOfCurrentStack
+  )
+{
+  EFI_SEC_PEI_HAND_OFF        SecCoreData;
+  EFI_FIRMWARE_VOLUME_HEADER  *BootPeiFv = (EFI_FIRMWARE_VOLUME_HEADER *)BootFv;
+
+  DEBUG ((DEBUG_INFO, "Entering C environment\n"));
+
+  ProcessLibraryConstructorList (NULL, NULL);
+
+  DEBUG ((
+    DEBUG_INFO,
+    "SecCoreStartupWithStack (0x%lx, 0x%lx)\n",
+    (UINTN)BootFv,
+    (UINTN)TopOfCurrentStack
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "(0x%lx, 0x%lx)\n",
+    (UINTN)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase)),
+    (UINTN)(FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
+    ));
+
+  // |-------------|       <-- TopOfCurrentStack
+  // |  BSP Stack  | 32k
+  // |-------------|
+  // |  BSP Heap   | 32k
+  // |-------------|       <-- SecCoreData.TemporaryRamBase
+  // |  Ap Stack   | 384k
+  // |-------------|
+  // |  Exception  | 64k
+  // |-------------|       <-- PcdOvmfSecPeiTempRamBase
+
+  ASSERT (
+    (UINTN)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) +
+            FixedPcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
+    (UINTN)TopOfCurrentStack
+    );
+
+  //
+  // Initialize SEC hand-off state
+  //
+  SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
+
+  SecCoreData.TemporaryRamSize = (UINTN)SIZE_64KB;
+  SecCoreData.TemporaryRamBase = (VOID *)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) - SecCoreData.TemporaryRamSize);
+
+  SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
+  SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
+  SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.BootFirmwareVolumeBase = BootPeiFv;
+  SecCoreData.BootFirmwareVolumeSize = (UINTN)BootPeiFv->FvLength;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "&SecCoreData.BootFirmwareVolumeBase=%lx SecCoreData.BootFirmwareVolumeBase=%lx\n",
+    (UINT64)&(SecCoreData.BootFirmwareVolumeBase),
+    (UINT64)(SecCoreData.BootFirmwareVolumeBase)
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "&SecCoreData.BootFirmwareVolumeSize=%lx SecCoreData.BootFirmwareVolumeSize=%lx\n",
+    (UINT64)&(SecCoreData.BootFirmwareVolumeSize),
+    (UINT64)(SecCoreData.BootFirmwareVolumeSize)
+    ));
+
+  //
+  // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
+  //
+  InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL);
+  SecStartupPhase2 (&SecCoreData);
+}
+
+/**
+  temporary memory to permanent memory and do stack switching.
+
+  @param[in]  PeiServices     Pointer to the PEI Services Table.
+  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
+  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
+  @param[in]  CopySize   The size of memory that needs to be migrated.
+
+  @retval   EFI_SUCCESS  Migration successful.
+**/
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+  IN CONST EFI_PEI_SERVICES  **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS    TemporaryMemoryBase,
+  IN EFI_PHYSICAL_ADDRESS    PermanentMemoryBase,
+  IN UINTN                   CopySize
+  )
+{
+  VOID                      *OldHeap;
+  VOID                      *NewHeap;
+  VOID                      *OldStack;
+  VOID                      *NewStack;
+  BASE_LIBRARY_JUMP_BUFFER  JumpBuffer;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "TemporaryRamMigration (0x%Lx, 0x%Lx, 0x%Lx)\n",
+    TemporaryMemoryBase,
+    PermanentMemoryBase,
+    (UINT64)CopySize
+    ));
+
+  OldHeap = (VOID *)(UINTN)TemporaryMemoryBase;
+  NewHeap = (VOID *)((UINTN)PermanentMemoryBase + (CopySize >> 1));
+
+  OldStack = (VOID *)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
+  NewStack = (VOID *)(UINTN)PermanentMemoryBase;
+
+  //
+  // Migrate Heap
+  //
+  CopyMem (NewHeap, OldHeap, CopySize >> 1);
+
+  //
+  // Migrate Stack
+  //
+  CopyMem (NewStack, OldStack, CopySize >> 1);
+
+  // Use SetJump ()/LongJump () to switch to a new stack.
+  //
+  if (SetJump (&JumpBuffer) == 0) {
+    JumpBuffer.SP = JumpBuffer.SP - (UINTN)OldStack + (UINTN)NewStack;
+    LongJump (&JumpBuffer, (UINTN)-1);
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/LoongArchVirt/Sec/SecMain.inf b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
new file mode 100644
index 0000000000..af29ba0551
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
@@ -0,0 +1,53 @@
+## @file
+#  SEC Driver
+#
+#  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SecMain
+  FILE_GUID                      = 57d02d4f-5a5d-4bfa-b7d6-ba0a4d2c72ce
+  MODULE_TYPE                    = SEC
+  VERSION_STRING                 = 1.0
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  LoongArch64/Start.S
+  SecMain.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  OvmfPkg/OvmfPkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  CpuExceptionHandlerLib
+  DebugAgentLib
+  DebugLib
+  IoLib
+  PcdLib
+  PeCoffLib
+  PeCoffGetEntryPointLib
+  PeCoffExtraActionLib
+
+[Ppis]
+  gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
+
+[FixedPcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112976): https://edk2.groups.io/g/devel/message/112976
Mute This Topic: https://groups.io/mt/103398640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v5 33/36] OvmfPkg/LoongArchVirt: Support SEC phase
Posted by maobibo 2 years, 1 month ago

On 2023/12/28 下午6:07, Chao Li wrote:
> Add SEC code for LoongArch virtual machine.
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
> 
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
> Co-authored-by: Bibo Mao <maobibo@loongson.cn>
> ---
>   OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S | 183 +++++++
>   OvmfPkg/LoongArchVirt/Sec/SecMain.c           | 507 ++++++++++++++++++
>   OvmfPkg/LoongArchVirt/Sec/SecMain.inf         |  53 ++
>   3 files changed, 743 insertions(+)
>   create mode 100644 OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
>   create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.c
>   create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.inf
> 
> diff --git a/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
> new file mode 100644
> index 0000000000..145f8ffc59
> --- /dev/null
> +++ b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
> @@ -0,0 +1,183 @@
> +#------------------------------------------------------------------------------
> +#
> +# Start for Loongson LoongArch processor
> +#
> +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#  @par Glossary:
> +#    - CSR - CPU Status Register
> +#    - EBASE - Exception Base Address
> +#------------------------------------------------------------------------------
> +#ifndef __ASSEMBLY__
> +#define __ASSEMBLY__
> +#endif
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +#include <Protocol/DebugSupport.h>
> +
> +#define BOOTCORE_ID 0
> +
> +//
> +// For coding convenience, define the maximum valid
> +// LoongArch exception.
> +// Since UEFI V2.11, it will be present in DebugSupport.h.
> +//
> +#define MAX_LOONGARCH_EXCEPTION  64
> +
> +ASM_GLOBAL ASM_PFX(_ModuleEntryPoint)
> +ASM_PFX(_ModuleEntryPoint):
> +  /* Disable interrupt */
> +  li.d     $t0, (1 << 2)
> +  csrxchg  $zero, $t0, LOONGARCH_CSR_CRMD
> +
> +  /* Read physical cpu number id */
> +  bl       GetApicId
> +  li.d     $t0, BOOTCORE_ID  //0
> +  bne      $a0, $t0, SlaveMain
> +
> +  /* Configure BSP reset ebase */
> +  li.d     $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
> +  bl       SetExceptionBaseAddress
> +  move     $t1, $a0
what is usage of PcdCpuExceptionVectorBaseAddress about BSP here?
Is there actual exception handler in PcdCpuExceptionVectorBaseAddress in 
sec stage?

> +
> +  /* Set BSP stack */
> +  li.d     $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize)  # stack base
> +  move     $sp, $t0
> +  addi.d   $sp, $sp, -0x8
> +
> +  /* Construct SEC and PEI step exception environment */
> +  la.pcrel $a1, ExceptionEntryStart
> +  la.pcrel $t0, ExceptionEntryEnd
> +  sub.d    $a2, $t0, $a1
> +  li.w     $t0, (MAX_LOONGARCH_EXCEPTION +  MAX_LOONGARCH_INTERRUPT) * 512
> +  bgeu     $a2, $t0, DeadLoop
> +  move     $a0, $t1
> +  bl       CopyMem
> +
> +CallEntry:
> +  /* Call C function make sure parameter true */
> +  li.d     $a0, FixedPcdGet64(PcdOvmfFdBaseAddress) # FW base
> +  addi.d   $a1, $sp, 0x8
> +  bl       SecCoreStartupWithStack
> +# End of _ModuleEntryPoint
> +
> +ASM_PFX(ClearMailBox):
> +  /* Clear mailbox */
> +  li.d      $t1, LOONGARCH_IOCSR_MBUF3
> +  iocsrwr.d $zero, $t1
> +  li.d      $t1, LOONGARCH_IOCSR_MBUF2
> +  iocsrwr.d $zero, $t1
> +  li.d      $t1, LOONGARCH_IOCSR_MBUF1
> +  iocsrwr.d $zero, $t1
> +  li.d      $t1, LOONGARCH_IOCSR_MBUF0
> +  iocsrwr.d $zero, $t1
> +  jirl      $zero, $ra, 0
> +# End of ClearMailBox
> +
> +ASM_PFX(EnableIPI):
> +  /* Enable IPI interrupt */
> +  li.d      $t1, (1 << 12)
> +  csrxchg   $t1, $t1, LOONGARCH_CSR_ECFG
> +
> +  addi.d    $t2, $zero, -1
> +  li.d      $t1, LOONGARCH_IOCSR_IPI_EN
> +  iocsrwr.w $t2, $t1
> +  jirl      $zero, $ra, 0
> +# End of EeableIPI
> +
> +#/**
> +#   Get APIC ID for every CPU.
> +#
> +#   @param   NULL
> +#   @return  APICID
> +#
> +#   UINTN
> +#   EFI_API
> +#   GetApicId (
> +#     VOID
> +#     )
> +#**/
> +ASM_PFX(GetApicId):
> +  csrrd $a0, LOONGARCH_CSR_CPUNUM
> +  andi  $a0, $a0, 0x3ff
> +  jirl  $zero, $ra, 0
> +# End of GetApicId
> +
> +ASM_PFX(ApInitStack):
> +  li.d   $t1, SIZE_1KB
> +  csrrd  $t0, LOONGARCH_CSR_TMID
> +  mul.d  $t1, $t0, $t1
> +  li.d   $t2, FixedPcdGet32(PcdCpuMaxLogicalProcessorNumber)
> +  bgeu   $t0, $t2, DeadLoop
> +  li.d   $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize) - SIZE_64KB
> +  sub.d  $sp, $t0, $t1
> +  addi.d $sp, $sp, -0x8
> +  jirl   $zero, $ra, 0
> +# End of ApInitStack
> +
> +ASM_PFX(SlaveMain):
> +  /* Set AP exception handle in flash */
> +  la.pcrel  $a0, ApException
> +  bl        SetExceptionBaseAddress
> +
> +  /* Clean up local mail box and open INT */
> +  bl        ClearMailBox
> +  bl        EnableIPI
> +  bl        EnableInterrupts
There will be potential problem if ipi interrupt happens after 
EnableInterrupts and before CpuSleep.
> +
> +WaitForWake:
> +  /* Wait for wakeup */
> +  bl        CpuSleep
> +  li.d      $t1, LOONGARCH_IOCSR_MBUF0
> +  iocsrrd.w $t2, $t1
> +  beqz      $t2, WaitForWake
> +
> +  /* Disable global interrupt */
> +  bl        DisableInterrupts
> +
> +  /* Disable IPI interrupt */
> +  li.d      $t0, (1 << 12)
> +  csrxchg   $zero, $t0, LOONGARCH_CSR_ECFG
> +
> +  /* Read mail buf and jump to specified entry */
> +  li.d      $t1, LOONGARCH_IOCSR_MBUF0
> +  iocsrrd.d $t0, $t1
> +  li.d      $t1, LOONGARCH_IOCSR_MBUF3
What is usage of mail buffer LOONGARCH_IOCSR_MBUF3 here? Do we have 
documented Multi-processor boot protocol?

Regards
Bibo Mao
> +  iocsrrd.d $a1, $t1
> +  bl        ClearMailBox
> +  beqz      $a1, NoParameterCall
> +
> +  //
> +  // If the parameters are not NULL, then calling happened in FW ENV.
> +  // Set the EBASE to be the same as BSP.
> +  //
> +  li.d      $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
> +  bl        SetExceptionBaseAddress
> +
> +  bl        ApInitStack
> +  bl        GetApicId
> +NoParameterCall:
> +  move      $ra, $t0
> +  jirl      $zero, $ra, 0x0
> +# End of SlaveMain
> +
> +.align 12
> +ASM_PFX(ApException):
> +  csrrd     $t0, LOONGARCH_CSR_ESTAT
> +  srli.d    $t0, $t0, 12
> +  beqz      $t0, DeadLoop
> +
> +  li.d      $t0, LOONGARCH_IOCSR_IPI_STATUS
> +  iocsrrd.w $t1, $t0
> +  li.d      $t0, LOONGARCH_IOCSR_IPI_CLEAR
> +  iocsrwr.w $t1, $t0
> +  ertn
> +# End of ApException
> +
> +ASM_PFX(DeadLoop):
> +  b   DeadLoop
> +# End of DeadLoop
> +.end
> diff --git a/OvmfPkg/LoongArchVirt/Sec/SecMain.c b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
> new file mode 100644
> index 0000000000..a7f4324811
> --- /dev/null
> +++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
> @@ -0,0 +1,507 @@
> +/** @file
> +  Main SEC phase code.  Transitions to PEI.
> +
> +  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugAgentLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/ExtractGuidedSectionLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PeCoffLib.h>
> +#include <Library/PeCoffGetEntryPointLib.h>
> +#include <Library/PeCoffExtraActionLib.h>
> +#include <Library/PeimEntryPoint.h>
> +
> +#include <Ppi/TemporaryRamSupport.h>
> +
> +/**
> +  temporary memory to permanent memory and do stack switching.
> +
> +  @param[in]  PeiServices     Pointer to the PEI Services Table.
> +  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
> +  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
> +  @param[in]  CopySize   The size of memory that needs to be migrated.
> +
> +  @retval   EFI_SUCCESS  Migration successful.
> +**/
> +EFI_STATUS
> +EFIAPI
> +TemporaryRamMigration (
> +  IN CONST EFI_PEI_SERVICES  **PeiServices,
> +  IN EFI_PHYSICAL_ADDRESS    TemporaryMemoryBase,
> +  IN EFI_PHYSICAL_ADDRESS    PermanentMemoryBase,
> +  IN UINTN                   CopySize
> +  );
> +
> +EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI  mTemporaryRamSupportPpi = {
> +  TemporaryRamMigration
> +};
> +
> +EFI_PEI_PPI_DESCRIPTOR  mPrivateDispatchTable[] = {
> +  {
> +    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +    &gEfiTemporaryRamSupportPpiGuid,
> +    &mTemporaryRamSupportPpi
> +  },
> +};
> +
> +/**
> +  Locates a section within a series of sections
> +  with the specified section type.
> +
> +  The Instance parameter indicates which instance of the section
> +  type to return. (0 is first instance, 1 is second...)
> +
> +  @param[in]   Sections        The sections to search
> +  @param[in]   SizeOfSections  Total size of all sections
> +  @param[in]   SectionType     The section type to locate
> +  @param[in]   Instance        The section instance number
> +  @param[out]  FoundSection    The FFS section if found
> +
> +  @retval EFI_SUCCESS           The file and section was found
> +  @retval EFI_NOT_FOUND         The file and section was not found
> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
> +**/
> +EFI_STATUS
> +FindFfsSectionInstance (
> +  IN  VOID                       *Sections,
> +  IN  UINTN                      SizeOfSections,
> +  IN  EFI_SECTION_TYPE           SectionType,
> +  IN  UINTN                      Instance,
> +  OUT EFI_COMMON_SECTION_HEADER  **FoundSection
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS       CurrentAddress;
> +  UINT32                     Size;
> +  EFI_PHYSICAL_ADDRESS       EndOfSections;
> +  EFI_COMMON_SECTION_HEADER  *Section;
> +  EFI_PHYSICAL_ADDRESS       EndOfSection;
> +
> +  //
> +  // Loop through the FFS file sections within the PEI Core FFS file
> +  //
> +  EndOfSection  = (EFI_PHYSICAL_ADDRESS)(UINTN)Sections;
> +  EndOfSections = EndOfSection + SizeOfSections;
> +  for ( ; ; ) {
> +    if (EndOfSection == EndOfSections) {
> +      break;
> +    }
> +
> +    CurrentAddress = (EndOfSection + 3) & ~(3ULL);
> +    if (CurrentAddress >= EndOfSections) {
> +      return EFI_VOLUME_CORRUPTED;
> +    }
> +
> +    Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
> +
> +    Size = SECTION_SIZE (Section);
> +    if (Size < sizeof (*Section)) {
> +      return EFI_VOLUME_CORRUPTED;
> +    }
> +
> +    EndOfSection = CurrentAddress + Size;
> +    if (EndOfSection > EndOfSections) {
> +      return EFI_VOLUME_CORRUPTED;
> +    }
> +
> +    //
> +    // Look for the requested section type
> +    //
> +    if (Section->Type == SectionType) {
> +      if (Instance == 0) {
> +        *FoundSection = Section;
> +        return EFI_SUCCESS;
> +      } else {
> +        Instance--;
> +      }
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Locates a section within a series of sections
> +  with the specified section type.
> +
> +  @param[in]   Sections        The sections to search
> +  @param[in]   SizeOfSections  Total size of all sections
> +  @param[in]   SectionType     The section type to locate
> +  @param[out]  FoundSection    The FFS section if found
> +
> +  @retval EFI_SUCCESS           The file and section was found
> +  @retval EFI_NOT_FOUND         The file and section was not found
> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
> +**/
> +EFI_STATUS
> +FindFfsSectionInSections (
> +  IN  VOID                       *Sections,
> +  IN  UINTN                      SizeOfSections,
> +  IN  EFI_SECTION_TYPE           SectionType,
> +  OUT EFI_COMMON_SECTION_HEADER  **FoundSection
> +  )
> +{
> +  return FindFfsSectionInstance (
> +           Sections,
> +           SizeOfSections,
> +           SectionType,
> +           0,
> +           FoundSection
> +           );
> +}
> +
> +/**
> +  Locates a FFS file with the specified file type and a section
> +  within that file with the specified section type.
> +
> +  @param[in]   Fv            The firmware volume to search
> +  @param[in]   FileType      The file type to locate
> +  @param[in]   SectionType   The section type to locate
> +  @param[out]  FoundSection  The FFS section if found
> +
> +  @retval EFI_SUCCESS           The file and section was found
> +  @retval EFI_NOT_FOUND         The file and section was not found
> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
> +**/
> +EFI_STATUS
> +FindFfsFileAndSection (
> +  IN  EFI_FIRMWARE_VOLUME_HEADER  *Fv,
> +  IN  EFI_FV_FILETYPE             FileType,
> +  IN  EFI_SECTION_TYPE            SectionType,
> +  OUT EFI_COMMON_SECTION_HEADER   **FoundSection
> +  )
> +{
> +  EFI_STATUS            Status;
> +  EFI_PHYSICAL_ADDRESS  CurrentAddress;
> +  EFI_PHYSICAL_ADDRESS  EndOfFirmwareVolume;
> +  EFI_FFS_FILE_HEADER   *File;
> +  UINT32                Size;
> +  EFI_PHYSICAL_ADDRESS  EndOfFile;
> +
> +  if (Fv->Signature != EFI_FVH_SIGNATURE) {
> +    DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));
> +    return EFI_VOLUME_CORRUPTED;
> +  }
> +
> +  CurrentAddress      = (EFI_PHYSICAL_ADDRESS)(UINTN)Fv;
> +  EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
> +
> +  //
> +  // Loop through the FFS files in the Boot Firmware Volume
> +  //
> +  for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
> +    CurrentAddress = (EndOfFile + 7) & ~(7ULL);
> +    if (CurrentAddress > EndOfFirmwareVolume) {
> +      return EFI_VOLUME_CORRUPTED;
> +    }
> +
> +    File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;
> +    Size = *(UINT32 *)File->Size & 0xffffff;
> +    if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
> +      return EFI_VOLUME_CORRUPTED;
> +    }
> +
> +    EndOfFile = CurrentAddress + Size;
> +    if (EndOfFile > EndOfFirmwareVolume) {
> +      return EFI_VOLUME_CORRUPTED;
> +    }
> +
> +    //
> +    // Look for the request file type
> +    //
> +    if (File->Type != FileType) {
> +      continue;
> +    }
> +
> +    Status = FindFfsSectionInSections (
> +               (VOID *)(File + 1),
> +               (UINTN)EndOfFile - (UINTN)(File + 1),
> +               SectionType,
> +               FoundSection
> +               );
> +    if (!EFI_ERROR (Status) ||
> +        (Status == EFI_VOLUME_CORRUPTED))
> +    {
> +      return Status;
> +    }
> +  }
> +}
> +
> +/**
> +  Locates the PEI Core entry point address
> +
> +  @param[in]  Fv                 The firmware volume to search
> +  @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
> +
> +  @retval EFI_SUCCESS           The file and section was found
> +  @retval EFI_NOT_FOUND         The file and section was not found
> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
> +**/
> +EFI_STATUS
> +FindPeiCoreImageBaseInFv (
> +  IN  EFI_FIRMWARE_VOLUME_HEADER  *Fv,
> +  OUT  EFI_PHYSICAL_ADDRESS       *PeiCoreImageBase
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  EFI_COMMON_SECTION_HEADER  *Section;
> +
> +  Status = FindFfsFileAndSection (
> +             Fv,
> +             EFI_FV_FILETYPE_PEI_CORE,
> +             EFI_SECTION_PE32,
> +             &Section
> +             );
> +  if (EFI_ERROR (Status)) {
> +    Status = FindFfsFileAndSection (
> +               Fv,
> +               EFI_FV_FILETYPE_PEI_CORE,
> +               EFI_SECTION_TE,
> +               &Section
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
> +      return Status;
> +    }
> +  }
> +
> +  *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Find and return Pei Core entry point.
> +
> +  It also find SEC and PEI Core file debug information. It will report them if
> +  remote debug is enabled.
> +**/
> +VOID
> +FindAndReportEntryPoints (
> +  IN  EFI_FIRMWARE_VOLUME_HEADER  **BootFirmwareVolumePtr,
> +  OUT EFI_PEI_CORE_ENTRY_POINT    *PeiCoreEntryPoint
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  EFI_PHYSICAL_ADDRESS          PeiCoreImageBase = 0;
> +  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
> +
> +  Status = FindPeiCoreImageBaseInFv (*BootFirmwareVolumePtr, &PeiCoreImageBase);
> +  ASSERT (Status == EFI_SUCCESS);
> +
> +  ZeroMem ((VOID *)&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
> +
> +  //
> +  // Report PEI Core debug information when remote debug is enabled
> +  //
> +  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
> +  ImageContext.PdbPointer   = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
> +  PeCoffLoaderRelocateImageExtraAction (&ImageContext);
> +
> +  //
> +  // Find PEI Core entry point
> +  //
> +  Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint);
> +  if (EFI_ERROR (Status)) {
> +    *PeiCoreEntryPoint = 0;
> +  }
> +
> +  return;
> +}
> +
> +/**
> +  Find the peicore entry point and jump to the entry point to execute.
> +
> +  @param[in] Context    The first input parameter of InitializeDebugAgent().
> +**/
> +VOID
> +EFIAPI
> +SecStartupPhase2 (
> +  IN VOID  *Context
> +  )
> +{
> +  EFI_SEC_PEI_HAND_OFF        *SecCoreData;
> +  EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
> +  EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
> +
> +  SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
> +
> +  //
> +  // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
> +  // is enabled.
> +  //
> +  BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
> +  FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
> +  SecCoreData->BootFirmwareVolumeBase = BootFv;
> +  SecCoreData->BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
> +
> +  DEBUG ((DEBUG_INFO, "Find Pei EntryPoint=%p\n", PeiCoreEntryPoint));
> +
> +  //
> +  // Transfer the control to the PEI core
> +  //
> +  DEBUG ((DEBUG_INFO, "SecStartupPhase2 %p\n", PeiCoreEntryPoint));
> +
> +  (*PeiCoreEntryPoint)(SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
> +
> +  //
> +  // If we get here then the PEI Core returned, which is not recoverable.
> +  //
> +  ASSERT (FALSE);
> +  CpuDeadLoop ();
> +}
> +
> +/**
> +  Entry point to the C language phase of SEC. initialize some temporary memory and set up the stack,
> +  the control is transferred to this function.
> +
> +  @param[in]  BootFv   The pointer to the PEI FV in memory.
> +  @param[in]  TopOfCurrentStack  Top of Current Stack.
> +**/
> +VOID
> +EFIAPI
> +SecCoreStartupWithStack (
> +  IN EFI_FIRMWARE_VOLUME_HEADER  *BootFv,
> +  IN VOID                        *TopOfCurrentStack
> +  )
> +{
> +  EFI_SEC_PEI_HAND_OFF        SecCoreData;
> +  EFI_FIRMWARE_VOLUME_HEADER  *BootPeiFv = (EFI_FIRMWARE_VOLUME_HEADER *)BootFv;
> +
> +  DEBUG ((DEBUG_INFO, "Entering C environment\n"));
> +
> +  ProcessLibraryConstructorList (NULL, NULL);
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "SecCoreStartupWithStack (0x%lx, 0x%lx)\n",
> +    (UINTN)BootFv,
> +    (UINTN)TopOfCurrentStack
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "(0x%lx, 0x%lx)\n",
> +    (UINTN)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase)),
> +    (UINTN)(FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
> +    ));
> +
> +  // |-------------|       <-- TopOfCurrentStack
> +  // |  BSP Stack  | 32k
> +  // |-------------|
> +  // |  BSP Heap   | 32k
> +  // |-------------|       <-- SecCoreData.TemporaryRamBase
> +  // |  Ap Stack   | 384k
> +  // |-------------|
> +  // |  Exception  | 64k
> +  // |-------------|       <-- PcdOvmfSecPeiTempRamBase
> +
> +  ASSERT (
> +    (UINTN)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) +
> +            FixedPcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
> +    (UINTN)TopOfCurrentStack
> +    );
> +
> +  //
> +  // Initialize SEC hand-off state
> +  //
> +  SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
> +
> +  SecCoreData.TemporaryRamSize = (UINTN)SIZE_64KB;
> +  SecCoreData.TemporaryRamBase = (VOID *)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) - SecCoreData.TemporaryRamSize);
> +
> +  SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
> +  SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
> +
> +  SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
> +  SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
> +
> +  SecCoreData.BootFirmwareVolumeBase = BootPeiFv;
> +  SecCoreData.BootFirmwareVolumeSize = (UINTN)BootPeiFv->FvLength;
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "&SecCoreData.BootFirmwareVolumeBase=%lx SecCoreData.BootFirmwareVolumeBase=%lx\n",
> +    (UINT64)&(SecCoreData.BootFirmwareVolumeBase),
> +    (UINT64)(SecCoreData.BootFirmwareVolumeBase)
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "&SecCoreData.BootFirmwareVolumeSize=%lx SecCoreData.BootFirmwareVolumeSize=%lx\n",
> +    (UINT64)&(SecCoreData.BootFirmwareVolumeSize),
> +    (UINT64)(SecCoreData.BootFirmwareVolumeSize)
> +    ));
> +
> +  //
> +  // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
> +  //
> +  InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL);
> +  SecStartupPhase2 (&SecCoreData);
> +}
> +
> +/**
> +  temporary memory to permanent memory and do stack switching.
> +
> +  @param[in]  PeiServices     Pointer to the PEI Services Table.
> +  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
> +  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
> +  @param[in]  CopySize   The size of memory that needs to be migrated.
> +
> +  @retval   EFI_SUCCESS  Migration successful.
> +**/
> +EFI_STATUS
> +EFIAPI
> +TemporaryRamMigration (
> +  IN CONST EFI_PEI_SERVICES  **PeiServices,
> +  IN EFI_PHYSICAL_ADDRESS    TemporaryMemoryBase,
> +  IN EFI_PHYSICAL_ADDRESS    PermanentMemoryBase,
> +  IN UINTN                   CopySize
> +  )
> +{
> +  VOID                      *OldHeap;
> +  VOID                      *NewHeap;
> +  VOID                      *OldStack;
> +  VOID                      *NewStack;
> +  BASE_LIBRARY_JUMP_BUFFER  JumpBuffer;
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "TemporaryRamMigration (0x%Lx, 0x%Lx, 0x%Lx)\n",
> +    TemporaryMemoryBase,
> +    PermanentMemoryBase,
> +    (UINT64)CopySize
> +    ));
> +
> +  OldHeap = (VOID *)(UINTN)TemporaryMemoryBase;
> +  NewHeap = (VOID *)((UINTN)PermanentMemoryBase + (CopySize >> 1));
> +
> +  OldStack = (VOID *)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
> +  NewStack = (VOID *)(UINTN)PermanentMemoryBase;
> +
> +  //
> +  // Migrate Heap
> +  //
> +  CopyMem (NewHeap, OldHeap, CopySize >> 1);
> +
> +  //
> +  // Migrate Stack
> +  //
> +  CopyMem (NewStack, OldStack, CopySize >> 1);
> +
> +  // Use SetJump ()/LongJump () to switch to a new stack.
> +  //
> +  if (SetJump (&JumpBuffer) == 0) {
> +    JumpBuffer.SP = JumpBuffer.SP - (UINTN)OldStack + (UINTN)NewStack;
> +    LongJump (&JumpBuffer, (UINTN)-1);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/OvmfPkg/LoongArchVirt/Sec/SecMain.inf b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
> new file mode 100644
> index 0000000000..af29ba0551
> --- /dev/null
> +++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
> @@ -0,0 +1,53 @@
> +## @file
> +#  SEC Driver
> +#
> +#  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = SecMain
> +  FILE_GUID                      = 57d02d4f-5a5d-4bfa-b7d6-ba0a4d2c72ce
> +  MODULE_TYPE                    = SEC
> +  VERSION_STRING                 = 1.0
> +
> +#
> +#  VALID_ARCHITECTURES           = LOONGARCH64
> +#
> +
> +[Sources]
> +  LoongArch64/Start.S
> +  SecMain.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  OvmfPkg/OvmfPkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  CpuExceptionHandlerLib
> +  DebugAgentLib
> +  DebugLib
> +  IoLib
> +  PcdLib
> +  PeCoffLib
> +  PeCoffGetEntryPointLib
> +  PeCoffExtraActionLib
> +
> +[Ppis]
> +  gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
> +
> +[FixedPcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
> +
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
> +
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
> 



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113110): https://edk2.groups.io/g/devel/message/113110
Mute This Topic: https://groups.io/mt/103398640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [PATCH v5 33/36] OvmfPkg/LoongArchVirt: Support SEC phase
Posted by Chao Li 2 years, 1 month ago
Hi Bibo,

Here are my comments:


Thanks,
Chao
On 2024/1/4 09:49, maobibo wrote:
>
>
> On 2023/12/28 下午6:07, Chao Li wrote:
>> Add SEC code for LoongArch virtual machine.
>>
>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
>> Cc: Jiewen Yao <jiewen.yao@intel.com>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Signed-off-by: Chao Li <lichao@loongson.cn>
>> Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
>> Co-authored-by: Bibo Mao <maobibo@loongson.cn>
>> ---
>>   OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S | 183 +++++++
>>   OvmfPkg/LoongArchVirt/Sec/SecMain.c           | 507 ++++++++++++++++++
>>   OvmfPkg/LoongArchVirt/Sec/SecMain.inf         |  53 ++
>>   3 files changed, 743 insertions(+)
>>   create mode 100644 OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
>>   create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.c
>>   create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.inf
>>
>> diff --git a/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S 
>> b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
>> new file mode 100644
>> index 0000000000..145f8ffc59
>> --- /dev/null
>> +++ b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
>> @@ -0,0 +1,183 @@
>> +#------------------------------------------------------------------------------ 
>>
>> +#
>> +# Start for Loongson LoongArch processor
>> +#
>> +# Copyright (c) 2024 Loongson Technology Corporation Limited. All 
>> rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +#  @par Glossary:
>> +#    - CSR - CPU Status Register
>> +#    - EBASE - Exception Base Address
>> +#------------------------------------------------------------------------------ 
>>
>> +#ifndef __ASSEMBLY__
>> +#define __ASSEMBLY__
>> +#endif
>> +
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Register/LoongArch64/Csr.h>
>> +#include <Protocol/DebugSupport.h>
>> +
>> +#define BOOTCORE_ID 0
>> +
>> +//
>> +// For coding convenience, define the maximum valid
>> +// LoongArch exception.
>> +// Since UEFI V2.11, it will be present in DebugSupport.h.
>> +//
>> +#define MAX_LOONGARCH_EXCEPTION  64
>> +
>> +ASM_GLOBAL ASM_PFX(_ModuleEntryPoint)
>> +ASM_PFX(_ModuleEntryPoint):
>> +  /* Disable interrupt */
>> +  li.d     $t0, (1 << 2)
>> +  csrxchg  $zero, $t0, LOONGARCH_CSR_CRMD
>> +
>> +  /* Read physical cpu number id */
>> +  bl       GetApicId
>> +  li.d     $t0, BOOTCORE_ID  //0
>> +  bne      $a0, $t0, SlaveMain
>> +
>> +  /* Configure BSP reset ebase */
>> +  li.d     $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
>> +  bl       SetExceptionBaseAddress
>> +  move     $t1, $a0
> what is usage of PcdCpuExceptionVectorBaseAddress about BSP here?
> Is there actual exception handler in PcdCpuExceptionVectorBaseAddress 
> in sec stage?
There are some mistake in the order between setting up exception base 
and copying the exception code, I will fix them in V6.
>
>> +
>> +  /* Set BSP stack */
>> +  li.d     $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + 
>> FixedPcdGet32(PcdOvmfSecPeiTempRamSize)  # stack base
>> +  move     $sp, $t0
>> +  addi.d   $sp, $sp, -0x8
>> +
>> +  /* Construct SEC and PEI step exception environment */
>> +  la.pcrel $a1, ExceptionEntryStart
>> +  la.pcrel $t0, ExceptionEntryEnd
>> +  sub.d    $a2, $t0, $a1
>> +  li.w     $t0, (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) 
>> * 512
>> +  bgeu     $a2, $t0, DeadLoop
>> +  move     $a0, $t1
>> +  bl       CopyMem
>> +
>> +CallEntry:
>> +  /* Call C function make sure parameter true */
>> +  li.d     $a0, FixedPcdGet64(PcdOvmfFdBaseAddress) # FW base
>> +  addi.d   $a1, $sp, 0x8
>> +  bl       SecCoreStartupWithStack
>> +# End of _ModuleEntryPoint
>> +
>> +ASM_PFX(ClearMailBox):
>> +  /* Clear mailbox */
>> +  li.d      $t1, LOONGARCH_IOCSR_MBUF3
>> +  iocsrwr.d $zero, $t1
>> +  li.d      $t1, LOONGARCH_IOCSR_MBUF2
>> +  iocsrwr.d $zero, $t1
>> +  li.d      $t1, LOONGARCH_IOCSR_MBUF1
>> +  iocsrwr.d $zero, $t1
>> +  li.d      $t1, LOONGARCH_IOCSR_MBUF0
>> +  iocsrwr.d $zero, $t1
>> +  jirl      $zero, $ra, 0
>> +# End of ClearMailBox
>> +
>> +ASM_PFX(EnableIPI):
>> +  /* Enable IPI interrupt */
>> +  li.d      $t1, (1 << 12)
>> +  csrxchg   $t1, $t1, LOONGARCH_CSR_ECFG
>> +
>> +  addi.d    $t2, $zero, -1
>> +  li.d      $t1, LOONGARCH_IOCSR_IPI_EN
>> +  iocsrwr.w $t2, $t1
>> +  jirl      $zero, $ra, 0
>> +# End of EeableIPI
>> +
>> +#/**
>> +#   Get APIC ID for every CPU.
>> +#
>> +#   @param   NULL
>> +#   @return  APICID
>> +#
>> +#   UINTN
>> +#   EFI_API
>> +#   GetApicId (
>> +#     VOID
>> +#     )
>> +#**/
>> +ASM_PFX(GetApicId):
>> +  csrrd $a0, LOONGARCH_CSR_CPUNUM
>> +  andi  $a0, $a0, 0x3ff
>> +  jirl  $zero, $ra, 0
>> +# End of GetApicId
>> +
>> +ASM_PFX(ApInitStack):
>> +  li.d   $t1, SIZE_1KB
>> +  csrrd  $t0, LOONGARCH_CSR_TMID
>> +  mul.d  $t1, $t0, $t1
>> +  li.d   $t2, FixedPcdGet32(PcdCpuMaxLogicalProcessorNumber)
>> +  bgeu   $t0, $t2, DeadLoop
>> +  li.d   $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + 
>> FixedPcdGet32(PcdOvmfSecPeiTempRamSize) - SIZE_64KB
>> +  sub.d  $sp, $t0, $t1
>> +  addi.d $sp, $sp, -0x8
>> +  jirl   $zero, $ra, 0
>> +# End of ApInitStack
>> +
>> +ASM_PFX(SlaveMain):
>> +  /* Set AP exception handle in flash */
>> +  la.pcrel  $a0, ApException
>> +  bl        SetExceptionBaseAddress
>> +
>> +  /* Clean up local mail box and open INT */
>> +  bl        ClearMailBox
>> +  bl        EnableIPI
>> +  bl        EnableInterrupts
> There will be potential problem if ipi interrupt happens after 
> EnableInterrupts and before CpuSleep.
Yes, there are some issues, in V6 I will add logic to jump to kernel in 
ApException.
>> +
>> +WaitForWake:
>> +  /* Wait for wakeup */
>> +  bl        CpuSleep
>> +  li.d      $t1, LOONGARCH_IOCSR_MBUF0
>> +  iocsrrd.w $t2, $t1
>> +  beqz      $t2, WaitForWake
>> +
>> +  /* Disable global interrupt */
>> +  bl        DisableInterrupts
>> +
>> +  /* Disable IPI interrupt */
>> +  li.d      $t0, (1 << 12)
>> +  csrxchg   $zero, $t0, LOONGARCH_CSR_ECFG
>> +
>> +  /* Read mail buf and jump to specified entry */
>> +  li.d      $t1, LOONGARCH_IOCSR_MBUF0
>> +  iocsrrd.d $t0, $t1
>> +  li.d      $t1, LOONGARCH_IOCSR_MBUF3
> What is usage of mail buffer LOONGARCH_IOCSR_MBUF3 here? Do we have 
> documented Multi-processor boot protocol?
In the linux kernel, the IPI vector 0 is used for the SMP boot CPU, I 
beleve the documentation for multi-processor is coming soon, it is on 
the way.
>
> Regards
> Bibo Mao
>> +  iocsrrd.d $a1, $t1
>> +  bl        ClearMailBox
>> +  beqz      $a1, NoParameterCall
>> +
>> +  //
>> +  // If the parameters are not NULL, then calling happened in FW ENV.
>> +  // Set the EBASE to be the same as BSP.
>> +  //
>> +  li.d      $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
>> +  bl        SetExceptionBaseAddress
>> +
>> +  bl        ApInitStack
>> +  bl        GetApicId
>> +NoParameterCall:
>> +  move      $ra, $t0
>> +  jirl      $zero, $ra, 0x0
>> +# End of SlaveMain
>> +
>> +.align 12
>> +ASM_PFX(ApException):
>> +  csrrd     $t0, LOONGARCH_CSR_ESTAT
>> +  srli.d    $t0, $t0, 12
>> +  beqz      $t0, DeadLoop
>> +
>> +  li.d      $t0, LOONGARCH_IOCSR_IPI_STATUS
>> +  iocsrrd.w $t1, $t0
>> +  li.d      $t0, LOONGARCH_IOCSR_IPI_CLEAR
>> +  iocsrwr.w $t1, $t0
>> +  ertn
>> +# End of ApException
>> +
>> +ASM_PFX(DeadLoop):
>> +  b   DeadLoop
>> +# End of DeadLoop
>> +.end
>> diff --git a/OvmfPkg/LoongArchVirt/Sec/SecMain.c 
>> b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
>> new file mode 100644
>> index 0000000000..a7f4324811
>> --- /dev/null
>> +++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
>> @@ -0,0 +1,507 @@
>> +/** @file
>> +  Main SEC phase code.  Transitions to PEI.
>> +
>> +  Copyright (c) 2024 Loongson Technology Corporation Limited. All 
>> rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <PiPei.h>
>> +
>> +#include <Library/BaseLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugAgentLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/ExtractGuidedSectionLib.h>
>> +#include <Library/IoLib.h>
>> +#include <Library/PeiServicesLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/PeCoffLib.h>
>> +#include <Library/PeCoffGetEntryPointLib.h>
>> +#include <Library/PeCoffExtraActionLib.h>
>> +#include <Library/PeimEntryPoint.h>
>> +
>> +#include <Ppi/TemporaryRamSupport.h>
>> +
>> +/**
>> +  temporary memory to permanent memory and do stack switching.
>> +
>> +  @param[in]  PeiServices     Pointer to the PEI Services Table.
>> +  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
>> +  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
>> +  @param[in]  CopySize   The size of memory that needs to be migrated.
>> +
>> +  @retval   EFI_SUCCESS  Migration successful.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +TemporaryRamMigration (
>> +  IN CONST EFI_PEI_SERVICES  **PeiServices,
>> +  IN EFI_PHYSICAL_ADDRESS    TemporaryMemoryBase,
>> +  IN EFI_PHYSICAL_ADDRESS    PermanentMemoryBase,
>> +  IN UINTN                   CopySize
>> +  );
>> +
>> +EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI  mTemporaryRamSupportPpi = {
>> +  TemporaryRamMigration
>> +};
>> +
>> +EFI_PEI_PPI_DESCRIPTOR  mPrivateDispatchTable[] = {
>> +  {
>> +    (EFI_PEI_PPI_DESCRIPTOR_PPI | 
>> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
>> +    &gEfiTemporaryRamSupportPpiGuid,
>> +    &mTemporaryRamSupportPpi
>> +  },
>> +};
>> +
>> +/**
>> +  Locates a section within a series of sections
>> +  with the specified section type.
>> +
>> +  The Instance parameter indicates which instance of the section
>> +  type to return. (0 is first instance, 1 is second...)
>> +
>> +  @param[in]   Sections        The sections to search
>> +  @param[in]   SizeOfSections  Total size of all sections
>> +  @param[in]   SectionType     The section type to locate
>> +  @param[in]   Instance        The section instance number
>> +  @param[out]  FoundSection    The FFS section if found
>> +
>> +  @retval EFI_SUCCESS           The file and section was found
>> +  @retval EFI_NOT_FOUND         The file and section was not found
>> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
>> +**/
>> +EFI_STATUS
>> +FindFfsSectionInstance (
>> +  IN  VOID                       *Sections,
>> +  IN  UINTN                      SizeOfSections,
>> +  IN  EFI_SECTION_TYPE           SectionType,
>> +  IN  UINTN                      Instance,
>> +  OUT EFI_COMMON_SECTION_HEADER  **FoundSection
>> +  )
>> +{
>> +  EFI_PHYSICAL_ADDRESS       CurrentAddress;
>> +  UINT32                     Size;
>> +  EFI_PHYSICAL_ADDRESS       EndOfSections;
>> +  EFI_COMMON_SECTION_HEADER  *Section;
>> +  EFI_PHYSICAL_ADDRESS       EndOfSection;
>> +
>> +  //
>> +  // Loop through the FFS file sections within the PEI Core FFS file
>> +  //
>> +  EndOfSection  = (EFI_PHYSICAL_ADDRESS)(UINTN)Sections;
>> +  EndOfSections = EndOfSection + SizeOfSections;
>> +  for ( ; ; ) {
>> +    if (EndOfSection == EndOfSections) {
>> +      break;
>> +    }
>> +
>> +    CurrentAddress = (EndOfSection + 3) & ~(3ULL);
>> +    if (CurrentAddress >= EndOfSections) {
>> +      return EFI_VOLUME_CORRUPTED;
>> +    }
>> +
>> +    Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
>> +
>> +    Size = SECTION_SIZE (Section);
>> +    if (Size < sizeof (*Section)) {
>> +      return EFI_VOLUME_CORRUPTED;
>> +    }
>> +
>> +    EndOfSection = CurrentAddress + Size;
>> +    if (EndOfSection > EndOfSections) {
>> +      return EFI_VOLUME_CORRUPTED;
>> +    }
>> +
>> +    //
>> +    // Look for the requested section type
>> +    //
>> +    if (Section->Type == SectionType) {
>> +      if (Instance == 0) {
>> +        *FoundSection = Section;
>> +        return EFI_SUCCESS;
>> +      } else {
>> +        Instance--;
>> +      }
>> +    }
>> +  }
>> +
>> +  return EFI_NOT_FOUND;
>> +}
>> +
>> +/**
>> +  Locates a section within a series of sections
>> +  with the specified section type.
>> +
>> +  @param[in]   Sections        The sections to search
>> +  @param[in]   SizeOfSections  Total size of all sections
>> +  @param[in]   SectionType     The section type to locate
>> +  @param[out]  FoundSection    The FFS section if found
>> +
>> +  @retval EFI_SUCCESS           The file and section was found
>> +  @retval EFI_NOT_FOUND         The file and section was not found
>> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
>> +**/
>> +EFI_STATUS
>> +FindFfsSectionInSections (
>> +  IN  VOID                       *Sections,
>> +  IN  UINTN                      SizeOfSections,
>> +  IN  EFI_SECTION_TYPE           SectionType,
>> +  OUT EFI_COMMON_SECTION_HEADER  **FoundSection
>> +  )
>> +{
>> +  return FindFfsSectionInstance (
>> +           Sections,
>> +           SizeOfSections,
>> +           SectionType,
>> +           0,
>> +           FoundSection
>> +           );
>> +}
>> +
>> +/**
>> +  Locates a FFS file with the specified file type and a section
>> +  within that file with the specified section type.
>> +
>> +  @param[in]   Fv            The firmware volume to search
>> +  @param[in]   FileType      The file type to locate
>> +  @param[in]   SectionType   The section type to locate
>> +  @param[out]  FoundSection  The FFS section if found
>> +
>> +  @retval EFI_SUCCESS           The file and section was found
>> +  @retval EFI_NOT_FOUND         The file and section was not found
>> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
>> +**/
>> +EFI_STATUS
>> +FindFfsFileAndSection (
>> +  IN  EFI_FIRMWARE_VOLUME_HEADER  *Fv,
>> +  IN  EFI_FV_FILETYPE             FileType,
>> +  IN  EFI_SECTION_TYPE            SectionType,
>> +  OUT EFI_COMMON_SECTION_HEADER   **FoundSection
>> +  )
>> +{
>> +  EFI_STATUS            Status;
>> +  EFI_PHYSICAL_ADDRESS  CurrentAddress;
>> +  EFI_PHYSICAL_ADDRESS  EndOfFirmwareVolume;
>> +  EFI_FFS_FILE_HEADER   *File;
>> +  UINT32                Size;
>> +  EFI_PHYSICAL_ADDRESS  EndOfFile;
>> +
>> +  if (Fv->Signature != EFI_FVH_SIGNATURE) {
>> +    DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header 
>> signature\n", Fv));
>> +    return EFI_VOLUME_CORRUPTED;
>> +  }
>> +
>> +  CurrentAddress      = (EFI_PHYSICAL_ADDRESS)(UINTN)Fv;
>> +  EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
>> +
>> +  //
>> +  // Loop through the FFS files in the Boot Firmware Volume
>> +  //
>> +  for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
>> +    CurrentAddress = (EndOfFile + 7) & ~(7ULL);
>> +    if (CurrentAddress > EndOfFirmwareVolume) {
>> +      return EFI_VOLUME_CORRUPTED;
>> +    }
>> +
>> +    File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;
>> +    Size = *(UINT32 *)File->Size & 0xffffff;
>> +    if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
>> +      return EFI_VOLUME_CORRUPTED;
>> +    }
>> +
>> +    EndOfFile = CurrentAddress + Size;
>> +    if (EndOfFile > EndOfFirmwareVolume) {
>> +      return EFI_VOLUME_CORRUPTED;
>> +    }
>> +
>> +    //
>> +    // Look for the request file type
>> +    //
>> +    if (File->Type != FileType) {
>> +      continue;
>> +    }
>> +
>> +    Status = FindFfsSectionInSections (
>> +               (VOID *)(File + 1),
>> +               (UINTN)EndOfFile - (UINTN)(File + 1),
>> +               SectionType,
>> +               FoundSection
>> +               );
>> +    if (!EFI_ERROR (Status) ||
>> +        (Status == EFI_VOLUME_CORRUPTED))
>> +    {
>> +      return Status;
>> +    }
>> +  }
>> +}
>> +
>> +/**
>> +  Locates the PEI Core entry point address
>> +
>> +  @param[in]  Fv                 The firmware volume to search
>> +  @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
>> +
>> +  @retval EFI_SUCCESS           The file and section was found
>> +  @retval EFI_NOT_FOUND         The file and section was not found
>> +  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
>> +**/
>> +EFI_STATUS
>> +FindPeiCoreImageBaseInFv (
>> +  IN  EFI_FIRMWARE_VOLUME_HEADER  *Fv,
>> +  OUT  EFI_PHYSICAL_ADDRESS       *PeiCoreImageBase
>> +  )
>> +{
>> +  EFI_STATUS                 Status;
>> +  EFI_COMMON_SECTION_HEADER  *Section;
>> +
>> +  Status = FindFfsFileAndSection (
>> +             Fv,
>> +             EFI_FV_FILETYPE_PEI_CORE,
>> +             EFI_SECTION_PE32,
>> +             &Section
>> +             );
>> +  if (EFI_ERROR (Status)) {
>> +    Status = FindFfsFileAndSection (
>> +               Fv,
>> +               EFI_FV_FILETYPE_PEI_CORE,
>> +               EFI_SECTION_TE,
>> +               &Section
>> +               );
>> +    if (EFI_ERROR (Status)) {
>> +      DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
>> +      return Status;
>> +    }
>> +  }
>> +
>> +  *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  Find and return Pei Core entry point.
>> +
>> +  It also find SEC and PEI Core file debug information. It will 
>> report them if
>> +  remote debug is enabled.
>> +**/
>> +VOID
>> +FindAndReportEntryPoints (
>> +  IN  EFI_FIRMWARE_VOLUME_HEADER  **BootFirmwareVolumePtr,
>> +  OUT EFI_PEI_CORE_ENTRY_POINT    *PeiCoreEntryPoint
>> +  )
>> +{
>> +  EFI_STATUS                    Status;
>> +  EFI_PHYSICAL_ADDRESS          PeiCoreImageBase = 0;
>> +  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
>> +
>> +  Status = FindPeiCoreImageBaseInFv (*BootFirmwareVolumePtr, 
>> &PeiCoreImageBase);
>> +  ASSERT (Status == EFI_SUCCESS);
>> +
>> +  ZeroMem ((VOID *)&ImageContext, sizeof 
>> (PE_COFF_LOADER_IMAGE_CONTEXT));
>> +
>> +  //
>> +  // Report PEI Core debug information when remote debug is enabled
>> +  //
>> +  ImageContext.ImageAddress = 
>> (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
>> +  ImageContext.PdbPointer   = PeCoffLoaderGetPdbPointer ((VOID 
>> *)(UINTN)ImageContext.ImageAddress);
>> +  PeCoffLoaderRelocateImageExtraAction (&ImageContext);
>> +
>> +  //
>> +  // Find PEI Core entry point
>> +  //
>> +  Status = PeCoffLoaderGetEntryPoint ((VOID 
>> *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint);
>> +  if (EFI_ERROR (Status)) {
>> +    *PeiCoreEntryPoint = 0;
>> +  }
>> +
>> +  return;
>> +}
>> +
>> +/**
>> +  Find the peicore entry point and jump to the entry point to execute.
>> +
>> +  @param[in] Context    The first input parameter of 
>> InitializeDebugAgent().
>> +**/
>> +VOID
>> +EFIAPI
>> +SecStartupPhase2 (
>> +  IN VOID  *Context
>> +  )
>> +{
>> +  EFI_SEC_PEI_HAND_OFF        *SecCoreData;
>> +  EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
>> +  EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
>> +
>> +  SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
>> +
>> +  //
>> +  // Find PEI Core entry point. It will report SEC and Pei Core 
>> debug information if remote debug
>> +  // is enabled.
>> +  //
>> +  BootFv = (EFI_FIRMWARE_VOLUME_HEADER 
>> *)SecCoreData->BootFirmwareVolumeBase;
>> +  FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
>> +  SecCoreData->BootFirmwareVolumeBase = BootFv;
>> +  SecCoreData->BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
>> +
>> +  DEBUG ((DEBUG_INFO, "Find Pei EntryPoint=%p\n", PeiCoreEntryPoint));
>> +
>> +  //
>> +  // Transfer the control to the PEI core
>> +  //
>> +  DEBUG ((DEBUG_INFO, "SecStartupPhase2 %p\n", PeiCoreEntryPoint));
>> +
>> +  (*PeiCoreEntryPoint)(SecCoreData, (EFI_PEI_PPI_DESCRIPTOR 
>> *)&mPrivateDispatchTable);
>> +
>> +  //
>> +  // If we get here then the PEI Core returned, which is not 
>> recoverable.
>> +  //
>> +  ASSERT (FALSE);
>> +  CpuDeadLoop ();
>> +}
>> +
>> +/**
>> +  Entry point to the C language phase of SEC. initialize some 
>> temporary memory and set up the stack,
>> +  the control is transferred to this function.
>> +
>> +  @param[in]  BootFv   The pointer to the PEI FV in memory.
>> +  @param[in]  TopOfCurrentStack  Top of Current Stack.
>> +**/
>> +VOID
>> +EFIAPI
>> +SecCoreStartupWithStack (
>> +  IN EFI_FIRMWARE_VOLUME_HEADER  *BootFv,
>> +  IN VOID                        *TopOfCurrentStack
>> +  )
>> +{
>> +  EFI_SEC_PEI_HAND_OFF        SecCoreData;
>> +  EFI_FIRMWARE_VOLUME_HEADER  *BootPeiFv = 
>> (EFI_FIRMWARE_VOLUME_HEADER *)BootFv;
>> +
>> +  DEBUG ((DEBUG_INFO, "Entering C environment\n"));
>> +
>> +  ProcessLibraryConstructorList (NULL, NULL);
>> +
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "SecCoreStartupWithStack (0x%lx, 0x%lx)\n",
>> +    (UINTN)BootFv,
>> +    (UINTN)TopOfCurrentStack
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "(0x%lx, 0x%lx)\n",
>> +    (UINTN)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase)),
>> +    (UINTN)(FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
>> +    ));
>> +
>> +  // |-------------|       <-- TopOfCurrentStack
>> +  // |  BSP Stack  | 32k
>> +  // |-------------|
>> +  // |  BSP Heap   | 32k
>> +  // |-------------|       <-- SecCoreData.TemporaryRamBase
>> +  // |  Ap Stack   | 384k
>> +  // |-------------|
>> +  // |  Exception  | 64k
>> +  // |-------------|       <-- PcdOvmfSecPeiTempRamBase
>> +
>> +  ASSERT (
>> +    (UINTN)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) +
>> +            FixedPcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
>> +    (UINTN)TopOfCurrentStack
>> +    );
>> +
>> +  //
>> +  // Initialize SEC hand-off state
>> +  //
>> +  SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
>> +
>> +  SecCoreData.TemporaryRamSize = (UINTN)SIZE_64KB;
>> +  SecCoreData.TemporaryRamBase = (VOID *)(FixedPcdGet64 
>> (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) 
>> - SecCoreData.TemporaryRamSize);
>> +
>> +  SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
>> +  SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
>> +
>> +  SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + 
>> SecCoreData.PeiTemporaryRamSize;
>> +  SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
>> +
>> +  SecCoreData.BootFirmwareVolumeBase = BootPeiFv;
>> +  SecCoreData.BootFirmwareVolumeSize = (UINTN)BootPeiFv->FvLength;
>> +
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "&SecCoreData.BootFirmwareVolumeBase=%lx 
>> SecCoreData.BootFirmwareVolumeBase=%lx\n",
>> +    (UINT64)&(SecCoreData.BootFirmwareVolumeBase),
>> +    (UINT64)(SecCoreData.BootFirmwareVolumeBase)
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "&SecCoreData.BootFirmwareVolumeSize=%lx 
>> SecCoreData.BootFirmwareVolumeSize=%lx\n",
>> +    (UINT64)&(SecCoreData.BootFirmwareVolumeSize),
>> +    (UINT64)(SecCoreData.BootFirmwareVolumeSize)
>> +    ));
>> +
>> +  //
>> +  // Initialize Debug Agent to support source level debug in SEC/PEI 
>> phases before memory ready.
>> +  //
>> +  InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL);
>> +  SecStartupPhase2 (&SecCoreData);
>> +}
>> +
>> +/**
>> +  temporary memory to permanent memory and do stack switching.
>> +
>> +  @param[in]  PeiServices     Pointer to the PEI Services Table.
>> +  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
>> +  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
>> +  @param[in]  CopySize   The size of memory that needs to be migrated.
>> +
>> +  @retval   EFI_SUCCESS  Migration successful.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +TemporaryRamMigration (
>> +  IN CONST EFI_PEI_SERVICES  **PeiServices,
>> +  IN EFI_PHYSICAL_ADDRESS    TemporaryMemoryBase,
>> +  IN EFI_PHYSICAL_ADDRESS    PermanentMemoryBase,
>> +  IN UINTN                   CopySize
>> +  )
>> +{
>> +  VOID                      *OldHeap;
>> +  VOID                      *NewHeap;
>> +  VOID                      *OldStack;
>> +  VOID                      *NewStack;
>> +  BASE_LIBRARY_JUMP_BUFFER  JumpBuffer;
>> +
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "TemporaryRamMigration (0x%Lx, 0x%Lx, 0x%Lx)\n",
>> +    TemporaryMemoryBase,
>> +    PermanentMemoryBase,
>> +    (UINT64)CopySize
>> +    ));
>> +
>> +  OldHeap = (VOID *)(UINTN)TemporaryMemoryBase;
>> +  NewHeap = (VOID *)((UINTN)PermanentMemoryBase + (CopySize >> 1));
>> +
>> +  OldStack = (VOID *)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
>> +  NewStack = (VOID *)(UINTN)PermanentMemoryBase;
>> +
>> +  //
>> +  // Migrate Heap
>> +  //
>> +  CopyMem (NewHeap, OldHeap, CopySize >> 1);
>> +
>> +  //
>> +  // Migrate Stack
>> +  //
>> +  CopyMem (NewStack, OldStack, CopySize >> 1);
>> +
>> +  // Use SetJump ()/LongJump () to switch to a new stack.
>> +  //
>> +  if (SetJump (&JumpBuffer) == 0) {
>> +    JumpBuffer.SP = JumpBuffer.SP - (UINTN)OldStack + (UINTN)NewStack;
>> +    LongJump (&JumpBuffer, (UINTN)-1);
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> diff --git a/OvmfPkg/LoongArchVirt/Sec/SecMain.inf 
>> b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
>> new file mode 100644
>> index 0000000000..af29ba0551
>> --- /dev/null
>> +++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
>> @@ -0,0 +1,53 @@
>> +## @file
>> +#  SEC Driver
>> +#
>> +#  Copyright (c) 2024 Loongson Technology Corporation Limited. All 
>> rights reserved.<BR>
>> +#
>> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x00010005
>> +  BASE_NAME                      = SecMain
>> +  FILE_GUID                      = 57d02d4f-5a5d-4bfa-b7d6-ba0a4d2c72ce
>> +  MODULE_TYPE                    = SEC
>> +  VERSION_STRING                 = 1.0
>> +
>> +#
>> +#  VALID_ARCHITECTURES           = LOONGARCH64
>> +#
>> +
>> +[Sources]
>> +  LoongArch64/Start.S
>> +  SecMain.c
>> +
>> +[Packages]
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +  OvmfPkg/OvmfPkg.dec
>> +  UefiCpuPkg/UefiCpuPkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseLib
>> +  BaseMemoryLib
>> +  CpuExceptionHandlerLib
>> +  DebugAgentLib
>> +  DebugLib
>> +  IoLib
>> +  PcdLib
>> +  PeCoffLib
>> +  PeCoffGetEntryPointLib
>> +  PeCoffExtraActionLib
>> +
>> +[Ppis]
>> +  gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
>> +
>> +[FixedPcd]
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
>> +
>> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
>> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
>> +
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
>>
>
>
>
> 
>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113136): https://edk2.groups.io/g/devel/message/113136
Mute This Topic: https://groups.io/mt/103398640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-