Files
system76-edk2/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
Min Xu 8b76f23534 OvmfPkg: Enable TDX in ResetVector
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 then jump
   to Flat 32 protected mode again.

 - 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 <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2021-10-24 02:09:27 +00:00

223 lines
4.8 KiB
NASM

;------------------------------------------------------------------------------
; @file
; Intel TDX routines
;
; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
;------------------------------------------------------------------------------
%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] EBX[5:0] CPU Supported GPAW (48 or 52)
; Param[in] ESI[31:0] vCPU ID (BSP is 0, others are AP)
;
; Modified: EBX
;
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
;
; EBX[5:0] CPU supported GPA width
;
and ebx, 0x3f
mov DWORD[TDX_WORK_AREA_GPAW], ebx
ExitInitTdxWorkarea:
OneTimeCallRet InitTdxWorkarea
;
; Load the GDT and set the CS/DS/ES/FS/GS/SS.
;
; Modified: EAX, DS, ES, FS, GS, SS, CS
;
ReloadFlat32:
cli
mov eax, ADDR_OF(gdtr)
lgdt [eax]
jmp LINEAR_CODE_SEL:dword ADDR_OF(jumpToFlat32BitAndLandHere)
jumpToFlat32BitAndLandHere:
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:
;
; 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