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", __func__));
|
---|
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 = 0;
|
---|
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 | }
|
---|