From nobody Wed Apr 24 01:18:23 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+74625+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+74625+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1619765714; cv=none; d=zohomail.com; s=zohoarc; b=fDIaEDBrS5DXGgi/E3GNWbNShpHsdprNxFqm7AvEEvI+528F558qZiwCWtSo2DlP2nu3BA17wUkWcmDTw8uXA5XnikQsec1ciD8bnQlwymhWp/9l7RSibKg1ig7kbF3CoeLcA8auN4q3gydKaIRnQxLdOFnhvL0X4nq1JBzyaew= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1619765714; h=Cc:Date:From:List-Subscribe:List-Id:List-Help:List-Unsubscribe:Message-ID:Reply-To:Sender:Subject:To; bh=1y3NVBWL6a6EcB169ggQCnPQ2CMEuqcNpmgFwk8wntw=; b=XNJ+LV1I2Bkr/KInFxKIphjTkKcs+h0vbS/uWIDWjDsn6KlOuJwD/OBv96nKyjsrIRS5Vz0oTAq7B3ApE8koE7EmL8nVmGWesIrpkD1dRgfpNPGy8jsXLlJB8kkTCriSy2GNh0nnbQApgIa5F2dywXuJ4gKyyI5HbP8m/qPxfZs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+74625+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1619765714943676.0070620782973; Thu, 29 Apr 2021 23:55:14 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id ys2UYY1788612xpkbFQv5p0R; Thu, 29 Apr 2021 23:55:14 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web08.8168.1619765708894511027 for ; Thu, 29 Apr 2021 23:55:08 -0700 IronPort-SDR: QAXQz62xTGoWtUAwSV5wQVbiuz+Zg2iWLsCSnG4p5Q/cyHB0G0uQFgnP9IQh8Jh/kZKimQIHuL ySJSdXMqF2Ug== X-IronPort-AV: E=McAfee;i="6200,9189,9969"; a="176695079" X-IronPort-AV: E=Sophos;i="5.82,260,1613462400"; d="scan'208";a="176695079" X-Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Apr 2021 23:55:07 -0700 IronPort-SDR: uMP7PV8d4/ii+AM3mITBSsOvV4oTPIIJ+JX7NcDras5XEp7tS2tRuWFHtZtghXtyUYOnudfPrW DKKq4hcfbaGA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.82,260,1613462400"; d="scan'208";a="459230435" X-Received: from shwdesssddpdwei.ccr.corp.intel.com ([10.239.157.35]) by fmsmga002.fm.intel.com with ESMTP; 29 Apr 2021 23:55:05 -0700 From: "Sheng Wei" To: devel@edk2.groups.io Cc: Jenny Huang , Jiewen Yao , Ray Ni , Rangasai V Chaganty Subject: [edk2-devel] [PATCH] IntelSiliconPkg/VTd: Support queued invalidation interface Date: Fri, 30 Apr 2021 14:55:02 +0800 Message-Id: <20210430065502.15416-1-w.sheng@intel.com> Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,w.sheng@intel.com X-Gm-Message-State: rFRM3qHVfwdutJHeJYLgzUlKx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1619765714; bh=yz/2aOTs+y+a/1wCZeYR39JhQ6ER1b6tSMShWh8jLr8=; h=Cc:Date:From:Reply-To:Subject:To; b=Xu3TYnqAyDpU2l+B1x/Cn45PINIJ20sxnu0MWyK/H/CTlpJD7O5uvVMow4Ep4Sf8SIC +TN+w2cKJA5mIoOufznR/3r20bMsjihtTIkgD6s2RiML/dKA7Crz9tj9eoQVzrsO7NJcv 5g5WkeuHWml56s7RNIGzRwQjBergxEq9j3M= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add queued invalidation interface support for VTd core driver. For software to invalidate the various caching structures, the architecture supports the following two types of invalidation interfaces. 1. Register-based invalidation interface 2. Queued invalidation interface. BIOS shall check VER_REG to determine if register based invalidation can be used. Only for Major Version 6 or lower can support register based invalidation. For any version newer than that should use queue invalidation interface instead. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3366 Signed-off-by: Sheng Wei Cc: Jenny Huang Cc: Jiewen Yao Cc: Ray Ni Cc: Rangasai V Chaganty --- .../Feature/VTd/IntelVTdDmarPei/DmarTable.c | 2 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c | 443 +++++++++++++++++= ++-- .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c | 15 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h | 19 + .../Feature/VTd/IntelVTdDmarPei/TranslationTable.c | 2 - .../Feature/VTd/IntelVTdDxe/DmaProtection.h | 29 ++ .../Feature/VTd/IntelVTdDxe/VtdReg.c | 313 +++++++++++++-- .../IntelSiliconPkg/Include/IndustryStandard/Vtd.h | 57 +++ 8 files changed, 813 insertions(+), 67 deletions(-) diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Dmar= Table.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTab= le.c index d188f917..2154690d 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c @@ -561,6 +561,8 @@ ProcessDhrd ( DEBUG ((DEBUG_INFO," VTD BaseAddress - 0x%016lx\n", DmarDrhd->Register= BaseAddress)); VTdUnitInfo->VtdUnitBaseAddress =3D (UINT32) DmarDrhd->RegisterBaseAddre= ss; =20 + VTdUnitInfo->EnableQueuedInvalidation =3D 0; + DEBUG ((DEBUG_INFO," VTD Segment - %d\n", DmarDrhd->SegmentNumber)); VTdUnitInfo->Segment =3D DmarDrhd->SegmentNumber; =20 diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Inte= lVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Inte= lVTdDmar.c index 9ad2a494..f0bd7dc6 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDma= r.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDma= r.c @@ -66,30 +66,269 @@ FlushWriteBuffer ( } =20 /** - Invalidate VTd context cache. + Perpare cache invalidation interface. =20 - @param[in] VtdUnitBaseAddress The base address of the VTd engine. + @param[in] VTdUnitInfo The VTd engine unit information. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED Invalidation method is not supported. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. **/ EFI_STATUS -InvalidateContextCache ( - IN UINTN VtdUnitBaseAddress +PerpareCacheInvalidationInterface ( + IN VTD_UNIT_INFO *VTdUnitInfo ) { - UINT64 Reg64; + UINT16 QueueSize; + UINT64 Reg64; + UINT32 Reg32; + VTD_ECAP_REG ECapReg; + + + if (VTdUnitInfo->VerReg.Bits.Major <=3D 6) { + VTdUnitInfo->EnableQueuedInvalidation =3D 0; + DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for eng= ine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); + return EFI_SUCCESS; + } + + ECapReg.Uint64 =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + = R_ECAP_REG); + if (ECapReg.Bits.QI =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations i= nterface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); + return EFI_UNSUPPORTED; + } + + VTdUnitInfo->EnableQueuedInvalidation =3D 1; + DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [0x%x]= \n", VTdUnitInfo->VtdUnitBaseAddress)); + + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_RE= G); + if ((Reg32 & B_GSTS_REG_QIES) !=3D 0) { + DEBUG ((DEBUG_INFO,"Queued Invalidation Interface was enabled.\n")); + Reg32 &=3D (~B_GSTS_REG_QIES); + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg3= 2); + do { + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GST= S_REG); + } while ((Reg32 & B_GSTS_REG_QIES) !=3D 0); + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQA_REG, 0); + + if (VTdUnitInfo->QiDesc !=3D NULL) { + FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * V= TdUnitInfo->QiDescLength)); + VTdUnitInfo->QiDesc =3D NULL; + VTdUnitInfo->QiDescLength =3D 0; + } + } + + // + // Initialize the Invalidation Queue Tail Register to zero. + // + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, 0); + + // + // Setup the IQ address, size and descriptor width through the Invalidat= ion Queue Address Register + // + QueueSize =3D 0; + VTdUnitInfo->QiDescLength =3D 1 << (QueueSize + 8); + VTdUnitInfo->QiDesc =3D (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES(siz= eof(QI_DESC) * VTdUnitInfo->QiDescLength)); + + if (VTdUnitInfo->QiDesc =3D=3D NULL) { + VTdUnitInfo->QiDescLength =3D 0; + DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n")); + return EFI_OUT_OF_RESOURCES; + } + + DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", VTdUnitInfo->QiD= escLength)); + Reg64 =3D (UINT64) VTdUnitInfo->QiDesc; + Reg64 |=3D QueueSize; + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQA_REG, Reg64); + + // + // Enable the queued invalidation interface through the Global Command R= egister. + // When enabled, hardware sets the QIES field in the Global Status Regis= ter. + // + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_RE= G); + Reg32 |=3D B_GMCD_REG_QIE; + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32); + DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG =3D = 0x%x\n", Reg32)); + do { + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_= REG); + } while ((Reg32 & B_GSTS_REG_QIES) =3D=3D 0); + + VTdUnitInfo->QiFreeHead =3D 0; + + return EFI_SUCCESS; +} + +/** + Disable queued invalidation interface. + + @param[in] VTdUnitInfo The VTd engine unit information. +**/ +VOID +DisableQueuedInvalidationInterface ( + IN VTD_UNIT_INFO *VTdUnitInfo + ) +{ + UINT32 Reg32; + + if (VTdUnitInfo->EnableQueuedInvalidation !=3D 0) { + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_= REG); + Reg32 &=3D (~B_GMCD_REG_QIE); + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg3= 2); + DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. GCMD_REG = =3D 0x%x\n", Reg32)); + do { + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GST= S_REG); + } while ((Reg32 & B_GSTS_REG_QIES) !=3D 0); + + if (VTdUnitInfo->QiDesc !=3D NULL) { + FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * V= TdUnitInfo->QiDescLength)); + VTdUnitInfo->QiDesc =3D NULL; + VTdUnitInfo->QiDescLength =3D 0; + } + + VTdUnitInfo->EnableQueuedInvalidation =3D 0; + } +} + +/** + Check Queued Invalidation Fault. + + @param[in] VTdUnitInfo The VTd engine unit information. + + @retval EFI_SUCCESS The operation was successful. + @retval RETURN_DEVICE_ERROR A fault is detected. +**/ +EFI_STATUS +QueuedInvalidationCheckFault ( + IN VTD_UNIT_INFO *VTdUnitInfo + ) +{ + UINT32 fault_reg; + + fault_reg =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FST= S_REG); + + if (fault_reg & B_FSTS_REG_IQE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", faul= t_reg)); + fault_reg |=3D B_FSTS_REG_IQE; + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, faul= t_reg); + return RETURN_DEVICE_ERROR; + } + + if (fault_reg & B_FSTS_REG_ITE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", f= ault_reg)); + fault_reg |=3D B_FSTS_REG_ITE; + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, faul= t_reg); + return RETURN_DEVICE_ERROR; + } + + if (fault_reg & B_FSTS_REG_ICE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n",= fault_reg)); + fault_reg |=3D B_FSTS_REG_ICE; + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, faul= t_reg); + return RETURN_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Submit the queued invalidation descriptor to the remapping + hardware unit and wait for its completion. =20 - Reg64 =3D MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG); - if ((Reg64 & B_CCMD_REG_ICC) !=3D 0) { - DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is = set for VTD(%x)\n",VtdUnitBaseAddress)); - return EFI_DEVICE_ERROR; + @param[in] VTdUnitInfo The VTd engine unit information. + @param[in] desc The invalidate descriptor + + @retval EFI_SUCCESS The operation was successful. + @retval RETURN_DEVICE_ERROR A fault is detected. + @retval EFI_INVALID_PARAMETER Parameter is invalid. +**/ +EFI_STATUS +SubmitQueuedInvalidationDescriptor ( + IN VTD_UNIT_INFO *VTdUnitInfo, + IN QI_DESC *desc + ) +{ + EFI_STATUS rc; + UINT16 QiDescLength; + QI_DESC *BaseDesc; + UINT64 Reg64Iqt; + UINT64 Reg64Iqh; + + if (desc =3D=3D NULL) { + return EFI_INVALID_PARAMETER; } =20 - Reg64 &=3D ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK)); - Reg64 |=3D (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL); - MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64); + QiDescLength =3D VTdUnitInfo->QiDescLength; + BaseDesc =3D VTdUnitInfo->QiDesc; + + DEBUG((DEBUG_INFO, "[0x%x] Submit QI Descriptor [0x%08x, 0x%08x]\n", VTd= UnitInfo->VtdUnitBaseAddress, desc->low, desc->high)); + + BaseDesc[VTdUnitInfo->QiFreeHead].low =3D desc->low; + BaseDesc[VTdUnitInfo->QiFreeHead].high =3D desc->high; + FlushPageTableMemory(VTdUnitInfo, (UINTN) &BaseDesc[VTdUnitInfo->QiFreeH= ead], sizeof(QI_DESC)); + + DEBUG((DEBUG_INFO,"QI Free Head=3D0x%x\n", VTdUnitInfo->QiFreeHead)); + VTdUnitInfo->QiFreeHead =3D (VTdUnitInfo->QiFreeHead + 1) % QiDescLength; + + Reg64Iqh =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQH_= REG); + // + // Update the HW tail register indicating the presence of new descriptor= s. + // + Reg64Iqt =3D VTdUnitInfo->QiFreeHead << DMAR_IQ_SHIFT; + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, Reg64Iq= t); =20 + rc =3D EFI_SUCCESS; do { - Reg64 =3D MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG); - } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0); + rc =3D QueuedInvalidationCheckFault(VTdUnitInfo); + if (rc !=3D EFI_SUCCESS) { + DEBUG((DEBUG_ERROR,"Detect Queued Invalidation Fault.\n")); + break; + } + + Reg64Iqh =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQ= H_REG); + } while (Reg64Iqt !=3D Reg64Iqh); + + DEBUG((DEBUG_ERROR,"SubmitQueuedInvalidationDescriptor end\n")); + return rc; +} + +/** + Invalidate VTd context cache. + + @param[in] VTdUnitInfo The VTd engine unit information. +**/ +EFI_STATUS +InvalidateContextCache ( + IN VTD_UNIT_INFO *VTdUnitInfo + ) +{ + UINT64 Reg64; + QI_DESC QiDesc; + + if (VTdUnitInfo->EnableQueuedInvalidation =3D=3D 0) { + // + // Register-based Invalidation + // + Reg64 =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_CCMD_= REG); + if ((Reg64 & B_CCMD_REG_ICC) !=3D 0) { + DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC i= s set for VTD(%x)\n", (UINTN)VTdUnitInfo->VtdUnitBaseAddress)); + return EFI_DEVICE_ERROR; + } + + Reg64 &=3D ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK)); + Reg64 |=3D (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL); + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_CCMD_REG, Reg6= 4); + + do { + Reg64 =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_CCM= D_REG); + } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0); + } else { + // + // Queued Invalidation + // + QiDesc.low =3D QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(= 1) | QI_CC_TYPE; + QiDesc.high =3D 0; + + return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc); + } =20 return EFI_SUCCESS; } @@ -97,31 +336,102 @@ InvalidateContextCache ( /** Invalidate VTd IOTLB. =20 - @param[in] VtdUnitBaseAddress The base address of the VTd engine. + @param[in] VTdUnitInfo The VTd engine unit information. **/ EFI_STATUS InvalidateIOTLB ( - IN UINTN VtdUnitBaseAddress + IN VTD_UNIT_INFO *VTdUnitInfo ) { UINT64 Reg64; VTD_ECAP_REG ECapReg; + QI_DESC QiDesc; + + if (VTdUnitInfo->EnableQueuedInvalidation =3D=3D 0) { + // + // Register-based Invalidation + // + ECapReg.Uint64 =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress = + R_ECAP_REG); + + Reg64 =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + (ECapRe= g.Bits.IRO * 16) + R_IOTLB_REG); + if ((Reg64 & B_IOTLB_REG_IVT) !=3D 0) { + DEBUG ((DEBUG_ERROR, "ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is se= t for VTD(%x)\n", (UINTN)VTdUnitInfo->VtdUnitBaseAddress)); + return EFI_DEVICE_ERROR; + } =20 - ECapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG); + Reg64 &=3D ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK)); + Reg64 |=3D (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL); + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + (ECapReg.Bits.IR= O * 16) + R_IOTLB_REG, Reg64); =20 - Reg64 =3D MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_I= OTLB_REG); - if ((Reg64 & B_IOTLB_REG_IVT) !=3D 0) { - DEBUG ((DEBUG_ERROR, "ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set f= or VTD(%x)\n", VtdUnitBaseAddress)); - return EFI_DEVICE_ERROR; + do { + Reg64 =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + (ECap= Reg.Bits.IRO * 16) + R_IOTLB_REG); + } while ((Reg64 & B_IOTLB_REG_IVT) !=3D 0); + } else { + // + // Queued Invalidation + // + ECapReg.Uint64 =3D MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress = + R_ECAP_REG); + QiDesc.low =3D QI_IOTLB_DID(0) | QI_IOTLB_DR(cap_read_drain(ECapReg.Ui= nt64)) | QI_IOTLB_DW(cap_write_drain(ECapReg.Uint64)) | QI_IOTLB_GRAN(1) | = QI_IOTLB_TYPE; + QiDesc.high =3D QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0); + + return SubmitQueuedInvalidationDescriptor(VTdUnitInfo, &QiDesc); } =20 - Reg64 &=3D ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK)); - Reg64 |=3D (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL); - MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG,= Reg64); + return EFI_SUCCESS; +} + +/** + Enable DMAR translation inpre-mem phase. + + @param[in] VtdUnitBaseAddress The base address of the VTd engine. + @param[in] RootEntryTable The address of the VTd RootEntryTable. + + @retval EFI_SUCCESS DMAR translation is enabled. + @retval EFI_DEVICE_ERROR DMAR translation is not enabled. +**/ +EFI_STATUS +EnableDmarPreMem ( + IN UINTN VtdUnitBaseAddress, + IN UINTN RootEntryTable + ) +{ + UINT32 Reg32; + + DEBUG ((DEBUG_INFO, ">>>>>>EnableDmarPreMem() for engine [%x] \n", VtdUn= itBaseAddress)); + + DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable)); + MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (UINTN) RootEnt= ryTable); + + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_SRTP); + + DEBUG ((DEBUG_INFO, "EnableDmarPreMem: waiting for RTPS bit to be set...= \n")); + do { + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); + } while((Reg32 & B_GSTS_REG_RTPS) =3D=3D 0); + DEBUG ((DEBUG_INFO, "EnableDmarPreMem: R_GSTS_REG =3D 0x%x \n", Reg32)); =20 + // + // Init DMAr Fault Event and Data registers + // + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG); + + // + // Write Buffer Flush before invalidation + // + FlushWriteBuffer (VtdUnitBaseAddress); + + // + // Enable VTd + // + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_TE); + DEBUG ((DEBUG_INFO, "EnableDmarPreMem: Waiting B_GSTS_REG_TE ...\n")); do { - Reg64 =3D MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R= _IOTLB_REG); - } while ((Reg64 & B_IOTLB_REG_IVT) !=3D 0); + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); + } while ((Reg32 & B_GSTS_REG_TE) =3D=3D 0); + + DEBUG ((DEBUG_INFO, "VTD () enabled!<<<<<<\n")); =20 return EFI_SUCCESS; } @@ -129,59 +439,62 @@ InvalidateIOTLB ( /** Enable DMAR translation. =20 - @param[in] VtdUnitBaseAddress The base address of the VTd engine. - @param[in] RootEntryTable The address of the VTd RootEntryTa= ble. + @param[in] VTdUnitInfo The VTd engine unit information. + @param[in] RootEntryTable The address of the VTd RootEntryTable. =20 @retval EFI_SUCCESS DMAR translation is enabled. @retval EFI_DEVICE_ERROR DMAR translation is not enabled. **/ EFI_STATUS EnableDmar ( - IN UINTN VtdUnitBaseAddress, + IN VTD_UNIT_INFO *VTdUnitInfo, IN UINTN RootEntryTable ) { UINT32 Reg32; =20 - DEBUG ((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBase= Address)); + DEBUG ((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VTdUnitInfo= ->VtdUnitBaseAddress)); =20 DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable)); - MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (UINTN) RootEnt= ryTable); + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_RTADDR_REG, (UIN= T64) (UINTN) RootEntryTable); =20 - MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP); + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_RE= G); + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32 = | B_GMCD_REG_SRTP); =20 DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n")); do { - Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_= REG); } while((Reg32 & B_GSTS_REG_RTPS) =3D=3D 0); + DEBUG ((DEBUG_INFO, "EnableDmar: R_GSTS_REG =3D 0x%x \n", Reg32)); =20 // // Init DMAr Fault Event and Data registers // - Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG); + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FEDATA_= REG); =20 // // Write Buffer Flush before invalidation // - FlushWriteBuffer (VtdUnitBaseAddress); + FlushWriteBuffer ((UINTN)VTdUnitInfo->VtdUnitBaseAddress); =20 // // Invalidate the context cache // - InvalidateContextCache (VtdUnitBaseAddress); + InvalidateContextCache (VTdUnitInfo); =20 // // Invalidate the IOTLB cache // - InvalidateIOTLB (VtdUnitBaseAddress); + InvalidateIOTLB (VTdUnitInfo); =20 // // Enable VTd // - MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE); + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_RE= G); + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32 = | B_GMCD_REG_TE); DEBUG ((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n")); do { - Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); + Reg32 =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_= REG); } while ((Reg32 & B_GSTS_REG_TE) =3D=3D 0); =20 DEBUG ((DEBUG_INFO, "VTD () enabled!<<<<<<\n")); @@ -286,7 +599,7 @@ EnableVTdTranslationProtectionAll ( if ((EngineMask & LShiftU64(1, Index)) =3D=3D 0) { continue; } - EnableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress, (U= INTN) *RootEntryTable); + EnableDmarPreMem (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress, (UIN= TN) *RootEntryTable); } =20 return; @@ -311,10 +624,10 @@ EnableVTdTranslationProtection ( for (VtdIndex =3D 0; VtdIndex < VTdInfo->VTdEngineCount; VtdIndex++) { if (VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable !=3D 0) { DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) ExtRootEntryTable 0x%x\n", V= tdIndex, VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable)); - Status =3D EnableDmar (VTdInfo->VtdUnitInfo[VtdIndex].VtdUnitBaseAdd= ress, VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable); + Status =3D EnableDmar (&VTdInfo->VtdUnitInfo[VtdIndex], VTdInfo->Vtd= UnitInfo[VtdIndex].ExtRootEntryTable); } else { DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) RootEntryTable 0x%x\n", VtdI= ndex, VTdInfo->VtdUnitInfo[VtdIndex].RootEntryTable)); - Status =3D EnableDmar (VTdInfo->VtdUnitInfo[VtdIndex].VtdUnitBaseAdd= ress, VTdInfo->VtdUnitInfo[VtdIndex].RootEntryTable); + Status =3D EnableDmar (&VTdInfo->VtdUnitInfo[VtdIndex], VTdInfo->Vtd= UnitInfo[VtdIndex].RootEntryTable); } if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "EnableVtdDmar (%d) Failed !\n", VtdIndex)); @@ -345,11 +658,28 @@ DisableVTdTranslationProtection ( continue; } DisableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress); + + DisableQueuedInvalidationInterface(&VTdInfo->VtdUnitInfo[Index]); } =20 return; } =20 +/** + Dump VTd version registers. + + @param[in] VerReg The version register. +**/ +VOID +DumpVtdVerRegs ( + IN VTD_VER_REG *VerReg + ) +{ + DEBUG ((DEBUG_INFO, " VerReg:\n", VerReg->Uint32)); + DEBUG ((DEBUG_INFO, " Major - 0x%x\n", VerReg->Bits.Major)); + DEBUG ((DEBUG_INFO, " Minor - 0x%x\n", VerReg->Bits.Minor)); +} + /** Dump VTd capability registers. =20 @@ -414,6 +744,31 @@ DumpVtdECapRegs ( DEBUG ((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS)); } =20 +/** + Prepare VTD cache invalidation configuration. + + @param[in] VTdInfo The VTd engine context information. + + @retval EFI_SUCCESS Prepare Vtd config success +**/ +EFI_STATUS +PrepareVtdCacheInvalidationConfig ( + IN VTD_INFO *VTdInfo + ) +{ + UINTN Index; + EFI_STATUS Status; + + for (Index =3D 0; Index < VTdInfo->VTdEngineCount; Index++) { + Status =3D PerpareCacheInvalidationInterface(&VTdInfo->VtdUnitInfo[Ind= ex]); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + /** Prepare VTD configuration. =20 @@ -431,6 +786,9 @@ PrepareVtdConfig ( =20 for (Index =3D 0; Index < VTdInfo->VTdEngineCount; Index++) { DEBUG ((DEBUG_ERROR, "Dump VTd Capability (%d)\n", Index)); + VTdInfo->VtdUnitInfo[Index].VerReg.Uint32 =3D MmioRead32 (VTdInfo->Vtd= UnitInfo[Index].VtdUnitBaseAddress + R_VER_REG); + VTdInfo->VtdUnitInfo[Index].VerReg.Bits.Major =3D 7; + DumpVtdVerRegs (&VTdInfo->VtdUnitInfo[Index].VerReg); VTdInfo->VtdUnitInfo[Index].CapReg.Uint64 =3D MmioRead64 (VTdInfo->Vtd= UnitInfo[Index].VtdUnitBaseAddress + R_CAP_REG); DumpVtdCapRegs (&VTdInfo->VtdUnitInfo[Index].CapReg); VTdInfo->VtdUnitInfo[Index].ECapReg.Uint64 =3D MmioRead64 (VTdInfo->Vt= dUnitInfo[Index].VtdUnitBaseAddress + R_ECAP_REG); @@ -464,3 +822,4 @@ PrepareVtdConfig ( return EFI_SUCCESS; } =20 + diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Inte= lVTdDmarPei.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/I= ntelVTdDmarPei.c index f3c4a2bc..a8f7bfee 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDma= rPei.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDma= rPei.c @@ -482,6 +482,7 @@ InitVTdDmarForAll ( VOID *Hob; VTD_INFO *VTdInfo; UINT64 EngineMask; + EFI_STATUS Status; =20 Hob =3D GetFirstGuidHob (&mVTdInfoGuid); if (Hob =3D=3D NULL) { @@ -491,6 +492,13 @@ InitVTdDmarForAll ( VTdInfo =3D GET_GUID_HOB_DATA (Hob); EngineMask =3D LShiftU64 (1, VTdInfo->VTdEngineCount) - 1; =20 + DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n")); + Status =3D PrepareVtdConfig (VTdInfo); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + EnableVTdTranslationProtectionAll (VTdInfo, EngineMask); =20 return EFI_SUCCESS; @@ -596,6 +604,13 @@ InitVTdDmarForDma ( return Status; } =20 + DEBUG ((DEBUG_INFO, "PrepareVtdCacheInvalidationConfig\n")); + Status =3D PrepareVtdCacheInvalidationConfig (VTdInfo); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + // create root entry table DEBUG ((DEBUG_INFO, "SetupTranslationTable\n")); Status =3D SetupTranslationTable (VTdInfo); diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Inte= lVTdDmarPei.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/I= ntelVTdDmarPei.h index a3bb8827..e23a6c8e 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDma= rPei.h +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDma= rPei.h @@ -11,6 +11,8 @@ =20 #define MAX_VTD_PCI_DATA_NUMBER 0x100 =20 +#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32= )) + typedef struct { UINT8 DeviceType; VTD_SOURCE_ID PciSourceId; @@ -27,6 +29,7 @@ typedef struct { typedef struct { UINT32 VtdUnitBaseAddress; UINT16 Segment; + VTD_VER_REG VerReg; VTD_CAP_REG CapReg; VTD_ECAP_REG ECapReg; BOOLEAN Is5LevelPaging; @@ -37,6 +40,10 @@ typedef struct { UINT16 RootEntryTablePageSize; UINT16 ExtRootEntryTablePageSize; PEI_PCI_DEVICE_INFORMATION PciDeviceInfo; + UINT8 EnableQueuedInvalidation; + UINT16 QiDescLength; + QI_DESC *QiDesc; + UINT16 QiFreeHead; } VTD_UNIT_INFO; =20 typedef struct { @@ -123,6 +130,18 @@ DumpAcpiDMAR ( IN EFI_ACPI_DMAR_HEADER *Dmar ); =20 +/** + Prepare VTD cache invalidation configuration. + + @param[in] VTdInfo The VTd engine context information. + + @retval EFI_SUCCESS Prepare Vtd config success +**/ +EFI_STATUS +PrepareVtdCacheInvalidationConfig ( + IN VTD_INFO *VTdInfo + ); + /** Prepare VTD configuration. =20 diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Tran= slationTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/= TranslationTable.c index d417f5af..341e2beb 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Translation= Table.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/Translation= Table.c @@ -26,8 +26,6 @@ #define ALIGN_VALUE_UP(Value, Alignment) (((Value) + (Alignment) - 1) & (= ~((Alignment) - 1))) #define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1))) =20 -#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32= )) - /** Allocate zero pages. =20 diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProte= ction.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtecti= on.h index f641cea0..a24fbc37 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h @@ -69,6 +69,7 @@ typedef struct { typedef struct { UINTN VtdUnitBaseAddress; UINT16 Segment; + VTD_VER_REG VerReg; VTD_CAP_REG CapReg; VTD_ECAP_REG ECapReg; VTD_ROOT_ENTRY *RootEntryTable; @@ -78,6 +79,10 @@ typedef struct { BOOLEAN HasDirtyPages; PCI_DEVICE_INFORMATION PciDeviceInfo; BOOLEAN Is5LevelPaging; + UINT8 EnableQueuedInvalidation; + UINT16 QiDescLength; + QI_DESC *QiDesc; + UINT16 QiFreeHead; } VTD_UNIT_INFORMATION; =20 // @@ -179,6 +184,20 @@ FlushWriteBuffer ( IN UINTN VtdIndex ); =20 +/** + Perpare cache invalidation interface. + + @param[in] VtdIndex The index used to identify a VTd engine. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED Invalidation method is not supported. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +PerpareCacheInvalidationInterface ( + IN UINTN VtdIndex + ); + /** Invalidate VTd context cache. =20 @@ -230,6 +249,16 @@ DumpVtdRegsAll ( VOID ); =20 +/** + Dump VTd version registers. + + @param[in] VerReg The version register. +**/ +VOID +DumpVtdVerRegs ( + IN VTD_VER_REG *VerReg + ); + /** Dump VTd capability registers. =20 diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c= b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c index 686d235f..1049e940 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c @@ -55,31 +55,256 @@ FlushWriteBuffer ( } =20 /** - Invalidate VTd context cache. + Perpare cache invalidation interface. =20 @param[in] VtdIndex The index used to identify a VTd engine. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED Invalidation method is not supported. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. **/ EFI_STATUS -InvalidateContextCache ( +PerpareCacheInvalidationInterface ( IN UINTN VtdIndex ) { + UINT16 QueueSize; UINT64 Reg64; + UINT32 Reg32; =20 - Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress += R_CCMD_REG); - if ((Reg64 & B_CCMD_REG_ICC) !=3D 0) { - DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is = set for VTD(%d)\n",VtdIndex)); - return EFI_DEVICE_ERROR; + if (mVtdUnitInformation[VtdIndex].VerReg.Bits.Major <=3D 6) { + mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation =3D 0; + DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for eng= ine [%d]\n", VtdIndex)); + return EFI_SUCCESS; + } + + if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.QI =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations i= nterface for engine [%d]\n", VtdIndex)); + return EFI_UNSUPPORTED; + } + + mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation =3D 1; + DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [%d]\n= ", VtdIndex)); + + Reg32 =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress += R_GSTS_REG); + if ((Reg32 & B_GSTS_REG_QIES) !=3D 0) { + DEBUG ((DEBUG_ERROR,"Queued Invalidation Interface was enabled.\n")); + Reg32 &=3D (~B_GSTS_REG_QIES); + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD= _REG, Reg32); + do { + Reg32 =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss + R_GSTS_REG); + } while ((Reg32 & B_GSTS_REG_QIES) !=3D 0); + } + + // + // Initialize the Invalidation Queue Tail Register to zero. + // + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_RE= G, 0); + + // + // Setup the IQ address, size and descriptor width through the Invalidat= ion Queue Address Register + // + QueueSize =3D 0; + mVtdUnitInformation[VtdIndex].QiDescLength =3D 1 << (QueueSize + 8); + mVtdUnitInformation[VtdIndex].QiDesc =3D (QI_DESC *) AllocatePages (EFI_= SIZE_TO_PAGES(sizeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength)= ); + + if (mVtdUnitInformation[VtdIndex].QiDesc =3D=3D NULL) { + mVtdUnitInformation[VtdIndex].QiDescLength =3D 0; + DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n")); + return EFI_OUT_OF_RESOURCES; + } + + DEBUG ((DEBUG_INFO, "Invalidation Queue Length : %d\n", mVtdUnitInformat= ion[VtdIndex].QiDescLength)); + Reg64 =3D (UINT64) mVtdUnitInformation[VtdIndex].QiDesc; + Reg64 |=3D QueueSize; + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQA_RE= G, Reg64); + + // + // Enable the queued invalidation interface through the Global Command R= egister. + // When enabled, hardware sets the QIES field in the Global Status Regis= ter. + // + Reg32 =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress += R_GSTS_REG); + Reg32 |=3D B_GMCD_REG_QIE; + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_R= EG, Reg32); + DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG =3D = 0x%x\n", Reg32)); + do { + Reg32 =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + R_GSTS_REG); + } while ((Reg32 & B_GSTS_REG_QIES) =3D=3D 0); + + mVtdUnitInformation[VtdIndex].QiFreeHead =3D 0; + + return EFI_SUCCESS; +} + +/** + Disable queued invalidation interface. + + @param[in] VtdIndex The index used to identify a VTd engine. +**/ +VOID +DisableQueuedInvalidationInterface ( + IN UINTN VtdIndex + ) +{ + UINT32 Reg32; + + if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation !=3D 0) { + Reg32 =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + R_GSTS_REG); + Reg32 &=3D (~B_GMCD_REG_QIE); + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD= _REG, Reg32); + DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. GCMD_REG = =3D 0x%x\n", Reg32)); + do { + Reg32 =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss + R_GSTS_REG); + } while ((Reg32 & B_GSTS_REG_QIES) !=3D 0); + + if (mVtdUnitInformation[VtdIndex].QiDesc !=3D NULL) { + FreePages(mVtdUnitInformation[VtdIndex].QiDesc, EFI_SIZE_TO_PAGES(si= zeof(QI_DESC) * mVtdUnitInformation[VtdIndex].QiDescLength)); + mVtdUnitInformation[VtdIndex].QiDesc =3D NULL; + mVtdUnitInformation[VtdIndex].QiDescLength =3D 0; + } + + mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation =3D 0; + } +} + +/** + Check Queued Invalidation Fault. + + @param[in] VtdIndex The index used to identify a VTd engine. + + @retval EFI_SUCCESS The operation was successful. + @retval RETURN_DEVICE_ERROR A fault is detected. +**/ +EFI_STATUS +QueuedInvalidationCheckFault ( + IN UINTN VtdIndex + ) +{ + UINT32 fault_reg; + + fault_reg =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss + R_FSTS_REG); + + if (fault_reg & B_FSTS_REG_IQE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", faul= t_reg)); + fault_reg |=3D B_FSTS_REG_IQE; + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS= _REG, fault_reg); + return RETURN_DEVICE_ERROR; + } + + if (fault_reg & B_FSTS_REG_ITE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", f= ault_reg)); + fault_reg |=3D B_FSTS_REG_ITE; + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS= _REG, fault_reg); + return RETURN_DEVICE_ERROR; + } + + if (fault_reg & B_FSTS_REG_ICE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n",= fault_reg)); + fault_reg |=3D B_FSTS_REG_ICE; + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS= _REG, fault_reg); + return RETURN_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Submit the queued invalidation descriptor to the remapping + hardware unit and wait for its completion. + + @param[in] VtdIndex The index used to identify a VTd engine. + @param[in] desc The invalidate descriptor + + @retval EFI_SUCCESS The operation was successful. + @retval RETURN_DEVICE_ERROR A fault is detected. + @retval EFI_INVALID_PARAMETER Parameter is invalid. +**/ +EFI_STATUS +SubmitQueuedInvalidationDescriptor ( + IN UINTN VtdIndex, + IN QI_DESC *desc + ) +{ + EFI_STATUS rc; + UINT16 QiDescLength; + QI_DESC *BaseDesc; + UINT64 Reg64Iqt; + UINT64 Reg64Iqh; + + if (desc =3D=3D NULL) { + return EFI_INVALID_PARAMETER; } =20 - Reg64 &=3D ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK)); - Reg64 |=3D (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL); - MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_R= EG, Reg64); + QiDescLength =3D mVtdUnitInformation[VtdIndex].QiDescLength; + BaseDesc =3D mVtdUnitInformation[VtdIndex].QiDesc; + + DEBUG((DEBUG_INFO, "[%d] Submit QI Descriptor [0x%08x, 0x%08x] Free Head= (%d)\n", VtdIndex, desc->low, desc->high, mVtdUnitInformation[VtdIndex].Qi= FreeHead)); + + BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].low =3D desc->low; + BaseDesc[mVtdUnitInformation[VtdIndex].QiFreeHead].high =3D desc->high; + FlushPageTableMemory(VtdIndex, (UINTN) &BaseDesc[mVtdUnitInformation[Vtd= Index].QiFreeHead], sizeof(QI_DESC)); + + mVtdUnitInformation[VtdIndex].QiFreeHead =3D (mVtdUnitInformation[VtdInd= ex].QiFreeHead + 1) % QiDescLength; + + // + // Update the HW tail register indicating the presence of new descriptor= s. + // + Reg64Iqt =3D mVtdUnitInformation[VtdIndex].QiFreeHead << DMAR_IQ_SHIFT; + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_RE= G, Reg64Iqt); =20 + rc =3D EFI_SUCCESS; do { + rc =3D QueuedInvalidationCheckFault(VtdIndex); + if (rc !=3D EFI_SUCCESS) { + DEBUG((DEBUG_ERROR,"Detect Queued Invalidation Fault.\n")); + break; + } + + Reg64Iqh =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddr= ess + R_IQH_REG); + } while (Reg64Iqt !=3D Reg64Iqh); + + return rc; +} + +/** + Invalidate VTd context cache. + + @param[in] VtdIndex The index used to identify a VTd engine. +**/ +EFI_STATUS +InvalidateContextCache ( + IN UINTN VtdIndex + ) +{ + UINT64 Reg64; + QI_DESC QiDesc; + + if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation =3D=3D 0) { + // + // Register-based Invalidation + // Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + R_CCMD_REG); - } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0); + if ((Reg64 & B_CCMD_REG_ICC) !=3D 0) { + DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC i= s set for VTD(%d)\n",VtdIndex)); + return EFI_DEVICE_ERROR; + } + + Reg64 &=3D ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK)); + Reg64 |=3D (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL); + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD= _REG, Reg64); =20 + do { + Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss + R_CCMD_REG); + } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0); + } else { + // + // Queued Invalidation + // + QiDesc.low =3D QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC_GRAN(= 1) | QI_CC_TYPE; + QiDesc.high =3D 0; + + return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc); + } return EFI_SUCCESS; } =20 @@ -94,20 +319,34 @@ InvalidateIOTLB ( ) { UINT64 Reg64; + QI_DESC QiDesc; =20 - Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress += (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG); - if ((Reg64 & B_IOTLB_REG_IVT) !=3D 0) { - DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set fo= r VTD(%d)\n", VtdIndex)); - return EFI_DEVICE_ERROR; - } + if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation =3D=3D 0) { + // + // Register-based Invalidation + // + Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG); + if ((Reg64 & B_IOTLB_REG_IVT) !=3D 0) { + DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set = for VTD(%d)\n", VtdIndex)); + return EFI_DEVICE_ERROR; + } =20 - Reg64 &=3D ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK)); - Reg64 |=3D (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL); - MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUni= tInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64); + Reg64 &=3D ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK)); + Reg64 |=3D (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL); + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdU= nitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64); =20 - do { - Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG); - } while ((Reg64 & B_IOTLB_REG_IVT) !=3D 0); + do { + Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG); + } while ((Reg64 & B_IOTLB_REG_IVT) !=3D 0); + } else { + // + // Queued Invalidation + // + QiDesc.low =3D QI_IOTLB_DID(0) | QI_IOTLB_DR(cap_read_drain(mVtdUnitIn= formation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_DW(cap_write_drain(mVtdUnitI= nformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TYPE; + QiDesc.high =3D QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0); + + return SubmitQueuedInvalidationDescriptor(VtdIndex, &QiDesc); + } =20 return EFI_SUCCESS; } @@ -163,9 +402,12 @@ PrepareVtdConfig ( { UINTN Index; UINTN DomainNumber; + EFI_STATUS Status; =20 for (Index =3D 0; Index < mVtdUnitNumber; Index++) { DEBUG ((DEBUG_INFO, "Dump VTd Capability (%d)\n", Index)); + mVtdUnitInformation[Index].VerReg.Uint32 =3D MmioRead32 (mVtdUnitInfor= mation[Index].VtdUnitBaseAddress + R_VER_REG); + DumpVtdVerRegs (&mVtdUnitInformation[Index].VerReg); mVtdUnitInformation[Index].CapReg.Uint64 =3D MmioRead64 (mVtdUnitInfor= mation[Index].VtdUnitBaseAddress + R_CAP_REG); DumpVtdCapRegs (&mVtdUnitInformation[Index].CapReg); mVtdUnitInformation[Index].ECapReg.Uint64 =3D MmioRead64 (mVtdUnitInfo= rmation[Index].VtdUnitBaseAddress + R_ECAP_REG); @@ -190,6 +432,12 @@ PrepareVtdConfig ( DEBUG((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >=3D DomainNumber(= 0x%x) !!!!\n", mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber= , DomainNumber)); return ; } + + Status =3D PerpareCacheInvalidationInterface(Index); + if (EFI_ERROR (Status)) { + ASSERT(FALSE); + return; + } } return ; } @@ -252,7 +500,8 @@ EnableDmar ( MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADD= R_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].RootEntryTable); } =20 - MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_RE= G, B_GMCD_REG_SRTP); + Reg32 =3D MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + = R_GSTS_REG); + MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_RE= G, Reg32 | B_GMCD_REG_SRTP); =20 DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n")= ); do { @@ -282,7 +531,8 @@ EnableDmar ( // // Enable VTd // - MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_RE= G, B_GMCD_REG_TE); + Reg32 =3D MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + = R_GSTS_REG); + MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_RE= G, Reg32 | B_GMCD_REG_TE); DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n")); do { Reg32 =3D MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress = + R_GSTS_REG); @@ -360,6 +610,8 @@ DisableDmar ( DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32)); =20 DEBUG ((DEBUG_INFO,"VTD (%d) Disabled!<<<<<<\n",Index)); + + DisableQueuedInvalidationInterface(Index); } =20 mVtdEnabled =3D FALSE; @@ -380,6 +632,21 @@ DisableDmar ( return EFI_SUCCESS; } =20 +/** + Dump VTd version registers. + + @param[in] VerReg The version register. +**/ +VOID +DumpVtdVerRegs ( + IN VTD_VER_REG *VerReg + ) +{ + DEBUG ((DEBUG_INFO, " VerReg:\n", VerReg->Uint32)); + DEBUG ((DEBUG_INFO, " Major - 0x%x\n", VerReg->Bits.Major)); + DEBUG ((DEBUG_INFO, " Minor - 0x%x\n", VerReg->Bits.Minor)); +} + /** Dump VTd capability registers. =20 diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h b= /Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h index b2f745bd..199cb398 100644 --- a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h +++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h @@ -206,10 +206,12 @@ typedef union { #define B_CAP_REG_RWBF BIT4 #define R_ECAP_REG 0x10 #define R_GCMD_REG 0x18 +#define B_GMCD_REG_QIE BIT26 #define B_GMCD_REG_WBF BIT27 #define B_GMCD_REG_SRTP BIT30 #define B_GMCD_REG_TE BIT31 #define R_GSTS_REG 0x1C +#define B_GSTS_REG_QIES BIT26 #define B_GSTS_REG_WBF BIT27 #define B_GSTS_REG_RTPS BIT30 #define B_GSTS_REG_TE BIT31 @@ -221,6 +223,9 @@ typedef union { #define V_CCMD_REG_CIRG_DEVICE (BIT62|BIT61) #define B_CCMD_REG_ICC BIT63 #define R_FSTS_REG 0x34 +#define B_FSTS_REG_IQE BIT4 +#define B_FSTS_REG_ICE BIT5 +#define B_FSTS_REG_ITE BIT6 #define R_FECTL_REG 0x38 #define R_FEDATA_REG 0x3C #define R_FEADDR_REG 0x40 @@ -247,6 +252,58 @@ typedef union { #define R_PMEN_HIGH_BASE_REG 0x70 #define R_PMEN_HIGH_LIMITE_REG 0x78 =20 +#define R_IQH_REG 0x80 +#define R_IQT_REG 0x88 +#define DMAR_IQ_SHIFT 4 /* Invalidation queue head/tail shift */ + +#define R_IQA_REG 0x90 + +#define VTD_PAGE_SHIFT (12) +#define VTD_PAGE_SIZE (1UL << VTD_PAGE_SHIFT) +#define VTD_PAGE_MASK (((UINT64)-1) << VTD_PAGE_SHIFT) + +#define QI_CC_TYPE 0x1 +#define QI_IOTLB_TYPE 0x2 +#define QI_DIOTLB_TYPE 0x3 +#define QI_IEC_TYPE 0x4 +#define QI_IWD_TYPE 0x5 + +#define QI_CC_FM(fm) (((UINT64)fm) << 48) +#define QI_CC_SID(sid) (((UINT64)sid) << 32) +#define QI_CC_DID(did) (((UINT64)did) << 16) +#define QI_CC_GRAN(gran) (((UINT64)gran) << 4) + +#define QI_IOTLB_DID(did) (((UINT64)did) << 16) +#define QI_IOTLB_DR(dr) (((UINT64)dr) << 7) +#define QI_IOTLB_DW(dw) (((UINT64)dw) << 6) +#define QI_IOTLB_GRAN(gran) (((UINT64)gran) << 4) +#define QI_IOTLB_ADDR(addr) (((UINT64)addr) & VTD_PAGE_MASK) +#define QI_IOTLB_IH(ih) (((UINT64)ih) << 6) +#define QI_IOTLB_AM(am) (((UINT8)am)) + +#define cap_read_drain(c) (((c) >> 55) & 1) +#define cap_write_drain(c) (((c) >> 54) & 1) + +#define QI_IWD_STATUS_DATA(d) (((UINT64)d) << 32) +#define QI_IWD_STATUS_WRITE (((UINT64)1) << 5) + +// +// This is the queued invalidate descriptor. +// +typedef struct { + UINT64 low; + UINT64 high; +} QI_DESC; + +typedef union { + struct { + UINT8 Minor:4; + UINT8 Major:4; + UINT32 Rsvd:24; + } Bits; + UINT32 Uint32; +} VTD_VER_REG; + typedef union { struct { UINT8 ND:3; // Number of domains supported --=20 2.16.2.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#74625): https://edk2.groups.io/g/devel/message/74625 Mute This Topic: https://groups.io/mt/82475455/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-