From: Jinyu Tang <jinyu.tang@linux.dev>
To: Anup Patel <anup@brainfault.org>,
Anup Patel <apatel@ventanamicro.com>,
Atish Patra <atish.patra@linux.dev>
Cc: kvm@vger.kernel.org, kvm-riscv@lists.infradead.org,
linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org,
Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>,
Shuah Khan <shuah@kernel.org>, Paul Walmsley <pjw@kernel.org>,
Palmer Dabbelt <palmer@dabbelt.com>,
Albert Ou <aou@eecs.berkeley.edu>,
Alexandre Ghiti <alex@ghiti.fr>,
Andrew Jones <andrew.jones@oss.qualcomm.com>,
Conor Dooley <conor.dooley@microchip.com>,
Yong-Xuan Wang <yongxuan.wang@sifive.com>,
Nutty Liu <nutty.liu@hotmail.com>,
Yifei Jiang <jiangyifei@huawei.com>, Jinyu Tang <tjytimi@163.com>,
Jinyu Tang <jinyu.tang@linux.dev>,
Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH v4 1/5] KVM: riscv: Avoid overwriting G-stage tables with huge leaves
Date: Sat, 15 Aug 2026 06:00:15 -0400 [thread overview]
Message-ID: <20260815100019.860693-1-jinyu.tang@linux.dev> (raw)
In-Reply-To: <20260815095548.860018-1-jinyu.tang@linux.dev>
RISC-V KVM can overwrite an existing G-stage table entry when
installing a huge leaf mapping. If the target huge range already has a
lower-level page table, kvm_riscv_gstage_set_pte() can replace the
non-leaf entry with a leaf PTE and disconnect the lower-level page
table.
Reject replacing a valid table entry with a leaf PTE. If huge-page
installation hits such a conflict, fall back to a 4K mapping for the
original faulting GPA in the MMU fault path, where the original GPA and
HFN are still available.
Suggested-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
arch/riscv/kvm/gstage.c | 6 ++++++
arch/riscv/kvm/mmu.c | 24 +++++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index e5002cb9cbef..54d45addf18f 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -174,6 +174,12 @@ int kvm_riscv_gstage_set_pte(struct kvm_gstage *gstage,
if (pte_val(*ptep) != pte_val(map->pte)) {
bool was_invalid = !pte_val(*ptep);
+
+ /* Avoid replacing an existing lower-level table with a leaf mapping. */
+ if (!gstage_pte_leaf(ptep) && !was_invalid &&
+ gstage_pte_leaf(&map->pte))
+ return -EEXIST;
+
set_pte(ptep, map->pte);
if (gstage_pte_leaf(ptep) &&
!(was_invalid && riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)))
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 6035b5ec9503..bfd6168ebe30 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -625,10 +625,11 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
struct kvm_gstage_mapping *out_map)
{
int ret;
- kvm_pfn_t hfn;
+ kvm_pfn_t fault_hfn, hfn;
bool is_hugetlb;
bool writable;
unsigned int vma_pageshift;
+ gpa_t fault_gpa = gpa;
gfn_t gfn = gpa >> PAGE_SHIFT;
struct vm_area_struct *vma;
struct kvm *kvm = vcpu->kvm;
@@ -709,6 +710,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
}
if (is_error_noslot_pfn(hfn))
return -EFAULT;
+ fault_hfn = hfn + ((fault_gpa >> PAGE_SHIFT) - gfn);
/*
* If logging is active then we allow writable pages only
@@ -734,9 +736,29 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
mark_page_dirty_in_slot(kvm, memslot, gfn);
ret = kvm_riscv_gstage_map_page(&gstage, pcache, gpa, hfn << PAGE_SHIFT,
vma_pagesize, false, true, out_map);
+ if (ret == -EEXIST) {
+ /*
+ * Retry at 4K granularity for the original faulting GPA
+ * when a huge leaf cannot replace an existing table.
+ */
+ ret = kvm_riscv_gstage_map_page(&gstage, pcache, fault_gpa,
+ fault_hfn << PAGE_SHIFT,
+ PAGE_SIZE, false, true,
+ out_map);
+ }
} else {
ret = kvm_riscv_gstage_map_page(&gstage, pcache, gpa, hfn << PAGE_SHIFT,
vma_pagesize, true, true, out_map);
+ if (ret == -EEXIST) {
+ /*
+ * Retry at 4K granularity for the original faulting GPA
+ * when a huge leaf cannot replace an existing table.
+ */
+ ret = kvm_riscv_gstage_map_page(&gstage, pcache, fault_gpa,
+ fault_hfn << PAGE_SHIFT,
+ PAGE_SIZE, true, true,
+ out_map);
+ }
}
if (ret)
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
next parent reply other threads:[~2026-08-15 10:01 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260815095548.860018-1-jinyu.tang@linux.dev>
2026-08-15 10:00 ` Jinyu Tang [this message]
2026-08-15 10:06 ` [PATCH v4 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY Jinyu Tang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260815100019.860693-1-jinyu.tang@linux.dev \
--to=jinyu.tang@linux.dev \
--cc=alex@ghiti.fr \
--cc=andrew.jones@oss.qualcomm.com \
--cc=anup@brainfault.org \
--cc=aou@eecs.berkeley.edu \
--cc=apatel@ventanamicro.com \
--cc=atish.patra@linux.dev \
--cc=conor.dooley@microchip.com \
--cc=jiangyifei@huawei.com \
--cc=kvm-riscv@lists.infradead.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=nutty.liu@hotmail.com \
--cc=palmer@dabbelt.com \
--cc=pbonzini@redhat.com \
--cc=pjw@kernel.org \
--cc=sashiko-bot@kernel.org \
--cc=seanjc@google.com \
--cc=shuah@kernel.org \
--cc=tjytimi@163.com \
--cc=yongxuan.wang@sifive.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox