IntelSiliconPkg: Add VTd driver.
[mirror_edk2.git] / IntelSiliconPkg / IntelVTdDxe / DmaProtection.c
CommitLineData
c049fc99
JY
1/** @file\r
2\r
3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
4 This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution. The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php.\r
8\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12**/\r
13\r
14#include "DmaProtection.h"\r
15\r
16EFI_ACPI_SDT_PROTOCOL *mAcpiSdt;\r
17UINT64 mBelow4GMemoryLimit;\r
18UINT64 mAbove4GMemoryLimit;\r
19\r
20EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;\r
21\r
22/**\r
23 return the UEFI memory information.\r
24\r
25 @param[out] Below4GMemoryLimit The below 4GiB memory limit\r
26 @param[out] Above4GMemoryLimit The above 4GiB memory limit\r
27**/\r
28VOID\r
29ReturnUefiMemoryMap (\r
30 OUT UINT64 *Below4GMemoryLimit,\r
31 OUT UINT64 *Above4GMemoryLimit\r
32 )\r
33{\r
34 EFI_STATUS Status;\r
35 EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;\r
36 EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;\r
37 EFI_MEMORY_DESCRIPTOR *EfiEntry;\r
38 EFI_MEMORY_DESCRIPTOR *NextEfiEntry;\r
39 EFI_MEMORY_DESCRIPTOR TempEfiEntry;\r
40 UINTN EfiMemoryMapSize;\r
41 UINTN EfiMapKey;\r
42 UINTN EfiDescriptorSize;\r
43 UINT32 EfiDescriptorVersion;\r
44 UINT64 MemoryBlockLength;\r
45\r
46 *Below4GMemoryLimit = 0;\r
47 *Above4GMemoryLimit = 0;\r
48\r
49 //\r
50 // Get the EFI memory map.\r
51 //\r
52 EfiMemoryMapSize = 0;\r
53 EfiMemoryMap = NULL;\r
54 Status = gBS->GetMemoryMap (\r
55 &EfiMemoryMapSize,\r
56 EfiMemoryMap,\r
57 &EfiMapKey,\r
58 &EfiDescriptorSize,\r
59 &EfiDescriptorVersion\r
60 );\r
61 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
62\r
63 do {\r
64 //\r
65 // Use size returned back plus 1 descriptor for the AllocatePool.\r
66 // We don't just multiply by 2 since the "for" loop below terminates on\r
67 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize\r
68 // we process bogus entries and create bogus E820 entries.\r
69 //\r
70 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);\r
71 ASSERT (EfiMemoryMap != NULL);\r
72 Status = gBS->GetMemoryMap (\r
73 &EfiMemoryMapSize,\r
74 EfiMemoryMap,\r
75 &EfiMapKey,\r
76 &EfiDescriptorSize,\r
77 &EfiDescriptorVersion\r
78 );\r
79 if (EFI_ERROR (Status)) {\r
80 FreePool (EfiMemoryMap);\r
81 }\r
82 } while (Status == EFI_BUFFER_TOO_SMALL);\r
83\r
84 ASSERT_EFI_ERROR (Status);\r
85\r
86 //\r
87 // Sort memory map from low to high\r
88 //\r
89 EfiEntry = EfiMemoryMap;\r
90 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
91 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
92 while (EfiEntry < EfiMemoryMapEnd) {\r
93 while (NextEfiEntry < EfiMemoryMapEnd) {\r
94 if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {\r
95 CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
96 CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
97 CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
98 }\r
99\r
100 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);\r
101 }\r
102\r
103 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
104 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
105 }\r
106\r
107 //\r
108 //\r
109 //\r
110 DEBUG ((DEBUG_INFO, "MemoryMap:\n"));\r
111 EfiEntry = EfiMemoryMap;\r
112 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
113 while (EfiEntry < EfiMemoryMapEnd) {\r
114 MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));\r
115 DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));\r
116 switch (EfiEntry->Type) {\r
117 case EfiLoaderCode:\r
118 case EfiLoaderData:\r
119 case EfiBootServicesCode:\r
120 case EfiBootServicesData:\r
121 case EfiConventionalMemory:\r
122 case EfiRuntimeServicesCode:\r
123 case EfiRuntimeServicesData:\r
124 case EfiACPIReclaimMemory:\r
125 case EfiACPIMemoryNVS:\r
126 case EfiReservedMemoryType:\r
127 if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {\r
128 //\r
129 // Skip the memory block is under 1MB\r
130 //\r
131 } else if (EfiEntry->PhysicalStart >= BASE_4GB) {\r
132 if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
133 *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
134 }\r
135 } else {\r
136 if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
137 *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
138 }\r
139 }\r
140 break;\r
141 }\r
142 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
143 }\r
144\r
145 FreePool (EfiMemoryMap);\r
146\r
147 DEBUG ((DEBUG_INFO, "Result:\n"));\r
148 DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit));\r
149 DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit));\r
150\r
151 return ;\r
152}\r
153\r
154/**\r
155 Initialize platform VTd policy.\r
156**/\r
157VOID\r
158InitializePlatformVTdPolicy (\r
159 VOID\r
160 )\r
161{\r
162 EFI_STATUS Status;\r
163 UINTN DeviceInfoCount;\r
164 EDKII_PLATFORM_VTD_DEVICE_INFO *DeviceInfo;\r
165 UINTN Index;\r
166\r
167 //\r
168 // It is optional.\r
169 //\r
170 Status = gBS->LocateProtocol (\r
171 &gEdkiiPlatformVTdPolicyProtocolGuid,\r
172 NULL,\r
173 (VOID **)&mPlatformVTdPolicy\r
174 );\r
175 if (!EFI_ERROR(Status)) {\r
176 Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);\r
177 if (!EFI_ERROR(Status)) {\r
178 for (Index = 0; Index < DeviceInfoCount; Index++) {\r
179 AlwaysEnablePageAttribute (DeviceInfo[Index].Segment, DeviceInfo[Index].SourceId);\r
180 }\r
181 FreePool (DeviceInfo);\r
182 }\r
183 }\r
184}\r
185\r
186/**\r
187 Setup VTd engine.\r
188**/\r
189VOID\r
190SetupVtd (\r
191 VOID\r
192 )\r
193{\r
194 EFI_STATUS Status;\r
195 VOID *PciEnumerationComplete;\r
196 UINTN Index;\r
197 UINT64 Below4GMemoryLimit;\r
198 UINT64 Above4GMemoryLimit;\r
199\r
200 //\r
201 // PCI Enumeration must be done\r
202 //\r
203 Status = gBS->LocateProtocol (\r
204 &gEfiPciEnumerationCompleteProtocolGuid,\r
205 NULL,\r
206 &PciEnumerationComplete\r
207 );\r
208 ASSERT_EFI_ERROR (Status);\r
209\r
210 ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);\r
211 Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);\r
212 DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));\r
213\r
214 mBelow4GMemoryLimit = Below4GMemoryLimit;\r
215 mAbove4GMemoryLimit = Above4GMemoryLimit;\r
216\r
217 //\r
218 // 1. setup\r
219 //\r
220 DEBUG ((DEBUG_INFO, "GetDmarAcpiTable\n"));\r
221 Status = GetDmarAcpiTable ();\r
222 if (EFI_ERROR (Status)) {\r
223 return;\r
224 }\r
225 DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));\r
226 Status = ParseDmarAcpiTableDrhd ();\r
227 if (EFI_ERROR (Status)) {\r
228 return;\r
229 }\r
230 DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));\r
231 PrepareVtdConfig ();\r
232\r
233 //\r
234 // 2. initialization\r
235 //\r
236 DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));\r
237 Status = SetupTranslationTable ();\r
238 if (EFI_ERROR (Status)) {\r
239 return;\r
240 }\r
241\r
242 InitializePlatformVTdPolicy ();\r
243\r
244 ParseDmarAcpiTableRmrr ();\r
245\r
246 for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
247 DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));\r
248 if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {\r
249 DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);\r
250 }\r
251 if (mVtdUnitInformation[Index].RootEntryTable != NULL) {\r
252 DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);\r
253 }\r
254 }\r
255\r
256 //\r
257 // 3. enable\r
258 //\r
259 DEBUG ((DEBUG_INFO, "EnableDmar\n"));\r
260 Status = EnableDmar ();\r
261 if (EFI_ERROR (Status)) {\r
262 return;\r
263 }\r
264 DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));\r
265 DumpVtdRegsAll ();\r
266}\r
267\r
268/**\r
269 ACPI notification function.\r
270\r
271 @param[in] Table A pointer to the ACPI table header.\r
272 @param[in] Version The ACPI table's version.\r
273 @param[in] TableKey The table key for this ACPI table.\r
274\r
275 @retval EFI_SUCCESS The notification function is executed.\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279AcpiNotificationFunc (\r
280 IN EFI_ACPI_SDT_HEADER *Table,\r
281 IN EFI_ACPI_TABLE_VERSION Version,\r
282 IN UINTN TableKey\r
283 )\r
284{\r
285 if (Table->Signature == EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE) {\r
286 DEBUG((DEBUG_INFO, "Vtd AcpiNotificationFunc\n"));\r
287 SetupVtd ();\r
288 }\r
289 return EFI_SUCCESS;\r
290}\r
291\r
292/**\r
293 Exit boot service callback function.\r
294\r
295 @param[in] Event The event handle.\r
296 @param[in] Context The event content.\r
297**/\r
298VOID\r
299EFIAPI\r
300OnExitBootServices (\r
301 IN EFI_EVENT Event,\r
302 IN VOID *Context\r
303 )\r
304{\r
305 DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));\r
306 DumpVtdRegsAll ();\r
307 DisableDmar ();\r
308 DumpVtdRegsAll ();\r
309}\r
310\r
311/**\r
312 Legacy boot callback function.\r
313\r
314 @param[in] Event The event handle.\r
315 @param[in] Context The event content.\r
316**/\r
317VOID\r
318EFIAPI\r
319OnLegacyBoot (\r
320 EFI_EVENT Event,\r
321 VOID *Context\r
322 )\r
323{\r
324 DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));\r
325 DumpVtdRegsAll ();\r
326 DisableDmar ();\r
327 DumpVtdRegsAll ();\r
328}\r
329\r
330/**\r
331 Initialize DMA protection.\r
332**/\r
333VOID\r
334InitializeDmaProtection (\r
335 VOID\r
336 )\r
337{\r
338 EFI_STATUS Status;\r
339 EFI_EVENT ExitBootServicesEvent;\r
340 EFI_EVENT LegacyBootEvent;\r
341\r
342 Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **) &mAcpiSdt);\r
343 ASSERT_EFI_ERROR (Status);\r
344\r
345 Status = mAcpiSdt->RegisterNotify (TRUE, AcpiNotificationFunc);\r
346 ASSERT_EFI_ERROR (Status);\r
347\r
348 Status = gBS->CreateEventEx (\r
349 EVT_NOTIFY_SIGNAL,\r
350 TPL_NOTIFY,\r
351 OnExitBootServices,\r
352 NULL,\r
353 &gEfiEventExitBootServicesGuid,\r
354 &ExitBootServicesEvent\r
355 );\r
356 ASSERT_EFI_ERROR (Status);\r
357\r
358 Status = EfiCreateEventLegacyBootEx (\r
359 TPL_NOTIFY,\r
360 OnLegacyBoot,\r
361 NULL,\r
362 &LegacyBootEvent\r
363 );\r
364 ASSERT_EFI_ERROR (Status);\r
365\r
366 return ;\r
367}\r