X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=IntelSiliconPkg%2FFeature%2FVTd%2FIntelVTdDxe%2FDmaProtection.c;h=956ebb2d3d3d5c77be22e631c288b1a73b1daaee;hp=6052a0aebe45197d9fd81c8280bed467893b6a71;hb=370f16c5489609062d8ee0940f29f6c3393f1b68;hpb=f6f486e7bf7667ca7bcf50d808e056bd5ac7deaf diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c index 6052a0aebe..956ebb2d3d 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c @@ -1,13 +1,7 @@ /** @file - Copyright (c) 2017, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -18,6 +12,151 @@ UINT64 mAbove4GMemoryLimit; EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy; +VTD_ACCESS_REQUEST *mAccessRequest = NULL; +UINTN mAccessRequestCount = 0; +UINTN mAccessRequestMaxCount = 0; + +/** + Append VTd Access Request to global. + + @param[in] Segment The Segment used to identify a VTd engine. + @param[in] SourceId The SourceId used to identify a VTd engine and table entry. + @param[in] BaseAddress The base of device memory address to be used as the DMA memory. + @param[in] Length The length of device memory address to be used as the DMA memory. + @param[in] IoMmuAccess The IOMMU access. + + @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length. + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned. + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned. + @retval EFI_INVALID_PARAMETER Length is 0. + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access. + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU. + @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access. + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation. + +**/ +EFI_STATUS +RequestAccessAttribute ( + IN UINT16 Segment, + IN VTD_SOURCE_ID SourceId, + IN UINT64 BaseAddress, + IN UINT64 Length, + IN UINT64 IoMmuAccess + ) +{ + VTD_ACCESS_REQUEST *NewAccessRequest; + UINTN Index; + + // + // Optimization for memory. + // + // If the last record is to IoMmuAccess=0, + // Check previous records and remove the matched entry. + // + if (IoMmuAccess == 0) { + for (Index = 0; Index < mAccessRequestCount; Index++) { + if ((mAccessRequest[Index].Segment == Segment) && + (mAccessRequest[Index].SourceId.Uint16 == SourceId.Uint16) && + (mAccessRequest[Index].BaseAddress == BaseAddress) && + (mAccessRequest[Index].Length == Length) && + (mAccessRequest[Index].IoMmuAccess != 0)) { + // + // Remove this record [Index]. + // No need to add the new record. + // + if (Index != mAccessRequestCount - 1) { + CopyMem ( + &mAccessRequest[Index], + &mAccessRequest[Index + 1], + sizeof (VTD_ACCESS_REQUEST) * (mAccessRequestCount - 1 - Index) + ); + } + ZeroMem (&mAccessRequest[mAccessRequestCount - 1], sizeof(VTD_ACCESS_REQUEST)); + mAccessRequestCount--; + return EFI_SUCCESS; + } + } + } + + if (mAccessRequestCount >= mAccessRequestMaxCount) { + NewAccessRequest = AllocateZeroPool (sizeof(*NewAccessRequest) * (mAccessRequestMaxCount + MAX_VTD_ACCESS_REQUEST)); + if (NewAccessRequest == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mAccessRequestMaxCount += MAX_VTD_ACCESS_REQUEST; + if (mAccessRequest != NULL) { + CopyMem (NewAccessRequest, mAccessRequest, sizeof(*NewAccessRequest) * mAccessRequestCount); + FreePool (mAccessRequest); + } + mAccessRequest = NewAccessRequest; + } + + ASSERT (mAccessRequestCount < mAccessRequestMaxCount); + + mAccessRequest[mAccessRequestCount].Segment = Segment; + mAccessRequest[mAccessRequestCount].SourceId = SourceId; + mAccessRequest[mAccessRequestCount].BaseAddress = BaseAddress; + mAccessRequest[mAccessRequestCount].Length = Length; + mAccessRequest[mAccessRequestCount].IoMmuAccess = IoMmuAccess; + + mAccessRequestCount++; + + return EFI_SUCCESS; +} + +/** + Process Access Requests from before DMAR table is installed. + +**/ +VOID +ProcessRequestedAccessAttribute ( + VOID + ) +{ + UINTN Index; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute ...\n")); + + for (Index = 0; Index < mAccessRequestCount; Index++) { + DEBUG (( + DEBUG_INFO, + "PCI(S%x.B%x.D%x.F%x) ", + mAccessRequest[Index].Segment, + mAccessRequest[Index].SourceId.Bits.Bus, + mAccessRequest[Index].SourceId.Bits.Device, + mAccessRequest[Index].SourceId.Bits.Function + )); + DEBUG (( + DEBUG_INFO, + "(0x%lx~0x%lx) - %lx\n", + mAccessRequest[Index].BaseAddress, + mAccessRequest[Index].Length, + mAccessRequest[Index].IoMmuAccess + )); + Status = SetAccessAttribute ( + mAccessRequest[Index].Segment, + mAccessRequest[Index].SourceId, + mAccessRequest[Index].BaseAddress, + mAccessRequest[Index].Length, + mAccessRequest[Index].IoMmuAccess + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SetAccessAttribute %r: ", Status)); + } + } + + if (mAccessRequest != NULL) { + FreePool (mAccessRequest); + } + mAccessRequest = NULL; + mAccessRequestCount = 0; + mAccessRequestMaxCount = 0; + + DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute Done\n")); +} + /** return the UEFI memory information. @@ -370,6 +509,14 @@ SetupVtd ( ParseDmarAcpiTableRmrr (); + if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) == 0) { + // + // Support IOMMU access attribute request recording before DMAR table is installed. + // Here is to process the requests. + // + ProcessRequestedAccessAttribute (); + } + for (Index = 0; Index < mVtdUnitNumber; Index++) { DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment)); if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) { @@ -412,6 +559,9 @@ AcpiNotificationFunc ( Status = GetDmarAcpiTable (); if (EFI_ERROR (Status)) { + if (Status == EFI_ALREADY_STARTED) { + gBS->CloseEvent (Event); + } return; } SetupVtd (); @@ -431,9 +581,20 @@ OnExitBootServices ( IN VOID *Context ) { + UINTN VtdIndex; + DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n")); DumpVtdRegsAll (); + DEBUG ((DEBUG_INFO, "Invalidate all\n")); + for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) { + FlushWriteBuffer (VtdIndex); + + InvalidateContextCache (VtdIndex); + + InvalidateIOTLB (VtdIndex); + } + if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) { DisableDmar (); DumpVtdRegsAll (); @@ -470,28 +631,36 @@ InitializeDmaProtection ( EFI_STATUS Status; EFI_EVENT ExitBootServicesEvent; EFI_EVENT LegacyBootEvent; - EFI_EVENT Event; - + EFI_EVENT EventAcpi10; + EFI_EVENT EventAcpi20; + Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, + VTD_TPL_LEVEL, AcpiNotificationFunc, NULL, &gEfiAcpi10TableGuid, - &Event + &EventAcpi10 ); ASSERT_EFI_ERROR (Status); Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, + VTD_TPL_LEVEL, AcpiNotificationFunc, NULL, &gEfiAcpi20TableGuid, - &Event + &EventAcpi20 ); ASSERT_EFI_ERROR (Status); + // + // Signal the events initially for the case + // that DMAR table has been installed. + // + gBS->SignalEvent (EventAcpi20); + gBS->SignalEvent (EventAcpi10); + Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK,