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