]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/TdxDxe/TdxDxe.c
f0929998233c07a5e28da9a37328a414c1d002b2
[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 <Library/UefiBootServicesTableLib.h>
27 #include <ConfidentialComputingGuestAttr.h>
28 #include <IndustryStandard/Tdx.h>
29 #include <Library/PlatformInitLib.h>
30 #include <Library/TdxLib.h>
31 #include <TdxAcpiTable.h>
32 #include <Library/MemEncryptTdxLib.h>
33
34 VOID
35 SetPcdSettings (
36 EFI_HOB_PLATFORM_INFO *PlatformInfoHob
37 )
38 {
39 RETURN_STATUS PcdStatus;
40
41 PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, PlatformInfoHob->PcdConfidentialComputingGuestAttr);
42 ASSERT_RETURN_ERROR (PcdStatus);
43 PcdStatus = PcdSetBoolS (PcdSetNxForStack, PlatformInfoHob->PcdSetNxForStack);
44 ASSERT_RETURN_ERROR (PcdStatus);
45
46 DEBUG ((
47 DEBUG_INFO,
48 "HostBridgeDevId=0x%x, CCAttr=0x%x, SetNxForStack=%x\n",
49 PlatformInfoHob->HostBridgeDevId,
50 PlatformInfoHob->PcdConfidentialComputingGuestAttr,
51 PlatformInfoHob->PcdSetNxForStack
52 ));
53
54 PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, PlatformInfoHob->PcdCpuBootLogicalProcessorNumber);
55 ASSERT_RETURN_ERROR (PcdStatus);
56 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber);
57 ASSERT_RETURN_ERROR (PcdStatus);
58
59 DEBUG ((
60 DEBUG_INFO,
61 "MaxCpuCount=0x%x, BootCpuCount=0x%x\n",
62 PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber,
63 PlatformInfoHob->PcdCpuBootLogicalProcessorNumber
64 ));
65
66 if (TdIsEnabled ()) {
67 PcdStatus = PcdSet64S (PcdTdxSharedBitMask, TdSharedPageMask ());
68 ASSERT_RETURN_ERROR (PcdStatus);
69 DEBUG ((DEBUG_INFO, "TdxSharedBitMask=0x%llx\n", PcdGet64 (PcdTdxSharedBitMask)));
70 } else {
71 PcdStatus = PcdSet64S (PcdPciMmio64Base, PlatformInfoHob->PcdPciMmio64Base);
72 ASSERT_RETURN_ERROR (PcdStatus);
73 PcdStatus = PcdSet64S (PcdPciMmio64Size, PlatformInfoHob->PcdPciMmio64Size);
74 ASSERT_RETURN_ERROR (PcdStatus);
75 PcdStatus = PcdSet64S (PcdPciMmio32Base, PlatformInfoHob->PcdPciMmio32Base);
76 ASSERT_RETURN_ERROR (PcdStatus);
77 PcdStatus = PcdSet64S (PcdPciMmio32Size, PlatformInfoHob->PcdPciMmio32Size);
78 ASSERT_RETURN_ERROR (PcdStatus);
79 PcdStatus = PcdSet64S (PcdPciIoBase, PlatformInfoHob->PcdPciIoBase);
80 ASSERT_RETURN_ERROR (PcdStatus);
81 PcdStatus = PcdSet64S (PcdPciIoSize, PlatformInfoHob->PcdPciIoSize);
82 ASSERT_RETURN_ERROR (PcdStatus);
83 }
84 }
85
86 /**
87 Location of resource hob matching type and starting address
88
89 @param[in] Type The type of resource hob to locate.
90
91 @param[in] Start The resource hob must at least begin at address.
92
93 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
94 **/
95 STATIC
96 EFI_HOB_RESOURCE_DESCRIPTOR *
97 GetResourceDescriptor (
98 EFI_RESOURCE_TYPE Type,
99 EFI_PHYSICAL_ADDRESS Start,
100 EFI_PHYSICAL_ADDRESS End
101 )
102 {
103 EFI_PEI_HOB_POINTERS Hob;
104 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
105
106 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
107 while (Hob.Raw != NULL) {
108 DEBUG ((
109 DEBUG_INFO,
110 "%a:%d: resource type 0x%x %llx %llx\n",
111 __func__,
112 __LINE__,
113 Hob.ResourceDescriptor->ResourceType,
114 Hob.ResourceDescriptor->PhysicalStart,
115 Hob.ResourceDescriptor->ResourceLength
116 ));
117
118 if ((Hob.ResourceDescriptor->ResourceType == Type) &&
119 (Hob.ResourceDescriptor->PhysicalStart >= Start) &&
120 ((Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength) < End))
121 {
122 ResourceDescriptor = Hob.ResourceDescriptor;
123 break;
124 }
125
126 Hob.Raw = GET_NEXT_HOB (Hob);
127 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
128 }
129
130 return ResourceDescriptor;
131 }
132
133 /**
134 Location of resource hob matching type and highest address below end
135
136 @param[in] Type The type of resource hob to locate.
137
138 @param[in] End The resource hob return is the closest to the End address
139
140 @retval pointer to resource Return pointer to a resource hob that matches or NULL.
141 **/
142 STATIC
143 EFI_HOB_RESOURCE_DESCRIPTOR *
144 GetHighestResourceDescriptor (
145 EFI_RESOURCE_TYPE Type,
146 EFI_PHYSICAL_ADDRESS End
147 )
148 {
149 EFI_PEI_HOB_POINTERS Hob;
150 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
151
152 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
153 while (Hob.Raw != NULL) {
154 if ((Hob.ResourceDescriptor->ResourceType == Type) &&
155 (Hob.ResourceDescriptor->PhysicalStart < End))
156 {
157 if (!ResourceDescriptor ||
158 (ResourceDescriptor->PhysicalStart < Hob.ResourceDescriptor->PhysicalStart))
159 {
160 ResourceDescriptor = Hob.ResourceDescriptor;
161 }
162 }
163
164 Hob.Raw = GET_NEXT_HOB (Hob);
165 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
166 }
167
168 return ResourceDescriptor;
169 }
170
171 /**
172 Set the shared bit for mmio region in Tdx guest.
173
174 In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
175 For direct access, the shared bit of the PageTableEntry should be set.
176 The mmio region information is retrieved from hob list.
177
178 @retval EFI_SUCCESS The shared bit is set successfully.
179 @retval EFI_UNSUPPORTED Setting the shared bit of memory region
180 is not supported
181 **/
182 EFI_STATUS
183 SetMmioSharedBit (
184 VOID
185 )
186 {
187 EFI_PEI_HOB_POINTERS Hob;
188
189 Hob.Raw = (UINT8 *)GetHobList ();
190
191 //
192 // Parse the HOB list until end of list or matching type is found.
193 //
194 while (!END_OF_HOB_LIST (Hob)) {
195 if ( (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)
196 && (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO))
197 {
198 MemEncryptTdxSetPageSharedBit (
199 0,
200 Hob.ResourceDescriptor->PhysicalStart,
201 EFI_SIZE_TO_PAGES (Hob.ResourceDescriptor->ResourceLength)
202 );
203 }
204
205 Hob.Raw = GET_NEXT_HOB (Hob);
206 }
207
208 return EFI_SUCCESS;
209 }
210
211 EFI_STATUS
212 EFIAPI
213 TdxDxeEntryPoint (
214 IN EFI_HANDLE ImageHandle,
215 IN EFI_SYSTEM_TABLE *SystemTable
216 )
217 {
218 EFI_STATUS Status;
219 RETURN_STATUS PcdStatus;
220 EFI_HOB_RESOURCE_DESCRIPTOR *Res = NULL;
221 EFI_HOB_RESOURCE_DESCRIPTOR *MemRes = NULL;
222 EFI_HOB_PLATFORM_INFO *PlatformInfo = NULL;
223 EFI_HOB_GUID_TYPE *GuidHob;
224 UINT32 CpuMaxLogicalProcessorNumber;
225 TD_RETURN_DATA TdReturnData;
226 EFI_EVENT QemuAcpiTableEvent;
227 void *Registration;
228
229 GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
230
231 if (GuidHob == NULL) {
232 return EFI_UNSUPPORTED;
233 }
234
235 //
236 // Both Td and Non-Td guest have PlatformInfoHob which contains the HostBridgePciDevId
237 //
238 PlatformInfo = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
239 ASSERT (PlatformInfo->HostBridgeDevId != 0);
240 PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
241 ASSERT_RETURN_ERROR (PcdStatus);
242
243 #ifdef TDX_PEI_LESS_BOOT
244 //
245 // For Pei-less boot, PlatformInfo contains more information and
246 // need to set PCDs based on these information.
247 //
248 SetPcdSettings (PlatformInfo);
249 #endif
250
251 if (!TdIsEnabled ()) {
252 //
253 // If it is Non-Td guest, we're done.
254 //
255 return EFI_SUCCESS;
256 }
257
258 SetMmioSharedBit ();
259
260 //
261 // Call TDINFO to get actual number of cpus in domain
262 //
263 Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
264 ASSERT (Status == EFI_SUCCESS);
265
266 CpuMaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
267
268 //
269 // Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
270 // more than number of reported cpus, update.
271 //
272 if (CpuMaxLogicalProcessorNumber > TdReturnData.TdInfo.NumVcpus) {
273 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, TdReturnData.TdInfo.NumVcpus);
274 ASSERT_RETURN_ERROR (PcdStatus);
275 }
276
277 //
278 // Register for protocol notifications to call the AlterAcpiTable(),
279 // the protocol will be installed in AcpiPlatformDxe when the ACPI
280 // table provided by Qemu is ready.
281 //
282 Status = gBS->CreateEvent (
283 EVT_NOTIFY_SIGNAL,
284 TPL_CALLBACK,
285 AlterAcpiTable,
286 NULL,
287 &QemuAcpiTableEvent
288 );
289
290 Status = gBS->RegisterProtocolNotify (
291 &gQemuAcpiTableNotifyProtocolGuid,
292 QemuAcpiTableEvent,
293 &Registration
294 );
295
296 #define INIT_PCDSET(NAME, RES) do {\
297 PcdStatus = PcdSet64S (NAME##Base, (RES)->PhysicalStart); \
298 ASSERT_RETURN_ERROR (PcdStatus); \
299 PcdStatus = PcdSet64S (NAME##Size, (RES)->ResourceLength); \
300 ASSERT_RETURN_ERROR (PcdStatus); \
301 } while(0)
302
303 if (PlatformInfo) {
304 PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
305
306 if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, (EFI_PHYSICAL_ADDRESS)0x100000000, (EFI_PHYSICAL_ADDRESS)-1)) != NULL) {
307 INIT_PCDSET (PcdPciMmio64, Res);
308 }
309
310 if ((Res = GetResourceDescriptor (EFI_RESOURCE_IO, 0, 0x10001)) != NULL) {
311 INIT_PCDSET (PcdPciIo, Res);
312 }
313
314 //
315 // To find low mmio, first find top of low memory, and then search for io space.
316 //
317 if ((MemRes = GetHighestResourceDescriptor (EFI_RESOURCE_SYSTEM_MEMORY, 0xffc00000)) != NULL) {
318 if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, MemRes->PhysicalStart, 0x100000000)) != NULL) {
319 INIT_PCDSET (PcdPciMmio32, Res);
320 }
321 }
322 }
323
324 return EFI_SUCCESS;
325 }