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