* [PATCH v4 RESEND 0/5] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support
@ 2026-08-15 10:28 Jinyu Tang
2026-08-15 10:31 ` [PATCH v4 RESEND 1/5] KVM: riscv: Avoid overwriting G-stage tables with huge leaves Jinyu Tang
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Jinyu Tang @ 2026-08-15 10:28 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Atish Patra
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-kselftest,
Paolo Bonzini, Sean Christopherson, Shuah Khan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Jinyu Tang, Jinyu Tang
Add RISC-V support for the generic KVM_PRE_FAULT_MEMORY ioctl.
Patch 1 and patch 2 fix existing G-stage huge-page corner cases. They
are included first because the prefault hook relies on the map path
reporting the mapping that actually covers the requested GPA.
Patch 3 adds the RISC-V arch hook for KVM_PRE_FAULT_MEMORY. Patch 4 adds
Sv57 indexing support to the RISC-V KVM selftest helpers, and patch 5
enables the generic pre_fault_memory_test for RISC-V.
Patch 1 folds the previously posted standalone G-stage table overwrite
fix into this series:
https://lore.kernel.org/kvm-riscv/20260814105752.565325-1-jinyu.tang@linux.dev/T/#u
Changes in v4 resend:
- Resend the full series because the previous v4 send was interrupted
and the kvm-riscv list archive did not show a complete thread. No
code changes.
Changes in v4:
- Fold the standalone G-stage non-leaf overwrite fix into this series.
- Avoid THP adjustment when the original faulting GPA already has an
existing 4K G-stage leaf.
- Return an error for HWPOISON instead of reporting success without a
visible G-stage mapping. (Sashiko)
Changes in v3:
- Retry internally when the map path returns success without a visible
G-stage mapping, instead of exposing -EAGAIN. (Sashiko)
Changes in v2:
- Drop the per-test guest_modes_append_default() call from
pre_fault_memory_test.c. (Sean)
Jinyu Tang (5):
KVM: riscv: Avoid overwriting G-stage tables with huge leaves
KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves
KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
KVM: selftests: Add RISC-V Sv57 page table indexing
KVM: selftests: Enable pre_fault_memory_test for RISC-V
arch/riscv/kvm/Kconfig | 1 +
arch/riscv/kvm/gstage.c | 9 ++
arch/riscv/kvm/mmu.c | 83 ++++++++++++++++++-
arch/riscv/kvm/vm.c | 1 +
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../selftests/kvm/include/riscv/processor.h | 6 ++
.../selftests/kvm/lib/riscv/processor.c | 2 +
7 files changed, 100 insertions(+), 3 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 RESEND 1/5] KVM: riscv: Avoid overwriting G-stage tables with huge leaves
2026-08-15 10:28 [PATCH v4 RESEND 0/5] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
@ 2026-08-15 10:31 ` Jinyu Tang
2026-08-15 10:32 ` [PATCH v4 RESEND 2/5] KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves Jinyu Tang
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Jinyu Tang @ 2026-08-15 10:31 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Atish Patra
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-kselftest,
Paolo Bonzini, Sean Christopherson, Shuah Khan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Jinyu Tang
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
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 RESEND 2/5] KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves
2026-08-15 10:28 [PATCH v4 RESEND 0/5] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
2026-08-15 10:31 ` [PATCH v4 RESEND 1/5] KVM: riscv: Avoid overwriting G-stage tables with huge leaves Jinyu Tang
@ 2026-08-15 10:32 ` Jinyu Tang
2026-08-15 10:46 ` sashiko-bot
2026-08-15 10:33 ` [PATCH v4 RESEND 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY Jinyu Tang
` (2 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Jinyu Tang @ 2026-08-15 10:32 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Atish Patra
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-kselftest,
Paolo Bonzini, Sean Christopherson, Shuah Khan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Jinyu Tang
When dirty logging is disabled after a G-stage PMD mapping has been
split, the fault path may see a 4K G-stage leaf while the backing host
page is still THP-backed. The existing kvm_riscv_gstage_map_page()
comment says that this path should update the small leaf and leave huge
mapping recovery to a later ioctl path.
However, transparent_hugepage_adjust() runs before that G-stage lookup
and rewrites the fault GPA to the PMD base. If the original fault is not
at the PMD base, the lookup can find and update the wrong 4K leaf.
Check the original fault GPA in transparent_hugepage_adjust(). If it
already has a 4K G-stage leaf, skip THP adjustment and keep handling the
fault at PAGE_SIZE granularity.
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
arch/riscv/kvm/mmu.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index bfd6168ebe30..2fabcd409991 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -500,10 +500,21 @@ static int get_hva_mapping_size(struct kvm *kvm,
static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
struct kvm_memory_slot *memslot,
+ struct kvm_gstage *gstage,
unsigned long hva,
kvm_pfn_t *hfnp, gpa_t *gpa)
{
kvm_pfn_t hfn = *hfnp;
+ u32 ptep_level;
+ pte_t *ptep;
+
+ /*
+ * Keep the existing split G-stage leaf and update the original
+ * faulting 4K page in the vCPU fault path.
+ */
+ if (kvm_riscv_gstage_get_leaf(gstage, *gpa, &ptep, &ptep_level) &&
+ !ptep_level)
+ return PAGE_SIZE;
/*
* Make sure the adjustment is done only for THP pages. Also make
@@ -730,7 +741,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
* so do not promote them through the THP helper.
*/
if (!logging && !is_hugetlb && vma_pagesize == PAGE_SIZE)
- vma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, &hfn, &gpa);
+ vma_pagesize = transparent_hugepage_adjust(kvm, memslot, &gstage,
+ hva, &hfn, &gpa);
if (writable) {
mark_page_dirty_in_slot(kvm, memslot, gfn);
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 RESEND 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
2026-08-15 10:28 [PATCH v4 RESEND 0/5] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
2026-08-15 10:31 ` [PATCH v4 RESEND 1/5] KVM: riscv: Avoid overwriting G-stage tables with huge leaves Jinyu Tang
2026-08-15 10:32 ` [PATCH v4 RESEND 2/5] KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves Jinyu Tang
@ 2026-08-15 10:33 ` Jinyu Tang
2026-08-15 10:47 ` sashiko-bot
2026-08-15 10:34 ` [PATCH v4 RESEND 4/5] KVM: selftests: Add RISC-V Sv57 page table indexing Jinyu Tang
2026-08-15 10:34 ` [PATCH v4 RESEND 5/5] KVM: selftests: Enable pre_fault_memory_test for RISC-V Jinyu Tang
4 siblings, 1 reply; 8+ messages in thread
From: Jinyu Tang @ 2026-08-15 10:33 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Atish Patra
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-kselftest,
Paolo Bonzini, Sean Christopherson, Shuah Khan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Jinyu Tang
The generic KVM_PRE_FAULT_MEMORY ioctl lets userspace populate KVM page
tables before running a vCPU over a GPA range. x86 already supports the
ioctl, but RISC-V does not expose the capability and has no arch hook.
Add the RISC-V arch hook and reuse the existing G-stage fault mapping
path with a read access. Report progress using the G-stage mapping
returned by the map path, so the ioctl can advance by the actual leaf
size that covers the requested GPA. Retry until a mapping is installed
or a signal, VM-dead request, or real error is observed.
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
arch/riscv/kvm/Kconfig | 1 +
arch/riscv/kvm/gstage.c | 3 +++
arch/riscv/kvm/mmu.c | 45 ++++++++++++++++++++++++++++++++++++++++-
arch/riscv/kvm/vm.c | 1 +
4 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig
index ec2cee0a39e0..8ac209e8ac87 100644
--- a/arch/riscv/kvm/Kconfig
+++ b/arch/riscv/kvm/Kconfig
@@ -28,6 +28,7 @@ config KVM
select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_GENERIC_HARDWARE_ENABLING
+ select KVM_GENERIC_PRE_FAULT_MEMORY
select KVM_MMIO
select VIRT_XFER_TO_GUEST_WORK
select SCHED_INFO
diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index 54d45addf18f..dff315dfd24e 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -286,6 +286,9 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
out_map->level, true);
} else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) {
kvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot);
+ out_map->addr = ALIGN_DOWN(gpa, page_size);
+ out_map->level = ptep_level;
+ out_map->pte = ptep_get(ptep);
return 0;
}
}
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 2fabcd409991..f6ca86da53eb 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -717,7 +717,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
if (hfn == KVM_PFN_ERR_HWPOISON) {
send_sig_mceerr(BUS_MCEERR_AR, (void __user *)hva,
vma_pageshift, current);
- return 0;
+ return -EFAULT;
}
if (is_error_noslot_pfn(hfn))
return -EFAULT;
@@ -782,6 +782,49 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
return ret;
}
+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
+ struct kvm_pre_fault_memory *range)
+{
+ struct kvm_gstage_mapping out_map = { 0 };
+ struct kvm_memory_slot *memslot;
+ unsigned long map_size;
+ unsigned long hva;
+ gpa_t end;
+ gfn_t gfn;
+ int ret;
+
+ gfn = gpa_to_gfn(range->gpa);
+ memslot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
+ if (!memslot)
+ return -ENOENT;
+
+ hva = gfn_to_hva_memslot_prot(memslot, gfn, NULL);
+ if (kvm_is_error_hva(hva))
+ return -ENOENT;
+
+ for (;;) {
+ if (signal_pending(current))
+ return -EINTR;
+
+ if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu))
+ return -EIO;
+
+ cond_resched();
+ ret = kvm_riscv_mmu_map(vcpu, memslot, range->gpa, hva, false, &out_map);
+ if (ret)
+ return ret;
+
+ if (!pte_val(out_map.pte))
+ continue;
+
+ map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
+ end = out_map.addr + map_size;
+ break;
+ }
+
+ return min_t(u64, range->size, end - range->gpa);
+}
+
int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm)
{
struct page *pgd_page;
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index a9f083feeb76..58500a19b33b 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -187,6 +187,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_MP_STATE:
case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_SET_GUEST_DEBUG:
+ case KVM_CAP_PRE_FAULT_MEMORY:
r = 1;
break;
case KVM_CAP_NR_VCPUS:
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 RESEND 4/5] KVM: selftests: Add RISC-V Sv57 page table indexing
2026-08-15 10:28 [PATCH v4 RESEND 0/5] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
` (2 preceding siblings ...)
2026-08-15 10:33 ` [PATCH v4 RESEND 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY Jinyu Tang
@ 2026-08-15 10:34 ` Jinyu Tang
2026-08-15 10:34 ` [PATCH v4 RESEND 5/5] KVM: selftests: Enable pre_fault_memory_test for RISC-V Jinyu Tang
4 siblings, 0 replies; 8+ messages in thread
From: Jinyu Tang @ 2026-08-15 10:34 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Atish Patra
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-kselftest,
Paolo Bonzini, Sean Christopherson, Shuah Khan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Jinyu Tang
RISC-V selftests can create guests with five page-table levels, for
example when the selected guest mode is Sv57. The RISC-V page-table
walker only had index arrays for levels 0 through 3, so
virt_arch_pg_map() indexed past the end of the arrays when level 4 was
used.
Add the missing L4 index mask and shift so selftests can build guest
page tables for Sv57 VMs.
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
tools/testing/selftests/kvm/include/riscv/processor.h | 3 +++
tools/testing/selftests/kvm/lib/riscv/processor.c | 2 ++
2 files changed, 5 insertions(+)
diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h
index e3acf2ae9881..abde3c71c891 100644
--- a/tools/testing/selftests/kvm/include/riscv/processor.h
+++ b/tools/testing/selftests/kvm/include/riscv/processor.h
@@ -127,6 +127,9 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handl
void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler);
+/* L4 index Bit[56:48] */
+#define PGTBL_L4_INDEX_MASK 0x01FF000000000000ULL
+#define PGTBL_L4_INDEX_SHIFT 48
/* L3 index Bit[47:39] */
#define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL
#define PGTBL_L3_INDEX_SHIFT 39
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index ded5429f3448..b4d41a407553 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -43,6 +43,7 @@ static u64 pte_index_mask[] = {
PGTBL_L1_INDEX_MASK,
PGTBL_L2_INDEX_MASK,
PGTBL_L3_INDEX_MASK,
+ PGTBL_L4_INDEX_MASK,
};
static u32 pte_index_shift[] = {
@@ -50,6 +51,7 @@ static u32 pte_index_shift[] = {
PGTBL_L1_INDEX_SHIFT,
PGTBL_L2_INDEX_SHIFT,
PGTBL_L3_INDEX_SHIFT,
+ PGTBL_L4_INDEX_SHIFT,
};
static u64 pte_index(struct kvm_vm *vm, gva_t gva, int level)
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 RESEND 5/5] KVM: selftests: Enable pre_fault_memory_test for RISC-V
2026-08-15 10:28 [PATCH v4 RESEND 0/5] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
` (3 preceding siblings ...)
2026-08-15 10:34 ` [PATCH v4 RESEND 4/5] KVM: selftests: Add RISC-V Sv57 page table indexing Jinyu Tang
@ 2026-08-15 10:34 ` Jinyu Tang
4 siblings, 0 replies; 8+ messages in thread
From: Jinyu Tang @ 2026-08-15 10:34 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Atish Patra
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-kselftest,
Paolo Bonzini, Sean Christopherson, Shuah Khan, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Jinyu Tang
RISC-V now supports KVM_PRE_FAULT_MEMORY, so include the generic
pre_fault_memory_test in the RISC-V KVM selftest build.
The test uses PAGE_SIZE from the architecture processor header. Define
the normal 4K RISC-V selftest page size so the generic test can build
for RISC-V.
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
tools/testing/selftests/kvm/include/riscv/processor.h | 3 +++
2 files changed, 4 insertions(+)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 6fc34e9bf8e1..ac64ac92fd4b 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -225,6 +225,7 @@ TEST_GEN_PROGS_riscv += coalesced_io_test
TEST_GEN_PROGS_riscv += dirty_log_perf_test
TEST_GEN_PROGS_riscv += get-reg-list
TEST_GEN_PROGS_riscv += mmu_stress_test
+TEST_GEN_PROGS_riscv += pre_fault_memory_test
TEST_GEN_PROGS_riscv += rseq_test
TEST_GEN_PROGS_riscv += steal_time
diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h
index abde3c71c891..70487c8ed155 100644
--- a/tools/testing/selftests/kvm/include/riscv/processor.h
+++ b/tools/testing/selftests/kvm/include/riscv/processor.h
@@ -12,6 +12,9 @@
#include <asm/vdso/processor.h>
#include "kvm_util.h"
+#define PAGE_SHIFT 12
+#define PAGE_SIZE BIT_ULL(PAGE_SHIFT)
+
#define INSN_OPCODE_MASK 0x007c
#define INSN_OPCODE_SHIFT 2
#define INSN_OPCODE_SYSTEM 28
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v4 RESEND 2/5] KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves
2026-08-15 10:32 ` [PATCH v4 RESEND 2/5] KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves Jinyu Tang
@ 2026-08-15 10:46 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-15 10:46 UTC (permalink / raw)
To: Jinyu Tang; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The patch's fix for an infinite page fault livelock is incomplete. It fails to detect a split THP when the specific faulting GPA lacks a valid 4K leaf, leading to an incorrect PMD alignment and a continuing infinite loop.
--
--- Patch [2]: [PATCH v4 RESEND 2/5] KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves ---
commit e6651e4debdd3eb4a9adeb5c1e519831130009d2
Author: Jinyu Tang <jinyu.tang@linux.dev>
KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves
This commit attempts to fix a page fault handling issue where
transparent_hugepage_adjust() rewrites the fault GPA to the PMD base,
causing the wrong 4K leaf to be updated. It checks if the original fault
GPA already has a 4K G-stage leaf, and if so, skips THP adjustment.
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index bfd6168ebe308..2fabcd4099919 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
[ ... ]
> @@ -500,10 +500,21 @@ static int get_hva_mapping_size(struct kvm *kvm,
>
> static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
> struct kvm_memory_slot *memslot,
> + struct kvm_gstage *gstage,
> unsigned long hva,
> kvm_pfn_t *hfnp, gpa_t *gpa)
> {
> kvm_pfn_t hfn = *hfnp;
> + u32 ptep_level;
> + pte_t *ptep;
> +
> + /*
> + * Keep the existing split G-stage leaf and update the original
> + * faulting 4K page in the vCPU fault path.
> + */
> + if (kvm_riscv_gstage_get_leaf(gstage, *gpa, &ptep, &ptep_level) &&
> + !ptep_level)
> + return PAGE_SIZE;
[Severity: High]
This is a pre-existing issue, but does the fix remain incomplete when the
specific faulting GPA lacks a valid 4K leaf?
If the guest accesses a 4K page within a THP-backed region during dirty
logging, it gets faulted in. If another page in that same split PMD directory
remains unmapped when dirty logging is disabled, what happens when the guest
eventually faults on the unmapped offset?
In that scenario, kvm_riscv_gstage_get_leaf() for the unmapped GPA returns
false. This allows transparent_hugepage_adjust() to fall through and align the
GPA to the PMD base.
When kvm_riscv_gstage_map_page() is subsequently called with the PMD-aligned
GPA and PMD_SIZE, it finds the existing 4K leaf at the PMD base. Because the
PFNs match, it updates the protection of the base leaf and returns success,
without mapping the originally faulting GPA or replacing the split table.
Can this result in an infinite page fault loop since the faulted page is
never actually mapped?
>
> /*
> * Make sure the adjustment is done only for THP pages. Also make
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260815102833.864330-1-jinyu.tang@linux.dev?part=2
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 RESEND 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
2026-08-15 10:33 ` [PATCH v4 RESEND 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY Jinyu Tang
@ 2026-08-15 10:47 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-15 10:47 UTC (permalink / raw)
To: Jinyu Tang; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Modifying the HWPOISON path in `kvm_riscv_mmu_map()` to return `-EFAULT` breaks standard `KVM_RUN` memory error handling.
- [High] Incorrect address and boundary calculation for `out_map.addr` causes KVM to skip pre-faulting requested memory or underflow range calculations.
--
--- Patch [3]: [PATCH v4 RESEND 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY ---
commit 28eceecf0e650b3722970e6824e30848edb82b44
Author: Jinyu Tang <jinyu.tang@linux.dev>
KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
The generic KVM_PRE_FAULT_MEMORY ioctl lets userspace populate KVM page
tables before running a vCPU over a GPA range. This commit implements the
arch hook for RISC-V and reuses the G-stage fault mapping path.
> diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
> index 54d45addf18f9..dff315dfd24ed 100644
> --- a/arch/riscv/kvm/gstage.c
> +++ b/arch/riscv/kvm/gstage.c
> @@ -286,6 +286,9 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
> out_map->level, true);
> } else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) {
> kvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot);
> + out_map->addr = ALIGN_DOWN(gpa, page_size);
> + out_map->level = ptep_level;
[Severity: High]
When pre-faulting a range backed by THP, could aligning out_map->addr to the
huge page size while setting out_map->level to the existing leaf size (e.g.,
4KB) cause an underflow later?
If out_map->addr is aligned to a 2MB boundary in kvm_riscv_gstage_map_page(),
but the map_size is calculated using the 4KB level in
kvm_arch_vcpu_pre_fault_memory():
map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
end = out_map.addr + map_size;
The calculated end might be less than range->gpa. For example, if range->gpa
is (2MB_aligned_gpa + 8KB), then (end - range->gpa) would underflow to a
massive unsigned value, causing the ioctl to silently return range->size and
terminate early without actually pre-faulting the requested memory.
> + out_map->pte = ptep_get(ptep);
> return 0;
> }
> }
[ ... ]
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2fabcd4099919..f6ca86da53eb8 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -717,7 +717,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
> if (hfn == KVM_PFN_ERR_HWPOISON) {
> send_sig_mceerr(BUS_MCEERR_AR, (void __user *)hva,
> vma_pageshift, current);
> - return 0;
> + return -EFAULT;
[Severity: Critical]
Does returning -EFAULT here break the standard KVM_RUN memory error handling?
By returning -EFAULT instead of 0 for KVM_PFN_ERR_HWPOISON, KVM_RUN will exit
to userspace with -EFAULT. Userspace VMMs (like QEMU) typically treat an
-EFAULT from KVM_RUN as an unrecoverable hypervisor error and will abruptly
terminate the VM.
Returning 0 allows the run loop to exit cleanly with -EINTR, ensuring the VMM
can handle the queued SIGBUS (via send_sig_mceerr()), isolate the poisoned
page, and inject a Machine Check Exception into the guest.
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260815102833.864330-1-jinyu.tang@linux.dev?part=3
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-15 10:47 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-15 10:28 [PATCH v4 RESEND 0/5] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
2026-08-15 10:31 ` [PATCH v4 RESEND 1/5] KVM: riscv: Avoid overwriting G-stage tables with huge leaves Jinyu Tang
2026-08-15 10:32 ` [PATCH v4 RESEND 2/5] KVM: riscv: Avoid THP adjustment for existing 4K G-stage leaves Jinyu Tang
2026-08-15 10:46 ` sashiko-bot
2026-08-15 10:33 ` [PATCH v4 RESEND 3/5] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY Jinyu Tang
2026-08-15 10:47 ` sashiko-bot
2026-08-15 10:34 ` [PATCH v4 RESEND 4/5] KVM: selftests: Add RISC-V Sv57 page table indexing Jinyu Tang
2026-08-15 10:34 ` [PATCH v4 RESEND 5/5] KVM: selftests: Enable pre_fault_memory_test for RISC-V Jinyu Tang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox