]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/TdxDxe/TdxDxe.c
ArmPkg: implement EFI_MP_SERVICES_PROTOCOL based on PSCI calls
[mirror_edk2.git] / OvmfPkg / TdxDxe / TdxDxe.c
1 /** @file
2
3 TDX Dxe driver. This driver is dispatched early in DXE, due to being list
4 in APRIORI.
5
6 This module is responsible for:
7 - Sets max logical cpus based on TDINFO
8 - Sets PCI PCDs based on resource hobs
9 - Alter MATD table to record address of Mailbox
10
11 Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
12
13 SPDX-License-Identifier: BSD-2-Clause-Patent
14
15 **/
16
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/DxeServicesTableLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/PcdLib.h>
23 #include <Library/UefiLib.h>
24 #include <Library/HobLib.h>
25 #include <Protocol/Cpu.h>
26 #include <Protocol/MpInitLibDepProtocols.h>
27 #include <Protocol/MemoryAccept.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <ConfidentialComputingGuestAttr.h>
30 #include <IndustryStandard/Tdx.h>
31 #include <Library/PlatformInitLib.h>
32 #include <Library/TdxLib.h>
33 #include <TdxAcpiTable.h>
34 #include <Library/MemEncryptTdxLib.h>
35
36 #define ALIGNED_2MB_MASK 0x1fffff
37 EFI_HANDLE mTdxDxeHandle = NULL;
38
39 EFI_STATUS
40 EFIAPI
41 TdxMemoryAccept (
42 IN EDKII_MEMORY_ACCEPT_PROTOCOL *This,
43 IN EFI_PHYSICAL_ADDRESS StartAddress,
44 IN UINTN Size
45 )
46 {
47 EFI_STATUS Status;
48 UINT32 AcceptPageSize;
49 UINT64 StartAddress1;
50 UINT64 StartAddress2;
51 UINT64 StartAddress3;
52 UINT64 Length1;
53 UINT64 Length2;
54 UINT64 Length3;
55 UINT64 Pages;
56
57 AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
58 StartAddress1 = 0;
59 StartAddress2 = 0;
60 StartAddress3 = 0;
61 Length1 = 0;
62 Length2 = 0;
63 Length3 = 0;
64
65 if (Size == 0) {
66 return EFI_SUCCESS;
67 }
68
69 if (ALIGN_VALUE (StartAddress, SIZE_2MB) != StartAddress) {
70 StartAddress1 = StartAddress;
71 Length1 = ALIGN_VALUE (StartAddress, SIZE_2MB) - StartAddress;
72 if (Length1 >= Size) {
73 Length1 = Size;
74 }
75
76 StartAddress += Length1;
77 Size -= Length1;
78 }
79
80 if (Size > SIZE_2MB) {
81 StartAddress2 = StartAddress;
82 Length2 = Size & ~(UINT64)ALIGNED_2MB_MASK;
83 StartAddress += Length2;
84 Size -= Length2;
85 }
86
87 if (Size) {
88 StartAddress3 = StartAddress;
89 Length3 = Size;
90 }
91
92 Status = EFI_SUCCESS;
93 if (Length1 > 0) {
94 Pages = Length1 / SIZE_4KB;
95 Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);
96 if (EFI_ERROR (Status)) {
97 return Status;
98 }
99 }
100
101 if (Length2 > 0) {
102 Pages = Length2 / AcceptPageSize;
103 Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);
104 if (EFI_ERROR (Status)) {
105 return Status;
106 }
107 }
108
109 if (Length3 > 0) {
110 Pages = Length3 / SIZE_4KB;
111 Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);
112 ASSERT (!EFI_ERROR (Status));
113 if (EFI_ERROR (Status)) {
114 return Status;
115 }
116 }
117
118 return Status;
119 }
120
121 EDKII_MEMORY_ACCEPT_PROTOCOL mMemoryAcceptProtocol = {
122 TdxMemoryAccept
123 };
124
125 VOID
126 SetPcdSettings (
127 EFI_HOB_PLATFORM_INFO *PlatformInfoHob
128 )
129 {
130 RETURN_STATUS PcdStatus;
131
132 PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, PlatformInfoHob->PcdConfidentialComputingGuestAttr);
133 ASSERT_RETURN_ERROR (PcdStatus);
134 PcdStatus = PcdSetBoolS (PcdSetNxForStack, PlatformInfoHob->PcdSetNxForStack);
135 ASSERT_RETURN_ERROR (PcdStatus);
136
137 DEBUG ((
138 DEBUG_INFO,
139 "HostBridgeDevId=0x%x, CCAttr=0x%x, SetNxForStack=%x\n",
140 PlatformInfoHob->HostBridgeDevId,
141 PlatformInfoHob->PcdConfidentialComputingGuestAttr,
142 PlatformInfoHob->PcdSetNxForStack
143 ));
144
145 PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, PlatformInfoHob->PcdCpuBootLogicalProcessorNumber);
146 ASSERT_RETURN_ERROR (PcdStatus);
147 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber);
148 ASSERT_RETURN_ERROR (PcdStatus);
149
150 DEBUG ((
151 DEBUG_INFO,
152 "MaxCpuCount=0x%x, BootCpuCount=0x%x\n",
153 PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber,
154 PlatformInfoHob->PcdCpuBootLogicalProcessorNumber
155 ));
156
157 PcdSet64S (PcdEmuVariableNvStoreReserved, PlatformInfoHob->PcdEmuVariableNvStoreReserved);
158
159 if (TdIsEnabled ()) {
160 PcdStatus = PcdSet64S (PcdTdxSharedBitMask, TdSharedPageMask ());
161 ASSERT_RETURN_ERROR (PcdStatus);
162 DEBUG ((DEBUG_INFO, "TdxSharedBitMask=0x%llx\n", PcdGet64 (PcdTdxSharedBitMask)));
163 }
164
165 PcdStatus = PcdSet64S (PcdPciMmio64Base, PlatformInfoHob->PcdPciMmio64Base);
166 ASSERT_RETURN_ERROR (PcdStatus);
167 PcdStatus = PcdSet64S (PcdPciMmio64Size, PlatformInfoHob->PcdPciMmio64Size);
168 ASSERT_RETURN_ERROR (PcdStatus);
169 PcdStatus = PcdSet64S (PcdPciMmio32Base, PlatformInfoHob->PcdPciMmio32Base);
170 ASSERT_RETURN_ERROR (PcdStatus);
171 PcdStatus = PcdSet64S (PcdPciMmio32Size, PlatformInfoHob->PcdPciMmio32Size);
172 ASSERT_RETURN_ERROR (PcdStatus);
173 PcdStatus = PcdSet64S (PcdPciIoBase, PlatformInfoHob->PcdPciIoBase);
174 ASSERT_RETURN_ERROR (PcdStatus);
175 PcdStatus = PcdSet64S (PcdPciIoSize, PlatformInfoHob->PcdPciIoSize);
176 ASSERT_RETURN_ERROR (PcdStatus);
177 }
178
179 /**
180 Location of resource hob matching type and starting address
181
182 @param[in] Type The type of resource hob to locate.
183
184 @param[in] Start The resource hob must at least begin at address.
185
186 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
187 **/
188 STATIC
189 EFI_HOB_RESOURCE_DESCRIPTOR *
190 GetResourceDescriptor (
191 EFI_RESOURCE_TYPE Type,
192 EFI_PHYSICAL_ADDRESS Start,
193 EFI_PHYSICAL_ADDRESS End
194 )
195 {
196 EFI_PEI_HOB_POINTERS Hob;
197 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
198
199 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
200 while (Hob.Raw != NULL) {
201 DEBUG ((
202 DEBUG_INFO,
203 "%a:%d: resource type 0x%x %llx %llx\n",
204 __func__,
205 __LINE__,
206 Hob.ResourceDescriptor->ResourceType,
207 Hob.ResourceDescriptor->PhysicalStart,
208 Hob.ResourceDescriptor->ResourceLength
209 ));
210
211 if ((Hob.ResourceDescriptor->ResourceType == Type) &&
212 (Hob.ResourceDescriptor->PhysicalStart >= Start) &&
213 ((Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength) < End))
214 {
215 ResourceDescriptor = Hob.ResourceDescriptor;
216 break;
217 }
218
219 Hob.Raw = GET_NEXT_HOB (Hob);
220 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
221 }
222
223 return ResourceDescriptor;
224 }
225
226 /**
227 Location of resource hob matching type and highest address below end
228
229 @param[in] Type The type of resource hob to locate.
230
231 @param[in] End The resource hob return is the closest to the End address
232
233 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
234 **/
235 STATIC
236 EFI_HOB_RESOURCE_DESCRIPTOR *
237 GetHighestResourceDescriptor (
238 EFI_RESOURCE_TYPE Type,
239 EFI_PHYSICAL_ADDRESS End
240 )
241 {
242 EFI_PEI_HOB_POINTERS Hob;
243 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
244
245 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
246 while (Hob.Raw != NULL) {
247 if ((Hob.ResourceDescriptor->ResourceType == Type) &&
248 (Hob.ResourceDescriptor->PhysicalStart < End))
249 {
250 if (!ResourceDescriptor ||
251 (ResourceDescriptor->PhysicalStart < Hob.ResourceDescriptor->PhysicalStart))
252 {
253 ResourceDescriptor = Hob.ResourceDescriptor;
254 }
255 }
256
257 Hob.Raw = GET_NEXT_HOB (Hob);
258 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
259 }
260
261 return ResourceDescriptor;
262 }
263
264 /**
265 Set the shared bit for mmio region in Tdx guest.
266
267 In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
268 For direct access, the shared bit of the PageTableEntry should be set.
269 The mmio region information is retrieved from hob list.
270
271 @retval EFI_SUCCESS The shared bit is set successfully.
272 @retval EFI_UNSUPPORTED Setting the shared bit of memory region
273 is not supported
274 **/
275 EFI_STATUS
276 SetMmioSharedBit (
277 VOID
278 )
279 {
280 EFI_PEI_HOB_POINTERS Hob;
281
282 Hob.Raw = (UINT8 *)GetHobList ();
283
284 //
285 // Parse the HOB list until end of list or matching type is found.
286 //
287 while (!END_OF_HOB_LIST (Hob)) {
288 if ( (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)
289 && (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO))
290 {
291 MemEncryptTdxSetPageSharedBit (
292 0,
293 Hob.ResourceDescriptor->PhysicalStart,
294 EFI_SIZE_TO_PAGES (Hob.ResourceDescriptor->ResourceLength)
295 );
296 }
297
298 Hob.Raw = GET_NEXT_HOB (Hob);
299 }
300
301 return EFI_SUCCESS;
302 }
303
304 EFI_STATUS
305 EFIAPI
306 TdxDxeEntryPoint (
307 IN EFI_HANDLE ImageHandle,
308 IN EFI_SYSTEM_TABLE *SystemTable
309 )
310 {
311 EFI_STATUS Status;
312 RETURN_STATUS PcdStatus;
313 EFI_HOB_RESOURCE_DESCRIPTOR *Res = NULL;
314 EFI_HOB_RESOURCE_DESCRIPTOR *MemRes = NULL;
315 EFI_HOB_PLATFORM_INFO *PlatformInfo = NULL;
316 EFI_HOB_GUID_TYPE *GuidHob;
317 UINT32 CpuMaxLogicalProcessorNumber;
318 TD_RETURN_DATA TdReturnData;
319 EFI_EVENT QemuAcpiTableEvent;
320 void *Registration;
321
322 GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
323
324 if (GuidHob == NULL) {
325 return EFI_UNSUPPORTED;
326 }
327
328 //
329 // Both Td and Non-Td guest have PlatformInfoHob which contains the HostBridgePciDevId
330 //
331 PlatformInfo = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
332 ASSERT (PlatformInfo->HostBridgeDevId != 0);
333 PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
334 ASSERT_RETURN_ERROR (PcdStatus);
335
336 #ifdef TDX_PEI_LESS_BOOT
337 //
338 // For Pei-less boot, PlatformInfo contains more information and
339 // need to set PCDs based on these information.
340 //
341 SetPcdSettings (PlatformInfo);
342 #endif
343
344 if (!TdIsEnabled ()) {
345 //
346 // If it is Non-Td guest, we install gEfiMpInitLibMpDepProtocolGuid so that
347 // MpInitLib will be used in CpuDxe driver.
348 //
349 gBS->InstallProtocolInterface (
350 &ImageHandle,
351 &gEfiMpInitLibMpDepProtocolGuid,
352 EFI_NATIVE_INTERFACE,
353 NULL
354 );
355
356 return EFI_SUCCESS;
357 }
358
359 SetMmioSharedBit ();
360
361 //
362 // It is Td guest, we install gEfiMpInitLibUpDepProtocolGuid so that
363 // MpInitLibUp will be used in CpuDxe driver.
364 //
365 gBS->InstallProtocolInterface (
366 &ImageHandle,
367 &gEfiMpInitLibUpDepProtocolGuid,
368 EFI_NATIVE_INTERFACE,
369 NULL
370 );
371
372 //
373 // Install MemoryAccept protocol for TDX
374 //
375 Status = gBS->InstallProtocolInterface (
376 &mTdxDxeHandle,
377 &gEdkiiMemoryAcceptProtocolGuid,
378 EFI_NATIVE_INTERFACE,
379 &mMemoryAcceptProtocol
380 );
381 if (EFI_ERROR (Status)) {
382 DEBUG ((DEBUG_ERROR, "Install EdkiiMemoryAcceptProtocol failed.\n"));
383 }
384
385 //
386 // Call TDINFO to get actual number of cpus in domain
387 //
388 Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
389 ASSERT (Status == EFI_SUCCESS);
390
391 CpuMaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
392
393 //
394 // Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
395 // more than number of reported cpus, update.
396 //
397 if (CpuMaxLogicalProcessorNumber > TdReturnData.TdInfo.NumVcpus) {
398 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, TdReturnData.TdInfo.NumVcpus);
399 ASSERT_RETURN_ERROR (PcdStatus);
400 }
401
402 //
403 // Register for protocol notifications to call the AlterAcpiTable(),
404 // the protocol will be installed in AcpiPlatformDxe when the ACPI
405 // table provided by Qemu is ready.
406 //
407 Status = gBS->CreateEvent (
408 EVT_NOTIFY_SIGNAL,
409 TPL_CALLBACK,
410 AlterAcpiTable,
411 NULL,
412 &QemuAcpiTableEvent
413 );
414
415 Status = gBS->RegisterProtocolNotify (
416 &gQemuAcpiTableNotifyProtocolGuid,
417 QemuAcpiTableEvent,
418 &Registration
419 );
420
421 #define INIT_PCDSET(NAME, RES) do {\
422 PcdStatus = PcdSet64S (NAME##Base, (RES)->PhysicalStart); \
423 ASSERT_RETURN_ERROR (PcdStatus); \
424 PcdStatus = PcdSet64S (NAME##Size, (RES)->ResourceLength); \
425 ASSERT_RETURN_ERROR (PcdStatus); \
426 } while(0)
427
428 if (PlatformInfo) {
429 PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
430
431 if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, (EFI_PHYSICAL_ADDRESS)0x100000000, (EFI_PHYSICAL_ADDRESS)-1)) != NULL) {
432 INIT_PCDSET (PcdPciMmio64, Res);
433 }
434
435 if ((Res = GetResourceDescriptor (EFI_RESOURCE_IO, 0, 0x10001)) != NULL) {
436 INIT_PCDSET (PcdPciIo, Res);
437 }
438
439 //
440 // To find low mmio, first find top of low memory, and then search for io space.
441 //
442 if ((MemRes = GetHighestResourceDescriptor (EFI_RESOURCE_SYSTEM_MEMORY, 0xffc00000)) != NULL) {
443 if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, MemRes->PhysicalStart, 0x100000000)) != NULL) {
444 INIT_PCDSET (PcdPciMmio32, Res);
445 }
446 }
447 }
448
449 return EFI_SUCCESS;
450 }