IntelSiliconPkg/VtdPmrPei: Add premem support.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmrPei.c
1 /** @file
2
3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
4
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License which accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <Uefi.h>
16 #include <PiPei.h>
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/IoLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/PeiServicesLib.h>
23 #include <Library/HobLib.h>
24 #include <IndustryStandard/Vtd.h>
25 #include <Ppi/IoMmu.h>
26 #include <Ppi/VtdInfo.h>
27 #include <Ppi/MemoryDiscovered.h>
28 #include <Ppi/EndOfPeiPhase.h>
29
30 #include "IntelVTdPmrPei.h"
31
32 #define TOTAL_DMA_BUFFER_SIZE SIZE_4MB
33 #define TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB
34
35 EFI_GUID mVTdInfoGuid = {
36 0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }
37 };
38
39 EFI_GUID mDmaBufferInfoGuid = {
40 0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }
41 };
42
43 typedef struct {
44 UINTN DmaBufferBase;
45 UINTN DmaBufferSize;
46 UINTN DmaBufferCurrentTop;
47 UINTN DmaBufferCurrentBottom;
48 } DMA_BUFFER_INFO;
49
50 #define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')
51 typedef struct {
52 UINT32 Signature;
53 EDKII_IOMMU_OPERATION Operation;
54 UINTN NumberOfBytes;
55 EFI_PHYSICAL_ADDRESS HostAddress;
56 EFI_PHYSICAL_ADDRESS DeviceAddress;
57 } MAP_INFO;
58
59 /**
60
61 PEI Memory Layout:
62
63 +------------------+ <=============== PHMR.Limit (Top of memory)
64 | Mem Resource |
65 | |
66
67 +------------------+ <------- EfiMemoryTop
68 | PEI allocated |
69 =========== +==================+ <=============== PHMR.Base
70 ^ | Commom Buf |
71 | | -------------- |
72 DMA Buffer | * DMA FREE * |
73 | | -------------- |
74 V | Read/Write Buf |
75 =========== +==================+ <=============== PLMR.Limit
76 | PEI allocated |
77 | -------------- | <------- EfiFreeMemoryTop
78 | * PEI FREE * |
79 | -------------- | <------- EfiFreeMemoryBottom
80 | hob |
81 | -------------- |
82 | Stack |
83 +------------------+ <------- EfiMemoryBottom / Stack Bottom
84
85 +------------------+
86 | Mem Alloc Hob |
87 +------------------+
88
89 | |
90 | Mem Resource |
91 +------------------+ <=============== PLMR.Base (0)
92 **/
93
94 /**
95 Set IOMMU attribute for a system memory.
96
97 If the IOMMU PPI exists, the system memory cannot be used
98 for DMA by default.
99
100 When a device requests a DMA access for a system memory,
101 the device driver need use SetAttribute() to update the IOMMU
102 attribute to request DMA access (read and/or write).
103
104 @param[in] This The PPI instance pointer.
105 @param[in] Mapping The mapping value returned from Map().
106 @param[in] IoMmuAccess The IOMMU access.
107
108 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
109 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
110 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
111 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
112 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.
113 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
114 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
115
116 **/
117 EFI_STATUS
118 EFIAPI
119 PeiIoMmuSetAttribute (
120 IN EDKII_IOMMU_PPI *This,
121 IN VOID *Mapping,
122 IN UINT64 IoMmuAccess
123 )
124 {
125 return EFI_SUCCESS;
126 }
127
128 /**
129 Provides the controller-specific addresses required to access system memory from a
130 DMA bus master.
131
132 @param This The PPI instance pointer.
133 @param Operation Indicates if the bus master is going to read or write to system memory.
134 @param HostAddress The system memory address to map to the PCI controller.
135 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
136 that were mapped.
137 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
138 access the hosts HostAddress.
139 @param Mapping A resulting value to pass to Unmap().
140
141 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
142 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
143 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
144 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
145 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
146
147 **/
148 EFI_STATUS
149 EFIAPI
150 PeiIoMmuMap (
151 IN EDKII_IOMMU_PPI *This,
152 IN EDKII_IOMMU_OPERATION Operation,
153 IN VOID *HostAddress,
154 IN OUT UINTN *NumberOfBytes,
155 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
156 OUT VOID **Mapping
157 )
158 {
159 MAP_INFO *MapInfo;
160 UINTN Length;
161 VOID *Hob;
162 DMA_BUFFER_INFO *DmaBufferInfo;
163
164 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
165 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
166
167 if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
168 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
169 *DeviceAddress = (UINTN)HostAddress;
170 *Mapping = 0;
171 return EFI_SUCCESS;
172 }
173
174 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));
175 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
176 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
177
178 Length = *NumberOfBytes + sizeof(MAP_INFO);
179 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
180 DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
181 ASSERT (FALSE);
182 return EFI_OUT_OF_RESOURCES;
183 }
184
185 *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;
186 DmaBufferInfo->DmaBufferCurrentBottom += Length;
187
188 MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);
189 MapInfo->Signature = MAP_INFO_SIGNATURE;
190 MapInfo->Operation = Operation;
191 MapInfo->NumberOfBytes = *NumberOfBytes;
192 MapInfo->HostAddress = (UINTN)HostAddress;
193 MapInfo->DeviceAddress = *DeviceAddress;
194 *Mapping = MapInfo;
195 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));
196
197 //
198 // If this is a read operation from the Bus Master's point of view,
199 // then copy the contents of the real buffer into the mapped buffer
200 // so the Bus Master can read the contents of the real buffer.
201 //
202 if (Operation == EdkiiIoMmuOperationBusMasterRead ||
203 Operation == EdkiiIoMmuOperationBusMasterRead64) {
204 CopyMem (
205 (VOID *) (UINTN) MapInfo->DeviceAddress,
206 (VOID *) (UINTN) MapInfo->HostAddress,
207 MapInfo->NumberOfBytes
208 );
209 }
210
211 return EFI_SUCCESS;
212 }
213
214 /**
215 Completes the Map() operation and releases any corresponding resources.
216
217 @param This The PPI instance pointer.
218 @param Mapping The mapping value returned from Map().
219
220 @retval EFI_SUCCESS The range was unmapped.
221 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
222 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
223 **/
224 EFI_STATUS
225 EFIAPI
226 PeiIoMmuUnmap (
227 IN EDKII_IOMMU_PPI *This,
228 IN VOID *Mapping
229 )
230 {
231 MAP_INFO *MapInfo;
232 UINTN Length;
233 VOID *Hob;
234 DMA_BUFFER_INFO *DmaBufferInfo;
235
236 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
237 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
238
239 if (Mapping == NULL) {
240 return EFI_SUCCESS;
241 }
242
243 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));
244 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
245 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
246
247 MapInfo = Mapping;
248 ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);
249 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));
250
251 //
252 // If this is a write operation from the Bus Master's point of view,
253 // then copy the contents of the mapped buffer into the real buffer
254 // so the processor can read the contents of the real buffer.
255 //
256 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||
257 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {
258 CopyMem (
259 (VOID *) (UINTN) MapInfo->HostAddress,
260 (VOID *) (UINTN) MapInfo->DeviceAddress,
261 MapInfo->NumberOfBytes
262 );
263 }
264
265 Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);
266 if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
267 DmaBufferInfo->DmaBufferCurrentBottom -= Length;
268 }
269
270 return EFI_SUCCESS;
271 }
272
273 /**
274 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
275 OperationBusMasterCommonBuffer64 mapping.
276
277 @param This The PPI instance pointer.
278 @param MemoryType The type of memory to allocate, EfiBootServicesData or
279 EfiRuntimeServicesData.
280 @param Pages The number of pages to allocate.
281 @param HostAddress A pointer to store the base system memory address of the
282 allocated range.
283 @param Attributes The requested bit mask of attributes for the allocated range.
284
285 @retval EFI_SUCCESS The requested memory pages were allocated.
286 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
287 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
288 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
289 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
290
291 **/
292 EFI_STATUS
293 EFIAPI
294 PeiIoMmuAllocateBuffer (
295 IN EDKII_IOMMU_PPI *This,
296 IN EFI_MEMORY_TYPE MemoryType,
297 IN UINTN Pages,
298 IN OUT VOID **HostAddress,
299 IN UINT64 Attributes
300 )
301 {
302 UINTN Length;
303 VOID *Hob;
304 DMA_BUFFER_INFO *DmaBufferInfo;
305
306 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
307 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
308
309 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));
310 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
311 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
312
313 Length = EFI_PAGES_TO_SIZE(Pages);
314 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
315 DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
316 ASSERT (FALSE);
317 return EFI_OUT_OF_RESOURCES;
318 }
319 *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);
320 DmaBufferInfo->DmaBufferCurrentTop -= Length;
321
322 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));
323 return EFI_SUCCESS;
324 }
325
326 /**
327 Frees memory that was allocated with AllocateBuffer().
328
329 @param This The PPI instance pointer.
330 @param Pages The number of pages to free.
331 @param HostAddress The base system memory address of the allocated range.
332
333 @retval EFI_SUCCESS The requested memory pages were freed.
334 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
335 was not allocated with AllocateBuffer().
336
337 **/
338 EFI_STATUS
339 EFIAPI
340 PeiIoMmuFreeBuffer (
341 IN EDKII_IOMMU_PPI *This,
342 IN UINTN Pages,
343 IN VOID *HostAddress
344 )
345 {
346 UINTN Length;
347 VOID *Hob;
348 DMA_BUFFER_INFO *DmaBufferInfo;
349
350 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
351 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
352
353 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));
354 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
355 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
356
357 Length = EFI_PAGES_TO_SIZE(Pages);
358 if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {
359 DmaBufferInfo->DmaBufferCurrentTop += Length;
360 }
361
362 return EFI_SUCCESS;
363 }
364
365 EDKII_IOMMU_PPI mIoMmuPpi = {
366 EDKII_IOMMU_PPI_REVISION,
367 PeiIoMmuSetAttribute,
368 PeiIoMmuMap,
369 PeiIoMmuUnmap,
370 PeiIoMmuAllocateBuffer,
371 PeiIoMmuFreeBuffer,
372 };
373
374 CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {
375 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
376 &gEdkiiIoMmuPpiGuid,
377 (VOID *) &mIoMmuPpi
378 };
379
380 #define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
381 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
382 EFI_RESOURCE_ATTRIBUTE_TESTED | \
383 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
384 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
385 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \
386 )
387
388 #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED)
389
390 #define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED)
391
392 #define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
393
394 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mResourceTypeShortName[] = {
395 "Mem",
396 "MMIO",
397 "I/O",
398 "FD",
399 "MM Port I/O",
400 "Reserved Mem",
401 "Reserved I/O",
402 };
403
404 /**
405 Return the short name of resource type.
406
407 @param Type resource type.
408
409 @return the short name of resource type.
410 **/
411 CHAR8 *
412 ShortNameOfResourceType (
413 IN UINT32 Type
414 )
415 {
416 if (Type < sizeof(mResourceTypeShortName) / sizeof(mResourceTypeShortName[0])) {
417 return mResourceTypeShortName[Type];
418 } else {
419 return "Unknown";
420 }
421 }
422
423 /**
424 Dump resource hob.
425
426 @param HobList the HOB list.
427 **/
428 VOID
429 DumpResourceHob (
430 IN VOID *HobList
431 )
432 {
433 EFI_PEI_HOB_POINTERS Hob;
434 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
435
436 DEBUG ((DEBUG_VERBOSE, "Resource Descriptor HOBs\n"));
437 for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
438 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
439 ResourceHob = Hob.ResourceDescriptor;
440 DEBUG ((DEBUG_VERBOSE,
441 " BA=%016lx L=%016lx Attr=%08x ",
442 ResourceHob->PhysicalStart,
443 ResourceHob->ResourceLength,
444 ResourceHob->ResourceAttribute
445 ));
446 DEBUG ((DEBUG_VERBOSE, ShortNameOfResourceType(ResourceHob->ResourceType)));
447 switch (ResourceHob->ResourceType) {
448 case EFI_RESOURCE_SYSTEM_MEMORY:
449 if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) != 0) {
450 DEBUG ((DEBUG_VERBOSE, " (Persistent)"));
451 } else if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) != 0) {
452 DEBUG ((DEBUG_VERBOSE, " (MoreReliable)"));
453 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
454 DEBUG ((DEBUG_VERBOSE, " (Tested)"));
455 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
456 DEBUG ((DEBUG_VERBOSE, " (Init)"));
457 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
458 DEBUG ((DEBUG_VERBOSE, " (Present)"));
459 } else {
460 DEBUG ((DEBUG_VERBOSE, " (Unknown)"));
461 }
462 break;
463 default:
464 break;
465 }
466 DEBUG ((DEBUG_VERBOSE, "\n"));
467 }
468 }
469 }
470
471 /**
472 Dump PHIT hob.
473
474 @param HobList the HOB list.
475 **/
476 VOID
477 DumpPhitHob (
478 IN VOID *HobList
479 )
480 {
481 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
482
483 PhitHob = HobList;
484 ASSERT(GET_HOB_TYPE(HobList) == EFI_HOB_TYPE_HANDOFF);
485 DEBUG ((DEBUG_VERBOSE, "PHIT HOB\n"));
486 DEBUG ((DEBUG_VERBOSE, " PhitHob - 0x%x\n", PhitHob));
487 DEBUG ((DEBUG_VERBOSE, " BootMode - 0x%x\n", PhitHob->BootMode));
488 DEBUG ((DEBUG_VERBOSE, " EfiMemoryTop - 0x%016lx\n", PhitHob->EfiMemoryTop));
489 DEBUG ((DEBUG_VERBOSE, " EfiMemoryBottom - 0x%016lx\n", PhitHob->EfiMemoryBottom));
490 DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryTop - 0x%016lx\n", PhitHob->EfiFreeMemoryTop));
491 DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryBottom - 0x%016lx\n", PhitHob->EfiFreeMemoryBottom));
492 DEBUG ((DEBUG_VERBOSE, " EfiEndOfHobList - 0x%lx\n", PhitHob->EfiEndOfHobList));
493 }
494
495 /**
496 Get the highest memory.
497
498 @return the highest memory.
499 **/
500 UINT64
501 GetTopMemory (
502 VOID
503 )
504 {
505 VOID *HobList;
506 EFI_PEI_HOB_POINTERS Hob;
507 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
508 UINT64 TopMemory;
509 UINT64 ResourceTop;
510
511 HobList = GetHobList ();
512
513 TopMemory = 0;
514 for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
515 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
516 ResourceHob = Hob.ResourceDescriptor;
517 switch (ResourceHob->ResourceType) {
518 case EFI_RESOURCE_SYSTEM_MEMORY:
519 ResourceTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
520 if (TopMemory < ResourceTop) {
521 TopMemory = ResourceTop;
522 }
523 break;
524 default:
525 break;
526 }
527 DEBUG ((DEBUG_VERBOSE, "\n"));
528 }
529 }
530 return TopMemory;
531 }
532
533 /**
534 Initialize DMA protection.
535
536 @param VTdInfo The VTd engine context information.
537 @param DmaBufferSize the DMA buffer size
538 @param DmaBufferBase the DMA buffer base
539
540 @retval EFI_SUCCESS the DMA protection is initialized.
541 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.
542 **/
543 EFI_STATUS
544 InitDmaProtection (
545 IN VTD_INFO *VTdInfo,
546 IN UINTN DmaBufferSize,
547 OUT UINTN *DmaBufferBase
548 )
549 {
550 EFI_STATUS Status;
551 VOID *HobList;
552 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
553 UINT32 LowMemoryAlignment;
554 UINT64 HighMemoryAlignment;
555 UINTN MemoryAlignment;
556 UINTN LowBottom;
557 UINTN LowTop;
558 UINTN HighBottom;
559 UINT64 HighTop;
560
561 HobList = GetHobList ();
562 DumpPhitHob (HobList);
563 DumpResourceHob (HobList);
564
565 PhitHob = HobList;
566
567 ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);
568
569 LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
570 HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
571 if (LowMemoryAlignment < HighMemoryAlignment) {
572 MemoryAlignment = (UINTN)HighMemoryAlignment;
573 } else {
574 MemoryAlignment = LowMemoryAlignment;
575 }
576 ASSERT (DmaBufferSize == ALIGN_VALUE(DmaBufferSize, MemoryAlignment));
577 *DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferSize), MemoryAlignment);
578 ASSERT (*DmaBufferBase != 0);
579 if (*DmaBufferBase == 0) {
580 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));
581 return EFI_OUT_OF_RESOURCES;
582 }
583
584 LowBottom = 0;
585 LowTop = *DmaBufferBase;
586 HighBottom = *DmaBufferBase + DmaBufferSize;
587 HighTop = GetTopMemory ();
588
589 Status = SetDmaProtectedRange (
590 VTdInfo,
591 VTdInfo->EngineMask,
592 (UINT32)LowBottom,
593 (UINT32)(LowTop - LowBottom),
594 HighBottom,
595 HighTop - HighBottom
596 );
597
598 if (EFI_ERROR(Status)) {
599 FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));
600 }
601
602 return Status;
603 }
604
605 /**
606 Initializes the Intel VTd Info.
607
608 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
609 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
610
611 **/
612 EFI_STATUS
613 InitVTdInfo (
614 VOID
615 )
616 {
617 EFI_STATUS Status;
618 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
619 VOID *Hob;
620
621 Status = PeiServicesLocatePpi (
622 &gEdkiiVTdInfoPpiGuid,
623 0,
624 NULL,
625 (VOID **)&AcpiDmarTable
626 );
627 ASSERT_EFI_ERROR(Status);
628
629 DumpAcpiDMAR (AcpiDmarTable);
630
631 //
632 // Clear old VTdInfo Hob.
633 //
634 Hob = GetFirstGuidHob (&mVTdInfoGuid);
635 if (Hob != NULL) {
636 ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));
637 }
638
639 //
640 // Get DMAR information to local VTdInfo
641 //
642 Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);
643 if (EFI_ERROR(Status)) {
644 return Status;
645 }
646
647 //
648 // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.
649 //
650
651 return EFI_SUCCESS;
652 }
653
654 /**
655 Initializes the Intel VTd PMR for all memory.
656
657 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
658 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
659
660 **/
661 EFI_STATUS
662 InitVTdPmrForAll (
663 VOID
664 )
665 {
666 EFI_STATUS Status;
667 VOID *Hob;
668 VTD_INFO *VTdInfo;
669 UINTN LowBottom;
670 UINTN LowTop;
671 UINTN HighBottom;
672 UINT64 HighTop;
673
674 Hob = GetFirstGuidHob (&mVTdInfoGuid);
675 VTdInfo = GET_GUID_HOB_DATA(Hob);
676
677 LowBottom = 0;
678 LowTop = 0;
679 HighBottom = 0;
680 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth);
681
682 Status = SetDmaProtectedRange (
683 VTdInfo,
684 VTdInfo->EngineMask,
685 (UINT32)LowBottom,
686 (UINT32)(LowTop - LowBottom),
687 HighBottom,
688 HighTop - HighBottom
689 );
690
691 return Status;
692 }
693
694 /**
695 Initializes the Intel VTd PMR for DMA buffer.
696
697 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
698 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
699
700 **/
701 EFI_STATUS
702 InitVTdPmrForDma (
703 VOID
704 )
705 {
706 EFI_STATUS Status;
707 VOID *Hob;
708 VTD_INFO *VTdInfo;
709 DMA_BUFFER_INFO *DmaBufferInfo;
710
711 Hob = GetFirstGuidHob (&mVTdInfoGuid);
712 VTdInfo = GET_GUID_HOB_DATA(Hob);
713
714 //
715 // If there is RMRR memory, parse it here.
716 //
717 ParseDmarAcpiTableRmrr (VTdInfo);
718
719 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
720 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
721
722 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));
723 //
724 // Find a pre-memory in resource hob as DMA buffer
725 // Mark PEI memory to be DMA protected.
726 //
727 Status = InitDmaProtection (VTdInfo, DmaBufferInfo->DmaBufferSize, &DmaBufferInfo->DmaBufferBase);
728 if (EFI_ERROR(Status)) {
729 return Status;
730 }
731
732 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));
733
734 DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
735 DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;
736
737 //
738 // Install PPI.
739 //
740 Status = PeiServicesInstallPpi (&mIoMmuPpiList);
741 ASSERT_EFI_ERROR(Status);
742
743 return Status;
744 }
745
746 /**
747 This function handles S3 resume task at the end of PEI
748
749 @param[in] PeiServices Pointer to PEI Services Table.
750 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
751 caused this function to execute.
752 @param[in] Ppi Pointer to the PPI data associated with this function.
753
754 @retval EFI_STATUS Always return EFI_SUCCESS
755 **/
756 EFI_STATUS
757 EFIAPI
758 S3EndOfPeiNotify(
759 IN EFI_PEI_SERVICES **PeiServices,
760 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
761 IN VOID *Ppi
762 )
763 {
764 VOID *Hob;
765 VTD_INFO *VTdInfo;
766 UINT64 EngineMask;
767
768 DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
769
770 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
771 Hob = GetFirstGuidHob (&mVTdInfoGuid);
772 if (Hob == NULL) {
773 return EFI_SUCCESS;
774 }
775 VTdInfo = GET_GUID_HOB_DATA(Hob);
776
777 EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;
778 DisableDmaProtection (VTdInfo, EngineMask);
779 }
780 return EFI_SUCCESS;
781 }
782
783 EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
784 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
785 &gEfiEndOfPeiSignalPpiGuid,
786 S3EndOfPeiNotify
787 };
788
789 /**
790 This function handles VTd engine setup
791
792 @param[in] PeiServices Pointer to PEI Services Table.
793 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
794 caused this function to execute.
795 @param[in] Ppi Pointer to the PPI data associated with this function.
796
797 @retval EFI_STATUS Always return EFI_SUCCESS
798 **/
799 EFI_STATUS
800 EFIAPI
801 VTdInfoNotify (
802 IN EFI_PEI_SERVICES **PeiServices,
803 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
804 IN VOID *Ppi
805 )
806 {
807 EFI_STATUS Status;
808 VOID *MemoryDiscovered;
809 UINT64 EnabledEngineMask;
810 VOID *Hob;
811 VTD_INFO *VTdInfo;
812 BOOLEAN MemoryInitialized;
813
814 DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));
815
816 //
817 // Check if memory is initialized.
818 //
819 MemoryInitialized = FALSE;
820 Status = PeiServicesLocatePpi (
821 &gEfiPeiMemoryDiscoveredPpiGuid,
822 0,
823 NULL,
824 &MemoryDiscovered
825 );
826 if (!EFI_ERROR(Status)) {
827 MemoryInitialized = TRUE;
828 }
829
830 DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));
831
832 if (!MemoryInitialized) {
833 //
834 // If the memory is not initialized,
835 // Protect all system memory
836 //
837 InitVTdInfo ();
838 InitVTdPmrForAll ();
839 } else {
840 //
841 // If the memory is initialized,
842 // Allocate DMA buffer and protect rest system memory
843 //
844
845 //
846 // NOTE: We need reinit VTdInfo because previous information might be overriden.
847 //
848 InitVTdInfo ();
849
850 Hob = GetFirstGuidHob (&mVTdInfoGuid);
851 VTdInfo = GET_GUID_HOB_DATA(Hob);
852
853 //
854 // NOTE: We need check if PMR is enabled or not.
855 //
856 EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);
857 if (EnabledEngineMask != 0) {
858 EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
859 DisableDmaProtection (VTdInfo, EnabledEngineMask);
860 }
861 InitVTdPmrForDma ();
862 if (EnabledEngineMask != 0) {
863 DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
864 }
865
866 }
867
868 return EFI_SUCCESS;
869 }
870
871 EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {
872 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
873 &gEdkiiVTdInfoPpiGuid,
874 VTdInfoNotify
875 };
876
877 /**
878 Initializes the Intel VTd PMR PEIM.
879
880 @param FileHandle Handle of the file being invoked.
881 @param PeiServices Describes the list of possible PEI Services.
882
883 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
884 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
885
886 **/
887 EFI_STATUS
888 EFIAPI
889 IntelVTdPmrInitialize (
890 IN EFI_PEI_FILE_HANDLE FileHandle,
891 IN CONST EFI_PEI_SERVICES **PeiServices
892 )
893 {
894 EFI_STATUS Status;
895 EFI_BOOT_MODE BootMode;
896 DMA_BUFFER_INFO *DmaBufferInfo;
897
898 DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));
899
900 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
901 return EFI_UNSUPPORTED;
902 }
903
904 DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));
905 ASSERT(DmaBufferInfo != NULL);
906 if (DmaBufferInfo == NULL) {
907 return EFI_OUT_OF_RESOURCES;
908 }
909 ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));
910
911 PeiServicesGetBootMode (&BootMode);
912
913 if (BootMode == BOOT_ON_S3_RESUME) {
914 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;
915 } else {
916 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
917 }
918
919 Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);
920 ASSERT_EFI_ERROR (Status);
921
922 //
923 // Register EndOfPei Notify for S3
924 //
925 if (BootMode == BOOT_ON_S3_RESUME) {
926 Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);
927 ASSERT_EFI_ERROR (Status);
928 }
929
930 return EFI_SUCCESS;
931 }
932