3 TDX Dxe driver. This driver is dispatched early in DXE, due to being list
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
11 Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
36 #define ALIGNED_2MB_MASK 0x1fffff
37 EFI_HANDLE mTdxDxeHandle
= NULL
;
42 IN EDKII_MEMORY_ACCEPT_PROTOCOL
*This
,
43 IN EFI_PHYSICAL_ADDRESS StartAddress
,
48 UINT32 AcceptPageSize
;
57 AcceptPageSize
= FixedPcdGet32 (PcdTdxAcceptPageSize
);
69 if (ALIGN_VALUE (StartAddress
, SIZE_2MB
) != StartAddress
) {
70 StartAddress1
= StartAddress
;
71 Length1
= ALIGN_VALUE (StartAddress
, SIZE_2MB
) - StartAddress
;
72 if (Length1
>= Size
) {
76 StartAddress
+= Length1
;
80 if (Size
> SIZE_2MB
) {
81 StartAddress2
= StartAddress
;
82 Length2
= Size
& ~(UINT64
)ALIGNED_2MB_MASK
;
83 StartAddress
+= Length2
;
88 StartAddress3
= StartAddress
;
94 Pages
= Length1
/ SIZE_4KB
;
95 Status
= TdAcceptPages (StartAddress1
, Pages
, SIZE_4KB
);
96 if (EFI_ERROR (Status
)) {
102 Pages
= Length2
/ AcceptPageSize
;
103 Status
= TdAcceptPages (StartAddress2
, Pages
, AcceptPageSize
);
104 if (EFI_ERROR (Status
)) {
110 Pages
= Length3
/ SIZE_4KB
;
111 Status
= TdAcceptPages (StartAddress3
, Pages
, SIZE_4KB
);
112 ASSERT (!EFI_ERROR (Status
));
113 if (EFI_ERROR (Status
)) {
121 EDKII_MEMORY_ACCEPT_PROTOCOL mMemoryAcceptProtocol
= {
127 EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
130 RETURN_STATUS PcdStatus
;
132 PcdStatus
= PcdSet64S (PcdConfidentialComputingGuestAttr
, PlatformInfoHob
->PcdConfidentialComputingGuestAttr
);
133 ASSERT_RETURN_ERROR (PcdStatus
);
134 PcdStatus
= PcdSetBoolS (PcdSetNxForStack
, PlatformInfoHob
->PcdSetNxForStack
);
135 ASSERT_RETURN_ERROR (PcdStatus
);
139 "HostBridgeDevId=0x%x, CCAttr=0x%x, SetNxForStack=%x\n",
140 PlatformInfoHob
->HostBridgeDevId
,
141 PlatformInfoHob
->PcdConfidentialComputingGuestAttr
,
142 PlatformInfoHob
->PcdSetNxForStack
145 PcdStatus
= PcdSet32S (PcdCpuBootLogicalProcessorNumber
, PlatformInfoHob
->PcdCpuBootLogicalProcessorNumber
);
146 ASSERT_RETURN_ERROR (PcdStatus
);
147 PcdStatus
= PcdSet32S (PcdCpuMaxLogicalProcessorNumber
, PlatformInfoHob
->PcdCpuMaxLogicalProcessorNumber
);
148 ASSERT_RETURN_ERROR (PcdStatus
);
152 "MaxCpuCount=0x%x, BootCpuCount=0x%x\n",
153 PlatformInfoHob
->PcdCpuMaxLogicalProcessorNumber
,
154 PlatformInfoHob
->PcdCpuBootLogicalProcessorNumber
157 PcdSet64S (PcdEmuVariableNvStoreReserved
, PlatformInfoHob
->PcdEmuVariableNvStoreReserved
);
159 if (TdIsEnabled ()) {
160 PcdStatus
= PcdSet64S (PcdTdxSharedBitMask
, TdSharedPageMask ());
161 ASSERT_RETURN_ERROR (PcdStatus
);
162 DEBUG ((DEBUG_INFO
, "TdxSharedBitMask=0x%llx\n", PcdGet64 (PcdTdxSharedBitMask
)));
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
);
180 Location of resource hob matching type and starting address
182 @param[in] Type The type of resource hob to locate.
184 @param[in] Start The resource hob must at least begin at address.
186 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
189 EFI_HOB_RESOURCE_DESCRIPTOR
*
190 GetResourceDescriptor (
191 EFI_RESOURCE_TYPE Type
,
192 EFI_PHYSICAL_ADDRESS Start
,
193 EFI_PHYSICAL_ADDRESS End
196 EFI_PEI_HOB_POINTERS Hob
;
197 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceDescriptor
= NULL
;
199 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
);
200 while (Hob
.Raw
!= NULL
) {
203 "%a:%d: resource type 0x%x %llx %llx\n",
206 Hob
.ResourceDescriptor
->ResourceType
,
207 Hob
.ResourceDescriptor
->PhysicalStart
,
208 Hob
.ResourceDescriptor
->ResourceLength
211 if ((Hob
.ResourceDescriptor
->ResourceType
== Type
) &&
212 (Hob
.ResourceDescriptor
->PhysicalStart
>= Start
) &&
213 ((Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
) < End
))
215 ResourceDescriptor
= Hob
.ResourceDescriptor
;
219 Hob
.Raw
= GET_NEXT_HOB (Hob
);
220 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
, Hob
.Raw
);
223 return ResourceDescriptor
;
227 Location of resource hob matching type and highest address below end
229 @param[in] Type The type of resource hob to locate.
231 @param[in] End The resource hob return is the closest to the End address
233 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
236 EFI_HOB_RESOURCE_DESCRIPTOR
*
237 GetHighestResourceDescriptor (
238 EFI_RESOURCE_TYPE Type
,
239 EFI_PHYSICAL_ADDRESS End
242 EFI_PEI_HOB_POINTERS Hob
;
243 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceDescriptor
= NULL
;
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
))
250 if (!ResourceDescriptor
||
251 (ResourceDescriptor
->PhysicalStart
< Hob
.ResourceDescriptor
->PhysicalStart
))
253 ResourceDescriptor
= Hob
.ResourceDescriptor
;
257 Hob
.Raw
= GET_NEXT_HOB (Hob
);
258 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
, Hob
.Raw
);
261 return ResourceDescriptor
;
265 Set the shared bit for mmio region in Tdx guest.
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.
271 @retval EFI_SUCCESS The shared bit is set successfully.
272 @retval EFI_UNSUPPORTED Setting the shared bit of memory region
280 EFI_PEI_HOB_POINTERS Hob
;
282 Hob
.Raw
= (UINT8
*)GetHobList ();
285 // Parse the HOB list until end of list or matching type is found.
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
))
291 MemEncryptTdxSetPageSharedBit (
293 Hob
.ResourceDescriptor
->PhysicalStart
,
294 EFI_SIZE_TO_PAGES (Hob
.ResourceDescriptor
->ResourceLength
)
298 Hob
.Raw
= GET_NEXT_HOB (Hob
);
307 IN EFI_HANDLE ImageHandle
,
308 IN EFI_SYSTEM_TABLE
*SystemTable
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
;
322 GuidHob
= GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid
);
324 if (GuidHob
== NULL
) {
325 return EFI_UNSUPPORTED
;
329 // Both Td and Non-Td guest have PlatformInfoHob which contains the HostBridgePciDevId
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
);
336 #ifdef TDX_PEI_LESS_BOOT
338 // For Pei-less boot, PlatformInfo contains more information and
339 // need to set PCDs based on these information.
341 SetPcdSettings (PlatformInfo
);
344 if (!TdIsEnabled ()) {
346 // If it is Non-Td guest, we install gEfiMpInitLibMpDepProtocolGuid so that
347 // MpInitLib will be used in CpuDxe driver.
349 gBS
->InstallProtocolInterface (
351 &gEfiMpInitLibMpDepProtocolGuid
,
352 EFI_NATIVE_INTERFACE
,
362 // It is Td guest, we install gEfiMpInitLibUpDepProtocolGuid so that
363 // MpInitLibUp will be used in CpuDxe driver.
365 gBS
->InstallProtocolInterface (
367 &gEfiMpInitLibUpDepProtocolGuid
,
368 EFI_NATIVE_INTERFACE
,
373 // Install MemoryAccept protocol for TDX
375 Status
= gBS
->InstallProtocolInterface (
377 &gEdkiiMemoryAcceptProtocolGuid
,
378 EFI_NATIVE_INTERFACE
,
379 &mMemoryAcceptProtocol
381 if (EFI_ERROR (Status
)) {
382 DEBUG ((DEBUG_ERROR
, "Install EdkiiMemoryAcceptProtocol failed.\n"));
386 // Call TDINFO to get actual number of cpus in domain
388 Status
= TdCall (TDCALL_TDINFO
, 0, 0, 0, &TdReturnData
);
389 ASSERT (Status
== EFI_SUCCESS
);
391 CpuMaxLogicalProcessorNumber
= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
);
394 // Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
395 // more than number of reported cpus, update.
397 if (CpuMaxLogicalProcessorNumber
> TdReturnData
.TdInfo
.NumVcpus
) {
398 PcdStatus
= PcdSet32S (PcdCpuMaxLogicalProcessorNumber
, TdReturnData
.TdInfo
.NumVcpus
);
399 ASSERT_RETURN_ERROR (PcdStatus
);
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.
407 Status
= gBS
->CreateEvent (
415 Status
= gBS
->RegisterProtocolNotify (
416 &gQemuAcpiTableNotifyProtocolGuid
,
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); \
429 PcdSet16S (PcdOvmfHostBridgePciDevId
, PlatformInfo
->HostBridgeDevId
);
431 if ((Res
= GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO
, (EFI_PHYSICAL_ADDRESS
)0x100000000, (EFI_PHYSICAL_ADDRESS
)-1)) != NULL
) {
432 INIT_PCDSET (PcdPciMmio64
, Res
);
435 if ((Res
= GetResourceDescriptor (EFI_RESOURCE_IO
, 0, 0x10001)) != NULL
) {
436 INIT_PCDSET (PcdPciIo
, Res
);
440 // To find low mmio, first find top of low memory, and then search for io space.
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
);