From: Jinyu Tang <jinyu.tang@linux.dev>
To: Anup Patel <anup@brainfault.org>,
Anup Patel <apatel@ventanamicro.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>
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,
Atish Patra <atish.patra@linux.dev>,
Paul Walmsley <pjw@kernel.org>,
Paul Walmsley <paul.walmsley@sifive.com>,
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>, Jinyu Tang <tjytimi@163.com>,
Jinyu Tang <jinyu.tang@linux.dev>
Subject: [PATCH v2 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
Date: Wed, 12 Aug 2026 07:03:14 +0800 [thread overview]
Message-ID: <20260811230316.218770-2-jinyu.tang@linux.dev> (raw)
In-Reply-To: <20260811230316.218770-1-jinyu.tang@linux.dev>
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.
Unlike x86, RISC-V's G-stage fault path does not return a detailed
result such as RET_PF_FIXED or RET_PF_RETRY. Treat a successful call
that does not return a visible G-stage mapping as no progress, instead
of reporting that a page was prefaulted.
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 | 33 +++++++++++++++++++++++++++++++++
arch/riscv/kvm/vm.c | 1 +
4 files changed, 38 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..c96e21740c91 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,39 @@ 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;
+
+ ret = kvm_riscv_mmu_map(vcpu, memslot, range->gpa, hva, false, &out_map);
+ if (ret)
+ return ret;
+
+ if (!pte_val(out_map.pte))
+ return -EAGAIN;
+
+ 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
WARNING: multiple messages have this Message-ID (diff)
From: Jinyu Tang <jinyu.tang@linux.dev>
To: Anup Patel <anup@brainfault.org>,
Anup Patel <apatel@ventanamicro.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>
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,
Atish Patra <atish.patra@linux.dev>,
Paul Walmsley <pjw@kernel.org>,
Paul Walmsley <paul.walmsley@sifive.com>,
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>, Jinyu Tang <tjytimi@163.com>,
Jinyu Tang <jinyu.tang@linux.dev>
Subject: [PATCH v2 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
Date: Wed, 12 Aug 2026 07:03:14 +0800 [thread overview]
Message-ID: <20260811230316.218770-2-jinyu.tang@linux.dev> (raw)
In-Reply-To: <20260811230316.218770-1-jinyu.tang@linux.dev>
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.
Unlike x86, RISC-V's G-stage fault path does not return a detailed
result such as RET_PF_FIXED or RET_PF_RETRY. Treat a successful call
that does not return a visible G-stage mapping as no progress, instead
of reporting that a page was prefaulted.
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 | 33 +++++++++++++++++++++++++++++++++
arch/riscv/kvm/vm.c | 1 +
4 files changed, 38 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..c96e21740c91 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,39 @@ 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;
+
+ ret = kvm_riscv_mmu_map(vcpu, memslot, range->gpa, hva, false, &out_map);
+ if (ret)
+ return ret;
+
+ if (!pte_val(out_map.pte))
+ return -EAGAIN;
+
+ 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
WARNING: multiple messages have this Message-ID (diff)
From: Jinyu Tang <jinyu.tang@linux.dev>
To: Anup Patel <anup@brainfault.org>,
Anup Patel <apatel@ventanamicro.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>
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,
Atish Patra <atish.patra@linux.dev>,
Paul Walmsley <pjw@kernel.org>,
Paul Walmsley <paul.walmsley@sifive.com>,
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>, Jinyu Tang <tjytimi@163.com>,
Jinyu Tang <jinyu.tang@linux.dev>
Subject: [PATCH v2 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY
Date: Wed, 12 Aug 2026 07:03:14 +0800 [thread overview]
Message-ID: <20260811230316.218770-2-jinyu.tang@linux.dev> (raw)
In-Reply-To: <20260811230316.218770-1-jinyu.tang@linux.dev>
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.
Unlike x86, RISC-V's G-stage fault path does not return a detailed
result such as RET_PF_FIXED or RET_PF_RETRY. Treat a successful call
that does not return a visible G-stage mapping as no progress, instead
of reporting that a page was prefaulted.
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 | 33 +++++++++++++++++++++++++++++++++
arch/riscv/kvm/vm.c | 1 +
4 files changed, 38 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..c96e21740c91 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,39 @@ 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;
+
+ ret = kvm_riscv_mmu_map(vcpu, memslot, range->gpa, hva, false, &out_map);
+ if (ret)
+ return ret;
+
+ if (!pte_val(out_map.pte))
+ return -EAGAIN;
+
+ 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
next prev parent reply other threads:[~2026-08-11 23:03 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-11 23:03 [PATCH v2 0/3] KVM: riscv: Add KVM_PRE_FAULT_MEMORY support Jinyu Tang
2026-08-11 23:03 ` Jinyu Tang
2026-08-11 23:03 ` Jinyu Tang
2026-08-11 23:03 ` Jinyu Tang [this message]
2026-08-11 23:03 ` [PATCH v2 1/3] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY Jinyu Tang
2026-08-11 23:03 ` Jinyu Tang
2026-08-11 23:23 ` sashiko-bot
2026-08-11 23:03 ` [PATCH v2 2/3] KVM: selftests: Add RISC-V Sv57 page table indexing Jinyu Tang
2026-08-11 23:03 ` Jinyu Tang
2026-08-11 23:03 ` Jinyu Tang
2026-08-11 23:03 ` [PATCH v2 3/3] KVM: selftests: Enable pre_fault_memory_test for RISC-V Jinyu Tang
2026-08-11 23:03 ` Jinyu Tang
2026-08-11 23:03 ` 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=20260811230316.218770-2-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=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=paul.walmsley@sifive.com \
--cc=pbonzini@redhat.com \
--cc=pjw@kernel.org \
--cc=seanjc@google.com \
--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 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.