From nobody Sat May 30 19:21:09 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=suse.de ARC-Seal: i=1; a=rsa-sha256; t=1777473200; cv=none; d=zohomail.com; s=zohoarc; b=b3DwgOWy/JHIxLyGLgMxo0XlzJU/OoeSqgAJcTIC3P/RpvfheQNkBS4ebBmzfTWGiDDiRCdp/lYe34G6m1cEbvM1fm5d5Zelb1YGiokbYEH86/BhwJaXjEP4k/yVtUit1MfjLiWNSWWOOgDFkxWHCBeH2ywu/8Nk4B6l3yfjcLk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777473200; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=n+99JTyQugWLzYbzwsmhPQy7c+ZhxKK2m7BsT5+aVAg=; b=JMEm9Ta6pllkfhHsn6RbR3PoCMaSUbGdGgTv2nQyAVvBDH7hL2T1fsXpX1BX3F8W657lKJ1cqoBSAW+gb1IYcDfcEZPcxYmnSzbXwCt/kB/fLrWQdPcfcsLvOJl7RXmifQvx4oXmud/DoyTEVpbkyQjDZNdqMaFcHonOuGDxtk4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777473200764705.3128327205276; Wed, 29 Apr 2026 07:33:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wI5yH-000741-OA; Wed, 29 Apr 2026 10:33:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wI5y9-00073d-MG for qemu-devel@nongnu.org; Wed, 29 Apr 2026 10:32:54 -0400 Received: from smtp-out1.suse.de ([2a07:de40:b251:101:10:150:64:1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wI5y6-0007pj-CD for qemu-devel@nongnu.org; Wed, 29 Apr 2026 10:32:53 -0400 Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 6093C6A827; Wed, 29 Apr 2026 14:32:40 +0000 (UTC) Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id F156D593B3; Wed, 29 Apr 2026 14:32:38 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id wIFXL4YW8mksagAAD6G6ig (envelope-from ); Wed, 29 Apr 2026 14:32:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1777473164; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n+99JTyQugWLzYbzwsmhPQy7c+ZhxKK2m7BsT5+aVAg=; b=zq4KpK9Luj7iKuJotECNm0sggKacvogFoh/ggu2RsklaYndkuBcP4pDgfhAlVQDedUo5H1 z3z1iSeS736H0vSoIx5G7kBpAu2/6+XXi6eeAODCKDaL/sp6hJ1DfgsZAXcZ9ShECf4hu2 2Bi/kA2p16xVlfoCD1mrBhWliVzUD+w= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1777473164; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n+99JTyQugWLzYbzwsmhPQy7c+ZhxKK2m7BsT5+aVAg=; b=BCJXK5cQ+nVSqKZUWyNGMNdre6dabJcRTk6NlLxp5FYCkpJggWyFe1bqrD4qn/yOM87ntK SuW9UVLx5t26vjDQ== Authentication-Results: smtp-out1.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1777473160; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n+99JTyQugWLzYbzwsmhPQy7c+ZhxKK2m7BsT5+aVAg=; b=vUQBXWP6IobsGpdRgHpp0zJ3BL6HFwV11rCGRyh0QHvCvki1gH7eZ+p2UQCKKfSm3y1S21 SsavIGFG8ZWR89Kb+CBi3KHevZQouGZT2Iafu/1e+whML4S7dCwc/40CrnbJz8GDqi1KtQ dmxVrrPLVfg8Ig+HZLYlTs2/FrPOqzY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1777473160; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n+99JTyQugWLzYbzwsmhPQy7c+ZhxKK2m7BsT5+aVAg=; b=70ismuhQNqdGkAYIBbdnsyGuiSQf0XAKpiBx1S6hyM1lVG9EOUcQpGN9ocdl5ahc0ov4Tr pNxyuQT55tqZGqCA== From: Fabiano Rosas To: qemu-devel@nongnu.org Cc: Fengyuan Yu <15fengyuan@gmail.com>, Chao Liu , Tao Tang Subject: [PULL 1/3] tests/qtest/libqos: Add Intel IOMMU helper library Date: Wed, 29 Apr 2026 11:32:29 -0300 Message-ID: <20260429143235.25115-2-farosas@suse.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260429143235.25115-1-farosas@suse.de> References: <20260429143235.25115-1-farosas@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Spam-Score: -1.80 X-Spamd-Result: default: False [-1.80 / 50.00]; BAYES_HAM(-3.00)[100.00%]; SUSPICIOUS_RECIPS(1.50)[]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; ARC_NA(0.00)[]; TAGGED_RCPT(0.00)[]; MIME_TRACE(0.00)[0:+]; TO_DN_SOME(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; RCVD_TLS_ALL(0.00)[]; FREEMAIL_ENVRCPT(0.00)[gmail.com]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; FROM_HAS_DN(0.00)[]; FREEMAIL_CC(0.00)[gmail.com,phytium.com.cn]; RCPT_COUNT_THREE(0.00)[4]; FROM_EQ_ENVFROM(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; TO_MATCH_ENVRCPT_ALL(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[suse.de:mid, suse.de:email, imap1.dmz-prg2.suse.org:helo] Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a07:de40:b251:101:10:150:64:1; envelope-from=farosas@suse.de; helo=smtp-out1.suse.de X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @suse.de) (identity @suse.de) X-ZM-MESSAGEID: 1777473203385158500 From: Fengyuan Yu <15fengyuan@gmail.com> Introduce a libqos helper module for Intel IOMMU (VT-d) bare-metal testing via iommu-testdev. The helper provides routines to: - Build Legacy-mode structures: Root Entry Tables, Context Entry Tables, and 4-level page tables for 48-bit address translation - Build Scalable-mode structures: Scalable Context Entries, PASID Directory Entries, PASID Table Entries, and 4-level page tables for both second-level and first-level translation - Program VT-d registers (Root Table Address, Invalidation Queue, Fault Event MSI, Global Command) following the VT-d specification, with GSTS read-back verification for each step - Execute DMA translations through iommu-testdev and verify results by reading back guest memory The module supports all major VT-d translation modes through the QVTDTransMode enum: - Legacy pass-through - Legacy translated with 4-level paging - Scalable pass-through - Scalable Second-Level Translation - Scalable First-Level Translation Reviewed-by: Chao Liu Signed-off-by: Fengyuan Yu <15fengyuan@gmail.com> Reviewed-by: Fabiano Rosas Reviewed-by: Tao Tang Link: https://lore.kernel.org/qemu-devel/c4f7bf5d7985891a2db291193669ebe15d= d2ba15.1774421649.git.15fengyuan@gmail.com Signed-off-by: Fabiano Rosas --- MAINTAINERS | 1 + tests/qtest/libqos/meson.build | 3 + tests/qtest/libqos/qos-intel-iommu.c | 454 +++++++++++++++++++++++++++ tests/qtest/libqos/qos-intel-iommu.h | 185 +++++++++++ 4 files changed, 643 insertions(+) create mode 100644 tests/qtest/libqos/qos-intel-iommu.c create mode 100644 tests/qtest/libqos/qos-intel-iommu.h diff --git a/MAINTAINERS b/MAINTAINERS index 49f9bce818..3887dda851 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3597,6 +3597,7 @@ S: Maintained F: tests/qtest/libqos/qos-iommu* F: tests/qtest/libqos/qos-smmuv3* F: tests/qtest/libqos/qos-riscv-iommu* +F: tests/qtest/libqos/qos-intel-iommu* =20 Device Fuzzing M: Alexander Bulekov diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build index 4a69acad0d..96f2fc48b4 100644 --- a/tests/qtest/libqos/meson.build +++ b/tests/qtest/libqos/meson.build @@ -73,6 +73,9 @@ endif if config_all_devices.has_key('CONFIG_RISCV_IOMMU') libqos_srcs +=3D files('riscv-iommu.c', 'qos-riscv-iommu.c') endif +if config_all_devices.has_key('CONFIG_VTD') + libqos_srcs +=3D files('qos-intel-iommu.c') +endif if config_all_devices.has_key('CONFIG_TPCI200') libqos_srcs +=3D files('tpci200.c') endif diff --git a/tests/qtest/libqos/qos-intel-iommu.c b/tests/qtest/libqos/qos-= intel-iommu.c new file mode 100644 index 0000000000..f8ca4c871b --- /dev/null +++ b/tests/qtest/libqos/qos-intel-iommu.c @@ -0,0 +1,454 @@ +/* + * QOS Intel IOMMU (VT-d) Module Implementation + * + * This module provides Intel IOMMU-specific helper functions for libqos t= ests. + * + * Copyright (c) 2026 Fengyuan Yu <15fengyuan@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/i386/intel_iommu_internal.h" +#include "tests/qtest/libqos/pci.h" +#include "qos-iommu-testdev.h" +#include "qos-intel-iommu.h" + +#define QVTD_AW_48BIT_ENCODING 2 + +uint32_t qvtd_expected_dma_result(QVTDTestContext *ctx) +{ + return ctx->config.expected_result; +} + +uint32_t qvtd_build_dma_attrs(void) +{ + /* + * VT-d obtains the Requester ID (Source ID) from PCI bus/devfn routing + * via pci_device_iommu_address_space(), not from DMA attributes. + * + * For scalable mode, iommu-testdev does not set MemTxAttrs.pid, + * so the device's VTDAddressSpace has pasid=3DPCI_NO_PASID. + * vtd_do_iommu_translate() remaps PCI_NO_PASID to PASID_0 + * when root_scalable is set, which matches the PASID=3D0 entry + * we configure in qvtd_build_pasid_table_entry(). + */ + return 0; +} + +static void qvtd_build_root_entry(QTestState *qts, uint8_t bus, + uint64_t context_table_ptr, + QVTDTransMode mode) +{ + uint64_t root_entry_addr =3D QVTD_ROOT_TABLE_BASE + + (bus * sizeof(VTDRootEntry)); + uint64_t lo, hi; + + if (qvtd_is_scalable(mode)) { + /* + * Scalable-mode Root Entry (Section 9.2): + * lo =3D Lower Context Table Pointer + LP (Lower Present) + * hi =3D Upper Context Table Pointer + UP (Upper Present) + * + * Lower table covers devfn 0-127, Upper covers devfn 128-255. + * Only lower half is needed for test device (devfn < 128). + */ + lo =3D (context_table_ptr & VTD_ROOT_ENTRY_CTP) | VTD_ROOT_ENTRY_P; + hi =3D 0; /* UP=3D0: upper context table not present */ + } else { + /* + * Legacy Root Entry (Section 9.1): + * lo =3D Context Table Pointer + Present + * hi =3D Reserved + */ + lo =3D (context_table_ptr & VTD_ROOT_ENTRY_CTP) | VTD_ROOT_ENTRY_P; + hi =3D 0; + } + + qtest_writeq(qts, root_entry_addr, lo); + qtest_writeq(qts, root_entry_addr + 8, hi); +} + +static void qvtd_build_context_entry(QTestState *qts, uint16_t sid, + QVTDTransMode mode, uint64_t ssptptr) +{ + uint8_t devfn =3D sid & 0xff; + uint64_t context_entry_addr =3D QVTD_CONTEXT_TABLE_BASE + + (devfn * VTD_CTX_ENTRY_LEGACY_SIZE); + uint64_t lo, hi; + + if (mode =3D=3D QVTD_TM_LEGACY_PT) { + /* + * Pass-through mode (Section 9.3): + * lo: P + FPD(=3D0, fault enabled) + TT(=3DPass-through) + * hi: DID + AW + */ + lo =3D VTD_CONTEXT_ENTRY_P | VTD_CONTEXT_TT_PASS_THROUGH; + hi =3D ((uint64_t)QVTD_DOMAIN_ID << 8) | QVTD_AW_48BIT_ENCODING; + } else { + /* + * Translated mode (Section 9.3): + * lo: P + FPD(=3D0, fault enabled) + TT(=3DMulti-level) + SSPTPTR + * hi: DID + AW(=3D48-bit, 4-level) + */ + lo =3D VTD_CONTEXT_ENTRY_P | VTD_CONTEXT_TT_MULTI_LEVEL | + (ssptptr & VTD_CONTEXT_ENTRY_SSPTPTR); + hi =3D ((uint64_t)QVTD_DOMAIN_ID << 8) | QVTD_AW_48BIT_ENCODING; + } + + qtest_writeq(qts, context_entry_addr, lo); + qtest_writeq(qts, context_entry_addr + 8, hi); +} + +static void qvtd_build_scalable_context_entry(QTestState *qts, uint16_t si= d) +{ + uint8_t devfn =3D sid & 0xff; + uint64_t ce_addr =3D QVTD_CONTEXT_TABLE_BASE + + (devfn * VTD_CTX_ENTRY_SCALABLE_SIZE); + + /* + * Scalable-Mode Context Entry (Section 9.4), 32 bytes =3D 4 qwords: + * + * val[0]: P + FPD(=3D0) + DTE(=3D0) + PASIDE(=3D0) + PRE(=3D0) + HPTE= (=3D0) + * + EPTR(=3D0) + PDTS(=3D0) + PASIDDIRPTR + * val[1]: RID_PASID(=3D0) + PDTTE(=3D0) + PRE(=3D0) + RID_CG(=3D0) + * val[2]: Reserved (must be 0) + * val[3]: Reserved (must be 0) + */ + qtest_writeq(qts, ce_addr, + (QVTD_PASID_DIR_BASE & VTD_PASID_DIR_BASE_ADDR_MASK) | + VTD_CONTEXT_ENTRY_P); + qtest_writeq(qts, ce_addr + 8, 0); + qtest_writeq(qts, ce_addr + 16, 0); + qtest_writeq(qts, ce_addr + 24, 0); +} + +static void qvtd_build_pasid_dir_entry(QTestState *qts) +{ + uint64_t addr =3D QVTD_PASID_DIR_BASE + + VTD_PASID_DIR_INDEX(0) * VTD_PASID_DIR_ENTRY_SIZE; + + /* + * PASID Directory Entry (Section 9.5): + * P + FPD(=3D0, fault enabled) + SMPTBLPTR + */ + qtest_writeq(qts, addr, + (QVTD_PASID_TABLE_BASE & VTD_PASID_TABLE_BASE_ADDR_MASK) | + VTD_PASID_ENTRY_P); +} + +static void qvtd_build_pasid_table_entry(QTestState *qts, QVTDTransMode mo= de, + uint64_t ptptr) +{ + uint64_t addr =3D QVTD_PASID_TABLE_BASE + + VTD_PASID_TABLE_INDEX(0) * VTD_PASID_ENTRY_SIZE; + uint64_t val0, val1, val2; + + /* + * Scalable-Mode PASID Table Entry (Section 9.6), 64 bytes =3D 8 qword= s: + * + * val[0]: P + FPD(=3D0) + AW + PGTT + SSADE(=3D0) + SSPTPTR + * val[1]: DID + PWSNP(=3D0) + PGSNP(=3D0) + * + CD(=3D0) + EMTE(=3D0) + PAT(=3D0): Memory Type, + * all Reserved(0) since QEMU ECAP.MTS=3D0 + * val[2]: SRE(=3D0) + FSPM(=3D0, 4-level) + WPE(=3D0) + IGN + EAFE(= =3D0) + FSPTPTR + * val[3]: Reserved (must be 0) + * val[4]: HPT fields, Reserved(0) since QEMU ECAP.HPTS=3D0 + * val[5]: HPT fields, Reserved(0) since QEMU ECAP.HPTS=3D0 + * val[6]: Reserved (must be 0) + * val[7]: Reserved (must be 0) + */ + switch (mode) { + case QVTD_TM_SCALABLE_PT: + val0 =3D VTD_PASID_ENTRY_P | + ((uint64_t)VTD_SM_PASID_ENTRY_PT << 6); + val1 =3D (uint64_t)QVTD_DOMAIN_ID; + val2 =3D 0; + break; + case QVTD_TM_SCALABLE_SLT: + val0 =3D VTD_PASID_ENTRY_P | + ((uint64_t)VTD_SM_PASID_ENTRY_SST << 6) | + ((uint64_t)QVTD_AW_48BIT_ENCODING << 2) | + (ptptr & VTD_SM_PASID_ENTRY_SSPTPTR); + val1 =3D (uint64_t)QVTD_DOMAIN_ID; + val2 =3D 0; + break; + case QVTD_TM_SCALABLE_FLT: + /* + * val[2] fields for FLT (Section 9.6): + * SRE(=3D0, user-level DMA only) + FSPM(=3D0, 4-level) + + * WPE(=3D0, no supervisor write-protect) + IGN + EAFE(=3D0) + FSP= TPTR + */ + val0 =3D VTD_PASID_ENTRY_P | + ((uint64_t)VTD_SM_PASID_ENTRY_FST << 6); + val1 =3D (uint64_t)QVTD_DOMAIN_ID; + val2 =3D ptptr & QVTD_SM_PASID_ENTRY_FSPTPTR; + break; + default: + g_assert_not_reached(); + } + + qtest_writeq(qts, addr, val0); + qtest_writeq(qts, addr + 8, val1); + qtest_writeq(qts, addr + 16, val2); + qtest_writeq(qts, addr + 24, 0); + qtest_writeq(qts, addr + 32, 0); + qtest_writeq(qts, addr + 40, 0); + qtest_writeq(qts, addr + 48, 0); + qtest_writeq(qts, addr + 56, 0); +} + +/* + * VT-d second-level paging helpers. + * 4-level, 48-bit address space, 9 bits per level index. + */ +static uint32_t qvtd_get_table_index(uint64_t iova, int level) +{ + int shift =3D VTD_PAGE_SHIFT + VTD_LEVEL_BITS * (level - 1); + + return (iova >> shift) & ((1u << VTD_LEVEL_BITS) - 1); +} + +static uint64_t qvtd_get_table_addr(uint64_t base, int level, uint64_t iov= a) +{ + return base + (qvtd_get_table_index(iova, level) * QVTD_PTE_SIZE); +} + +static uint64_t qvtd_get_pte_attrs(void) +{ + /* Second-level: R/W in every paging entry (Section 3.7.1) */ + return VTD_SS_R | VTD_SS_W; +} + +static uint64_t qvtd_get_fl_pte_attrs(bool is_leaf) +{ + /* First-level: x86 page table format (VT-d spec Section 9.9) */ + uint64_t attrs =3D VTD_FS_P | VTD_FS_RW | VTD_FS_US | VTD_FS_A; + + if (is_leaf) { + attrs |=3D VTD_FS_D; + } + return attrs; +} + +void qvtd_setup_translation_tables(QTestState *qts, uint64_t iova, + QVTDTransMode mode) +{ + bool is_fl =3D (mode =3D=3D QVTD_TM_SCALABLE_FLT); + uint64_t non_leaf_attrs, leaf_attrs; + + if (is_fl) { + non_leaf_attrs =3D qvtd_get_fl_pte_attrs(false); + leaf_attrs =3D qvtd_get_fl_pte_attrs(true); + } else { + /* Second-level: all levels use identical R/W attrs (spec 3.7.1) */ + non_leaf_attrs =3D qvtd_get_pte_attrs(); + leaf_attrs =3D non_leaf_attrs; + } + + g_test_message("Page table setup: IOVA=3D0x%" PRIx64 + " PA=3D0x%" PRIx64 " %s", + (uint64_t)iova, (uint64_t)QVTD_PT_VAL, + is_fl ? "first-level" : "second-level"); + + /* PML4 (L4) -> PDPT (L3) -> PD (L2) -> PT (L1) -> PA */ + qtest_writeq(qts, qvtd_get_table_addr(QVTD_PT_L4_BASE, 4, iova), + QVTD_PT_L3_BASE | non_leaf_attrs); + qtest_writeq(qts, qvtd_get_table_addr(QVTD_PT_L3_BASE, 3, iova), + QVTD_PT_L2_BASE | non_leaf_attrs); + qtest_writeq(qts, qvtd_get_table_addr(QVTD_PT_L2_BASE, 2, iova), + QVTD_PT_L1_BASE | non_leaf_attrs); + qtest_writeq(qts, qvtd_get_table_addr(QVTD_PT_L1_BASE, 1, iova), + (QVTD_PT_VAL & VTD_PAGE_MASK_4K) | leaf_attrs); +} + +void qvtd_program_regs(QTestState *qts, uint64_t iommu_base, + QVTDTransMode mode) +{ + uint32_t gcmd =3D 0; + uint64_t rtaddr =3D QVTD_ROOT_TABLE_BASE; + + /* Set SMT bit for scalable mode (VT-d spec Section 9.1) */ + if (qvtd_is_scalable(mode)) { + rtaddr |=3D VTD_RTADDR_SMT; + } + + /* Set Root Table Address */ + qtest_writeq(qts, iommu_base + DMAR_RTADDR_REG, rtaddr); + + /* Set Root Table Pointer and verify */ + gcmd |=3D VTD_GCMD_SRTP; + qtest_writel(qts, iommu_base + DMAR_GCMD_REG, gcmd); + g_assert(qtest_readl(qts, iommu_base + DMAR_GSTS_REG) & VTD_GSTS_RTPS); + + /* Setup Invalidation Queue */ + qtest_writeq(qts, iommu_base + DMAR_IQA_REG, + QVTD_IQ_BASE | QVTD_IQ_QS); + qtest_writeq(qts, iommu_base + DMAR_IQH_REG, 0); + qtest_writeq(qts, iommu_base + DMAR_IQT_REG, 0); + + /* Enable Queued Invalidation and verify */ + gcmd |=3D VTD_GCMD_QIE; + qtest_writel(qts, iommu_base + DMAR_GCMD_REG, gcmd); + g_assert(qtest_readl(qts, iommu_base + DMAR_GSTS_REG) & VTD_GSTS_QIES); + + /* Setup Fault Event MSI */ + qtest_writel(qts, iommu_base + DMAR_FECTL_REG, 0x0); + qtest_writel(qts, iommu_base + DMAR_FEDATA_REG, QVTD_FAULT_IRQ_DATA); + qtest_writel(qts, iommu_base + DMAR_FEADDR_REG, QVTD_FAULT_IRQ_ADDR); + + /* Enable translation and verify */ + gcmd |=3D VTD_GCMD_TE; + qtest_writel(qts, iommu_base + DMAR_GCMD_REG, gcmd); + g_assert(qtest_readl(qts, iommu_base + DMAR_GSTS_REG) & VTD_GSTS_TES); +} + +uint32_t qvtd_build_translation(QTestState *qts, QVTDTransMode mode, + uint16_t sid) +{ + uint8_t bus =3D (sid >> 8) & 0xff; + + g_test_message("Build translation: IOVA=3D0x%" PRIx64 " PA=3D0x%" PRIx= 64 + " mode=3D%d", + (uint64_t)QVTD_IOVA, (uint64_t)QVTD_PT_VAL, mode); + + /* Clear IOMMU structure regions to avoid stale entries */ + qtest_memset(qts, QVTD_ROOT_TABLE_BASE, 0, 0x1000); + qtest_memset(qts, QVTD_PT_L4_BASE, 0, 0x4000); + + if (qvtd_is_scalable(mode)) { + /* Scalable: 32B context entries need 8KB */ + qtest_memset(qts, QVTD_CONTEXT_TABLE_BASE, 0, 0x2000); + qtest_memset(qts, QVTD_PASID_DIR_BASE, 0, 0x1000); + qtest_memset(qts, QVTD_PASID_TABLE_BASE, 0, 0x1000); + } else { + qtest_memset(qts, QVTD_CONTEXT_TABLE_BASE, 0, 0x1000); + } + + qvtd_build_root_entry(qts, bus, QVTD_CONTEXT_TABLE_BASE, mode); + + if (qvtd_is_scalable(mode)) { + /* Scalable path: context -> PASID dir -> PASID entry -> page tabl= es */ + qvtd_build_scalable_context_entry(qts, sid); + qvtd_build_pasid_dir_entry(qts); + + if (mode =3D=3D QVTD_TM_SCALABLE_PT) { + qvtd_build_pasid_table_entry(qts, mode, 0); + } else { + qvtd_setup_translation_tables(qts, QVTD_IOVA, mode); + qvtd_build_pasid_table_entry(qts, mode, QVTD_PT_L4_BASE); + } + } else { + /* Legacy path */ + if (mode =3D=3D QVTD_TM_LEGACY_PT) { + qvtd_build_context_entry(qts, sid, mode, 0); + } else { + qvtd_setup_translation_tables(qts, QVTD_IOVA, mode); + qvtd_build_context_entry(qts, sid, mode, QVTD_PT_L4_BASE); + } + } + + return 0; +} + +uint32_t qvtd_setup_and_enable_translation(QVTDTestContext *ctx) +{ + uint32_t build_result; + + /* Build translation structures first */ + build_result =3D qvtd_build_translation(ctx->qts, ctx->config.trans_mo= de, + ctx->sid); + if (build_result !=3D 0) { + g_test_message("Build failed: mode=3D%u sid=3D%u status=3D0x%x", + ctx->config.trans_mode, ctx->sid, build_result); + ctx->trans_status =3D build_result; + return ctx->trans_status; + } + + /* Program IOMMU registers (sets root table pointer, enables translati= on) */ + qvtd_program_regs(ctx->qts, ctx->iommu_base, ctx->config.trans_mode); + + ctx->trans_status =3D 0; + return ctx->trans_status; +} + +static bool qvtd_validate_test_result(QVTDTestContext *ctx) +{ + uint32_t expected =3D qvtd_expected_dma_result(ctx); + + g_test_message("-> Validating result: expected=3D0x%x actual=3D0x%x", + expected, ctx->dma_result); + return (ctx->dma_result =3D=3D expected); +} + +static uint32_t qvtd_single_translation_setup(void *opaque) +{ + return qvtd_setup_and_enable_translation(opaque); +} + +static uint32_t qvtd_single_translation_attrs(void *opaque) +{ + return qvtd_build_dma_attrs(); +} + +static bool qvtd_single_translation_validate(void *opaque) +{ + return qvtd_validate_test_result(opaque); +} + +static void qvtd_single_translation_report(void *opaque, uint32_t dma_resu= lt) +{ + QVTDTestContext *ctx =3D opaque; + + if (dma_result !=3D 0) { + g_test_message("DMA failed: mode=3D%u result=3D0x%x", + ctx->config.trans_mode, dma_result); + } else { + g_test_message("-> DMA succeeded: mode=3D%u", + ctx->config.trans_mode); + } +} + +void qvtd_run_translation_case(QTestState *qts, QPCIDevice *dev, + QPCIBar bar, uint64_t iommu_base, + const QVTDTestConfig *cfg) +{ + QVTDTestContext ctx =3D { + .qts =3D qts, + .dev =3D dev, + .bar =3D bar, + .iommu_base =3D iommu_base, + .config =3D *cfg, + .sid =3D dev->devfn, + }; + + QOSIOMMUTestdevDmaCfg dma =3D { + .dev =3D dev, + .bar =3D bar, + .iova =3D QVTD_IOVA, + .gpa =3D cfg->dma_gpa, + .len =3D cfg->dma_len, + }; + + qtest_memset(qts, cfg->dma_gpa, 0x00, cfg->dma_len); + qos_iommu_testdev_single_translation(&dma, &ctx, + qvtd_single_translation_setup, + qvtd_single_translation_attrs, + qvtd_single_translation_validate, + qvtd_single_translation_report, + &ctx.dma_result); + + if (ctx.dma_result =3D=3D 0 && ctx.config.expected_result =3D=3D 0) { + g_autofree uint8_t *buf =3D NULL; + + buf =3D g_malloc(ctx.config.dma_len); + qtest_memread(ctx.qts, ctx.config.dma_gpa, buf, ctx.config.dma_len= ); + + for (int i =3D 0; i < ctx.config.dma_len; i++) { + uint8_t expected; + + expected =3D (ITD_DMA_WRITE_VAL >> ((i % 4) * 8)) & 0xff; + g_assert_cmpuint(buf[i], =3D=3D, expected); + } + } +} diff --git a/tests/qtest/libqos/qos-intel-iommu.h b/tests/qtest/libqos/qos-= intel-iommu.h new file mode 100644 index 0000000000..c6cacc5c3f --- /dev/null +++ b/tests/qtest/libqos/qos-intel-iommu.h @@ -0,0 +1,185 @@ +/* + * QOS Intel IOMMU (VT-d) Module + * + * This module provides Intel IOMMU-specific helper functions for libqos t= ests, + * encapsulating VT-d setup, assertion, and cleanup operations. + * + * Copyright (c) 2026 Fengyuan Yu <15fengyuan@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QTEST_LIBQOS_INTEL_IOMMU_H +#define QTEST_LIBQOS_INTEL_IOMMU_H + +#include "hw/misc/iommu-testdev.h" +#include "hw/i386/intel_iommu_internal.h" + +/* + * Guest memory layout for IOMMU structures. + * All structures are placed in guest physical memory inside the 512MB RAM. + * Using 256MB mark (0x10000000) as base to ensure all structures fit in R= AM. + */ +#define QVTD_MEM_BASE 0x10000000ULL + +/* Root Entry Table: 256 entries * 16 bytes =3D 4KB */ +#define QVTD_ROOT_TABLE_BASE (QVTD_MEM_BASE + 0x00000000) + +/* Context Entry Table: 256 entries, 16B (legacy) or 32B (scalable) per en= try */ +#define QVTD_CONTEXT_TABLE_BASE (QVTD_MEM_BASE + 0x00001000) + +/* Page Tables: 4-level hierarchy for 48-bit address translation */ +#define QVTD_PT_L4_BASE (QVTD_MEM_BASE + 0x00010000) /* PML4 */ +#define QVTD_PT_L3_BASE (QVTD_MEM_BASE + 0x00011000) /* PDPT */ +#define QVTD_PT_L2_BASE (QVTD_MEM_BASE + 0x00012000) /* PD */ +#define QVTD_PT_L1_BASE (QVTD_MEM_BASE + 0x00013000) /* PT */ + +/* + * Invalidation Queue. + * IQA_REG bits[2:0] =3D QS, entries =3D 1 << (QS + 8), each entry 16 byte= s. + */ +#define QVTD_IQ_BASE (QVTD_MEM_BASE + 0x00020000) +#define QVTD_IQ_QS 0 /* QS=3D0 =E2=86=92 256 entries */ + +/* + * Fault Event MSI configuration. + */ +#define QVTD_FAULT_IRQ_ADDR 0xfee00000 /* APIC base */ +#define QVTD_FAULT_IRQ_DATA 0x0 + +/* Scalable mode PASID structures */ +#define QVTD_PASID_DIR_BASE (QVTD_MEM_BASE + 0x00030000) +#define QVTD_PASID_TABLE_BASE (QVTD_MEM_BASE + 0x00031000) + +/* Page table entry size (8 bytes per PTE) */ +#define QVTD_PTE_SIZE sizeof(uint64_t) + +/* FSPTPTR mask: same as VTD_SM_PASID_ENTRY_SSPTPTR, bits[63:12] */ +#define QVTD_SM_PASID_ENTRY_FSPTPTR VTD_SM_PASID_ENTRY_SSPTPTR + +/* Default Domain ID for single-domain tests */ +#define QVTD_DOMAIN_ID 0 + +/* Test IOVA and target physical address */ +#define QVTD_IOVA 0x0000000010200567ull +#define QVTD_PT_VAL (QVTD_MEM_BASE + 0x00100000) + +/* + * Translation modes supported by Intel IOMMU + */ +typedef enum QVTDTransMode { + QVTD_TM_LEGACY_PT, /* Legacy pass-through mode */ + QVTD_TM_LEGACY_TRANS, /* Legacy translated mode (4-level paging)= */ + QVTD_TM_SCALABLE_PT, /* Scalable pass-through mode */ + QVTD_TM_SCALABLE_SLT, /* Scalable Second Level Translation */ + QVTD_TM_SCALABLE_FLT, /* Scalable First Level Translation */ +} QVTDTransMode; + +static inline bool qvtd_is_scalable(QVTDTransMode mode) +{ + return mode =3D=3D QVTD_TM_SCALABLE_PT || + mode =3D=3D QVTD_TM_SCALABLE_SLT || + mode =3D=3D QVTD_TM_SCALABLE_FLT; +} + +typedef struct QVTDTestConfig { + QVTDTransMode trans_mode; /* Translation mode */ + uint64_t dma_gpa; /* GPA for readback validation */ + uint32_t dma_len; /* DMA length for testing */ + uint32_t expected_result; /* Expected DMA result */ +} QVTDTestConfig; + +typedef struct QVTDTestContext { + QTestState *qts; /* QTest state handle */ + QPCIDevice *dev; /* PCI device handle */ + QPCIBar bar; /* PCI BAR for MMIO access */ + QVTDTestConfig config; /* Test configuration */ + uint64_t iommu_base; /* Intel IOMMU base address */ + uint32_t trans_status; /* Translation configuration status */ + uint32_t dma_result; /* DMA operation result */ + uint16_t sid; /* Source ID (bus:devfn) */ +} QVTDTestContext; + +/* + * qvtd_setup_and_enable_translation - Complete translation setup and enab= le + * + * @ctx: Test context containing configuration and device handles + * + * Returns: Translation status (0 =3D success, non-zero =3D error) + * + * This function performs the complete translation setup sequence: + * 1. Builds VT-d structures (root/context entry, page tables) + * 2. Programs IOMMU registers and enables translation + * 3. Returns configuration status + */ +uint32_t qvtd_setup_and_enable_translation(QVTDTestContext *ctx); + +/* + * qvtd_build_translation - Build Intel IOMMU translation structures + * + * @qts: QTest state handle + * @mode: Translation mode (pass-through or translated) + * @sid: Source ID (bus:devfn) + * + * Returns: Build status (0 =3D success, non-zero =3D error) + * + * Constructs all necessary VT-d translation structures in guest memory: + * - Root Entry for the device's bus + * - Context Entry for the device + * - Complete 4-level page table hierarchy (if translated mode) + */ +uint32_t qvtd_build_translation(QTestState *qts, QVTDTransMode mode, + uint16_t sid); + +/* + * qvtd_program_regs - Program Intel IOMMU registers and enable translation + * + * @qts: QTest state handle + * @iommu_base: IOMMU base address + * @mode: Translation mode (scalable modes set RTADDR SMT bit) + * + * Programs IOMMU registers with the following sequence: + * 1. Set root table pointer (SRTP), with SMT bit for scalable mode + * 2. Setup invalidation queue (QIE) + * 3. Configure fault event MSI + * 4. Enable translation (TE) + * + * Each step verifies completion via GSTS register read-back. + */ +void qvtd_program_regs(QTestState *qts, uint64_t iommu_base, + QVTDTransMode mode); + +/* + * qvtd_setup_translation_tables - Setup complete VT-d page table hierarchy + * + * @qts: QTest state handle + * @iova: Input Virtual Address to translate + * @mode: Translation mode + * + * This builds the 4-level page table structure for translating + * the given IOVA to PA through Intel VT-d. The structure is: + * - PML4 (Level 4): IOVA bits [47:39] + * - PDPT (Level 3): IOVA bits [38:30] + * - PD (Level 2): IOVA bits [29:21] + * - PT (Level 1): IOVA bits [20:12] + * - Page offset: IOVA bits [11:0] + * + * The function writes all necessary Page Table Entries (PTEs) to guest + * memory using qtest_writeq(), setting up the complete translation path + * that the VT-d hardware will traverse during DMA operations. + */ +void qvtd_setup_translation_tables(QTestState *qts, uint64_t iova, + QVTDTransMode mode); + +/* Calculate expected DMA result */ +uint32_t qvtd_expected_dma_result(QVTDTestContext *ctx); + +/* Build DMA attributes for Intel VT-d */ +uint32_t qvtd_build_dma_attrs(void); + +/* High-level test execution helpers */ +void qvtd_run_translation_case(QTestState *qts, QPCIDevice *dev, + QPCIBar bar, uint64_t iommu_base, + const QVTDTestConfig *cfg); + +#endif /* QTEST_LIBQOS_INTEL_IOMMU_H */ --=20 2.51.0 From nobody Sat May 30 19:21:09 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=suse.de ARC-Seal: i=1; a=rsa-sha256; t=1777473222; cv=none; d=zohomail.com; s=zohoarc; b=CfsFS6qucmjjsp/N9xZqjuh+KD8BSNMeZdJLsncjih/M094aU6dkcFwfj+tbzmTGK+DV7mpVzzBO9NvIqGLxrvm/qmpPxLolsP+oD0aDedjHT4GClwye1k5zxrfabf7wAyScz7yxu18mKfw1L7zFyO8Ujs6blrfcVhGQXLf5kVo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777473222; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=8yVs8oYYUQJDcL18TH0v/eC11VU1GLIv2m3WS3+wh7Y=; b=h5YfOxah4H1tUwLiuYHRy0ytKKdOXvb9y+51f88UTBwkS44blZJ36gK0SB7983mK6ipHWux5aAWTLXMh58XdTzpzkokIKSXvOkCMTu9yoGsbWXSP6kjbOoXrrqwBd1vngXxEbuLzO/HEWaXz0586Q3k3bWvCy6GOWVzboo4GBOY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777473222806580.4424241793071; Wed, 29 Apr 2026 07:33:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wI5yN-00075t-6b; Wed, 29 Apr 2026 10:33:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wI5yC-000742-LG for qemu-devel@nongnu.org; Wed, 29 Apr 2026 10:32:56 -0400 Received: from smtp-out2.suse.de ([195.135.223.131]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wI5yA-0007qm-EB for qemu-devel@nongnu.org; Wed, 29 Apr 2026 10:32:56 -0400 Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id EA6CF5BD56; Wed, 29 Apr 2026 14:32:41 +0000 (UTC) Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id B6BEE593B4; Wed, 29 Apr 2026 14:32:40 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id 0CcFIYgW8mksagAAD6G6ig (envelope-from ); Wed, 29 Apr 2026 14:32:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1777473166; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8yVs8oYYUQJDcL18TH0v/eC11VU1GLIv2m3WS3+wh7Y=; b=z9+130a+CTcdZFymDKvYLHwGb9QgT1xsN4JR94WATqknhhq8p4k8Z1F4PFK9ryuqIy74So uusAL13458yuSS/OOz/9f1SzwyUUvGBYUh3Luu6DsgLB+X8qRNqF9swP//sjq1Kz/kYZjT fz58im5rCp2TbTpPQlbrKj14e35IrNs= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1777473166; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8yVs8oYYUQJDcL18TH0v/eC11VU1GLIv2m3WS3+wh7Y=; b=rWaFInrvmn0xTfSSOGW/Zbh4JP5SnBxC8Sqx26sK5sKESOrzxqO5lgb7xlHijk1YjSAGnR /gdyEryIv7rVyjAA== Authentication-Results: smtp-out2.suse.de; dkim=pass header.d=suse.de header.s=susede2_rsa header.b=MqzPIDPY; dkim=pass header.d=suse.de header.s=susede2_ed25519 header.b=E7g65csE DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1777473161; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8yVs8oYYUQJDcL18TH0v/eC11VU1GLIv2m3WS3+wh7Y=; b=MqzPIDPYVwcGUzJdLYHlsmmFtXWVpu9fwr9Hm9Wgg9oZdrVBfSCFBMudkl3qHaV1sDXStG JtFMm75RDmHf7UJaV5cMJk8J7QYPT9coF/RJIQnVDPqQ3iXlZgVLj1x8W4E22TFfu1dMME t7ztuTj2xY31yLuBO9Q0yKD0K6bMS+o= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1777473161; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8yVs8oYYUQJDcL18TH0v/eC11VU1GLIv2m3WS3+wh7Y=; b=E7g65csEWlJy5joZKJRM9jw7iskOKZfNycBT+E7FOmaUam3jU9I/d2oj6M2PkcmARYHhCw Hehl8eayvlfbLOCA== From: Fabiano Rosas To: qemu-devel@nongnu.org Cc: Fengyuan Yu <15fengyuan@gmail.com>, Chao Liu , Tao Tang Subject: [PULL 2/3] tests/qtest: Add Intel IOMMU bare-metal test Date: Wed, 29 Apr 2026 11:32:30 -0300 Message-ID: <20260429143235.25115-3-farosas@suse.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260429143235.25115-1-farosas@suse.de> References: <20260429143235.25115-1-farosas@suse.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Spamd-Result: default: False [-1.51 / 50.00]; BAYES_HAM(-3.00)[100.00%]; SUSPICIOUS_RECIPS(1.50)[]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_MISSING_CHARSET(0.50)[]; R_DKIM_ALLOW(-0.20)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.01)[]; TO_DN_SOME(0.00)[]; MIME_TRACE(0.00)[0:+]; TO_MATCH_ENVRCPT_ALL(0.00)[]; ARC_NA(0.00)[]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; RCVD_TLS_ALL(0.00)[]; SPAMHAUS_XBL(0.00)[2a07:de40:b281:104:10:150:64:97:from]; RCVD_COUNT_TWO(0.00)[2]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; FREEMAIL_CC(0.00)[gmail.com,phytium.com.cn]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo,imap1.dmz-prg2.suse.org:rdns,suse.de:mid,suse.de:dkim,suse.de:email]; RCVD_VIA_SMTP_AUTH(0.00)[]; TAGGED_RCPT(0.00)[]; DKIM_TRACE(0.00)[suse.de:+]; RCPT_COUNT_THREE(0.00)[4]; FREEMAIL_ENVRCPT(0.00)[gmail.com] X-Rspamd-Action: no action X-Spam-Score: -1.51 X-Rspamd-Server: rspamd1.dmz-prg2.suse.org X-Rspamd-Queue-Id: EA6CF5BD56 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=195.135.223.131; envelope-from=farosas@suse.de; helo=smtp-out2.suse.de X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @suse.de) (identity @suse.de) X-ZM-MESSAGEID: 1777473225401158500 Content-Type: text/plain; charset="utf-8" From: Fengyuan Yu <15fengyuan@gmail.com> Add a qtest suite for the Intel IOMMU (VT-d) device on the Q35 machine. The test exercises both Legacy and Scalable translation modes using iommu-testdev and the qos-intel-iommu helpers, without requiring any guest kernel or firmware. The test validates: - Legacy-mode Root Entry Table and Context Entry Table configuration - Scalable-mode Context Entry, PASID Directory, and PASID Table setup - Legacy-mode 4-level page table walks for 48-bit address translation - Scalable-mode second-level and first-level 4-level page table walks - Pass-through mode in both Legacy and Scalable modes - DMA transaction execution with memory content verification Reviewed-by: Chao Liu Signed-off-by: Fengyuan Yu <15fengyuan@gmail.com> Reviewed-by: Fabiano Rosas Reviewed-by: Tao Tang Link: https://lore.kernel.org/qemu-devel/ce3c44f3b07734a4f0ee43f55b21c85603= 4af1b1.1774421649.git.15fengyuan@gmail.com Signed-off-by: Fabiano Rosas --- MAINTAINERS | 1 + tests/qtest/iommu-intel-test.c | 216 +++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 + 3 files changed, 219 insertions(+) create mode 100644 tests/qtest/iommu-intel-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 3887dda851..b570c43673 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4010,6 +4010,7 @@ F: hw/i386/intel_iommu_accel.* F: include/hw/i386/intel_iommu.h F: tests/functional/x86_64/test_intel_iommu.py F: tests/qtest/intel-iommu-test.c +F: tests/qtest/iommu-intel-test.c =20 AMD-Vi Emulation M: Alejandro Jimenez diff --git a/tests/qtest/iommu-intel-test.c b/tests/qtest/iommu-intel-test.c new file mode 100644 index 0000000000..a52c45e298 --- /dev/null +++ b/tests/qtest/iommu-intel-test.c @@ -0,0 +1,216 @@ +/* + * QTest for Intel IOMMU (VT-d) with iommu-testdev + * + * This QTest file is used to test the Intel IOMMU with iommu-testdev so t= hat + * we can test VT-d without any guest kernel or firmware. + * + * Copyright (c) 2026 Fengyuan Yu <15fengyuan@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/pci.h" +#include "libqos/pci-pc.h" +#include "hw/i386/intel_iommu_internal.h" +#include "hw/misc/iommu-testdev.h" +#include "libqos/qos-intel-iommu.h" + +#define DMA_LEN 4 + +static uint64_t intel_iommu_expected_gpa(uint64_t iova) +{ + return (QVTD_PT_VAL & VTD_PAGE_MASK_4K) + (iova & 0xfff); +} + +static void save_fn(QPCIDevice *dev, int devfn, void *data) +{ + QPCIDevice **pdev =3D (QPCIDevice **) data; + + *pdev =3D dev; +} + +static QPCIDevice *setup_qtest_pci_device(QTestState *qts, QPCIBus **pcibu= s, + QPCIBar *bar) +{ + QPCIDevice *dev =3D NULL; + + *pcibus =3D qpci_new_pc(qts, NULL); + g_assert(*pcibus !=3D NULL); + + qpci_device_foreach(*pcibus, IOMMU_TESTDEV_VENDOR_ID, + IOMMU_TESTDEV_DEVICE_ID, save_fn, &dev); + + g_assert(dev); + qpci_device_enable(dev); + *bar =3D qpci_iomap(dev, 0, NULL); + g_assert_false(bar->is_io); + + return dev; +} + +static const char *qvtd_iommu_args(QVTDTransMode mode) +{ + switch (mode) { + case QVTD_TM_SCALABLE_FLT: + return "-device intel-iommu,x-scalable-mode=3Don,x-flts=3Don "; + case QVTD_TM_SCALABLE_PT: + case QVTD_TM_SCALABLE_SLT: + return "-device intel-iommu,x-scalable-mode=3Don "; + default: + return "-device intel-iommu "; + } +} + +static bool qvtd_check_caps(QTestState *qts, QVTDTransMode mode) +{ + uint64_t ecap =3D qtest_readq(qts, + Q35_HOST_BRIDGE_IOMMU_ADDR + DMAR_ECAP_REG= ); + + /* All scalable modes require SMTS */ + if (qvtd_is_scalable(mode) && !(ecap & VTD_ECAP_SMTS)) { + g_test_skip("ECAP.SMTS not supported"); + return false; + } + + switch (mode) { + case QVTD_TM_SCALABLE_PT: + if (!(ecap & VTD_ECAP_PT)) { + g_test_skip("ECAP.PT not supported"); + return false; + } + break; + case QVTD_TM_SCALABLE_SLT: + if (!(ecap & VTD_ECAP_SSTS)) { + g_test_skip("ECAP.SSTS not supported"); + return false; + } + break; + case QVTD_TM_SCALABLE_FLT: + if (!(ecap & VTD_ECAP_FSTS)) { + g_test_skip("ECAP.FSTS not supported"); + return false; + } + break; + default: + break; + } + + return true; +} + +static void run_intel_iommu_translation(const QVTDTestConfig *cfg) +{ + QTestState *qts; + QPCIBus *pcibus; + QPCIDevice *dev; + QPCIBar bar; + + if (!qtest_has_machine("q35")) { + g_test_skip("q35 machine not available"); + return; + } + + /* Initialize QEMU environment for Intel IOMMU testing */ + qts =3D qtest_initf("-machine q35 -smp 1 -m 512 -net none " + "%s -device iommu-testdev", + qvtd_iommu_args(cfg->trans_mode)); + + /* Check CAP/ECAP capabilities for required translation mode */ + if (!qvtd_check_caps(qts, cfg->trans_mode)) { + qtest_quit(qts); + return; + } + + /* Setup and configure IOMMU-testdev PCI device */ + dev =3D setup_qtest_pci_device(qts, &pcibus, &bar); + g_assert(dev); + + g_test_message("### Intel IOMMU translation mode=3D%d ###", cfg->trans= _mode); + qvtd_run_translation_case(qts, dev, bar, Q35_HOST_BRIDGE_IOMMU_ADDR, c= fg); + g_free(dev); + qpci_free_pc(pcibus); + qtest_quit(qts); +} + +static void test_intel_iommu_legacy_pt(void) +{ + QVTDTestConfig cfg =3D { + .trans_mode =3D QVTD_TM_LEGACY_PT, + .dma_gpa =3D QVTD_IOVA, /* pass-through: GPA =3D=3D IOVA */ + .dma_len =3D DMA_LEN, + .expected_result =3D 0, + }; + + run_intel_iommu_translation(&cfg); +} + +static void test_intel_iommu_legacy_trans(void) +{ + QVTDTestConfig cfg =3D { + .trans_mode =3D QVTD_TM_LEGACY_TRANS, + .dma_gpa =3D intel_iommu_expected_gpa(QVTD_IOVA), + .dma_len =3D DMA_LEN, + .expected_result =3D 0, + }; + + run_intel_iommu_translation(&cfg); +} + +static void test_intel_iommu_scalable_pt(void) +{ + QVTDTestConfig cfg =3D { + .trans_mode =3D QVTD_TM_SCALABLE_PT, + .dma_gpa =3D QVTD_IOVA, /* pass-through: GPA =3D=3D IOVA */ + .dma_len =3D DMA_LEN, + .expected_result =3D 0, + }; + + run_intel_iommu_translation(&cfg); +} + +static void test_intel_iommu_scalable_slt(void) +{ + QVTDTestConfig cfg =3D { + .trans_mode =3D QVTD_TM_SCALABLE_SLT, + .dma_gpa =3D intel_iommu_expected_gpa(QVTD_IOVA), + .dma_len =3D DMA_LEN, + .expected_result =3D 0, + }; + + run_intel_iommu_translation(&cfg); +} + +static void test_intel_iommu_scalable_flt(void) +{ + QVTDTestConfig cfg =3D { + .trans_mode =3D QVTD_TM_SCALABLE_FLT, + .dma_gpa =3D intel_iommu_expected_gpa(QVTD_IOVA), + .dma_len =3D DMA_LEN, + .expected_result =3D 0, + }; + + run_intel_iommu_translation(&cfg); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + /* Legacy mode tests */ + qtest_add_func("/iommu-testdev/intel/legacy-pt", + test_intel_iommu_legacy_pt); + qtest_add_func("/iommu-testdev/intel/legacy-trans", + test_intel_iommu_legacy_trans); + + /* Scalable mode tests */ + qtest_add_func("/iommu-testdev/intel/scalable-pt", + test_intel_iommu_scalable_pt); + qtest_add_func("/iommu-testdev/intel/scalable-slt", + test_intel_iommu_scalable_slt); + qtest_add_func("/iommu-testdev/intel/scalable-flt", + test_intel_iommu_scalable_flt); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index b735f55fc4..43f83ffd3a 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -96,6 +96,8 @@ qtests_i386 =3D \ (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] := []) + \ (config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) = + \ (config_all_devices.has_key('CONFIG_VTD') ? ['intel-iommu-test'] : []) += \ + (config_all_devices.has_key('CONFIG_VTD') and + config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') ? ['iommu-intel-test= '] : []) + \ (host_os !=3D 'windows' and = \ config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + = \ (config_all_devices.has_key('CONFIG_PCIE_PORT') and = \ --=20 2.51.0 From nobody Sat May 30 19:21:09 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=suse.de ARC-Seal: i=1; a=rsa-sha256; t=1777473200; cv=none; d=zohomail.com; s=zohoarc; b=fuhUrVJzJbop3FMkgSE6pbdlbUMJ1aJmvA5keNwltkSqihZAo4p7XoYkxxo6mnBQut2VfC9c/8aQH7GqaOzf4gkTEJ8dnfHSB2YHfIHz2IyHCvwQ0AsilIpRWPQeDrSQmQfowiE9zwGwFRvIxuxOXhVgh6a60S31vzvxc02qgcA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777473200; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=a6N0bLYt9BpqiOZWkw8Z9wpMUn0oIDsVhLfgEXDLVns=; b=mS/DDFiS6jjyxLs/91y6yMe8aJ9L88Sn2Uui5/1pMSiueW0pn3n5lVE6nMWXwt5sQHHm3UTeWRhKrX+3lw66jsnq48Z29vK6QfqF9oS14wDkENU8aKixTbMhZn/2tnwYowjCpeDs3jmYI75ObpeeHpZyg065xHP3djBPy/x/7P8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777473200334929.5640043453624; Wed, 29 Apr 2026 07:33:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wI5yJ-00075o-Qz; Wed, 29 Apr 2026 10:33:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wI5yF-00074U-3r for qemu-devel@nongnu.org; Wed, 29 Apr 2026 10:33:01 -0400 Received: from smtp-out1.suse.de ([2a07:de40:b251:101:10:150:64:1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wI5yD-0007rM-90 for qemu-devel@nongnu.org; Wed, 29 Apr 2026 10:32:58 -0400 Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 1F0F76A89D; Wed, 29 Apr 2026 14:32:46 +0000 (UTC) Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 4C621593B5; Wed, 29 Apr 2026 14:32:42 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id SDMKB4oW8mksagAAD6G6ig (envelope-from ); Wed, 29 Apr 2026 14:32:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1777473170; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=a6N0bLYt9BpqiOZWkw8Z9wpMUn0oIDsVhLfgEXDLVns=; b=dy2QqOH5ZP4zHTHoSnsvvC2aJSgPt4z9qp3+r0csLjX66f4qBW+CcVIP2/tXFgbucrGTfn 8XyHN1TO63FNaVkGThihwUchiTIAzv9m3XTFdvjC5JwyV782RyFQdxqfTs2HdJzJdGG6Js J36QbEL00bvyuNcOBwdgbUPdA5tCb6I= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1777473170; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=a6N0bLYt9BpqiOZWkw8Z9wpMUn0oIDsVhLfgEXDLVns=; b=SpLRpWaE9ax6IET1ZW0H9OpZVAh5OUze3hvtl/qnZgfzuCUCk4obc4CpeYD9vw/jmBKrc/ OW3mm82fhbpA7hBQ== Authentication-Results: smtp-out1.suse.de; dkim=pass header.d=suse.de header.s=susede2_rsa header.b=gSecMXOX; dkim=pass header.d=suse.de header.s=susede2_ed25519 header.b="f6/L2yDb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1777473166; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=a6N0bLYt9BpqiOZWkw8Z9wpMUn0oIDsVhLfgEXDLVns=; b=gSecMXOXUh22jcWGJO3Xjob0RWd6chl3TP4pxx1ndbzoX887GPumIgmXQZ72pWh5qRUObV /Q1Ssg/9X1qsjvhO8F9BPgdwskH0em6wVU7sIv3cvvld3kFstyAsFUBFPanxbkZNlgcOEN /vP34SZl+y5hb44b7x0Dee2dRX4UUWw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1777473166; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=a6N0bLYt9BpqiOZWkw8Z9wpMUn0oIDsVhLfgEXDLVns=; b=f6/L2yDb2LG+lSnc9TeHInGts77n++EUanRq4ZfKmhfIL+W/np3DzRb9BBBtv3SE0ZLG2K q2QHBMG40a84FaBw== From: Fabiano Rosas To: qemu-devel@nongnu.org Cc: Peter Maydell Subject: [PULL 3/3] tests/qtest: Make qtest_get_arch() cleverer Date: Wed, 29 Apr 2026 11:32:31 -0300 Message-ID: <20260429143235.25115-4-farosas@suse.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260429143235.25115-1-farosas@suse.de> References: <20260429143235.25115-1-farosas@suse.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Spamd-Result: default: False [-3.01 / 50.00]; BAYES_HAM(-3.00)[100.00%]; NEURAL_HAM_LONG(-1.00)[-1.000]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; R_DKIM_ALLOW(-0.20)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.01)[]; ARC_NA(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[]; MIME_TRACE(0.00)[0:+]; TO_MATCH_ENVRCPT_ALL(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo,imap1.dmz-prg2.suse.org:rdns,suse.de:mid,suse.de:dkim,suse.de:email]; RCVD_TLS_ALL(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; FROM_EQ_ENVFROM(0.00)[]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; RCPT_COUNT_TWO(0.00)[2]; SPAMHAUS_XBL(0.00)[2a07:de40:b281:104:10:150:64:97:from]; DKIM_TRACE(0.00)[suse.de:+] X-Rspamd-Action: no action X-Spam-Score: -3.01 X-Rspamd-Server: rspamd1.dmz-prg2.suse.org X-Rspamd-Queue-Id: 1F0F76A89D Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a07:de40:b251:101:10:150:64:1; envelope-from=farosas@suse.de; helo=smtp-out1.suse.de X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @suse.de) (identity @suse.de) X-ZM-MESSAGEID: 1777473203432158500 Content-Type: text/plain; charset="utf-8" From: Peter Maydell The qtest_get_arch() function tries to determine the architecture under test by extracting it from the binary name as provided in QTEST_QEMU_BINARY. The current logic finds the last '-' in the string and assumes everything beyond it is the architecture name. Although we also look for the substring "-system-", the only effect this check has is that we will exit with an error if it is not present. Because the logic at the moment is very simplistic, although it is possible to provide more complex commands than a bare QEMU binary path, such as: QTEST_QEMU_BINARY=3D'rr record ./qemu-system-x86_64' it is not possible to provide extra arguments to QEMU, such as: QTEST_QEMU_BINARY=3D'./qemu-system-x86_64 -d trace:foo' Because the "-system-" check and the "find the architecture" check are not the same, the latter example will pass the "we found -system-" check and not notice that the "architecture name" it has found starts further on in the string; so rather than printing an error it will return "d trace:foo" to the test. Improve the "find the architecture name" logic to look for the rightmost occurrence of the substring "-system-" in QTEST_QEMU_BINARY, and take the architecture name as starting there and continuing until the first whitespace character or the end of the string. Because we now need to potentially modify the environment variable string to terminate the architecture name if it is not the last part of the string, we make a copy of it which we cache in a static variable. This lets us avoid having to modify all the callers to get them to take ownership of the returned string. Signed-off-by: Peter Maydell Link: https://lore.kernel.org/qemu-devel/20260427150007.1185559-1-peter.may= dell@linaro.org Signed-off-by: Fabiano Rosas --- tests/qtest/libqtest.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 051faf31e1..116a8a3258 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1015,22 +1015,39 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) =20 const char *qtest_get_arch(void) { - const char *qemu =3D qtest_qemu_binary(NULL); - const char *end =3D strrchr(qemu, '-'); + /* + * We find and cache the architecture name once, because we need to + * allocate memory to hold it. This memory will stay around for + * the lifetime of this test process. + */ + static const char *arch; =20 - if (!end) { - fprintf(stderr, "Can't determine architecture from binary name.\n"= ); - exit(1); - } + if (!arch) { + /* + * Find the rightmost occurrence of "-system-"; the architecture + * name runs from there to the next whitespace. + */ + const char *qemu =3D qtest_qemu_binary(NULL); + const char *sysstr =3D g_strrstr(qemu, "-system-"); + + if (sysstr) { + g_auto(GStrv) tokens =3D g_strsplit_set(sysstr + strlen("-syst= em-"), + " \t", 2); + if (tokens && tokens[0]) { + arch =3D g_steal_pointer(&tokens[0]); + } + } =20 - if (!strstr(qemu, "-system-")) { - fprintf(stderr, "QTEST_QEMU_BINARY must end with *-system- " - "where 'arch' is the target\narchitecture (x86_64, aarch64= , " - "etc).\n"); - exit(1); + if (!arch) { + fprintf(stderr, "Can't determine architecture from binary name= .\n" + "QTEST_QEMU_BINARY must include *-system- where " + "'arch' is the target architecture " + "(x86_64, aarch64, etc).\n"); + exit(1); + } } =20 - return end + 1; + return arch; } =20 static bool qtest_qom_has_concrete_type(const char *parent_typename, --=20 2.51.0