diff --git a/OvmfPkg/Include/IndustryStandard/IntelTdx.h b/OvmfPkg/Include/IndustryStandard/IntelTdx.h index 1151f9edd5..e80688c459 100644 --- a/OvmfPkg/Include/IndustryStandard/IntelTdx.h +++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h @@ -63,6 +63,7 @@ typedef struct { typedef struct { UINT8 *RelocateApLoopFuncAddress; UINTN RelocateApLoopFuncSize; + UINT8 *RelocateApResetVector; } MP_RELOCATION_MAP; #pragma pack() diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c index 12e4501c5b..c3e08d8812 100644 --- a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c +++ b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c @@ -186,10 +186,13 @@ PlatformTdxPublishRamRegions ( // work area. We ought to prevent DXE from serving allocation requests // such that they would overlap the work area. // + // Since this memory range will be used by the Reset Vector on Maibox + // wakeup again, it must be reserved as ACPI NVS. + // BuildMemoryAllocationHob ( (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase), (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize), - EfiBootServicesData + EfiACPIMemoryNVS ); } } diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.c b/OvmfPkg/TdxDxe/TdxAcpiTable.c index d6d6975e56..4f62d7d729 100644 --- a/OvmfPkg/TdxDxe/TdxAcpiTable.c +++ b/OvmfPkg/TdxDxe/TdxAcpiTable.c @@ -28,6 +28,43 @@ #include #include +IA32_SEGMENT_DESCRIPTOR 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 +74,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 +131,7 @@ RelocateMailbox ( ApLoopFunc )); + SetMailboxResetVectorGDT (); // // Initialize mailbox // @@ -115,6 +155,13 @@ RelocateMailbox ( 0 ); + *ResetVector = (UINT64)ApLoopFunc + (RelocationMap.RelocateApResetVector - + RelocationMap.RelocateApLoopFuncAddress); + DEBUG (( + DEBUG_INFO, + "Ap Relocation: reset_vector %llx\n", + *ResetVector + )); return Address; } @@ -142,7 +189,8 @@ AlterAcpiTable ( UINT8 *NewMadtTable; UINTN NewMadtTableLength; EFI_PHYSICAL_ADDRESS RelocateMailboxAddress; - EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *MadtMpWk; + EFI_PHYSICAL_ADDRESS RelocateResetVector; + EFI_ACPI_6_6_MULTIPROCESSOR_WAKEUP_STRUCTURE *MadtMpWk; EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader; Index = 0; @@ -155,7 +203,7 @@ AlterAcpiTable ( return; } - RelocateMailboxAddress = RelocateMailbox (); + RelocateMailboxAddress = RelocateMailbox (&RelocateResetVector); if (RelocateMailboxAddress == 0) { ASSERT (FALSE); DEBUG ((DEBUG_ERROR, "Failed to relocate Td mailbox\n")); @@ -172,7 +220,7 @@ AlterAcpiTable ( break; } - NewMadtTableLength = Table->Length + sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE); + NewMadtTableLength = Table->Length + sizeof (EFI_ACPI_6_6_MULTIPROCESSOR_WAKEUP_STRUCTURE); NewMadtTable = AllocatePool (NewMadtTableLength); if (NewMadtTable == NULL) { DEBUG ((DEBUG_ERROR, "%a: OUT_OF_SOURCES error.\n", __func__)); @@ -183,12 +231,13 @@ AlterAcpiTable ( MadtHeader = (EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)NewMadtTable; MadtHeader->Header.Length = (UINT32)NewMadtTableLength; - MadtMpWk = (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *)(NewMadtTable + Table->Length); + MadtMpWk = (EFI_ACPI_6_6_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->Length = sizeof (EFI_ACPI_6_6_MULTIPROCESSOR_WAKEUP_STRUCTURE); + 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 6b7615dc36..6081665ffa 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 9793562884..69e4c0bfa5 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 6e909f7d02..e99d735b00 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 0xffc4 @@ -76,6 +86,7 @@ AsmRelocateApMailBoxLoopStart: test r10, r10 jnz Panic mov r8, r15 + mov qword[rel mailbox_address], rbx MailBoxLoop: ; Spin until command set @@ -104,6 +115,91 @@ MailBoxTest: jmp MailBoxLoop 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: @@ -112,8 +208,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 -