diff options
author | Star Zeng <star.zeng@intel.com> | 2018-01-03 15:08:18 +0800 |
---|---|---|
committer | Star Zeng <star.zeng@intel.com> | 2018-01-05 10:26:34 +0800 |
commit | 0bc94c748bc9b8645dd0566535708d88a5be0fe1 (patch) | |
tree | 80038a15ac1d53718da3ae657a3ae99641faaaa9 /IntelSiliconPkg/Feature/VTd | |
parent | 3a71670618dfa463b3377b752858df7964ad038c (diff) | |
download | edk2-0bc94c748bc9b8645dd0566535708d88a5be0fe1.zip edk2-0bc94c748bc9b8645dd0566535708d88a5be0fe1.tar.gz edk2-0bc94c748bc9b8645dd0566535708d88a5be0fe1.tar.bz2 |
IntelSiliconPkg IntelVTdDxe: Support early SetAttributes()
Support early SetAttributes() before DMAR table is installed.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Diffstat (limited to 'IntelSiliconPkg/Feature/VTd')
4 files changed, 202 insertions, 3 deletions
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c index d9b8885..557c18a 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c @@ -18,6 +18,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 +515,8 @@ SetupVtd ( ParseDmarAcpiTableRmrr ();
+ 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) {
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h index bc14ff9..767531e 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h @@ -1,6 +1,6 @@ /** @file
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
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
@@ -84,6 +84,21 @@ typedef struct { PCI_DEVICE_INFORMATION PciDeviceInfo;
} VTD_UNIT_INFORMATION;
+//
+// This is the initial max ACCESS request.
+// The number may be enlarged later.
+//
+#define MAX_VTD_ACCESS_REQUEST 0x100
+
+typedef struct {
+ UINT16 Segment;
+ VTD_SOURCE_ID SourceId;
+ UINT64 BaseAddress;
+ UINT64 Length;
+ UINT64 IoMmuAccess;
+} VTD_ACCESS_REQUEST;
+
+
/**
The scan bus callback function.
@@ -561,4 +576,33 @@ GetPciBusDeviceFunction ( OUT UINT8 *Function
);
+/**
+ 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
+ );
+
#endif
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c index b16bd93..b981bcd 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c @@ -27,7 +27,7 @@ typedef struct { #pragma pack()
-EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;
+EFI_ACPI_DMAR_HEADER *mAcpiDmarTable = NULL;
/**
Dump DMAR DeviceScopeEntry.
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c index 570b47c..841a5a9 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c @@ -1,7 +1,7 @@ /** @file
Intel VTd driver.
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
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
@@ -231,6 +231,14 @@ VTdSetAttribute ( DEBUG ((DEBUG_VERBOSE, "PCI(S%x.B%x.D%x.F%x) ", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
DEBUG ((DEBUG_VERBOSE, "(0x%lx~0x%lx) - %lx\n", DeviceAddress, Length, IoMmuAccess));
+ if (mAcpiDmarTable == NULL) {
+ //
+ // Record the entry to driver global variable.
+ // As such once VTd is activated, the setting can be adopted.
+ //
+ return RequestAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);
+ }
+
PERF_CODE (
AsciiSPrint (PerfToken, sizeof(PerfToken), "S%04xB%02xD%02xF%01x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function);
Identifier = (Segment << 16) | SourceId.Uint16;
|