From 1f29de4d2079876d66582886a6cd7335c98d527e Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 18 Dec 2021 21:36:08 +0800 Subject: OvmfPkg/IntelTdx: Add Sec to bring up both Legacy and Tdx guest RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 OvmfPkg/IntelTdx/Sec is a simplied version of OvmfPkg/Sec. There are below differences between these 2 Sec - IntelTdx/Sec only supports Legacy guest and Tdx guest in X64. - IntelTdx/Sec calls PeilessStartup () to jump from SEC to DXE directly. - IntelTdx/Sec uses MemoryAllocationLib / HobLib / PrePiLib in EmbeddedPkg. Cc: Michael D Kinney Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Gerd Hoffmann Acked-by: Gerd Hoffmann Reviewed-by: Jiewen Yao Signed-off-by: Min Xu --- OvmfPkg/IntelTdx/Sec/SecMain.c | 198 +++++++++++++++++++++++++++++++++ OvmfPkg/IntelTdx/Sec/SecMain.inf | 61 ++++++++++ OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm | 151 +++++++++++++++++++++++++ 3 files changed, 410 insertions(+) create mode 100644 OvmfPkg/IntelTdx/Sec/SecMain.c create mode 100644 OvmfPkg/IntelTdx/Sec/SecMain.inf create mode 100644 OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm (limited to 'OvmfPkg/IntelTdx') diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.c b/OvmfPkg/IntelTdx/Sec/SecMain.c new file mode 100644 index 0000000000..26d56be335 --- /dev/null +++ b/OvmfPkg/IntelTdx/Sec/SecMain.c @@ -0,0 +1,198 @@ +/** @file + Main SEC phase code. Transitions to PEI. + + Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 (TdIsEnabled ()) { + // + // 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 (ProcessTdxHobList () != 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 (TdIsEnabled ()) { + // + // 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 (); +} diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.inf b/OvmfPkg/IntelTdx/Sec/SecMain.inf new file mode 100644 index 0000000000..df2e749c35 --- /dev/null +++ b/OvmfPkg/IntelTdx/Sec/SecMain.inf @@ -0,0 +1,61 @@ +## @file +# SEC Driver +# +# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecMain + FILE_GUID = 69d96630-eb64-4b33-8491-13a5cf023dcf + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + ENTRY_POINT = SecMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = X64 +# + +[Sources] + SecMain.c + X64/SecEntry.nasm + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + OvmfPkg/OvmfPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + PcdLib + UefiCpuLib + DebugAgentLib + IoLib + PeCoffLib + PeCoffGetEntryPointLib + PeCoffExtraActionLib + ExtractGuidedSectionLib + LocalApicLib + MemEncryptSevLib + CpuExceptionHandlerLib + PeilessStartupLib + PlatformInitLib + +[Pcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize + gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress + gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase diff --git a/OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm b/OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm new file mode 100644 index 0000000000..4528fec309 --- /dev/null +++ b/OvmfPkg/IntelTdx/Sec/X64/SecEntry.nasm @@ -0,0 +1,151 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+;* SPDX-License-Identifier: BSD-2-Clause-Patent +;* +;* CpuAsm.asm +;* +;* Abstract: +;* +;------------------------------------------------------------------------------ + +#include +%include "TdxCommondefs.inc" + +DEFAULT REL +SECTION .text + +extern ASM_PFX(SecCoreStartupWithStack) + +%macro tdcall 0 + db 0x66, 0x0f, 0x01, 0xcc +%endmacro + +; +; SecCore Entry Point +; +; Processor is in flat protected mode +; +; @param[in] RAX Initial value of the EAX register (BIST: Built-in Self Test) +; @param[in] DI 'BP': boot-strap processor, or 'AP': application processor +; @param[in] RBP Pointer to the start of the Boot Firmware Volume +; @param[in] DS Selector allowing flat access to all addresses +; @param[in] ES Selector allowing flat access to all addresses +; @param[in] FS Selector allowing flat access to all addresses +; @param[in] GS Selector allowing flat access to all addresses +; @param[in] SS Selector allowing flat access to all addresses +; +; @return None This routine does not return +; +global ASM_PFX(_ModuleEntryPoint) +ASM_PFX(_ModuleEntryPoint): + + ; + ; Guest type is stored in OVMF_WORK_AREA + ; + %define OVMF_WORK_AREA FixedPcdGet32 (PcdOvmfWorkAreaBase) + %define VM_GUEST_TYPE_TDX 2 + mov eax, OVMF_WORK_AREA + cmp byte[eax], VM_GUEST_TYPE_TDX + jne InitStack + + mov rax, TDCALL_TDINFO + tdcall + + ; + ; R8 [31:0] NUM_VCPUS + ; [63:32] MAX_VCPUS + ; R9 [31:0] VCPU_INDEX + ; Td Guest set the VCPU0 as the BSP, others are the APs + ; APs jump to spinloop and get released by DXE's MpInitLib + ; + mov rax, r9 + and rax, 0xffff + test rax, rax + jne ParkAp + +InitStack: + + ; + ; Fill the temporary RAM with the initial stack value. + ; The loop below will seed the heap as well, but that's harmless. + ; + mov rax, (FixedPcdGet32 (PcdInitValueInTempStack) << 32) | FixedPcdGet32 (PcdInitValueInTempStack) + ; qword to store + mov rdi, FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) ; base address, + ; relative to + ; ES + mov rcx, FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 8 ; qword count + cld ; store from base + ; up + rep stosq + + ; + ; Load temporary RAM stack based on PCDs + ; + %define SEC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + \ + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize)) + mov rsp, SEC_TOP_OF_STACK + nop + + ; + ; Setup parameters and call SecCoreStartupWithStack + ; rcx: BootFirmwareVolumePtr + ; rdx: TopOfCurrentStack + ; + mov rcx, rbp + mov rdx, rsp + sub rsp, 0x20 + call ASM_PFX(SecCoreStartupWithStack) + + ; + ; Note: BSP never gets here. APs will be unblocked by DXE + ; + ; R8 [31:0] NUM_VCPUS + ; [63:32] MAX_VCPUS + ; R9 [31:0] VCPU_INDEX + ; +ParkAp: + + mov rbp, r9 + +.do_wait_loop: + mov rsp, FixedPcdGet32 (PcdOvmfSecGhcbBackupBase) + + ; + ; register itself in [rsp + CpuArrivalOffset] + ; + mov rax, 1 + lock xadd dword [rsp + CpuArrivalOffset], eax + inc eax + +.check_arrival_cnt: + cmp eax, r8d + je .check_command + mov eax, dword[rsp + CpuArrivalOffset] + jmp .check_arrival_cnt + +.check_command: + mov eax, dword[rsp + CommandOffset] + cmp eax, MpProtectedModeWakeupCommandNoop + je .check_command + + cmp eax, MpProtectedModeWakeupCommandWakeup + je .do_wakeup + + ; Don't support this command, so ignore + jmp .check_command + +.do_wakeup: + ; + ; BSP sets these variables before unblocking APs + ; RAX: WakeupVectorOffset + ; RBX: Relocated mailbox address + ; RBP: vCpuId + ; + mov rax, 0 + mov eax, dword[rsp + WakeupVectorOffset] + mov rbx, [rsp + WakeupArgsRelocatedMailBox] + nop + jmp rax + jmp $ -- cgit v1.2.3