From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by mx.groups.io with SMTP id smtpd.web11.8319.1634006416198781358 for ; Mon, 11 Oct 2021 19:40:17 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.43, mailfrom: min.m.xu@intel.com) X-IronPort-AV: E=McAfee;i="6200,9189,10134"; a="313215108" X-IronPort-AV: E=Sophos;i="5.85,366,1624345200"; d="scan'208";a="313215108" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 Oct 2021 19:40:02 -0700 X-IronPort-AV: E=Sophos;i="5.85,366,1624345200"; d="scan'208";a="490739069" Received: from mxu9-mobl1.ccr.corp.intel.com ([10.238.4.37]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 Oct 2021 19:40:00 -0700 From: "Min Xu" To: devel@edk2.groups.io Cc: Min Xu , Ard Biesheuvel , Jordan Justen , Gerd Hoffmann , Brijesh Singh , Erdem Aktas , James Bottomley , Jiewen Yao , Tom Lendacky Subject: [PATCH V9 4/4] OvmfPkg: Enable TDX in ResetVector Date: Tue, 12 Oct 2021 10:37:50 +0800 Message-Id: X-Mailer: git-send-email 2.29.2.windows.2 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 Intel's Trust Domain Extensions (Intel TDX) refers to an Intel technology that extends Virtual Machines Extensions (VMX) and Multi-Key Total Memory Encryption (MKTME) with a new kind of virutal machines guest called a Trust Domain (TD). A TD is desinged to run in a CPU mode that protects the confidentiality of TD memory contents and the TD's CPU state from other software, including the hosting Virtual-Machine Monitor (VMM), unless explicitly shared by the TD itself. Note: Intel TDX is only available on X64, so the Tdx related changes are in X64 path. In IA32 path, there may be null stub to make the build success. This patch includes below major changes. 1. Ia32/IntelTdx.asm IntelTdx.asm includes below routines used in ResetVector - IsTdx Check if the running system is Tdx guest. - InitTdxWorkarea It initialize the TDX_WORK_AREA. Because it is called by both BSP and APs and to avoid the race condition, only BSP can initialize the WORK_AREA. AP will wait until the field of TDX_WORK_AREA_PGTBL_READY is set. - ReloadFlat32 After reset all CPUs in TDX are initialized to 32-bit protected mode. But GDT register is not set. So this routine loads the GDT and set the CR0, then jump to Flat 32 protected mode again. After that CR4 and other registers are set. - InitTdx This routine wrap above 3 routines together to do Tdx initialization in ResetVector phase. - IsTdxEnabled It is a OneTimeCall to probe if TDX is enabled by checking the CC_WORK_AREA. - CheckTdxFeaturesBeforeBuildPagetables This routine is called to check if it is Non-TDX guest, TDX-Bsp or TDX-APs. Because in TDX guest all the initialization is done by BSP (including the page tables). APs should not build the tables. - TdxPostBuildPageTables It is called after Page Tables are built by BSP. byte[TDX_WORK_AREA_PGTBL_READY] is set by BSP to indicate APs can leave spin and go. 2. Ia32/PageTables64.asm As described above only the TDX BSP build the page tables. So PageTables64.asm is updated to make sure only TDX BSP build the PageTables. TDX APs will skip the page table building and set Cr3 directly. 3. Ia16/ResetVectorVtf0.asm In Tdx all CPUs "reset" to run on 32-bit protected mode with flat descriptor (paging disabled). But in Non-Td guest the initial state of CPUs is 16-bit real mode. To resolve this conflict, BITS 16/32 is used in the ResetVectorVtf0.asm. It checks the 32-bit protected mode or 16-bit real mode, then jump to the corresponding entry point. Cc: Ard Biesheuvel Cc: Jordan Justen Cc: Gerd Hoffmann Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Signed-off-by: Min Xu --- OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 20 ++ OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm | 11 + OvmfPkg/ResetVector/Ia32/IntelTdx.asm | 235 +++++++++++++++++++ OvmfPkg/ResetVector/Ia32/PageTables64.asm | 18 ++ OvmfPkg/ResetVector/Main.asm | 10 + OvmfPkg/ResetVector/ResetVector.nasmb | 1 + 6 files changed, 295 insertions(+) create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm index 7be43fb44a69..dee2e3f9de31 100644 --- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm @@ -177,10 +177,30 @@ resetVector: ; ; This is where the processor will begin execution ; +; In IA32 we follow the standard reset vector flow. While in X64, Td guest +; may be supported. Td guest requires the startup mode to be 32-bit +; protected mode but the legacy VM startup mode is 16-bit real mode. +; To make NASM generate such shared entry code that behaves correctly in +; both 16-bit and 32-bit mode, more BITS directives are added. +; +%ifdef ARCH_IA32 nop nop jmp EarlyBspInitReal16 +%else + + mov eax, cr0 + test al, 1 + jz .Real +BITS 32 + jmp Main32 +BITS 16 +.Real: + jmp EarlyBspInitReal16 + +%endif + ALIGN 16 fourGigabytes: diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm index c6d0d898bcd1..eb3546668ef8 100644 --- a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm +++ b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm @@ -21,6 +21,17 @@ Transition32FlatTo64Flat: bts eax, 5 ; enable PAE mov cr4, eax + ; + ; In TDX LME has already been set. So we're done and jump to enable + ; paging directly if Tdx is enabled. + ; EBX is cleared because in the later it will be used to check if + ; the second step of the SEV-ES mitigation is to be performed. + ; + xor ebx, ebx + OneTimeCall IsTdxEnabled + test eax, eax + jnz EnablePaging + mov ecx, 0xc0000080 rdmsr bts eax, 8 ; set LME diff --git a/OvmfPkg/ResetVector/Ia32/IntelTdx.asm b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm new file mode 100644 index 000000000000..f67b1bcf0b2e --- /dev/null +++ b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm @@ -0,0 +1,235 @@ +;------------------------------------------------------------------------------ +; @file +; Intel TDX routines +; +; Copyright (c) 2021, Intel Corporation. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;------------------------------------------------------------------------------ + +%define SEC_DEFAULT_CR0 0x00000023 +%define SEC_DEFAULT_CR4 0x640 +%define VM_GUEST_TDX 2 + +BITS 32 + +; +; Check if it is Intel Tdx +; +; Modified: EAX, EBX, ECX, EDX +; +; If it is Intel Tdx, EAX is 1 +; If it is not Intel Tdx, EAX is 0 +; +IsTdx: + ; + ; CPUID (0) + ; + mov eax, 0 + cpuid + cmp ebx, 0x756e6547 ; "Genu" + jne IsNotTdx + cmp edx, 0x49656e69 ; "ineI" + jne IsNotTdx + cmp ecx, 0x6c65746e ; "ntel" + jne IsNotTdx + + ; + ; CPUID (1) + ; + mov eax, 1 + cpuid + test ecx, 0x80000000 + jz IsNotTdx + + ; + ; CPUID[0].EAX >= 0x21? + ; + mov eax, 0 + cpuid + cmp eax, 0x21 + jl IsNotTdx + + ; + ; CPUID (0x21,0) + ; + mov eax, 0x21 + mov ecx, 0 + cpuid + + cmp ebx, 0x65746E49 ; "Inte" + jne IsNotTdx + cmp edx, 0x5844546C ; "lTDX" + jne IsNotTdx + cmp ecx, 0x20202020 ; " " + jne IsNotTdx + + mov eax, 1 + jmp ExitIsTdx + +IsNotTdx: + xor eax, eax + +ExitIsTdx: + + OneTimeCallRet IsTdx + +; +; Initialize work area if it is Tdx guest. Detailed definition is in +; OvmfPkg/Include/WorkArea.h. +; BSP and APs all go here. Only BSP initialize this work area. +; +; Param[in] EBP[5:0] CPU Supported GPAW (48 or 52) +; Param[in] ESI[31:0] vCPU ID (BSP is 0, others are AP) +; +; Modified: EBP +; +InitTdxWorkarea: + + ; + ; First check if it is Tdx + ; + OneTimeCall IsTdx + + test eax, eax + jz ExitInitTdxWorkarea + + cmp esi, 0 + je TdxBspEntry + + ; + ; In Td guest, BSP/AP shares the same entry point + ; BSP builds up the page table, while APs shouldn't do the same task. + ; Instead, APs just leverage the page table which is built by BSP. + ; APs will wait until the page table is ready. + ; +TdxApWait: + cmp byte[TDX_WORK_AREA_PGTBL_READY], 0 + je TdxApWait + jmp ExitInitTdxWorkarea + +TdxBspEntry: + ; + ; Set Type of WORK_AREA_GUEST_TYPE so that the following code can use + ; these information. + ; + mov byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX + + ; + ; EBP[5:0] CPU supported GPA width + ; + and ebp, 0x3f + mov DWORD[TDX_WORK_AREA_GPAW], ebp + +ExitInitTdxWorkarea: + OneTimeCallRet InitTdxWorkarea + +; +; Load the GDT and set the CR0. +; +; Modified: EAX, EBX, CR0, CR4, DS, ES, FS, GS, SS, CS +; +ReloadFlat32: + + cli + mov ebx, ADDR_OF(gdtr) + lgdt [ebx] + + mov eax, SEC_DEFAULT_CR0 + mov cr0, eax + + jmp LINEAR_CODE_SEL:dword ADDR_OF(jumpToFlat32BitAndLandHere) + +jumpToFlat32BitAndLandHere: + + mov eax, SEC_DEFAULT_CR4 + mov cr4, eax + + debugShowPostCode POSTCODE_32BIT_MODE + + mov ax, LINEAR_SEL + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + OneTimeCallRet ReloadFlat32 + +; +; Tdx initialization after entering into ResetVector +; +; Modified: EAX, EBX, ECX, EDX, EBP, EDI, ESP +; +InitTdx: + ; + ; Save EBX in EBP because EBX will be changed in ReloadFlat32 + ; + mov ebp, ebx + + ; + ; First load the GDT and jump to Flat32 mode + ; + OneTimeCall ReloadFlat32 + + ; + ; Initialization of Tdx work area + ; + OneTimeCall InitTdxWorkarea + + OneTimeCallRet InitTdx + +; +; Check TDX features, TDX or TDX-BSP or TDX-APs? +; +; By design TDX BSP is reponsible for initializing the PageTables. +; After PageTables are ready, byte[TDX_WORK_AREA_PGTBL_READY] is set to 1. +; APs will spin when byte[TDX_WORK_AREA_PGTBL_READY] is 0 until it is set to 1. +; +; When this routine is run on TDX BSP, byte[TDX_WORK_AREA_PGTBL_READY] should be 0. +; When this routine is run on TDX APs, byte[TDX_WORK_AREA_PGTBL_READY] should be 1. +; +; +; Modified: EAX, EDX +; +; 0-NonTdx, 1-TdxBsp, 2-TdxAps +; +CheckTdxFeaturesBeforeBuildPagetables: + xor eax, eax + cmp byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX + jne NotTdx + + xor edx, edx + mov al, byte[TDX_WORK_AREA_PGTBL_READY] + inc eax + +NotTdx: + OneTimeCallRet CheckTdxFeaturesBeforeBuildPagetables + +; +; Set byte[TDX_WORK_AREA_PGTBL_READY] to 1 +; +TdxPostBuildPageTables: + cmp byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX + jne ExitTdxPostBuildPageTables + mov byte[TDX_WORK_AREA_PGTBL_READY], 1 + +ExitTdxPostBuildPageTables: + OneTimeCallRet TdxPostBuildPageTables + +; +; Check if TDX is enabled +; +; Modified: EAX +; +; If TDX is enabled then EAX will be 1 +; If TDX is disabled then EAX will be 0. +; +IsTdxEnabled: + xor eax, eax + cmp byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX + jne TdxNotEnabled + mov eax, 1 + +TdxNotEnabled: + OneTimeCallRet IsTdxEnabled diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm index 02528221e560..317cad430f29 100644 --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm @@ -37,10 +37,23 @@ BITS 32 PAGE_READ_WRITE + \ PAGE_PRESENT) +%define TDX_BSP 1 +%define TDX_AP 2 + ; ; Modified: EAX, EBX, ECX, EDX ; SetCr3ForPageTables64: + ; Check the TDX features. + ; If it is TDX APs, then jump to SetCr3 directly. + ; In TD guest the initialization is done by BSP, including building + ; the page tables. APs will spin on until byte[TDX_WORK_AREA_PGTBL_READY] + ; is set. + OneTimeCall CheckTdxFeaturesBeforeBuildPagetables + cmp eax, TDX_BSP + je ClearOvmfPageTables + cmp eax, TDX_AP + je SetCr3 ; Check whether the SEV is active and populate the SevEsWorkArea OneTimeCall CheckSevFeatures @@ -50,6 +63,7 @@ SetCr3ForPageTables64: ; the page table build below. OneTimeCall GetSevCBitMaskAbove31 +ClearOvmfPageTables: ; ; For OVMF, build some initial page tables at ; PcdOvmfSecPageTablesBase - (PcdOvmfSecPageTablesBase + 0x6000). @@ -101,6 +115,10 @@ pageTableEntriesLoop: ; Clear the C-bit from the GHCB page if the SEV-ES is enabled. OneTimeCall SevClearPageEncMaskForGhcbPage + ; TDX will do some PostBuildPages task, such as setting + ; byte[TDX_WORK_AREA_PGTBL_READY]. + OneTimeCall TdxPostBuildPageTables + SetCr3: ; ; Set CR3 now that the paging structures are available diff --git a/OvmfPkg/ResetVector/Main.asm b/OvmfPkg/ResetVector/Main.asm index a501fbe880f2..07033e9470b5 100644 --- a/OvmfPkg/ResetVector/Main.asm +++ b/OvmfPkg/ResetVector/Main.asm @@ -42,6 +42,16 @@ BITS 32 ; work area when detected. mov byte[WORK_AREA_GUEST_TYPE], 0 + jmp SearchBfv + +; +; Entry point of Main32 +; +Main32: + OneTimeCall InitTdx + +SearchBfv: + %endif ; diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb index 711e0dac4cdf..75ec800af089 100644 --- a/OvmfPkg/ResetVector/ResetVector.nasmb +++ b/OvmfPkg/ResetVector/ResetVector.nasmb @@ -107,6 +107,7 @@ %include "Ia32/Flat32ToFlat64.asm" %include "Ia32/AmdSev.asm" %include "Ia32/PageTables64.asm" +%include "Ia32/IntelTdx.asm" %endif %include "Ia16/Real16ToFlat32.asm" -- 2.29.2.windows.2