* [PATCH v3 0/3] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, Jinyu Tang
This series adds RISC-V support for the generic KVM_PRE_FAULT_MEMORY
vcpu ioctl and enables the existing generic KVM selftest for RISC-V.
KVM_PRE_FAULT_MEMORY lets userspace ask KVM to populate stage-2 mappings
for a GPA range before running a vCPU that is expected to access that
range. x86 already supports the ioctl; RISC-V currently falls back to
normal first-touch G-stage faults.
Patch 1 implements the RISC-V arch hook using the existing G-stage map
path. Patch 2 fixes the RISC-V selftest page-table walker for Sv57,
which can be selected as the default guest mode. Patch 3 enables
pre_fault_memory_test for RISC-V.
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. RISC-V already initializes supported and
default guest modes from kvm_selftest_arch_init(), which is called by
the common kvm_selftest_init() constructor, as suggested by Sean.
Jinyu Tang (3):
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 | 3 ++
arch/riscv/kvm/mmu.c | 42 +++++++++++++++++++
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, 56 insertions(+)
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3 0/3] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, Jinyu Tang
This series adds RISC-V support for the generic KVM_PRE_FAULT_MEMORY
vcpu ioctl and enables the existing generic KVM selftest for RISC-V.
KVM_PRE_FAULT_MEMORY lets userspace ask KVM to populate stage-2 mappings
for a GPA range before running a vCPU that is expected to access that
range. x86 already supports the ioctl; RISC-V currently falls back to
normal first-touch G-stage faults.
Patch 1 implements the RISC-V arch hook using the existing G-stage map
path. Patch 2 fixes the RISC-V selftest page-table walker for Sv57,
which can be selected as the default guest mode. Patch 3 enables
pre_fault_memory_test for RISC-V.
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. RISC-V already initializes supported and
default guest modes from kvm_selftest_arch_init(), which is called by
the common kvm_selftest_init() constructor, as suggested by Sean.
Jinyu Tang (3):
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 | 3 ++
arch/riscv/kvm/mmu.c | 42 +++++++++++++++++++
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, 56 insertions(+)
--
2.43.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3 0/3] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, Jinyu Tang
This series adds RISC-V support for the generic KVM_PRE_FAULT_MEMORY
vcpu ioctl and enables the existing generic KVM selftest for RISC-V.
KVM_PRE_FAULT_MEMORY lets userspace ask KVM to populate stage-2 mappings
for a GPA range before running a vCPU that is expected to access that
range. x86 already supports the ioctl; RISC-V currently falls back to
normal first-touch G-stage faults.
Patch 1 implements the RISC-V arch hook using the existing G-stage map
path. Patch 2 fixes the RISC-V selftest page-table walker for Sv57,
which can be selected as the default guest mode. Patch 3 enables
pre_fault_memory_test for RISC-V.
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. RISC-V already initializes supported and
default guest modes from kvm_selftest_arch_init(), which is called by
the common kvm_selftest_init() constructor, as suggested by Sean.
Jinyu Tang (3):
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 | 3 ++
arch/riscv/kvm/mmu.c | 42 +++++++++++++++++++
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, 56 insertions(+)
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
2026-08-14 11:45 ` Jinyu Tang
(?)
@ 2026-08-14 11:45 ` Jinyu Tang
-1 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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>
---
v2 -> v3:
- Retry internally when the map path returns success without a visible
G-stage mapping, instead of exposing -EAGAIN. (Sashiko)
arch/riscv/kvm/Kconfig | 1 +
arch/riscv/kvm/gstage.c | 3 +++
arch/riscv/kvm/mmu.c | 42 +++++++++++++++++++++++++++++++++++++++++
arch/riscv/kvm/vm.c | 1 +
4 files changed, 47 insertions(+)
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 e5002cb9cbef..6bd8b8fd6ceb 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -280,6 +280,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 6035b5ec9503..33d4ba406b0d 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,48 @@ 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))
+ break;
+ }
+
+ map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
+ end = ALIGN_DOWN(range->gpa, map_size) + map_size;
+
+ 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
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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>
---
v2 -> v3:
- Retry internally when the map path returns success without a visible
G-stage mapping, instead of exposing -EAGAIN. (Sashiko)
arch/riscv/kvm/Kconfig | 1 +
arch/riscv/kvm/gstage.c | 3 +++
arch/riscv/kvm/mmu.c | 42 +++++++++++++++++++++++++++++++++++++++++
arch/riscv/kvm/vm.c | 1 +
4 files changed, 47 insertions(+)
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 e5002cb9cbef..6bd8b8fd6ceb 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -280,6 +280,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 6035b5ec9503..33d4ba406b0d 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,48 @@ 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))
+ break;
+ }
+
+ map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
+ end = ALIGN_DOWN(range->gpa, map_size) + map_size;
+
+ 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
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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>
---
v2 -> v3:
- Retry internally when the map path returns success without a visible
G-stage mapping, instead of exposing -EAGAIN. (Sashiko)
arch/riscv/kvm/Kconfig | 1 +
arch/riscv/kvm/gstage.c | 3 +++
arch/riscv/kvm/mmu.c | 42 +++++++++++++++++++++++++++++++++++++++++
arch/riscv/kvm/vm.c | 1 +
4 files changed, 47 insertions(+)
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 e5002cb9cbef..6bd8b8fd6ceb 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -280,6 +280,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 6035b5ec9503..33d4ba406b0d 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,48 @@ 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))
+ break;
+ }
+
+ map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
+ end = ALIGN_DOWN(range->gpa, map_size) + map_size;
+
+ 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] 13+ messages in thread
* [PATCH v3 2/3] KVM: selftests: Add RISC-V Sv57 page table indexing
2026-08-14 11:45 ` Jinyu Tang
(?)
@ 2026-08-14 11:45 ` Jinyu Tang
-1 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 2/3] KVM: selftests: Add RISC-V Sv57 page table indexing
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 2/3] KVM: selftests: Add RISC-V Sv57 page table indexing
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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] 13+ messages in thread
* [PATCH v3 3/3] KVM: selftests: Enable pre_fault_memory_test for RISC-V
2026-08-14 11:45 ` Jinyu Tang
(?)
@ 2026-08-14 11:45 ` Jinyu Tang
-1 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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>
---
v1 -> v2:
- Drop the per-test guest_modes_append_default() call from
pre_fault_memory_test.c. RISC-V already initializes supported and
default guest modes from kvm_selftest_arch_init(), which is called by
the common kvm_selftest_init() constructor, as suggested by Sean.
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] 13+ messages in thread
* [PATCH v3 3/3] KVM: selftests: Enable pre_fault_memory_test for RISC-V
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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>
---
v1 -> v2:
- Drop the per-test guest_modes_append_default() call from
pre_fault_memory_test.c. RISC-V already initializes supported and
default guest modes from kvm_selftest_arch_init(), which is called by
the common kvm_selftest_init() constructor, as suggested by Sean.
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
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 3/3] KVM: selftests: Enable pre_fault_memory_test for RISC-V
@ 2026-08-14 11:45 ` Jinyu Tang
0 siblings, 0 replies; 13+ messages in thread
From: Jinyu Tang @ 2026-08-14 11:45 UTC (permalink / raw)
To: Anup Patel, Anup Patel, Sean Christopherson
Cc: Paolo Bonzini, kvm, kvm-riscv, linux-riscv, linux-kernel,
Atish Patra, Paul Walmsley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Jinyu Tang, 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>
---
v1 -> v2:
- Drop the per-test guest_modes_append_default() call from
pre_fault_memory_test.c. RISC-V already initializes supported and
default guest modes from kvm_selftest_arch_init(), which is called by
the common kvm_selftest_init() constructor, as suggested by Sean.
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
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v3 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
2026-08-14 11:45 ` Jinyu Tang
(?)
(?)
@ 2026-08-14 12:04 ` sashiko-bot
-1 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-08-14 12:04 UTC (permalink / raw)
To: Jinyu Tang; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] The KVM_PRE_FAULT_MEMORY ioctl handler loops infinitely in the kernel if it encounters a HWPOISON page and the userspace thread has blocked SIGBUS.
- [Medium] kvm_arch_vcpu_pre_fault_memory() can silently skip requested pages and report false progress when mapping a split THP page.
Pre-existing issues:
- [High] Infinite VMExit page fault loop when a guest accesses an unaligned THP address on a split page table.
- [High] Physical page table leak when overwriting a lower-level page table directory with a huge page leaf PTE.
--
--- Patch [1]: [PATCH v3 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY ---
commit ac8ca417e02ba68eb7b7c58fbc637ee417dc2c72
Author: Jinyu Tang <jinyu.tang@linux.dev>
KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
This commit introduces the KVM_PRE_FAULT_MEMORY ioctl handler for RISC-V.
It reuses the existing G-stage fault mapping path with a read access to
populate KVM page tables before running a vCPU, looping until a mapping
is installed or an exit condition is met.
> diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
> index b0474fcf065aa..ebd1e8a4b9e38 100644
> --- a/arch/riscv/kvm/gstage.c
> +++ b/arch/riscv/kvm/gstage.c
> @@ -280,6 +280,9 @@ int kvm_riscv_gstage_map_page(...)
> } 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;
> }
> }
[Severity: High]
This isn't a bug introduced by this patch, but does this lead to an
infinite VMExit loop when a guest accesses an unaligned THP address on
a split page table?
During fault handling, transparent_hugepage_adjust() in kvm_riscv_mmu_map()
can silently overwrite the original faulting gpa with the 2MB-aligned
base address.
If the G-stage page table is currently split into 4KB PTEs, this block in
kvm_riscv_gstage_map_page() intentionally updates only the 4KB PTE at the
newly aligned gpa. The originally faulting 4KB page remains unmapped,
causing the guest to immediately fault again upon resumption.
[ ... ]
> out_map->pte = pfn_pte(PFN_DOWN(hpa), prot);
> out_map->pte = pte_mkdirty(out_map->pte);
>
> return kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
> }
[Severity: High]
This is a pre-existing issue, but does this leak physical page tables when
overwriting a lower-level page table directory with a huge page leaf PTE?
If 4KB leaf PTEs inside a THP-backed region are zapped (for example, via
MADV_DONTNEED) but the page directory remains, a subsequent fault triggers
a THP mapping. kvm_riscv_gstage_get_leaf() fails to find a leaf.
The code then falls through here to kvm_riscv_gstage_set_pte(), which blindly
overwrites the existing directory entry with a huge page leaf PTE. Because
freeing page tables is not yet supported, the orphaned child page tables
appear to be leaked.
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 8a0aa5e0e216e..c71c1ebb07857 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
[ ... ]
> + 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))
> + break;
> + }
[Severity: High]
Can this loop spin infinitely if the userspace thread blocks SIGBUS and
KVM encounters a hardware-poisoned page?
Looking at kvm_riscv_mmu_map(), it handles HWPOISON by calling
send_sig_mceerr() and returning 0 without populating out_map.
If the userspace thread has SIGBUS blocked, send_sig_mceerr() queues the
signal but might not set TIF_SIGPENDING. In that scenario, signal_pending()
won't catch the pending signal, out_map.pte remains empty, and the loop
will retry infinitely without yielding back to userspace.
> +
> + map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
> + end = ALIGN_DOWN(range->gpa, map_size) + map_size;
> +
> + return min_t(u64, range->size, end - range->gpa);
> +}
[Severity: Medium]
Does this miscalculate the mapped progress when handling a split THP page?
If transparent_hugepage_adjust() aligns the gpa down to the 2MB base and
kvm_riscv_gstage_map_page() falls back to a 4KB mapping, the 4KB PTE is
populated at the base address. out_map.addr is correctly set to this base.
However, the progress here is calculated using the original unaligned
range->gpa instead of out_map.addr. If the requested GPA was at an offset,
KVM might falsely report progress for the unmapped requested page while
actually mapping the unrequested base page.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260814114507.583424-1-jinyu.tang@linux.dev?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-08-14 12:04 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 11:45 [PATCH v3 0/3] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
2026-08-14 11:45 ` [PATCH v3 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
2026-08-14 12:04 ` sashiko-bot
2026-08-14 11:45 ` [PATCH v3 2/3] KVM: selftests: Add RISC-V Sv57 page table indexing Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
2026-08-14 11:45 ` [PATCH v3 3/3] KVM: selftests: Enable pre_fault_memory_test for RISC-V Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
2026-08-14 11:45 ` Jinyu Tang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.