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