4 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
6 Copyright (C) 2012-2014, Red Hat, Inc.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/DebugLib.h>
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Library/QemuFwCfgLib.h>
17 #include <Library/DxeServicesTableLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/OrderedCollectionLib.h>
20 #include <Library/TdxLib.h>
21 #include <IndustryStandard/Acpi.h>
22 #include <Protocol/AcpiSystemDescriptionTable.h>
23 #include <Protocol/AcpiTable.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/UefiLib.h>
26 #include <Library/TdxMailboxLib.h>
27 #include <Protocol/Cpu.h>
29 #include <TdxAcpiTable.h>
32 At the beginning of system boot, a 4K-aligned, 4K-size memory (Td mailbox) is
33 pre-allocated by host VMM. BSP & APs do the page accept together in that memory
36 After that TDVF is designed to relocate the mailbox to a 4K-aligned, 4K-size
37 memory block which is allocated in the ACPI Nvs memory. APs are waken up and
38 spin around the relocated mailbox for further command.
40 @return EFI_PHYSICAL_ADDRESS Address of the relocated mailbox
48 EFI_PHYSICAL_ADDRESS Address
;
50 UINT32 RelocationPages
;
51 MP_RELOCATION_MAP RelocationMap
;
52 MP_WAKEUP_MAILBOX
*RelocatedMailBox
;
57 ZeroMem (&RelocationMap
, sizeof (RelocationMap
));
60 // Get information needed to setup aps running in their
61 // run loop in allocated acpi reserved memory
62 // Add another page for mailbox
64 AsmGetRelocationMap (&RelocationMap
);
65 if ((RelocationMap
.RelocateApLoopFuncAddress
== 0) || (RelocationMap
.RelocateApLoopFuncSize
== 0)) {
66 DEBUG ((DEBUG_ERROR
, "Failed to get the RelocationMap.\n"));
70 RelocationPages
= EFI_SIZE_TO_PAGES ((UINT32
)RelocationMap
.RelocateApLoopFuncSize
) + 1;
72 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiACPIMemoryNVS
, RelocationPages
, &Address
);
73 if (EFI_ERROR (Status
)) {
74 DEBUG ((DEBUG_ERROR
, "Failed to allocate pages for MailboxRelocation. %r\n", Status
));
78 ZeroMem ((VOID
*)Address
, EFI_PAGES_TO_SIZE (RelocationPages
));
80 ApLoopFunc
= (VOID
*)((UINTN
)Address
+ EFI_PAGE_SIZE
);
84 RelocationMap
.RelocateApLoopFuncAddress
,
85 RelocationMap
.RelocateApLoopFuncSize
90 "Ap Relocation: mailbox %llx, loop %p\n",
98 RelocatedMailBox
= (MP_WAKEUP_MAILBOX
*)Address
;
99 RelocatedMailBox
->Command
= MpProtectedModeWakeupCommandNoop
;
100 RelocatedMailBox
->ApicId
= MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID
;
101 RelocatedMailBox
->WakeUpVector
= 0;
104 // Wakup APs and have been move to the finalized run loop
105 // They will spin until guest OS wakes them
109 MpSendWakeupCommand (
110 MpProtectedModeWakeupCommandWakeup
,
112 (UINT64
)RelocatedMailBox
,
122 Alter the MADT when ACPI Table from QEMU is available.
124 @param[in] Event Event whose notification function is being invoked
125 @param[in] Context Pointer to the notification function's context
134 EFI_ACPI_SDT_PROTOCOL
*AcpiSdtProtocol
;
135 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
138 EFI_ACPI_SDT_HEADER
*Table
;
139 EFI_ACPI_TABLE_VERSION Version
;
140 UINTN OriginalTableKey
;
143 UINTN NewMadtTableLength
;
144 EFI_PHYSICAL_ADDRESS RelocateMailboxAddress
;
145 EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE
*MadtMpWk
;
146 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*MadtHeader
;
152 Status
= gBS
->LocateProtocol (&gEfiAcpiSdtProtocolGuid
, NULL
, (void **)&AcpiSdtProtocol
);
153 if (EFI_ERROR (Status
)) {
154 DEBUG ((DEBUG_ERROR
, "Unable to locate ACPI SDT protocol.\n"));
158 RelocateMailboxAddress
= RelocateMailbox ();
159 if (RelocateMailboxAddress
== 0) {
161 DEBUG ((DEBUG_ERROR
, "Failed to relocate Td mailbox\n"));
166 Status
= AcpiSdtProtocol
->GetAcpiTable (Index
, &Table
, &Version
, &OriginalTableKey
);
168 if (!EFI_ERROR (Status
) && (Table
->Signature
== EFI_ACPI_1_0_APIC_SIGNATURE
)) {
169 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (void **)&AcpiTableProtocol
);
170 if (EFI_ERROR (Status
)) {
171 DEBUG ((DEBUG_ERROR
, "Unable to locate ACPI Table protocol.\n"));
175 NewMadtTableLength
= Table
->Length
+ sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE
);
176 NewMadtTable
= AllocatePool (NewMadtTableLength
);
177 if (NewMadtTable
== NULL
) {
178 DEBUG ((DEBUG_ERROR
, "%a: OUT_OF_SOURCES error.\n", __FUNCTION__
));
182 CopyMem (NewMadtTable
, (UINT8
*)Table
, Table
->Length
);
183 MadtHeader
= (EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*)NewMadtTable
;
184 MadtHeader
->Header
.Length
= (UINT32
)NewMadtTableLength
;
186 MadtMpWk
= (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE
*)(NewMadtTable
+ Table
->Length
);
187 MadtMpWk
->Type
= EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP
;
188 MadtMpWk
->Length
= sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE
);
189 MadtMpWk
->MailBoxVersion
= 1;
190 MadtMpWk
->Reserved
= 0;
191 MadtMpWk
->MailBoxAddress
= RelocateMailboxAddress
;
193 Status
= AcpiTableProtocol
->InstallAcpiTable (AcpiTableProtocol
, NewMadtTable
, NewMadtTableLength
, &NewTableKey
);
194 if (EFI_ERROR (Status
)) {
195 DEBUG ((DEBUG_ERROR
, "Failed to install new MADT table. %r\n", Status
));
199 Status
= AcpiTableProtocol
->UninstallAcpiTable (AcpiTableProtocol
, OriginalTableKey
);
200 if (EFI_ERROR (Status
)) {
201 DEBUG ((DEBUG_ERROR
, "Uninstall old MADT table error.\n"));
208 } while (!EFI_ERROR (Status
));
210 if (NewMadtTable
!= NULL
) {
211 FreePool (NewMadtTable
);