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