qemu/intel_iommu-Add-missed-sanity-check-for-256-bit-inva.patch
Jiabo Feng 7bb77ea74f QEMU update to version 6.2.0-103:
- Introduce the SM4 cipher algorithms (OSCCA GB/T 32907-2016).
- intel_iommu: Add missed sanity check for 256-bit invalidation queue
- linux-user: use 'max' instead of 'qemu32' / 'qemu64' by default
- chardev/baum: Use definitions to avoid dynamic stack allocation
- ui/console: Get tab completion working again in the SDL monitor vc
- s390x/tcg: Fix opcode for lzrf
- virtiofsd: use g_date_time_get_microsecond to get subsecond
- ui/curses: Avoid dynamic stack allocation
- target/m68k: always call gen_exit_tb() after writes to SR
- target/m68k: Perform writback before modifying SR
- target/m68k: Fix MACSR to CCR
- target/m68k: Implement atomic test-and-set
- block/nvme: nvme_process_completion() fix bound for cid
- hw/pci-host: pnv_phb{3, 4}: Fix heap out-of-bound access failure
- target/ppc: Zero second doubleword of VSR registers for FPR insns
- target/ppc: Set OV32 when OV is set
- target/ppc: Zero second doubleword for VSX madd instructions
- target/ppc: Set result to QNaN for DENBCD when VXCVI occurs
- hw/pci: Add parenthesis to PCI_BUILD_BDF macro
- intel_iommu: Send IQE event when setting reserved bit in IQT_TAIL
- acpi: cpuhp: fix guest-visible maximum access size to the legacy reg block
- acpi: ged: Add macro for acpi sleep control register
- hw/pci-bridge: Add a Kconfig switch for the normal PCI bridge
- ui/vnc: fix handling of VNC_FEATURE_XVP
- s390/sclp: fix SCLP facility map
- docs/tools/qemu-img.rst: fix typo (sumarizes)
- chardev/char: fix qemu_chr_is_busy() check
- edu: fix DMA range upper bound check
- platform-bus: fix refcount leak
- hw/net/virtio-net: fix qemu set used ring flag even vhost started
- hw/net/can/sja1000: fix bug for single acceptance filter and standard frame
- tests/avocado: fix typo in replay_linux
- util/userfaultfd: Remove unused uffd_poll_events
- hw/core/ptimer: fix timer zero period condition for freq > 1GHz
- hcd-ohci: Drop ohci_service_iso_td() if ed->head & OHCI_DPTR_MASK is zero
- tests/unit/test-vmstate: Avoid dynamic stack allocation
- hw/usb/hcd-ohci: Use definition to avoid dynamic stack allocation
- hw/i386/multiboot: Avoid dynamic stack allocation
- hw/ppc/spapr: Fix code style problems reported by checkpatch
- chardev/baum: Replace magic values by X_MAX / Y_MAX definitions
- hw/intc/xics: Avoid dynamic stack allocation
- hw/net/e1000e_core: Use definition to avoid dynamic stack allocation
- intel_iommu: Fix invalidation descriptor type field
- configs: Fix typo in the sh4-softmmu devices config file

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
(cherry picked from commit 9813ed21ec2499c50cb58ac5fb114a1641708eb2)
2024-11-30 11:32:24 +08:00

181 lines
7.7 KiB
Diff

From c14cdf57217aaf043b5ac1087b7ade9b3b5cd730 Mon Sep 17 00:00:00 2001
From: tangzhongrui <tangzhongrui@cmss.chinamobile.com>
Date: Wed, 6 Nov 2024 10:55:43 +0800
Subject: [PATCH] intel_iommu: Add missed sanity check for 256-bit invalidation
queue
According to VTD spec, a 256-bit descriptor will result in an invalid
descriptor error if submitted in an IQ that is setup to provide hardware
with 128-bit descriptors (IQA_REG.DW=0). Meanwhile, there are old inv desc
types (e.g. iotlb_inv_desc) that can be either 128bits or 256bits. If a
128-bit version of this descriptor is submitted into an IQ that is setup
to provide hardware with 256-bit descriptors will also result in an invalid
descriptor error.
The 2nd will be captured by the tail register update. So we only need to
focus on the 1st.
Because the reserved bit check between different types of invalidation desc
are common, so introduce a common function vtd_inv_desc_reserved_check()
to do all the checks and pass the differences as parameters.
With this change, need to replace error_report_once() call with error_report()
to catch different call sites. This isn't an issue as error_report_once()
here is mainly used to help debug guest error, but it only dumps once in
qemu life cycle and doesn't help much, we need error_report() instead.
Fixes: c0c1d351849b ("intel_iommu: add 256 bits qi_desc support")
Suggested-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Message-Id: <20241104125536.1236118-3-zhenzhong.duan@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Zhongrui Tang tangzhongrui_yewu@cmss.chinamobile.com
---
hw/i386/intel_iommu.c | 80 ++++++++++++++++++++++++----------
hw/i386/intel_iommu_internal.h | 1 +
2 files changed, 59 insertions(+), 22 deletions(-)
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 2f8bcc1557..296a32a927 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -2293,15 +2293,51 @@ static bool vtd_get_inv_desc(IntelIOMMUState *s,
return true;
}
+static bool vtd_inv_desc_reserved_check(IntelIOMMUState *s,
+ VTDInvDesc *inv_desc,
+ uint64_t mask[4], bool dw,
+ const char *func_name,
+ const char *desc_type)
+{
+ if (s->iq_dw) {
+ if (inv_desc->val[0] & mask[0] || inv_desc->val[1] & mask[1] ||
+ inv_desc->val[2] & mask[2] || inv_desc->val[3] & mask[3]) {
+ error_report("%s: invalid %s desc val[3]: 0x%"PRIx64
+ " val[2]: 0x%"PRIx64" val[1]=0x%"PRIx64
+ " val[0]=0x%"PRIx64" (reserved nonzero)",
+ func_name, desc_type, inv_desc->val[3],
+ inv_desc->val[2], inv_desc->val[1],
+ inv_desc->val[0]);
+ return false;
+ }
+ } else {
+ if (dw) {
+ error_report("%s: 256-bit %s desc in 128-bit invalidation queue",
+ func_name, desc_type);
+ return false;
+ }
+
+ if (inv_desc->lo & mask[0] || inv_desc->hi & mask[1]) {
+ error_report("%s: invalid %s desc: hi=%"PRIx64", lo=%"PRIx64
+ " (reserved nonzero)", func_name, desc_type,
+ inv_desc->hi, inv_desc->lo);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
{
- if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) ||
- (inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) {
- error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
- " (reserved nonzero)", __func__, inv_desc->hi,
- inv_desc->lo);
+ uint64_t mask[4] = {VTD_INV_DESC_WAIT_RSVD_LO, VTD_INV_DESC_WAIT_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "wait")) {
return false;
}
+
if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) {
/* Status Write */
uint32_t status_data = (uint32_t)(inv_desc->lo >>
@@ -2335,13 +2371,14 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
uint16_t sid, fmask;
+ uint64_t mask[4] = {VTD_INV_DESC_CC_RSVD, VTD_INV_DESC_ALL_ONE,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
- if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
- error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
- " (reserved nonzero)", __func__, inv_desc->hi,
- inv_desc->lo);
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "cc inv")) {
return false;
}
+
switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
case VTD_INV_DESC_CC_DOMAIN:
trace_vtd_inv_desc_cc_domain(
@@ -2371,12 +2408,11 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
uint16_t domain_id;
uint8_t am;
hwaddr addr;
+ uint64_t mask[4] = {VTD_INV_DESC_IOTLB_RSVD_LO, VTD_INV_DESC_IOTLB_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
- if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
- (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
- error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
- ", lo=0x%"PRIx64" (reserved bits unzero)",
- __func__, inv_desc->hi, inv_desc->lo);
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "iotlb inv")) {
return false;
}
@@ -2439,6 +2475,14 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
uint8_t devfn;
bool size;
uint8_t bus_num;
+ uint64_t mask[4] = {VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO,
+ VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "dev-iotlb inv")) {
+ return false;
+ }
addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi);
sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo);
@@ -2446,14 +2490,6 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
bus_num = sid >> 8;
size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi);
- if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) ||
- (inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) {
- error_report_once("%s: invalid dev-iotlb inv desc: hi=%"PRIx64
- ", lo=%"PRIx64" (reserved nonzero)", __func__,
- inv_desc->hi, inv_desc->lo);
- return false;
- }
-
vtd_bus = vtd_find_as_from_bus_num(s, bus_num);
if (!vtd_bus) {
goto done;
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index 2b2f0dd848..827b91e2ba 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -340,6 +340,7 @@ union VTDInvDesc {
typedef union VTDInvDesc VTDInvDesc;
/* Masks for struct VTDInvDesc */
+#define VTD_INV_DESC_ALL_ONE -1ULL
#define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \
((val) & 0xfULL))
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
--
2.41.0.windows.1