| /** @file | |
| Main SEC phase code. Transitions to PEI. | |
| Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR> | |
| (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
| Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <PiPei.h> | |
| #include <Library/PeimEntryPoint.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/PcdLib.h> | |
| #include <Library/CpuLib.h> | |
| #include <Library/DebugAgentLib.h> | |
| #include <Library/IoLib.h> | |
| #include <Library/PeCoffLib.h> | |
| #include <Library/PeCoffGetEntryPointLib.h> | |
| #include <Library/LocalApicLib.h> | |
| #include <Library/CpuExceptionHandlerLib.h> | |
| #include <IndustryStandard/Tdx.h> | |
| #include <Library/TdxHelperLib.h> | |
| #include <Library/CcProbeLib.h> | |
| #include <Library/PeilessStartupLib.h> | |
| #define SEC_IDT_ENTRY_COUNT 34 | |
| typedef struct _SEC_IDT_TABLE { | |
| EFI_PEI_SERVICES *PeiService; | |
| IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT]; | |
| } SEC_IDT_TABLE; | |
| // | |
| // Template of an IDT entry pointing to 10:FFFFFFE4h. | |
| // | |
| IA32_IDT_GATE_DESCRIPTOR mIdtEntryTemplate = { | |
| { // Bits | |
| 0xffe4, // OffsetLow | |
| 0x10, // Selector | |
| 0x0, // Reserved_0 | |
| IA32_IDT_GATE_TYPE_INTERRUPT_32, // GateType | |
| 0xffff // OffsetHigh | |
| } | |
| }; | |
| VOID | |
| EFIAPI | |
| SecCoreStartupWithStack ( | |
| IN EFI_FIRMWARE_VOLUME_HEADER *BootFv, | |
| IN VOID *TopOfCurrentStack | |
| ) | |
| { | |
| EFI_SEC_PEI_HAND_OFF SecCoreData; | |
| SEC_IDT_TABLE IdtTableInStack; | |
| IA32_DESCRIPTOR IdtDescriptor; | |
| UINT32 Index; | |
| volatile UINT8 *Table; | |
| if (CcProbe () == CcGuestTypeIntelTdx) { | |
| // | |
| // From the security perspective all the external input should be measured before | |
| // it is consumed. TdHob and Configuration FV (Cfv) image are passed from VMM | |
| // and should be measured here. | |
| // | |
| if (EFI_ERROR (TdxHelperMeasureTdHob ())) { | |
| CpuDeadLoop (); | |
| } | |
| if (EFI_ERROR (TdxHelperMeasureCfvImage ())) { | |
| CpuDeadLoop (); | |
| } | |
| // | |
| // For Td guests, the memory map info is in TdHobLib. It should be processed | |
| // first so that the memory is accepted. Otherwise access to the unaccepted | |
| // memory will trigger tripple fault. | |
| // | |
| if (TdxHelperProcessTdHob () != EFI_SUCCESS) { | |
| CpuDeadLoop (); | |
| } | |
| } | |
| // | |
| // To ensure SMM can't be compromised on S3 resume, we must force re-init of | |
| // the BaseExtractGuidedSectionLib. Since this is before library contructors | |
| // are called, we must use a loop rather than SetMem. | |
| // | |
| Table = (UINT8 *)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress); | |
| for (Index = 0; | |
| Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize); | |
| ++Index) | |
| { | |
| Table[Index] = 0; | |
| } | |
| // | |
| // Initialize IDT - Since this is before library constructors are called, | |
| // we use a loop rather than CopyMem. | |
| // | |
| IdtTableInStack.PeiService = NULL; | |
| for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) { | |
| // | |
| // Declare the local variables that actually move the data elements as | |
| // volatile to prevent the optimizer from replacing this function with | |
| // the intrinsic memcpy() | |
| // | |
| CONST UINT8 *Src; | |
| volatile UINT8 *Dst; | |
| UINTN Byte; | |
| Src = (CONST UINT8 *)&mIdtEntryTemplate; | |
| Dst = (volatile UINT8 *)&IdtTableInStack.IdtTable[Index]; | |
| for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) { | |
| Dst[Byte] = Src[Byte]; | |
| } | |
| } | |
| IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable; | |
| IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1); | |
| ProcessLibraryConstructorList (NULL, NULL); | |
| // | |
| // Load the IDTR. | |
| // | |
| AsmWriteIdtr (&IdtDescriptor); | |
| if (CcProbe () == CcGuestTypeIntelTdx) { | |
| // | |
| // InitializeCpuExceptionHandlers () should be called in Td guests so that | |
| // #VE exceptions can be handled correctly. | |
| // | |
| InitializeCpuExceptionHandlers (NULL); | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "SecCoreStartupWithStack(0x%x, 0x%x)\n", | |
| (UINT32)(UINTN)BootFv, | |
| (UINT32)(UINTN)TopOfCurrentStack | |
| )); | |
| // | |
| // Initialize floating point operating environment | |
| // to be compliant with UEFI spec. | |
| // | |
| InitializeFloatingPointUnits (); | |
| // | |
| // ASSERT that the Page Tables were set by the reset vector code to | |
| // the address we expect. | |
| // | |
| ASSERT (AsmReadCr3 () == (UINTN)PcdGet32 (PcdOvmfSecPageTablesBase)); | |
| // | |
| // |-------------| <-- TopOfCurrentStack | |
| // | Stack | 32k | |
| // |-------------| | |
| // | Heap | 32k | |
| // |-------------| <-- SecCoreData.TemporaryRamBase | |
| // | |
| ASSERT ( | |
| (UINTN)(PcdGet32 (PcdOvmfSecPeiTempRamBase) + | |
| PcdGet32 (PcdOvmfSecPeiTempRamSize)) == | |
| (UINTN)TopOfCurrentStack | |
| ); | |
| // | |
| // Initialize SEC hand-off state | |
| // | |
| SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF); | |
| SecCoreData.TemporaryRamSize = (UINTN)PcdGet32 (PcdOvmfSecPeiTempRamSize); | |
| SecCoreData.TemporaryRamBase = (VOID *)((UINT8 *)TopOfCurrentStack - 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 = BootFv; | |
| SecCoreData.BootFirmwareVolumeSize = (UINTN)BootFv->FvLength; | |
| // | |
| // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled | |
| // | |
| IoWrite8 (0x21, 0xff); | |
| IoWrite8 (0xA1, 0xff); | |
| // | |
| // Initialize Local APIC Timer hardware and disable Local APIC Timer | |
| // interrupts before initializing the Debug Agent and the debug timer is | |
| // enabled. | |
| // | |
| InitializeApicTimer (0, MAX_UINT32, TRUE, 5); | |
| DisableApicTimerInterrupt (); | |
| PeilessStartup (&SecCoreData); | |
| ASSERT (FALSE); | |
| CpuDeadLoop (); | |
| } |