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 <Library/UefiBootServicesTableLib.h>
28 #include <ConfidentialComputingGuestAttr.h>
29 #include <IndustryStandard/Tdx.h>
30 #include <Library/PlatformInitLib.h>
31 #include <Library/TdxLib.h>
32 #include <TdxAcpiTable.h>
33 #include <Library/MemEncryptTdxLib.h>
37 EFI_HOB_PLATFORM_INFO
*PlatformInfoHob
40 RETURN_STATUS PcdStatus
;
42 PcdStatus
= PcdSet64S (PcdConfidentialComputingGuestAttr
, PlatformInfoHob
->PcdConfidentialComputingGuestAttr
);
43 ASSERT_RETURN_ERROR (PcdStatus
);
44 PcdStatus
= PcdSetBoolS (PcdSetNxForStack
, PlatformInfoHob
->PcdSetNxForStack
);
45 ASSERT_RETURN_ERROR (PcdStatus
);
49 "HostBridgeDevId=0x%x, CCAttr=0x%x, SetNxForStack=%x\n",
50 PlatformInfoHob
->HostBridgeDevId
,
51 PlatformInfoHob
->PcdConfidentialComputingGuestAttr
,
52 PlatformInfoHob
->PcdSetNxForStack
55 PcdStatus
= PcdSet32S (PcdCpuBootLogicalProcessorNumber
, PlatformInfoHob
->PcdCpuBootLogicalProcessorNumber
);
56 ASSERT_RETURN_ERROR (PcdStatus
);
57 PcdStatus
= PcdSet32S (PcdCpuMaxLogicalProcessorNumber
, PlatformInfoHob
->PcdCpuMaxLogicalProcessorNumber
);
58 ASSERT_RETURN_ERROR (PcdStatus
);
62 "MaxCpuCount=0x%x, BootCpuCount=0x%x\n",
63 PlatformInfoHob
->PcdCpuMaxLogicalProcessorNumber
,
64 PlatformInfoHob
->PcdCpuBootLogicalProcessorNumber
67 PcdSet64S (PcdEmuVariableNvStoreReserved
, PlatformInfoHob
->PcdEmuVariableNvStoreReserved
);
70 PcdStatus
= PcdSet64S (PcdTdxSharedBitMask
, TdSharedPageMask ());
71 ASSERT_RETURN_ERROR (PcdStatus
);
72 DEBUG ((DEBUG_INFO
, "TdxSharedBitMask=0x%llx\n", PcdGet64 (PcdTdxSharedBitMask
)));
75 PcdStatus
= PcdSet64S (PcdPciMmio64Base
, PlatformInfoHob
->PcdPciMmio64Base
);
76 ASSERT_RETURN_ERROR (PcdStatus
);
77 PcdStatus
= PcdSet64S (PcdPciMmio64Size
, PlatformInfoHob
->PcdPciMmio64Size
);
78 ASSERT_RETURN_ERROR (PcdStatus
);
79 PcdStatus
= PcdSet64S (PcdPciMmio32Base
, PlatformInfoHob
->PcdPciMmio32Base
);
80 ASSERT_RETURN_ERROR (PcdStatus
);
81 PcdStatus
= PcdSet64S (PcdPciMmio32Size
, PlatformInfoHob
->PcdPciMmio32Size
);
82 ASSERT_RETURN_ERROR (PcdStatus
);
83 PcdStatus
= PcdSet64S (PcdPciIoBase
, PlatformInfoHob
->PcdPciIoBase
);
84 ASSERT_RETURN_ERROR (PcdStatus
);
85 PcdStatus
= PcdSet64S (PcdPciIoSize
, PlatformInfoHob
->PcdPciIoSize
);
86 ASSERT_RETURN_ERROR (PcdStatus
);
90 Location of resource hob matching type and starting address
92 @param[in] Type The type of resource hob to locate.
94 @param[in] Start The resource hob must at least begin at address.
96 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
99 EFI_HOB_RESOURCE_DESCRIPTOR
*
100 GetResourceDescriptor (
101 EFI_RESOURCE_TYPE Type
,
102 EFI_PHYSICAL_ADDRESS Start
,
103 EFI_PHYSICAL_ADDRESS End
106 EFI_PEI_HOB_POINTERS Hob
;
107 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceDescriptor
= NULL
;
109 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
);
110 while (Hob
.Raw
!= NULL
) {
113 "%a:%d: resource type 0x%x %llx %llx\n",
116 Hob
.ResourceDescriptor
->ResourceType
,
117 Hob
.ResourceDescriptor
->PhysicalStart
,
118 Hob
.ResourceDescriptor
->ResourceLength
121 if ((Hob
.ResourceDescriptor
->ResourceType
== Type
) &&
122 (Hob
.ResourceDescriptor
->PhysicalStart
>= Start
) &&
123 ((Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
) < End
))
125 ResourceDescriptor
= Hob
.ResourceDescriptor
;
129 Hob
.Raw
= GET_NEXT_HOB (Hob
);
130 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
, Hob
.Raw
);
133 return ResourceDescriptor
;
137 Location of resource hob matching type and highest address below end
139 @param[in] Type The type of resource hob to locate.
141 @param[in] End The resource hob return is the closest to the End address
143 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
146 EFI_HOB_RESOURCE_DESCRIPTOR
*
147 GetHighestResourceDescriptor (
148 EFI_RESOURCE_TYPE Type
,
149 EFI_PHYSICAL_ADDRESS End
152 EFI_PEI_HOB_POINTERS Hob
;
153 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceDescriptor
= NULL
;
155 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
);
156 while (Hob
.Raw
!= NULL
) {
157 if ((Hob
.ResourceDescriptor
->ResourceType
== Type
) &&
158 (Hob
.ResourceDescriptor
->PhysicalStart
< End
))
160 if (!ResourceDescriptor
||
161 (ResourceDescriptor
->PhysicalStart
< Hob
.ResourceDescriptor
->PhysicalStart
))
163 ResourceDescriptor
= Hob
.ResourceDescriptor
;
167 Hob
.Raw
= GET_NEXT_HOB (Hob
);
168 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
, Hob
.Raw
);
171 return ResourceDescriptor
;
175 Set the shared bit for mmio region in Tdx guest.
177 In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
178 For direct access, the shared bit of the PageTableEntry should be set.
179 The mmio region information is retrieved from hob list.
181 @retval EFI_SUCCESS The shared bit is set successfully.
182 @retval EFI_UNSUPPORTED Setting the shared bit of memory region
190 EFI_PEI_HOB_POINTERS Hob
;
192 Hob
.Raw
= (UINT8
*)GetHobList ();
195 // Parse the HOB list until end of list or matching type is found.
197 while (!END_OF_HOB_LIST (Hob
)) {
198 if ( (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
)
199 && (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_MEMORY_MAPPED_IO
))
201 MemEncryptTdxSetPageSharedBit (
203 Hob
.ResourceDescriptor
->PhysicalStart
,
204 EFI_SIZE_TO_PAGES (Hob
.ResourceDescriptor
->ResourceLength
)
208 Hob
.Raw
= GET_NEXT_HOB (Hob
);
217 IN EFI_HANDLE ImageHandle
,
218 IN EFI_SYSTEM_TABLE
*SystemTable
222 RETURN_STATUS PcdStatus
;
223 EFI_HOB_RESOURCE_DESCRIPTOR
*Res
= NULL
;
224 EFI_HOB_RESOURCE_DESCRIPTOR
*MemRes
= NULL
;
225 EFI_HOB_PLATFORM_INFO
*PlatformInfo
= NULL
;
226 EFI_HOB_GUID_TYPE
*GuidHob
;
227 UINT32 CpuMaxLogicalProcessorNumber
;
228 TD_RETURN_DATA TdReturnData
;
229 EFI_EVENT QemuAcpiTableEvent
;
232 GuidHob
= GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid
);
234 if (GuidHob
== NULL
) {
235 return EFI_UNSUPPORTED
;
239 // Both Td and Non-Td guest have PlatformInfoHob which contains the HostBridgePciDevId
241 PlatformInfo
= (EFI_HOB_PLATFORM_INFO
*)GET_GUID_HOB_DATA (GuidHob
);
242 ASSERT (PlatformInfo
->HostBridgeDevId
!= 0);
243 PcdStatus
= PcdSet16S (PcdOvmfHostBridgePciDevId
, PlatformInfo
->HostBridgeDevId
);
244 ASSERT_RETURN_ERROR (PcdStatus
);
246 #ifdef TDX_PEI_LESS_BOOT
248 // For Pei-less boot, PlatformInfo contains more information and
249 // need to set PCDs based on these information.
251 SetPcdSettings (PlatformInfo
);
254 if (!TdIsEnabled ()) {
256 // If it is Non-Td guest, we install gEfiMpInitLibMpDepProtocolGuid so that
257 // MpInitLib will be used in CpuDxe driver.
259 gBS
->InstallProtocolInterface (
261 &gEfiMpInitLibMpDepProtocolGuid
,
262 EFI_NATIVE_INTERFACE
,
272 // It is Td guest, we install gEfiMpInitLibUpDepProtocolGuid so that
273 // MpInitLibUp will be used in CpuDxe driver.
275 gBS
->InstallProtocolInterface (
277 &gEfiMpInitLibUpDepProtocolGuid
,
278 EFI_NATIVE_INTERFACE
,
283 // Call TDINFO to get actual number of cpus in domain
285 Status
= TdCall (TDCALL_TDINFO
, 0, 0, 0, &TdReturnData
);
286 ASSERT (Status
== EFI_SUCCESS
);
288 CpuMaxLogicalProcessorNumber
= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
);
291 // Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
292 // more than number of reported cpus, update.
294 if (CpuMaxLogicalProcessorNumber
> TdReturnData
.TdInfo
.NumVcpus
) {
295 PcdStatus
= PcdSet32S (PcdCpuMaxLogicalProcessorNumber
, TdReturnData
.TdInfo
.NumVcpus
);
296 ASSERT_RETURN_ERROR (PcdStatus
);
300 // Register for protocol notifications to call the AlterAcpiTable(),
301 // the protocol will be installed in AcpiPlatformDxe when the ACPI
302 // table provided by Qemu is ready.
304 Status
= gBS
->CreateEvent (
312 Status
= gBS
->RegisterProtocolNotify (
313 &gQemuAcpiTableNotifyProtocolGuid
,
318 #define INIT_PCDSET(NAME, RES) do {\
319 PcdStatus = PcdSet64S (NAME##Base, (RES)->PhysicalStart); \
320 ASSERT_RETURN_ERROR (PcdStatus); \
321 PcdStatus = PcdSet64S (NAME##Size, (RES)->ResourceLength); \
322 ASSERT_RETURN_ERROR (PcdStatus); \
326 PcdSet16S (PcdOvmfHostBridgePciDevId
, PlatformInfo
->HostBridgeDevId
);
328 if ((Res
= GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO
, (EFI_PHYSICAL_ADDRESS
)0x100000000, (EFI_PHYSICAL_ADDRESS
)-1)) != NULL
) {
329 INIT_PCDSET (PcdPciMmio64
, Res
);
332 if ((Res
= GetResourceDescriptor (EFI_RESOURCE_IO
, 0, 0x10001)) != NULL
) {
333 INIT_PCDSET (PcdPciIo
, Res
);
337 // To find low mmio, first find top of low memory, and then search for io space.
339 if ((MemRes
= GetHighestResourceDescriptor (EFI_RESOURCE_SYSTEM_MEMORY
, 0xffc00000)) != NULL
) {
340 if ((Res
= GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO
, MemRes
->PhysicalStart
, 0x100000000)) != NULL
) {
341 INIT_PCDSET (PcdPciMmio32
, Res
);