]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/TdxDxe/TdxAcpiTable.c
OvmfPkg: Add TdxDxe driver
[mirror_edk2.git] / OvmfPkg / TdxDxe / TdxAcpiTable.c
1 /** @file
2 OVMF ACPI QEMU support
3
4 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
5
6 Copyright (C) 2012-2014, Red Hat, Inc.
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
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>
28 #include <Uefi.h>
29 #include <TdxAcpiTable.h>
30
31 /**
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
34 region.
35
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.
39
40 @return EFI_PHYSICAL_ADDRESS Address of the relocated mailbox
41 **/
42 EFI_PHYSICAL_ADDRESS
43 EFIAPI
44 RelocateMailbox (
45 VOID
46 )
47 {
48 EFI_PHYSICAL_ADDRESS Address;
49 VOID *ApLoopFunc;
50 UINT32 RelocationPages;
51 MP_RELOCATION_MAP RelocationMap;
52 MP_WAKEUP_MAILBOX *RelocatedMailBox;
53 EFI_STATUS Status;
54
55 Address = 0;
56 ApLoopFunc = NULL;
57 ZeroMem (&RelocationMap, sizeof (RelocationMap));
58
59 //
60 // Get information needed to setup aps running in their
61 // run loop in allocated acpi reserved memory
62 // Add another page for mailbox
63 //
64 AsmGetRelocationMap (&RelocationMap);
65 if ((RelocationMap.RelocateApLoopFuncAddress == 0) || (RelocationMap.RelocateApLoopFuncSize == 0)) {
66 DEBUG ((DEBUG_ERROR, "Failed to get the RelocationMap.\n"));
67 return 0;
68 }
69
70 RelocationPages = EFI_SIZE_TO_PAGES ((UINT32)RelocationMap.RelocateApLoopFuncSize) + 1;
71
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));
75 return 0;
76 }
77
78 ZeroMem ((VOID *)Address, EFI_PAGES_TO_SIZE (RelocationPages));
79
80 ApLoopFunc = (VOID *)((UINTN)Address + EFI_PAGE_SIZE);
81
82 CopyMem (
83 ApLoopFunc,
84 RelocationMap.RelocateApLoopFuncAddress,
85 RelocationMap.RelocateApLoopFuncSize
86 );
87
88 DEBUG ((
89 DEBUG_INFO,
90 "Ap Relocation: mailbox %llx, loop %p\n",
91 Address,
92 ApLoopFunc
93 ));
94
95 //
96 // Initialize mailbox
97 //
98 RelocatedMailBox = (MP_WAKEUP_MAILBOX *)Address;
99 RelocatedMailBox->Command = MpProtectedModeWakeupCommandNoop;
100 RelocatedMailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
101 RelocatedMailBox->WakeUpVector = 0;
102
103 //
104 // Wakup APs and have been move to the finalized run loop
105 // They will spin until guest OS wakes them
106 //
107 MpSerializeStart ();
108
109 MpSendWakeupCommand (
110 MpProtectedModeWakeupCommandWakeup,
111 (UINT64)ApLoopFunc,
112 (UINT64)RelocatedMailBox,
113 0,
114 0,
115 0
116 );
117
118 return Address;
119 }
120
121 /**
122 Alter the MADT when ACPI Table from QEMU is available.
123
124 @param[in] Event Event whose notification function is being invoked
125 @param[in] Context Pointer to the notification function's context
126 **/
127 VOID
128 EFIAPI
129 AlterAcpiTable (
130 IN EFI_EVENT Event,
131 IN VOID *Context
132 )
133 {
134 EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
135 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
136 EFI_STATUS Status;
137 UINTN Index;
138 EFI_ACPI_SDT_HEADER *Table;
139 EFI_ACPI_TABLE_VERSION Version;
140 UINTN OriginalTableKey;
141 UINTN NewTableKey;
142 UINT8 *NewMadtTable;
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;
147
148 Index = 0;
149 NewMadtTable = NULL;
150 MadtHeader = NULL;
151
152 Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (void **)&AcpiSdtProtocol);
153 if (EFI_ERROR (Status)) {
154 DEBUG ((DEBUG_ERROR, "Unable to locate ACPI SDT protocol.\n"));
155 return;
156 }
157
158 RelocateMailboxAddress = RelocateMailbox ();
159 if (RelocateMailboxAddress == 0) {
160 ASSERT (FALSE);
161 DEBUG ((DEBUG_ERROR, "Failed to relocate Td mailbox\n"));
162 return;
163 }
164
165 do {
166 Status = AcpiSdtProtocol->GetAcpiTable (Index, &Table, &Version, &OriginalTableKey);
167
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"));
172 break;
173 }
174
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__));
179 break;
180 }
181
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;
185
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;
192
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));
196 break;
197 }
198
199 Status = AcpiTableProtocol->UninstallAcpiTable (AcpiTableProtocol, OriginalTableKey);
200 if (EFI_ERROR (Status)) {
201 DEBUG ((DEBUG_ERROR, "Uninstall old MADT table error.\n"));
202 }
203
204 break;
205 }
206
207 Index++;
208 } while (!EFI_ERROR (Status));
209
210 if (NewMadtTable != NULL) {
211 FreePool (NewMadtTable);
212 }
213 }