From nobody Mon Nov 25 04:36:39 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+75745+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+75745+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1622083610; cv=none; d=zohomail.com; s=zohoarc; b=H5rOJ4x7zpeuh2pbgQ79HrSaaEo2nWAZ0OFdoDd7wqGak+HigEmj2aks7DVQVTQI0uA/5zOTzfipY0gPqH6mgcnqVQo5//HhOnqAGeOVlBpnKk6IV4fFm8EiwZ4iCsAJUxK2j4IHj0G+SkVkKQbEt4Y0hjKaolrn53ylQZhykVA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1622083610; h=Cc:Date:From:List-Subscribe:List-Id:List-Help:List-Unsubscribe:Message-ID:Reply-To:Sender:Subject:To; bh=4I4NmFq9cOST6A+lbIpn7eBQ5gHMjQoQZgsNfwXbCQI=; b=DJkqPUrQkkAjr/OQKzIWJFyHkm87Ki+WuqGNr8pMyK5yhtRsHsiWu7/xFK/eBpth3lvuqXVErffZXBuW6NKlymEUjWtD4Q9BdLs+gImMofIxoGNEAdXYWg0eTOPeQlv0bkZv/diS6fgkegtsNHj2lml4TrEBuMEiGaiygpAd8fE= 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+75745+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 1622083610307123.39531978649359; Wed, 26 May 2021 19:46:50 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id i8osYY1788612xtCtApCH7yW; Wed, 26 May 2021 19:46:49 -0700 X-Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by mx.groups.io with SMTP id smtpd.web08.1917.1622083604290971428 for ; Wed, 26 May 2021 19:46:44 -0700 IronPort-SDR: OuK/Ezvbtqj6pnDZ+rgs/jeJsQddLlwr2ZFp4BfkHZKZL6kNxWylSrdQNnokp9JgX/IHkgkfLj hBnyEtU//Yqw== X-IronPort-AV: E=McAfee;i="6200,9189,9996"; a="190010107" X-IronPort-AV: E=Sophos;i="5.82,333,1613462400"; d="scan'208";a="190010107" X-Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 May 2021 19:46:41 -0700 IronPort-SDR: hgBaODudB4lB02biJWsBPOPK1ys8OpsrXKycq9b/l+Fcq7JY5otHDVBC58G4ddoxDdxK4KrSKt hFas8B8+Kf8A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.82,333,1613462400"; d="scan'208";a="477288388" X-Received: from shwdesssddpdwei.ccr.corp.intel.com ([10.239.157.26]) by orsmga001.jf.intel.com with ESMTP; 26 May 2021 19:46:39 -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: Thu, 27 May 2021 10:46:36 +0800 Message-Id: <20210527024636.3160-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: LqhcB3hncC93FwG89HoKYlVix1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1622083609; bh=h2EIG17g3uMp70Tew1It8JwePmM0Shr9mjzifdp53ks=; h=Cc:Date:From:Reply-To:Subject:To; b=BE8eVjXOuFMol8sFMTP2EhOQqlDngG5dJladAGQ7rreFm6iheEk6nSMiPUmODaMwV9g IdHtwnFwTEhpeGa7L0HXbha2ckPNz35kWL53TDIpzxofBYxfXNMkM4GrvnXRVUAbCSz8d mC0SltxFPBtHFOQUy+Kz3+vdXEhlOhjiXFI= 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 Reviewed-by: Jenny Huang --- .../Feature/VTd/IntelVTdDmarPei/DmarTable.c | 2 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c | 560 +++++++++++++++++= ---- .../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 | 315 +++++++++++- .../IntelSiliconPkg/Include/IndustryStandard/Vtd.h | 57 +++ 8 files changed, 876 insertions(+), 123 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..c3a939c9 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)(UINTN)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); =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; + 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 FaultReg; + + FaultReg =3D MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS= _REG); + + if (FaultReg & B_FSTS_REG_IQE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", Faul= tReg)); + FaultReg |=3D B_FSTS_REG_IQE; + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, Faul= tReg); + return RETURN_DEVICE_ERROR; + } + + if (FaultReg & B_FSTS_REG_ITE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", F= aultReg)); + FaultReg |=3D B_FSTS_REG_ITE; + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, Faul= tReg); + return RETURN_DEVICE_ERROR; + } + + if (FaultReg & B_FSTS_REG_ICE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n",= FaultReg)); + FaultReg |=3D B_FSTS_REG_ICE; + MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_FSTS_REG, Faul= tReg); + return RETURN_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Submit the queued invalidation descriptor to the remapping + hardware unit and wait for its completion. + + @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 Status; + 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; =20 + 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); + + Status =3D EFI_SUCCESS; do { - Reg64 =3D MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG); - } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0); + Status =3D QueuedInvalidationCheckFault(VTdUnitInfo); + if (Status !=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 Status; +} + +/** + 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; +} =20 +/** + 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 { - 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_RTPS) =3D=3D 0); + DEBUG ((DEBUG_INFO, "EnableDmarPreMem: R_GSTS_REG =3D 0x%x \n", Reg32)); + + // + // 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 { + 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")); @@ -252,6 +565,86 @@ 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. + + @param[in] CapReg The capability register. +**/ +VOID +DumpVtdCapRegs ( + IN VTD_CAP_REG *CapReg + ) +{ + DEBUG ((DEBUG_INFO, " CapReg:\n", CapReg->Uint64)); + DEBUG ((DEBUG_INFO, " ND - 0x%x\n", CapReg->Bits.ND)); + DEBUG ((DEBUG_INFO, " AFL - 0x%x\n", CapReg->Bits.AFL)); + DEBUG ((DEBUG_INFO, " RWBF - 0x%x\n", CapReg->Bits.RWBF)); + DEBUG ((DEBUG_INFO, " PLMR - 0x%x\n", CapReg->Bits.PLMR)); + DEBUG ((DEBUG_INFO, " PHMR - 0x%x\n", CapReg->Bits.PHMR)); + DEBUG ((DEBUG_INFO, " CM - 0x%x\n", CapReg->Bits.CM)); + DEBUG ((DEBUG_INFO, " SAGAW - 0x%x\n", CapReg->Bits.SAGAW)); + DEBUG ((DEBUG_INFO, " MGAW - 0x%x\n", CapReg->Bits.MGAW)); + DEBUG ((DEBUG_INFO, " ZLR - 0x%x\n", CapReg->Bits.ZLR)); + DEBUG ((DEBUG_INFO, " FRO - 0x%x\n", CapReg->Bits.FRO)); + DEBUG ((DEBUG_INFO, " SLLPS - 0x%x\n", CapReg->Bits.SLLPS)); + DEBUG ((DEBUG_INFO, " PSI - 0x%x\n", CapReg->Bits.PSI)); + DEBUG ((DEBUG_INFO, " NFR - 0x%x\n", CapReg->Bits.NFR)); + DEBUG ((DEBUG_INFO, " MAMV - 0x%x\n", CapReg->Bits.MAMV)); + DEBUG ((DEBUG_INFO, " DWD - 0x%x\n", CapReg->Bits.DWD)); + DEBUG ((DEBUG_INFO, " DRD - 0x%x\n", CapReg->Bits.DRD)); + DEBUG ((DEBUG_INFO, " FL1GP - 0x%x\n", CapReg->Bits.FL1GP)); + DEBUG ((DEBUG_INFO, " PI - 0x%x\n", CapReg->Bits.PI)); +} + +/** + Dump VTd extended capability registers. + + @param[in] ECapReg The extended capability register. +**/ +VOID +DumpVtdECapRegs ( + IN VTD_ECAP_REG *ECapReg + ) +{ + DEBUG ((DEBUG_INFO, " ECapReg:\n", ECapReg->Uint64)); + DEBUG ((DEBUG_INFO, " C - 0x%x\n", ECapReg->Bits.C)); + DEBUG ((DEBUG_INFO, " QI - 0x%x\n", ECapReg->Bits.QI)); + DEBUG ((DEBUG_INFO, " DT - 0x%x\n", ECapReg->Bits.DT)); + DEBUG ((DEBUG_INFO, " IR - 0x%x\n", ECapReg->Bits.IR)); + DEBUG ((DEBUG_INFO, " EIM - 0x%x\n", ECapReg->Bits.EIM)); + DEBUG ((DEBUG_INFO, " PT - 0x%x\n", ECapReg->Bits.PT)); + DEBUG ((DEBUG_INFO, " SC - 0x%x\n", ECapReg->Bits.SC)); + DEBUG ((DEBUG_INFO, " IRO - 0x%x\n", ECapReg->Bits.IRO)); + DEBUG ((DEBUG_INFO, " MHMV - 0x%x\n", ECapReg->Bits.MHMV)); + DEBUG ((DEBUG_INFO, " ECS - 0x%x\n", ECapReg->Bits.ECS)); + DEBUG ((DEBUG_INFO, " MTS - 0x%x\n", ECapReg->Bits.MTS)); + DEBUG ((DEBUG_INFO, " NEST - 0x%x\n", ECapReg->Bits.NEST)); + DEBUG ((DEBUG_INFO, " DIS - 0x%x\n", ECapReg->Bits.DIS)); + DEBUG ((DEBUG_INFO, " PASID - 0x%x\n", ECapReg->Bits.PASID)); + DEBUG ((DEBUG_INFO, " PRS - 0x%x\n", ECapReg->Bits.PRS)); + DEBUG ((DEBUG_INFO, " ERS - 0x%x\n", ECapReg->Bits.ERS)); + DEBUG ((DEBUG_INFO, " SRS - 0x%x\n", ECapReg->Bits.SRS)); + DEBUG ((DEBUG_INFO, " NWFS - 0x%x\n", ECapReg->Bits.NWFS)); + DEBUG ((DEBUG_INFO, " EAFS - 0x%x\n", ECapReg->Bits.EAFS)); + DEBUG ((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS)); +} + + /** Enable VTd translation table protection for all. =20 @@ -286,7 +679,15 @@ EnableVTdTranslationProtectionAll ( if ((EngineMask & LShiftU64(1, Index)) =3D=3D 0) { continue; } - EnableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress, (U= INTN) *RootEntryTable); + + VTdInfo->VtdUnitInfo[Index].VerReg.Uint32 =3D MmioRead32 (VTdInfo->Vtd= UnitInfo[Index].VtdUnitBaseAddress + R_VER_REG); + 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); + DumpVtdECapRegs (&VTdInfo->VtdUnitInfo[Index].ECapReg); + + EnableDmarPreMem (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress, (UIN= TN) *RootEntryTable); } =20 return; @@ -311,10 +712,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,73 +746,36 @@ DisableVTdTranslationProtection ( continue; } DisableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress); + + DisableQueuedInvalidationInterface(&VTdInfo->VtdUnitInfo[Index]); } =20 return; } =20 /** - Dump VTd capability registers. + Prepare VTD cache invalidation configuration. =20 - @param[in] CapReg The capability register. + @param[in] VTdInfo The VTd engine context information. + + @retval EFI_SUCCESS Prepare Vtd config success **/ -VOID -DumpVtdCapRegs ( - IN VTD_CAP_REG *CapReg +EFI_STATUS +PrepareVtdCacheInvalidationConfig ( + IN VTD_INFO *VTdInfo ) { - DEBUG ((DEBUG_INFO, " CapReg:\n", CapReg->Uint64)); - DEBUG ((DEBUG_INFO, " ND - 0x%x\n", CapReg->Bits.ND)); - DEBUG ((DEBUG_INFO, " AFL - 0x%x\n", CapReg->Bits.AFL)); - DEBUG ((DEBUG_INFO, " RWBF - 0x%x\n", CapReg->Bits.RWBF)); - DEBUG ((DEBUG_INFO, " PLMR - 0x%x\n", CapReg->Bits.PLMR)); - DEBUG ((DEBUG_INFO, " PHMR - 0x%x\n", CapReg->Bits.PHMR)); - DEBUG ((DEBUG_INFO, " CM - 0x%x\n", CapReg->Bits.CM)); - DEBUG ((DEBUG_INFO, " SAGAW - 0x%x\n", CapReg->Bits.SAGAW)); - DEBUG ((DEBUG_INFO, " MGAW - 0x%x\n", CapReg->Bits.MGAW)); - DEBUG ((DEBUG_INFO, " ZLR - 0x%x\n", CapReg->Bits.ZLR)); - DEBUG ((DEBUG_INFO, " FRO - 0x%x\n", CapReg->Bits.FRO)); - DEBUG ((DEBUG_INFO, " SLLPS - 0x%x\n", CapReg->Bits.SLLPS)); - DEBUG ((DEBUG_INFO, " PSI - 0x%x\n", CapReg->Bits.PSI)); - DEBUG ((DEBUG_INFO, " NFR - 0x%x\n", CapReg->Bits.NFR)); - DEBUG ((DEBUG_INFO, " MAMV - 0x%x\n", CapReg->Bits.MAMV)); - DEBUG ((DEBUG_INFO, " DWD - 0x%x\n", CapReg->Bits.DWD)); - DEBUG ((DEBUG_INFO, " DRD - 0x%x\n", CapReg->Bits.DRD)); - DEBUG ((DEBUG_INFO, " FL1GP - 0x%x\n", CapReg->Bits.FL1GP)); - DEBUG ((DEBUG_INFO, " PI - 0x%x\n", CapReg->Bits.PI)); -} + UINTN Index; + EFI_STATUS Status; =20 -/** - Dump VTd extended capability registers. + for (Index =3D 0; Index < VTdInfo->VTdEngineCount; Index++) { + Status =3D PerpareCacheInvalidationInterface(&VTdInfo->VtdUnitInfo[Ind= ex]); + if (EFI_ERROR (Status)) { + return Status; + } + } =20 - @param[in] ECapReg The extended capability register. -**/ -VOID -DumpVtdECapRegs ( - IN VTD_ECAP_REG *ECapReg - ) -{ - DEBUG ((DEBUG_INFO, " ECapReg:\n", ECapReg->Uint64)); - DEBUG ((DEBUG_INFO, " C - 0x%x\n", ECapReg->Bits.C)); - DEBUG ((DEBUG_INFO, " QI - 0x%x\n", ECapReg->Bits.QI)); - DEBUG ((DEBUG_INFO, " DT - 0x%x\n", ECapReg->Bits.DT)); - DEBUG ((DEBUG_INFO, " IR - 0x%x\n", ECapReg->Bits.IR)); - DEBUG ((DEBUG_INFO, " EIM - 0x%x\n", ECapReg->Bits.EIM)); - DEBUG ((DEBUG_INFO, " PT - 0x%x\n", ECapReg->Bits.PT)); - DEBUG ((DEBUG_INFO, " SC - 0x%x\n", ECapReg->Bits.SC)); - DEBUG ((DEBUG_INFO, " IRO - 0x%x\n", ECapReg->Bits.IRO)); - DEBUG ((DEBUG_INFO, " MHMV - 0x%x\n", ECapReg->Bits.MHMV)); - DEBUG ((DEBUG_INFO, " ECS - 0x%x\n", ECapReg->Bits.ECS)); - DEBUG ((DEBUG_INFO, " MTS - 0x%x\n", ECapReg->Bits.MTS)); - DEBUG ((DEBUG_INFO, " NEST - 0x%x\n", ECapReg->Bits.NEST)); - DEBUG ((DEBUG_INFO, " DIS - 0x%x\n", ECapReg->Bits.DIS)); - DEBUG ((DEBUG_INFO, " PASID - 0x%x\n", ECapReg->Bits.PASID)); - DEBUG ((DEBUG_INFO, " PRS - 0x%x\n", ECapReg->Bits.PRS)); - DEBUG ((DEBUG_INFO, " ERS - 0x%x\n", ECapReg->Bits.ERS)); - DEBUG ((DEBUG_INFO, " SRS - 0x%x\n", ECapReg->Bits.SRS)); - DEBUG ((DEBUG_INFO, " NWFS - 0x%x\n", ECapReg->Bits.NWFS)); - DEBUG ((DEBUG_INFO, " EAFS - 0x%x\n", ECapReg->Bits.EAFS)); - DEBUG ((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS)); + return EFI_SUCCESS; } =20 /** @@ -431,6 +795,8 @@ 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); + 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); 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..1ce9c1c0 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c @@ -55,59 +55,298 @@ 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); } =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); + // + // Initialize the Invalidation Queue Tail Register to zero. + // + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_IQT_RE= G, 0); =20 + // + // 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)(UINTN)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 { - Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + R_CCMD_REG); - } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0); + Reg32 =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + R_GSTS_REG); + } while ((Reg32 & B_GSTS_REG_QIES) =3D=3D 0); + + mVtdUnitInformation[VtdIndex].QiFreeHead =3D 0; =20 return EFI_SUCCESS; } =20 /** - Invalidate VTd IOTLB. + 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. =20 @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 -InvalidateIOTLB ( +QueuedInvalidationCheckFault ( IN UINTN VtdIndex ) { - UINT64 Reg64; + UINT32 FaultReg; =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; + FaultReg =3D MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddres= s + R_FSTS_REG); + + if (FaultReg & B_FSTS_REG_IQE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Queue Error [0x%08x]\n", Faul= tReg)); + FaultReg |=3D B_FSTS_REG_IQE; + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS= _REG, FaultReg); + return RETURN_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); + if (FaultReg & B_FSTS_REG_ITE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Time-out Error [0x%08x]\n", F= aultReg)); + FaultReg |=3D B_FSTS_REG_ITE; + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS= _REG, FaultReg); + return RETURN_DEVICE_ERROR; + } + + if (FaultReg & B_FSTS_REG_ICE) { + DEBUG((DEBUG_ERROR, "Detect Invalidation Completion Error [0x%08x]\n",= FaultReg)); + FaultReg |=3D B_FSTS_REG_ICE; + MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS= _REG, FaultReg); + 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 Status; + UINT16 QiDescLength; + QI_DESC *BaseDesc; + UINT64 Reg64Iqt; + UINT64 Reg64Iqh; + + if (Desc =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + 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)); =20 + 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); + + Status =3D EFI_SUCCESS; do { + Status =3D QueuedInvalidationCheckFault(VtdIndex); + if (Status !=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 Status; +} + +/** + 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); + 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); + + 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; +} + +/** + Invalidate VTd IOTLB. + + @param[in] VtdIndex The index used to identify a VTd engine. +**/ +EFI_STATUS +InvalidateIOTLB ( + IN UINTN VtdIndex + ) +{ + UINT64 Reg64; + QI_DESC QiDesc; + + 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); - } while ((Reg64 & B_IOTLB_REG_IVT) !=3D 0); + 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; + } + + 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); + + 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..a759ca10 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 (#75745): https://edk2.groups.io/g/devel/message/75745 Mute This Topic: https://groups.io/mt/83117152/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-