From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from Atcsqr.andestech.com (60-248-80-70.hinet-ip.hinet.net [60.248.80.70]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 88D0731BCB6 for ; Mon, 17 Nov 2025 08:49:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.248.80.70 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763369393; cv=none; b=Oxl76dNR8hmNTlwMprPLJjy3qOL+TYyn2JmKxLG9lRfNoDff7l0IVwaTShYe28xSMM2l2hkgxvYKx4UO6DsL1vy/MhGyhf1H0HPbPaLqjqW49GGbnfSAjTlAmUQjPJJ8GKaE3/yBZqt+7TBJ9iZ7/qEuhd08gt7sf8ST7SFHVH0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763369393; c=relaxed/simple; bh=5rq7hC+3whNZCqhr0ZHxQujF367+hptZaUKGj/4QSIE=; h=From:To:CC:Subject:Date:Message-ID:MIME-Version:Content-Type; b=nVbLBEHnmoURggJJYANUe1ST9Bc6Liy9vHDqGHC7kvYXclBRmsbtI7VbfFFnq4Xsv3tRw58+wFeqSuW6TZC9aGNy3+bGYL7ofLPCD5ey5ZCXTzAFucz4MR/vj44AkGi4IfyFOSPMpRZ7ypGaxocLsrd8zZgmYAMC/it/sbDu440= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=permerror header.from=andestech.com; spf=pass smtp.mailfrom=andestech.com; arc=none smtp.client-ip=60.248.80.70 Authentication-Results: smtp.subspace.kernel.org; dmarc=permerror header.from=andestech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=andestech.com Received: from mail.andestech.com (ATCPCS34.andestech.com [10.0.1.134]) by Atcsqr.andestech.com with ESMTPS id 5AH8kHmt097165 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=OK); Mon, 17 Nov 2025 16:46:17 +0800 (+08) (envelope-from minachou@andestech.com) Received: from swlinux02.andestech.com (10.0.15.183) by ATCPCS34.andestech.com (10.0.1.134) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Mon, 17 Nov 2025 16:46:17 +0800 From: Hui Min Mina Chou To: , , , , , CC: , , , , , , , , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Subject: [PATCH v4] RISC-V: KVM: Flush VS-stage TLB after VCPU migration for split two-stage TLBs Date: Mon, 17 Nov 2025 16:45:55 +0800 Message-ID: <20251117084555.157642-1-minachou@andestech.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-ClientProxiedBy: ATCPCS33.andestech.com (10.0.1.100) To ATCPCS34.andestech.com (10.0.1.134) X-DKIM-Results: atcpcs34.andestech.com; dkim=none; X-DNSRBL: X-SPAM-SOURCE-CHECK: pass X-MAIL:Atcsqr.andestech.com 5AH8kHmt097165 Most implementations cache the combined result of two-stage translation, but some, like Andes cores, use split TLBs that store VS-stage and G-stage entries separately. On such systems, when a VCPU migrates to another CPU, an additional HFENCE.VVMA is required to avoid using stale VS-stage entries, which could otherwise cause guest faults. Introduce a static key to identify CPUs with split two-stage TLBs. When enabled, KVM issues an extra HFENCE.VVMA on VCPU migration to prevent stale VS-stage mappings. Signed-off-by: Hui Min Mina Chou Signed-off-by: Ben Zong-You Xie Reviewed-by: Radim Krčmář --- Changelog: v4: - Rename the patch subject - Remove the Fixes tag - Add a static key so that HFENCE.VVMA is issued only on CPUs with split two-stage TLBs - Add kvm_riscv_setup_vendor_features() to detect mvendorid/marchid and enable the key when required v3: - Resolved build warning; updated header declaration and call side to kvm_riscv_local_tlb_sanitize - Add Radim Krčmář's Reviewed-by tag (https://lore.kernel.org/all/20251023032517.2527193-1-minachou@andestech.com/) v2: - Updated Fixes commit to 92e450507d56 - Renamed function to kvm_riscv_local_tlb_sanitize (https://lore.kernel.org/all/20251021083105.4029305-1-minachou@andestech.com/) --- arch/riscv/include/asm/kvm_host.h | 2 ++ arch/riscv/include/asm/kvm_vmid.h | 2 +- arch/riscv/kvm/main.c | 14 ++++++++++++++ arch/riscv/kvm/vcpu.c | 2 +- arch/riscv/kvm/vmid.c | 6 +++++- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index d71d3299a335..21abac2f804e 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -323,4 +323,6 @@ bool kvm_riscv_vcpu_stopped(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu); +DECLARE_STATIC_KEY_FALSE(kvm_riscv_tlb_split_mode); + #endif /* __RISCV_KVM_HOST_H__ */ diff --git a/arch/riscv/include/asm/kvm_vmid.h b/arch/riscv/include/asm/kvm_vmid.h index ab98e1434fb7..75fb6e872ccd 100644 --- a/arch/riscv/include/asm/kvm_vmid.h +++ b/arch/riscv/include/asm/kvm_vmid.h @@ -22,6 +22,6 @@ unsigned long kvm_riscv_gstage_vmid_bits(void); int kvm_riscv_gstage_vmid_init(struct kvm *kvm); bool kvm_riscv_gstage_vmid_ver_changed(struct kvm_vmid *vmid); void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu); -void kvm_riscv_gstage_vmid_sanitize(struct kvm_vcpu *vcpu); +void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu); #endif diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index 67c876de74ef..bf0e4f1abe0f 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -15,6 +15,18 @@ #include #include +DEFINE_STATIC_KEY_FALSE(kvm_riscv_tlb_split_mode); + +static void kvm_riscv_setup_vendor_features(void) +{ + /* Andes AX66: split two-stage TLBs */ + if (riscv_cached_mvendorid(0) == ANDES_VENDOR_ID && + (riscv_cached_marchid(0) & 0xFFFF) == 0x8A66) { + static_branch_enable(&kvm_riscv_tlb_split_mode); + kvm_info("using split two-stage TLBs requiring extra HFENCE.VVMA\n"); + } +} + long kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -159,6 +171,8 @@ static int __init riscv_kvm_init(void) kvm_info("AIA available with %d guest external interrupts\n", kvm_riscv_aia_nr_hgei); + kvm_riscv_setup_vendor_features(); + kvm_register_perf_callbacks(NULL); rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 3ebcfffaa978..796218e4a462 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -968,7 +968,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) * Note: This should be done after G-stage VMID has been * updated using kvm_riscv_gstage_vmid_ver_changed() */ - kvm_riscv_gstage_vmid_sanitize(vcpu); + kvm_riscv_local_tlb_sanitize(vcpu); trace_kvm_entry(vcpu); diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c index 3b426c800480..1dbd50c67a88 100644 --- a/arch/riscv/kvm/vmid.c +++ b/arch/riscv/kvm/vmid.c @@ -125,7 +125,7 @@ void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu) kvm_make_request(KVM_REQ_UPDATE_HGATP, v); } -void kvm_riscv_gstage_vmid_sanitize(struct kvm_vcpu *vcpu) +void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu) { unsigned long vmid; @@ -146,4 +146,8 @@ void kvm_riscv_gstage_vmid_sanitize(struct kvm_vcpu *vcpu) vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid); kvm_riscv_local_hfence_gvma_vmid_all(vmid); + + /* For split TLB designs, flush VS-stage entries also */ + if (static_branch_unlikely(&kvm_riscv_tlb_split_mode)) + kvm_riscv_local_hfence_vvma_all(vmid); } -- 2.34.1