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