1 /** @file
2 
3   Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
4   SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 **/
7 
8 #ifndef _DMAR_PROTECTION_H_
9 #define _DMAR_PROTECTION_H_
10 
11 #include <Uefi.h>
12 #include <PiDxe.h>
13 
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/IoLib.h>
19 #include <Library/PciSegmentLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiLib.h>
22 #include <Library/CacheMaintenanceLib.h>
23 #include <Library/PerformanceLib.h>
24 #include <Library/PrintLib.h>
25 #include <Library/ReportStatusCodeLib.h>
26 
27 #include <Guid/EventGroup.h>
28 #include <Guid/Acpi.h>
29 
30 #include <Protocol/DxeSmmReadyToLock.h>
31 #include <Protocol/PciRootBridgeIo.h>
32 #include <Protocol/PciIo.h>
33 #include <Protocol/PciEnumerationComplete.h>
34 #include <Protocol/PlatformVtdPolicy.h>
35 #include <Protocol/IoMmu.h>
36 
37 #include <IndustryStandard/Pci.h>
38 #include <IndustryStandard/DmaRemappingReportingTable.h>
39 #include <IndustryStandard/Vtd.h>
40 
41 #define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32))
42 
43 #define ALIGN_VALUE_UP(Value, Alignment)  (((Value) + (Alignment) - 1) & (~((Alignment) - 1)))
44 #define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))
45 
46 #define VTD_TPL_LEVEL TPL_NOTIFY
47 
48 //
49 // This is the initial max PCI DATA number.
50 // The number may be enlarged later.
51 //
52 #define MAX_VTD_PCI_DATA_NUMBER             0x100
53 
54 typedef struct {
55   UINT8                            DeviceType;
56   VTD_SOURCE_ID                    PciSourceId;
57   EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId;
58   // for statistic analysis
59   UINTN                            AccessCount;
60 } PCI_DEVICE_DATA;
61 
62 typedef struct {
63   BOOLEAN                          IncludeAllFlag;
64   UINTN                            PciDeviceDataNumber;
65   UINTN                            PciDeviceDataMaxNumber;
66   PCI_DEVICE_DATA                  *PciDeviceData;
67 } PCI_DEVICE_INFORMATION;
68 
69 typedef struct {
70   UINTN                            VtdUnitBaseAddress;
71   UINT16                           Segment;
72   VTD_CAP_REG                      CapReg;
73   VTD_ECAP_REG                     ECapReg;
74   VTD_ROOT_ENTRY                   *RootEntryTable;
75   VTD_EXT_ROOT_ENTRY               *ExtRootEntryTable;
76   VTD_SECOND_LEVEL_PAGING_ENTRY    *FixedSecondLevelPagingEntry;
77   BOOLEAN                          HasDirtyContext;
78   BOOLEAN                          HasDirtyPages;
79   PCI_DEVICE_INFORMATION           PciDeviceInfo;
80 } VTD_UNIT_INFORMATION;
81 
82 //
83 // This is the initial max ACCESS request.
84 // The number may be enlarged later.
85 //
86 #define MAX_VTD_ACCESS_REQUEST      0x100
87 
88 typedef struct {
89   UINT16                Segment;
90   VTD_SOURCE_ID         SourceId;
91   UINT64                BaseAddress;
92   UINT64                Length;
93   UINT64                IoMmuAccess;
94 } VTD_ACCESS_REQUEST;
95 
96 
97 /**
98   The scan bus callback function.
99 
100   It is called in PCI bus scan for each PCI device under the bus.
101 
102   @param[in]  Context               The context of the callback.
103   @param[in]  Segment               The segment of the source.
104   @param[in]  Bus                   The bus of the source.
105   @param[in]  Device                The device of the source.
106   @param[in]  Function              The function of the source.
107 
108   @retval EFI_SUCCESS           The specific PCI device is processed in the callback.
109 **/
110 typedef
111 EFI_STATUS
112 (EFIAPI *SCAN_BUS_FUNC_CALLBACK_FUNC) (
113   IN VOID           *Context,
114   IN UINT16         Segment,
115   IN UINT8          Bus,
116   IN UINT8          Device,
117   IN UINT8          Function
118   );
119 
120 extern EFI_ACPI_DMAR_HEADER  *mAcpiDmarTable;
121 
122 extern UINTN                            mVtdUnitNumber;
123 extern VTD_UNIT_INFORMATION             *mVtdUnitInformation;
124 
125 extern UINT64                           mBelow4GMemoryLimit;
126 extern UINT64                           mAbove4GMemoryLimit;
127 
128 extern EDKII_PLATFORM_VTD_POLICY_PROTOCOL   *mPlatformVTdPolicy;
129 
130 /**
131   Prepare VTD configuration.
132 **/
133 VOID
134 PrepareVtdConfig (
135   VOID
136   );
137 
138 /**
139   Setup VTd translation table.
140 
141   @retval EFI_SUCCESS           Setup translation table successfully.
142   @retval EFI_OUT_OF_RESOURCE   Setup translation table fail.
143 **/
144 EFI_STATUS
145 SetupTranslationTable (
146   VOID
147   );
148 
149 /**
150   Enable DMAR translation.
151 
152   @retval EFI_SUCCESS           DMAR translation is enabled.
153   @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
154 **/
155 EFI_STATUS
156 EnableDmar (
157   VOID
158   );
159 
160 /**
161   Disable DMAR translation.
162 
163   @retval EFI_SUCCESS           DMAR translation is disabled.
164   @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
165 **/
166 EFI_STATUS
167 DisableDmar (
168   VOID
169   );
170 
171 /**
172   Flush VTd engine write buffer.
173 
174   @param[in]  VtdIndex          The index used to identify a VTd engine.
175 **/
176 VOID
177 FlushWriteBuffer (
178   IN UINTN  VtdIndex
179   );
180 
181 /**
182   Invalidate VTd context cache.
183 
184   @param[in]  VtdIndex          The index used to identify a VTd engine.
185 **/
186 EFI_STATUS
187 InvalidateContextCache (
188   IN UINTN  VtdIndex
189   );
190 
191 /**
192   Invalidate VTd IOTLB.
193 
194   @param[in]  VtdIndex          The index used to identify a VTd engine.
195 **/
196 EFI_STATUS
197 InvalidateIOTLB (
198   IN UINTN  VtdIndex
199   );
200 
201 /**
202   Invalid VTd global IOTLB.
203 
204   @param[in]  VtdIndex              The index of VTd engine.
205 
206   @retval EFI_SUCCESS           VTd global IOTLB is invalidated.
207   @retval EFI_DEVICE_ERROR      VTd global IOTLB is not invalidated.
208 **/
209 EFI_STATUS
210 InvalidateVtdIOTLBGlobal (
211   IN UINTN  VtdIndex
212   );
213 
214 /**
215   Dump VTd registers.
216 
217   @param[in]  VtdIndex              The index of VTd engine.
218 **/
219 VOID
220 DumpVtdRegs (
221   IN UINTN  VtdIndex
222   );
223 
224 /**
225   Dump VTd registers for all VTd engine.
226 **/
227 VOID
228 DumpVtdRegsAll (
229   VOID
230   );
231 
232 /**
233   Dump VTd capability registers.
234 
235   @param[in]  CapReg              The capability register.
236 **/
237 VOID
238 DumpVtdCapRegs (
239   IN VTD_CAP_REG *CapReg
240   );
241 
242 /**
243   Dump VTd extended capability registers.
244 
245   @param[in]  ECapReg              The extended capability register.
246 **/
247 VOID
248 DumpVtdECapRegs (
249   IN VTD_ECAP_REG *ECapReg
250   );
251 
252 /**
253   Register PCI device to VTd engine.
254 
255   @param[in]  VtdIndex              The index of VTd engine.
256   @param[in]  Segment               The segment of the source.
257   @param[in]  SourceId              The SourceId of the source.
258   @param[in]  DeviceType            The DMAR device scope type.
259   @param[in]  CheckExist            TRUE: ERROR will be returned if the PCI device is already registered.
260                                     FALSE: SUCCESS will be returned if the PCI device is registered.
261 
262   @retval EFI_SUCCESS           The PCI device is registered.
263   @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
264   @retval EFI_ALREADY_STARTED   The device is already registered.
265 **/
266 EFI_STATUS
267 RegisterPciDevice (
268   IN UINTN          VtdIndex,
269   IN UINT16         Segment,
270   IN VTD_SOURCE_ID  SourceId,
271   IN UINT8          DeviceType,
272   IN BOOLEAN        CheckExist
273   );
274 
275 /**
276   The scan bus callback function to always enable page attribute.
277 
278   @param[in]  Context               The context of the callback.
279   @param[in]  Segment               The segment of the source.
280   @param[in]  Bus                   The bus of the source.
281   @param[in]  Device                The device of the source.
282   @param[in]  Function              The function of the source.
283 
284   @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
285 **/
286 EFI_STATUS
287 EFIAPI
288 ScanBusCallbackRegisterPciDevice (
289   IN VOID           *Context,
290   IN UINT16         Segment,
291   IN UINT8          Bus,
292   IN UINT8          Device,
293   IN UINT8          Function
294   );
295 
296 /**
297   Scan PCI bus and invoke callback function for each PCI devices under the bus.
298 
299   @param[in]  Context               The context of the callback function.
300   @param[in]  Segment               The segment of the source.
301   @param[in]  Bus                   The bus of the source.
302   @param[in]  Callback              The callback function in PCI scan.
303 
304   @retval EFI_SUCCESS           The PCI devices under the bus are scaned.
305 **/
306 EFI_STATUS
307 ScanPciBus (
308   IN VOID                         *Context,
309   IN UINT16                       Segment,
310   IN UINT8                        Bus,
311   IN SCAN_BUS_FUNC_CALLBACK_FUNC  Callback
312   );
313 
314 /**
315   Dump the PCI device information managed by this VTd engine.
316 
317   @param[in]  VtdIndex              The index of VTd engine.
318 **/
319 VOID
320 DumpPciDeviceInfo (
321   IN UINTN  VtdIndex
322   );
323 
324 /**
325   Find the VTd index by the Segment and SourceId.
326 
327   @param[in]  Segment               The segment of the source.
328   @param[in]  SourceId              The SourceId of the source.
329   @param[out] ExtContextEntry       The ExtContextEntry of the source.
330   @param[out] ContextEntry          The ContextEntry of the source.
331 
332   @return The index of the VTd engine.
333   @retval (UINTN)-1  The VTd engine is not found.
334 **/
335 UINTN
336 FindVtdIndexByPciDevice (
337   IN  UINT16                  Segment,
338   IN  VTD_SOURCE_ID           SourceId,
339   OUT VTD_EXT_CONTEXT_ENTRY   **ExtContextEntry,
340   OUT VTD_CONTEXT_ENTRY       **ContextEntry
341   );
342 
343 /**
344   Get the DMAR ACPI table.
345 
346   @retval EFI_SUCCESS           The DMAR ACPI table is got.
347   @retval EFI_ALREADY_STARTED   The DMAR ACPI table has been got previously.
348   @retval EFI_NOT_FOUND         The DMAR ACPI table is not found.
349 **/
350 EFI_STATUS
351 GetDmarAcpiTable (
352   VOID
353   );
354 
355 /**
356   Parse DMAR DRHD table.
357 
358   @return EFI_SUCCESS  The DMAR DRHD table is parsed.
359 **/
360 EFI_STATUS
361 ParseDmarAcpiTableDrhd (
362   VOID
363   );
364 
365 /**
366   Parse DMAR RMRR table.
367 
368   @return EFI_SUCCESS  The DMAR RMRR table is parsed.
369 **/
370 EFI_STATUS
371 ParseDmarAcpiTableRmrr (
372   VOID
373   );
374 
375 /**
376   Dump DMAR context entry table.
377 
378   @param[in]  RootEntry DMAR root entry.
379 **/
380 VOID
381 DumpDmarContextEntryTable (
382   IN VTD_ROOT_ENTRY *RootEntry
383   );
384 
385 /**
386   Dump DMAR extended context entry table.
387 
388   @param[in]  ExtRootEntry DMAR extended root entry.
389 **/
390 VOID
391 DumpDmarExtContextEntryTable (
392   IN VTD_EXT_ROOT_ENTRY *ExtRootEntry
393   );
394 
395 /**
396   Dump DMAR second level paging entry.
397 
398   @param[in]  SecondLevelPagingEntry The second level paging entry.
399 **/
400 VOID
401 DumpSecondLevelPagingEntry (
402   IN VOID *SecondLevelPagingEntry
403   );
404 
405 /**
406   Set VTd attribute for a system memory.
407 
408   @param[in]  VtdIndex                The index used to identify a VTd engine.
409   @param[in]  DomainIdentifier        The domain ID of the source.
410   @param[in]  SecondLevelPagingEntry  The second level paging entry in VTd table for the device.
411   @param[in]  BaseAddress             The base of device memory address to be used as the DMA memory.
412   @param[in]  Length                  The length of device memory address to be used as the DMA memory.
413   @param[in]  IoMmuAccess             The IOMMU access.
414 
415   @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
416   @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
417   @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
418   @retval EFI_INVALID_PARAMETER  Length is 0.
419   @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
420   @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
421   @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
422   @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
423   @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
424 **/
425 EFI_STATUS
426 SetPageAttribute (
427   IN UINTN                         VtdIndex,
428   IN UINT16                        DomainIdentifier,
429   IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
430   IN UINT64                        BaseAddress,
431   IN UINT64                        Length,
432   IN UINT64                        IoMmuAccess
433   );
434 
435 /**
436   Set VTd attribute for a system memory.
437 
438   @param[in]  Segment           The Segment used to identify a VTd engine.
439   @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
440   @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
441   @param[in]  Length            The length of device memory address to be used as the DMA memory.
442   @param[in]  IoMmuAccess       The IOMMU access.
443 
444   @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
445   @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
446   @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
447   @retval EFI_INVALID_PARAMETER  Length is 0.
448   @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
449   @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
450   @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
451   @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
452   @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
453 **/
454 EFI_STATUS
455 SetAccessAttribute (
456   IN UINT16                Segment,
457   IN VTD_SOURCE_ID         SourceId,
458   IN UINT64                BaseAddress,
459   IN UINT64                Length,
460   IN UINT64                IoMmuAccess
461   );
462 
463 /**
464   Return the index of PCI data.
465 
466   @param[in]  VtdIndex          The index used to identify a VTd engine.
467   @param[in]  Segment           The Segment used to identify a VTd engine.
468   @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
469 
470   @return The index of the PCI data.
471   @retval (UINTN)-1  The PCI data is not found.
472 **/
473 UINTN
474 GetPciDataIndex (
475   IN UINTN          VtdIndex,
476   IN UINT16         Segment,
477   IN VTD_SOURCE_ID  SourceId
478   );
479 
480 /**
481   Dump VTd registers if there is error.
482 **/
483 VOID
484 DumpVtdIfError (
485   VOID
486   );
487 
488 /**
489   Initialize platform VTd policy.
490 **/
491 VOID
492 InitializePlatformVTdPolicy (
493   VOID
494   );
495 
496 /**
497   Always enable the VTd page attribute for the device.
498 
499   @param[in]  Segment           The Segment used to identify a VTd engine.
500   @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
501 
502   @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
503 **/
504 EFI_STATUS
505 AlwaysEnablePageAttribute (
506   IN UINT16                  Segment,
507   IN VTD_SOURCE_ID           SourceId
508   );
509 
510 /**
511   Convert the DeviceHandle to SourceId and Segment.
512 
513   @param[in]  DeviceHandle      The device who initiates the DMA access request.
514   @param[out] Segment           The Segment used to identify a VTd engine.
515   @param[out] SourceId          The SourceId used to identify a VTd engine and table entry.
516 
517   @retval EFI_SUCCESS            The Segment and SourceId are returned.
518   @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
519   @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
520 **/
521 EFI_STATUS
522 DeviceHandleToSourceId (
523   IN EFI_HANDLE            DeviceHandle,
524   OUT UINT16               *Segment,
525   OUT VTD_SOURCE_ID        *SourceId
526   );
527 
528 /**
529   Get device information from mapping.
530 
531   @param[in]  Mapping        The mapping.
532   @param[out] DeviceAddress  The device address of the mapping.
533   @param[out] NumberOfPages  The number of pages of the mapping.
534 
535   @retval EFI_SUCCESS            The device information is returned.
536   @retval EFI_INVALID_PARAMETER  The mapping is invalid.
537 **/
538 EFI_STATUS
539 GetDeviceInfoFromMapping (
540   IN  VOID                                     *Mapping,
541   OUT EFI_PHYSICAL_ADDRESS                     *DeviceAddress,
542   OUT UINTN                                    *NumberOfPages
543   );
544 
545 /**
546   Initialize DMA protection.
547 **/
548 VOID
549 InitializeDmaProtection (
550   VOID
551   );
552 
553 /**
554   Allocate zero pages.
555 
556   @param[in]  Pages the number of pages.
557 
558   @return the page address.
559   @retval NULL No resource to allocate pages.
560 **/
561 VOID *
562 EFIAPI
563 AllocateZeroPages (
564   IN UINTN  Pages
565   );
566 
567 /**
568   Flush VTD page table and context table memory.
569 
570   This action is to make sure the IOMMU engine can get final data in memory.
571 
572   @param[in]  VtdIndex          The index used to identify a VTd engine.
573   @param[in]  Base              The base address of memory to be flushed.
574   @param[in]  Size              The size of memory in bytes to be flushed.
575 **/
576 VOID
577 FlushPageTableMemory (
578   IN UINTN  VtdIndex,
579   IN UINTN  Base,
580   IN UINTN  Size
581   );
582 
583 /**
584   Get PCI device information from DMAR DevScopeEntry.
585 
586   @param[in]  Segment               The segment number.
587   @param[in]  DmarDevScopeEntry     DMAR DevScopeEntry
588   @param[out] Bus                   The bus number.
589   @param[out] Device                The device number.
590   @param[out] Function              The function number.
591 
592   @retval EFI_SUCCESS  The PCI device information is returned.
593 **/
594 EFI_STATUS
595 GetPciBusDeviceFunction (
596   IN  UINT16                                      Segment,
597   IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,
598   OUT UINT8                                       *Bus,
599   OUT UINT8                                       *Device,
600   OUT UINT8                                       *Function
601   );
602 
603 /**
604   Append VTd Access Request to global.
605 
606   @param[in]  Segment           The Segment used to identify a VTd engine.
607   @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
608   @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
609   @param[in]  Length            The length of device memory address to be used as the DMA memory.
610   @param[in]  IoMmuAccess       The IOMMU access.
611 
612   @retval EFI_SUCCESS           The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
613   @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
614   @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
615   @retval EFI_INVALID_PARAMETER Length is 0.
616   @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
617   @retval EFI_UNSUPPORTED       The bit mask of IoMmuAccess is not supported by the IOMMU.
618   @retval EFI_UNSUPPORTED       The IOMMU does not support the memory range specified by BaseAddress and Length.
619   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to modify the IOMMU access.
620   @retval EFI_DEVICE_ERROR      The IOMMU device reported an error while attempting the operation.
621 
622 **/
623 EFI_STATUS
624 RequestAccessAttribute (
625   IN UINT16                 Segment,
626   IN VTD_SOURCE_ID          SourceId,
627   IN UINT64                 BaseAddress,
628   IN UINT64                 Length,
629   IN UINT64                 IoMmuAccess
630   );
631 
632 #endif
633