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