]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
IntelSiliconPkg IntelVTdPmrPei: Install IoMmu PPI before enabling PMR
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmrPei.c
1 /** @file
2
3 Copyright (c) 2017 - 2018, 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 (+ alignment) (1 << (HostAddressWidth + 1))
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 (+ alignment)
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, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
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 /**
381 Initialize DMA protection.
382
383 @param VTdInfo The VTd engine context information.
384
385 @retval EFI_SUCCESS the DMA protection is initialized.
386 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.
387 **/
388 EFI_STATUS
389 InitDmaProtection (
390 IN VTD_INFO *VTdInfo
391 )
392 {
393 EFI_STATUS Status;
394 UINT32 LowMemoryAlignment;
395 UINT64 HighMemoryAlignment;
396 UINTN MemoryAlignment;
397 UINTN LowBottom;
398 UINTN LowTop;
399 UINTN HighBottom;
400 UINT64 HighTop;
401 DMA_BUFFER_INFO *DmaBufferInfo;
402 VOID *Hob;
403
404 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
405 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
406
407 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));
408
409 LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
410 HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
411 if (LowMemoryAlignment < HighMemoryAlignment) {
412 MemoryAlignment = (UINTN)HighMemoryAlignment;
413 } else {
414 MemoryAlignment = LowMemoryAlignment;
415 }
416 ASSERT (DmaBufferInfo->DmaBufferSize == ALIGN_VALUE(DmaBufferInfo->DmaBufferSize, MemoryAlignment));
417 DmaBufferInfo->DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize), MemoryAlignment);
418 ASSERT (DmaBufferInfo->DmaBufferBase != 0);
419 if (DmaBufferInfo->DmaBufferBase == 0) {
420 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));
421 return EFI_OUT_OF_RESOURCES;
422 }
423
424 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));
425
426 DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
427 DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;
428
429 //
430 // Install PPI.
431 //
432 Status = PeiServicesInstallPpi (&mIoMmuPpiList);
433 ASSERT_EFI_ERROR(Status);
434
435 LowBottom = 0;
436 LowTop = DmaBufferInfo->DmaBufferBase;
437 HighBottom = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
438 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
439
440 Status = SetDmaProtectedRange (
441 VTdInfo,
442 VTdInfo->EngineMask,
443 (UINT32)LowBottom,
444 (UINT32)(LowTop - LowBottom),
445 HighBottom,
446 HighTop - HighBottom
447 );
448
449 if (EFI_ERROR(Status)) {
450 FreePages ((VOID *)DmaBufferInfo->DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize));
451 }
452
453 return Status;
454 }
455
456 /**
457 Initializes the Intel VTd Info.
458
459 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
460 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
461
462 **/
463 EFI_STATUS
464 InitVTdInfo (
465 VOID
466 )
467 {
468 EFI_STATUS Status;
469 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
470 VOID *Hob;
471
472 Status = PeiServicesLocatePpi (
473 &gEdkiiVTdInfoPpiGuid,
474 0,
475 NULL,
476 (VOID **)&AcpiDmarTable
477 );
478 ASSERT_EFI_ERROR(Status);
479
480 DumpAcpiDMAR (AcpiDmarTable);
481
482 //
483 // Clear old VTdInfo Hob.
484 //
485 Hob = GetFirstGuidHob (&mVTdInfoGuid);
486 if (Hob != NULL) {
487 ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));
488 }
489
490 //
491 // Get DMAR information to local VTdInfo
492 //
493 Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);
494 if (EFI_ERROR(Status)) {
495 return Status;
496 }
497
498 //
499 // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.
500 //
501
502 return EFI_SUCCESS;
503 }
504
505 /**
506 Initializes the Intel VTd PMR for all memory.
507
508 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
509 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
510
511 **/
512 EFI_STATUS
513 InitVTdPmrForAll (
514 VOID
515 )
516 {
517 EFI_STATUS Status;
518 VOID *Hob;
519 VTD_INFO *VTdInfo;
520 UINTN LowBottom;
521 UINTN LowTop;
522 UINTN HighBottom;
523 UINT64 HighTop;
524
525 Hob = GetFirstGuidHob (&mVTdInfoGuid);
526 VTdInfo = GET_GUID_HOB_DATA(Hob);
527
528 LowBottom = 0;
529 LowTop = 0;
530 HighBottom = 0;
531 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
532
533 Status = SetDmaProtectedRange (
534 VTdInfo,
535 VTdInfo->EngineMask,
536 (UINT32)LowBottom,
537 (UINT32)(LowTop - LowBottom),
538 HighBottom,
539 HighTop - HighBottom
540 );
541
542 return Status;
543 }
544
545 /**
546 Initializes the Intel VTd PMR for DMA buffer.
547
548 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
549 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
550
551 **/
552 EFI_STATUS
553 InitVTdPmrForDma (
554 VOID
555 )
556 {
557 EFI_STATUS Status;
558 VOID *Hob;
559 VTD_INFO *VTdInfo;
560
561 Hob = GetFirstGuidHob (&mVTdInfoGuid);
562 VTdInfo = GET_GUID_HOB_DATA(Hob);
563
564 //
565 // If there is RMRR memory, parse it here.
566 //
567 ParseDmarAcpiTableRmrr (VTdInfo);
568
569 //
570 // Allocate a range in PEI memory as DMA buffer
571 // Mark others to be DMA protected.
572 //
573 Status = InitDmaProtection (VTdInfo);
574
575 return Status;
576 }
577
578 /**
579 This function handles S3 resume task at the end of PEI
580
581 @param[in] PeiServices Pointer to PEI Services Table.
582 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
583 caused this function to execute.
584 @param[in] Ppi Pointer to the PPI data associated with this function.
585
586 @retval EFI_STATUS Always return EFI_SUCCESS
587 **/
588 EFI_STATUS
589 EFIAPI
590 S3EndOfPeiNotify(
591 IN EFI_PEI_SERVICES **PeiServices,
592 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
593 IN VOID *Ppi
594 )
595 {
596 VOID *Hob;
597 VTD_INFO *VTdInfo;
598 UINT64 EngineMask;
599
600 DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
601
602 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
603 Hob = GetFirstGuidHob (&mVTdInfoGuid);
604 if (Hob == NULL) {
605 return EFI_SUCCESS;
606 }
607 VTdInfo = GET_GUID_HOB_DATA(Hob);
608
609 EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;
610 DisableDmaProtection (VTdInfo, EngineMask);
611 }
612 return EFI_SUCCESS;
613 }
614
615 EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
616 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
617 &gEfiEndOfPeiSignalPpiGuid,
618 S3EndOfPeiNotify
619 };
620
621 /**
622 This function handles VTd engine setup
623
624 @param[in] PeiServices Pointer to PEI Services Table.
625 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
626 caused this function to execute.
627 @param[in] Ppi Pointer to the PPI data associated with this function.
628
629 @retval EFI_STATUS Always return EFI_SUCCESS
630 **/
631 EFI_STATUS
632 EFIAPI
633 VTdInfoNotify (
634 IN EFI_PEI_SERVICES **PeiServices,
635 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
636 IN VOID *Ppi
637 )
638 {
639 EFI_STATUS Status;
640 VOID *MemoryDiscovered;
641 UINT64 EnabledEngineMask;
642 VOID *Hob;
643 VTD_INFO *VTdInfo;
644 BOOLEAN MemoryInitialized;
645
646 DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));
647
648 //
649 // Check if memory is initialized.
650 //
651 MemoryInitialized = FALSE;
652 Status = PeiServicesLocatePpi (
653 &gEfiPeiMemoryDiscoveredPpiGuid,
654 0,
655 NULL,
656 &MemoryDiscovered
657 );
658 if (!EFI_ERROR(Status)) {
659 MemoryInitialized = TRUE;
660 }
661
662 DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));
663
664 if (!MemoryInitialized) {
665 //
666 // If the memory is not initialized,
667 // Protect all system memory
668 //
669 InitVTdInfo ();
670 InitVTdPmrForAll ();
671 } else {
672 //
673 // If the memory is initialized,
674 // Allocate DMA buffer and protect rest system memory
675 //
676
677 //
678 // NOTE: We need reinit VTdInfo because previous information might be overriden.
679 //
680 InitVTdInfo ();
681
682 Hob = GetFirstGuidHob (&mVTdInfoGuid);
683 VTdInfo = GET_GUID_HOB_DATA(Hob);
684
685 //
686 // NOTE: We need check if PMR is enabled or not.
687 //
688 EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);
689 if (EnabledEngineMask != 0) {
690 EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
691 DisableDmaProtection (VTdInfo, EnabledEngineMask);
692 }
693 InitVTdPmrForDma ();
694 if (EnabledEngineMask != 0) {
695 DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
696 }
697
698 }
699
700 return EFI_SUCCESS;
701 }
702
703 EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {
704 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
705 &gEdkiiVTdInfoPpiGuid,
706 VTdInfoNotify
707 };
708
709 /**
710 Initializes the Intel VTd PMR PEIM.
711
712 @param FileHandle Handle of the file being invoked.
713 @param PeiServices Describes the list of possible PEI Services.
714
715 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
716 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
717
718 **/
719 EFI_STATUS
720 EFIAPI
721 IntelVTdPmrInitialize (
722 IN EFI_PEI_FILE_HANDLE FileHandle,
723 IN CONST EFI_PEI_SERVICES **PeiServices
724 )
725 {
726 EFI_STATUS Status;
727 EFI_BOOT_MODE BootMode;
728 DMA_BUFFER_INFO *DmaBufferInfo;
729
730 DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));
731
732 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
733 return EFI_UNSUPPORTED;
734 }
735
736 DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));
737 ASSERT(DmaBufferInfo != NULL);
738 if (DmaBufferInfo == NULL) {
739 return EFI_OUT_OF_RESOURCES;
740 }
741 ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));
742
743 PeiServicesGetBootMode (&BootMode);
744
745 if (BootMode == BOOT_ON_S3_RESUME) {
746 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;
747 } else {
748 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
749 }
750
751 Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);
752 ASSERT_EFI_ERROR (Status);
753
754 //
755 // Register EndOfPei Notify for S3
756 //
757 if (BootMode == BOOT_ON_S3_RESUME) {
758 Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);
759 ASSERT_EFI_ERROR (Status);
760 }
761
762 return EFI_SUCCESS;
763 }
764