audk/OvmfPkg/ResetVector/Ia32/IntelTdx.asm

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