diff --git a/OvmfPkg/Include/IndustryStandard/IntelTdx.h b/OvmfPkg/Include/IndustryStandard/IntelTdx.h index fc383468489..68126b8a3cd 100644 --- a/OvmfPkg/Include/IndustryStandard/IntelTdx.h +++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h @@ -61,6 +61,7 @@ typedef struct { typedef struct { UINT8 *RelocateApLoopFuncAddress; UINTN RelocateApLoopFuncSize; + UINT8 *RelocateApResetVector; } MP_RELOCATION_MAP; #pragma pack() diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.c b/OvmfPkg/TdxDxe/TdxAcpiTable.c index d6d6975e567..ca977fb9265 100644 --- a/OvmfPkg/TdxDxe/TdxAcpiTable.c +++ b/OvmfPkg/TdxDxe/TdxAcpiTable.c @@ -28,6 +28,46 @@ #include #include + + IA32_GDT mGdtEntries[] = { + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, /* 0x0: reserve */ + { + { 0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0 } + }, /* 0x8: compatibility mode */ + { + { 0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0 } + }, /* 0x10: for long mode */ + { + { 0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0 } + }, /* 0x18: data */ + { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, /* 0x20: reserve */ +}; + + +/** + At the beginning of ResetVector in OS, the GDT needs to be reloaded. +**/ +VOID +SetMailboxResetVectorGDT ( + VOID + ) +{ + TDX_WORK_AREA *TdxWorkArea; + + TdxWorkArea = (TDX_WORK_AREA *)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase); + ASSERT (TdxWorkArea != NULL); + ZeroMem ((VOID *)TdxWorkArea->MailboxGdt.Data, sizeof (TdxWorkArea->MailboxGdt.Data)); + + CopyMem((VOID *)TdxWorkArea->MailboxGdt.Data, (VOID *)mGdtEntries, sizeof(mGdtEntries)); + TdxWorkArea->MailboxGdt.Gdtr.Base = (UINTN)TdxWorkArea->MailboxGdt.Data; + TdxWorkArea->MailboxGdt.Gdtr.Limit = sizeof (mGdtEntries) - 1; +} + + /** At the beginning of system boot, a 4K-aligned, 4K-size memory (Td mailbox) is pre-allocated by host VMM. BSP & APs do the page accept together in that memory @@ -37,12 +77,14 @@ memory block which is allocated in the ACPI Nvs memory. APs are waken up and spin around the relocated mailbox for further command. + @param[in, out] ResetVector Pointer to the ResetVector + @return EFI_PHYSICAL_ADDRESS Address of the relocated mailbox **/ EFI_PHYSICAL_ADDRESS EFIAPI RelocateMailbox ( - VOID + EFI_PHYSICAL_ADDRESS *ResetVector ) { EFI_PHYSICAL_ADDRESS Address; @@ -92,6 +134,7 @@ RelocateMailbox ( ApLoopFunc )); + SetMailboxResetVectorGDT(); // // Initialize mailbox // @@ -115,6 +158,13 @@ RelocateMailbox ( 0 ); + *ResetVector = (UINT64)ApLoopFunc + (RelocationMap.RelocateApResetVector - + RelocationMap.RelocateApLoopFuncAddress); + DEBUG (( + DEBUG_INFO, + "Ap Relocation: reset_vector %llx\n", + *ResetVector + )); return Address; } @@ -142,6 +192,7 @@ AlterAcpiTable ( UINT8 *NewMadtTable; UINTN NewMadtTableLength; EFI_PHYSICAL_ADDRESS RelocateMailboxAddress; + EFI_PHYSICAL_ADDRESS RelocateResetVector; EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *MadtMpWk; EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader; @@ -155,7 +206,7 @@ AlterAcpiTable ( return; } - RelocateMailboxAddress = RelocateMailbox (); + RelocateMailboxAddress = RelocateMailbox (&RelocateResetVector); if (RelocateMailboxAddress == 0) { ASSERT (FALSE); DEBUG ((DEBUG_ERROR, "Failed to relocate Td mailbox\n")); @@ -186,9 +237,10 @@ AlterAcpiTable ( MadtMpWk = (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *)(NewMadtTable + Table->Length); MadtMpWk->Type = EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP; MadtMpWk->Length = sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE); - MadtMpWk->MailBoxVersion = 0; + MadtMpWk->MailBoxVersion = 1; MadtMpWk->Reserved = 0; MadtMpWk->MailBoxAddress = RelocateMailboxAddress; + MadtMpWk->ResetVector = RelocateResetVector; Status = AcpiTableProtocol->InstallAcpiTable (AcpiTableProtocol, NewMadtTable, NewMadtTableLength, &NewTableKey); if (EFI_ERROR (Status)) { diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.h b/OvmfPkg/TdxDxe/TdxAcpiTable.h index 6b7615dc368..89fbe98d864 100644 --- a/OvmfPkg/TdxDxe/TdxAcpiTable.h +++ b/OvmfPkg/TdxDxe/TdxAcpiTable.h @@ -18,6 +18,8 @@ #include #include #include +#include + #include #include @@ -41,7 +43,7 @@ AsmGetRelocationMap ( EFI_PHYSICAL_ADDRESS EFIAPI RelocateMailbox ( - VOID + EFI_PHYSICAL_ADDRESS *ResetVector ); /** diff --git a/OvmfPkg/TdxDxe/TdxDxe.inf b/OvmfPkg/TdxDxe/TdxDxe.inf index 9793562884c..69e4c0bfa54 100644 --- a/OvmfPkg/TdxDxe/TdxDxe.inf +++ b/OvmfPkg/TdxDxe/TdxDxe.inf @@ -71,3 +71,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize diff --git a/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm b/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm index a398c1964bb..654d41d9330 100644 --- a/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm +++ b/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm @@ -16,8 +16,18 @@ DEFAULT REL +SECTION .bss +global STACK_BASE +STACK_BASE: + resb 1024 +STACK_TOP: + SECTION .text +%define TDX_WORK_AREA_MAILBOX_GDTR (FixedPcdGet32 (PcdOvmfWorkAreaBase) + 128) + +%define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset)) + BITS 64 %define TDVMCALL_EXPOSE_REGS_MASK 0xffec @@ -49,6 +59,7 @@ AsmRelocateApMailBoxLoopStart: test r10, r10 jnz Panic mov r8, r15 + mov qword[rel mailbox_address], rbx MailBoxLoop: ; Spin until command set @@ -81,6 +92,91 @@ MailBoxSleep: jmp $ Panic: ud2 + +AsmRelocateApResetVector: + +.prepareStack: + ; The stack can then be used to switch from long mode to compatibility mode + mov rsp, STACK_TOP + +.loadGDT: + cli + mov rax, TDX_WORK_AREA_MAILBOX_GDTR + lgdt [rax] + +.loadSwicthModeCode: + mov rcx, dword 0x10 ; load long mode selector + shl rcx, 32 + lea rdx, [LongMode] ; assume address < 4G + or rcx, rdx + push rcx + + mov rcx, dword 0x08 ; load compatible mode selector + shl rcx, 32 + lea rdx, [Compatible] ; assume address < 4G + or rcx, rdx + push rcx + retf + +BITS 32 +Compatible: + mov eax, dword 0x18 +; ; reload DS/ES/SS to make sure they are correct referred to current GDT + mov ds, ax + mov es, ax + mov ss, ax + ; reload the fs and gs + mov fs, ax + mov gs, ax + + ; Must clear the CR4.PCIDE before clearing paging + mov ecx, cr4 + btc ecx, 17 + mov cr4, ecx + ; + ; Disable paging + ; + mov ecx, cr0 + btc ecx, 31 + mov cr0, ecx + ; +RestoreCr0: + ; Only enable PE(bit 0), NE(bit 5), ET(bit 4) 0x31 + mov eax, dword 0x31 + mov cr0, eax + + + ; Only Enable MCE(bit 6), VMXE(bit 13) 0x2040 + ; TDX enforeced the VMXE = 1 and mask it in VMM, so not set it. +RestoreCr4: + mov eax, 0x40 + mov cr4, eax +SetCr3: + ; + ; Can use the boot page tables since it's reserved + + mov eax, PT_ADDR (0) + mov cr3, eax + +EnablePAE: + mov eax, cr4 + bts eax, 5 + mov cr4, eax + +EnablePaging: + mov eax, cr0 + bts eax, 31 ; set PG + mov cr0, eax ; enable paging + ; return to LongMode + retf + +BITS 64 +LongMode: + mov rbx, qword[rel mailbox_address] + jmp AsmRelocateApMailBoxLoopStart +align 16 +mailbox_address: + dq 0 BITS 64 AsmRelocateApMailBoxLoopEnd: @@ -89,8 +185,10 @@ AsmRelocateApMailBoxLoopEnd: ;------------------------------------------------------------------------------------- global ASM_PFX(AsmGetRelocationMap) ASM_PFX(AsmGetRelocationMap): + ; mov byte[TDX_WORK_AREA_MB_PGTBL_READY], 0 lea rax, [AsmRelocateApMailBoxLoopStart] mov qword [rcx], rax mov qword [rcx + 8h], AsmRelocateApMailBoxLoopEnd - AsmRelocateApMailBoxLoopStart + lea rax, [AsmRelocateApResetVector] + mov qword [rcx + 10h], rax ret -