* [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM
@ 2026-05-26 12:50 fangyu.yu
2026-05-26 12:50 ` [PATCH v2 1/7] riscv: Add kexec trampoline text section to vmlinux.lds.S fangyu.yu
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
In a RISC-V kernel, both kexec and crashdump need to hand off execution
to the next kernel after tearing down the current kernel address space.
However, under virtualization the guest uses two-stage address
translation, and pc does not jump to stvec after setting satp to zero,
so the legacy single-step "csrw satp,0 + stvec redirect" sequence
traps with "kvm run failed Operation not supported" and the VCPU dies.
v1 (Link below) addressed the crash path only. v2 extends the same
mechanism to the normal kexec path (kexec -l/-e) and reworks the
trampoline as a shared piece of infrastructure between the two paths.
This patch set introduces a dedicated kexec trampoline text section and
builds a minimal trampoline page table for it. Both handoffs are then
reworked into a two-pass trampoline:
1. First enter via the kernel VA, install the trampoline page table,
and jump to the trampoline VA(=PA) of the entry stub;
2. Continue execution with PC already on a PA, drop SATP with
csrw satp,0 (now safe because PC re-anchoring is moot), and
jump directly to the target -- either the crash kernel entry
(crash path) or the per-image control_code_buffer that runs
the relocate body with SATP=0 throughout (normal path).
With this, both kexec and crashdump in RISC-V guests become robust
against the two-stage translation.
Tested on QEMU virt under two configurations:
* HS-mode bare (QEMU TCG) -- regression check
- normal kexec: kexec -l/-e succeeds, second kernel boots and
prints the userspace SECOND BOOT marker.
- crash kdump: panic triggers crash kernel boot, /proc/vmcore
opens cleanly in crash and shows the panic
backtrace.
* VS-mode (L0 x86 + QEMU TCG -> L1 riscv64 + KVM -> L2)
Before this series, both paths die with
kvm run failed Operation not supported
and an all-zero M-mode register dump on the SATP transition.
After this series, both paths succeed end-to-end and the
vmcore opens cleanly in crash.
---
Changes in v2:
- Extend the trampoline mechanism to the normal kexec path; the
legacy stvec trick in riscv_kexec_relocate (csrw satp,0 followed
by jr s6 to land at PA) is replaced by a small wrapper
riscv_kexec_relocate_entry in .kexec.tramp.text that performs
the same two-step transition used by the crash path and then
hands off to the PA of control_code_buffer.
- Page-align both ends of the .kexec.tramp.text section so no
.rodata neighbour can leak into the identity-mapped executable
trampoline page, and assert the section fits within one page.
- In machine_kexec() pin t3 = 0 and the call arguments (a0..a4)
to their ABI registers via local register asm variables and
perform the final jr inside the inline asm block, so the
compiler can never insert a scratch use of t3 between the
argument setup and the trampoline entry. The bare
"asm volatile ("li t3, 0" ::: "t3")" placebo used in v1 is
not actually a guarantee.
- Link to v1:
https://lore.kernel.org/linux-riscv/20260324114527.91494-1-fangyu.yu@linux.alibaba.com/
Fangyu Yu (7):
riscv: Add kexec trampoline text section to vmlinux.lds.S
riscv: kexec: Place norelocate trampoline into .kexec.tramp.text
riscv: kexec: Build trampoline page tables for crash kernel entry
riscv: kexec: Switch to trampoline page table before norelocate
riscv: kexec: Always build the trampoline page table
riscv: kexec: Add the relocate-trampoline wrapper
riscv: kexec: Route normal kexec through the trampoline page table
arch/riscv/include/asm/kexec.h | 5 ++
arch/riscv/kernel/image-vars.h | 14 ++++
arch/riscv/kernel/kexec_relocate.S | 97 +++++++++++++++++------
arch/riscv/kernel/machine_kexec.c | 123 +++++++++++++++++++++++++++--
arch/riscv/kernel/vmlinux.lds.S | 1 +
5 files changed, 209 insertions(+), 31 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/7] riscv: Add kexec trampoline text section to vmlinux.lds.S
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
@ 2026-05-26 12:50 ` fangyu.yu
2026-05-26 12:50 ` [PATCH v2 2/7] riscv: kexec: Place norelocate trampoline into .kexec.tramp.text fangyu.yu
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
When CONFIG_KEXEC_CORE is enabled, add a dedicated .kexec.tramp.text
area to the RISC-V kernel linker script.
This introduces a KEXEC_TRAMP_TEXT linker snippet in image-vars.h and
uses it from vmlinux.lds.S to:
- align both the start and the end to PAGE_SIZE
- define __kexec_tramp_text_start/__kexec_tramp_text_end
- KEEP all .kexec.tramp.text* input sections
- ASSERT the trampoline text fits within one page
The end-of-section page alignment guarantees that the trampoline page,
which is later identity-mapped as PAGE_KERNEL_EXEC, contains nothing but
the trampoline code and padding (no shared neighbour data).
When kexec is disabled, KEXEC_TRAMP_TEXT expands to nothing.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kernel/image-vars.h | 14 ++++++++++++++
arch/riscv/kernel/vmlinux.lds.S | 1 +
2 files changed, 15 insertions(+)
diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
index 3bd9d06a8b8f..35ee3f059afa 100644
--- a/arch/riscv/kernel/image-vars.h
+++ b/arch/riscv/kernel/image-vars.h
@@ -34,4 +34,18 @@ __efistub_sysfb_primary_display = sysfb_primary_display;
#endif
+#ifdef CONFIG_KEXEC_CORE
+#define KEXEC_TRAMP_TEXT \
+ . = ALIGN(PAGE_SIZE); \
+ __kexec_tramp_text_start = .; \
+ KEEP(*(.kexec.tramp.text)) \
+ KEEP(*(.kexec.tramp.text.*)) \
+ __kexec_tramp_text_end = .; \
+ ASSERT((__kexec_tramp_text_end - __kexec_tramp_text_start) <= PAGE_SIZE, \
+ ".kexec.tramp.text exceeds 4K"); \
+ . = ALIGN(PAGE_SIZE);
+#else
+#define KEXEC_TRAMP_TEXT /* nothing */
+#endif
+
#endif /* __RISCV_KERNEL_IMAGE_VARS_H */
diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
index 1f4f8496941a..fc7758e5b819 100644
--- a/arch/riscv/kernel/vmlinux.lds.S
+++ b/arch/riscv/kernel/vmlinux.lds.S
@@ -41,6 +41,7 @@ SECTIONS
ENTRY_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
+ KEXEC_TRAMP_TEXT
_etext = .;
}
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/7] riscv: kexec: Place norelocate trampoline into .kexec.tramp.text
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
2026-05-26 12:50 ` [PATCH v2 1/7] riscv: Add kexec trampoline text section to vmlinux.lds.S fangyu.yu
@ 2026-05-26 12:50 ` fangyu.yu
2026-05-26 12:50 ` [PATCH v2 3/7] riscv: kexec: Build trampoline page tables for crash kernel entry fangyu.yu
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Move riscv_kexec_norelocate out of the generic .text section and into
a dedicated executable trampoline section, .kexec.tramp.text.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/include/asm/kexec.h | 4 ++++
arch/riscv/kernel/kexec_relocate.S | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h
index b9ee8346cc8c..6466c1f00d41 100644
--- a/arch/riscv/include/asm/kexec.h
+++ b/arch/riscv/include/asm/kexec.h
@@ -75,4 +75,8 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
unsigned long cmdline_len);
#endif
+#ifndef __ASSEMBLY__
+extern char __kexec_tramp_text_start[];
+#endif
+
#endif
diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index de0a4b35d01e..af6b99f5b0fd 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -147,7 +147,7 @@ riscv_kexec_relocate_end:
/* Used for jumping to crashkernel */
-.section ".text"
+.section ".kexec.tramp.text", "ax"
SYM_CODE_START(riscv_kexec_norelocate)
/*
* s0: (const) Phys address to jump to
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 3/7] riscv: kexec: Build trampoline page tables for crash kernel entry
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
2026-05-26 12:50 ` [PATCH v2 1/7] riscv: Add kexec trampoline text section to vmlinux.lds.S fangyu.yu
2026-05-26 12:50 ` [PATCH v2 2/7] riscv: kexec: Place norelocate trampoline into .kexec.tramp.text fangyu.yu
@ 2026-05-26 12:50 ` fangyu.yu
2026-05-26 12:50 ` [PATCH v2 4/7] riscv: kexec: Switch to trampoline page table before norelocate fangyu.yu
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Crash kexec uses riscv_kexec_norelocate as a trampoline to jump into
the crashkernel. Add a small helper to build dedicated 4KB page tables
that map the trampoline page as executable.
Two mappings are installed:
- VA(__kexec_tramp_text_start) -> PA(__kexec_tramp_text_start)
- PA(__kexec_tramp_text_start) -> PA(__kexec_tramp_text_start)
This allows the trampoline to run regardless of whether it is entered
via its linked virtual address or its physical address.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kernel/machine_kexec.c | 67 +++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 2306ce3e5f22..9b4b495e7c15 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -18,6 +18,65 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
+static pgd_t kexec_tramp_pgd[PTRS_PER_PGD] __aligned(PAGE_SIZE);
+static p4d_t kexec_tramp_p4d[PTRS_PER_P4D] __aligned(PAGE_SIZE);
+static pud_t kexec_tramp_pud[PTRS_PER_PUD] __aligned(PAGE_SIZE);
+static pmd_t kexec_tramp_pmd[PTRS_PER_PMD] __aligned(PAGE_SIZE);
+static pte_t kexec_tramp_pte[PTRS_PER_PTE] __aligned(PAGE_SIZE);
+static p4d_t kexec_tramp_p4d2[PTRS_PER_P4D] __aligned(PAGE_SIZE);
+static pud_t kexec_tramp_pud2[PTRS_PER_PUD] __aligned(PAGE_SIZE);
+static pmd_t kexec_tramp_pmd2[PTRS_PER_PMD] __aligned(PAGE_SIZE);
+static pte_t kexec_tramp_pte2[PTRS_PER_PTE] __aligned(PAGE_SIZE);
+
+static void map_tramp_page(p4d_t *p4ds, pud_t *puds, pmd_t *pmds, pte_t *ptes,
+ unsigned long va, unsigned long pa)
+{
+ pgd_t *pgd = (pgd_t *)kexec_tramp_pgd + pgd_index(va);
+ pmd_t *pmd;
+
+ if (pgtable_l5_enabled) {
+ p4d_t *p4d;
+
+ set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa_symbol(p4ds)), PAGE_TABLE));
+ p4d = (p4d_t *)p4ds + p4d_index(va);
+ if (pgtable_l4_enabled)
+ set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa_symbol(puds)),
+ PAGE_TABLE));
+ else
+ set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa_symbol(pmds)),
+ PAGE_TABLE));
+ } else {
+ set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa_symbol(puds)), PAGE_TABLE));
+ }
+
+ if (pgtable_l4_enabled) {
+ pud_t *pud = (pud_t *)puds + pud_index(va);
+
+ set_pud(pud, pfn_pud(PFN_DOWN(__pa_symbol(pmds)), PAGE_TABLE));
+ pmd = (pmd_t *)pmds + pmd_index(va);
+ } else {
+ pmd = (pmd_t *)puds + pmd_index(va);
+ }
+ set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa_symbol(ptes)), PAGE_TABLE));
+
+ set_pte((pte_t *)ptes + pte_index(va),
+ pfn_pte(PFN_DOWN(pa), PAGE_KERNEL_EXEC));
+}
+
+static void riscv_kexec_build_tramp(unsigned long va, unsigned long pa)
+{
+ /* VA -> PA: map the trampoline page via its kernel VA. */
+ map_tramp_page(kexec_tramp_p4d, kexec_tramp_pud,
+ kexec_tramp_pmd, kexec_tramp_pte, va, pa);
+
+ /*
+ * PA -> PA: identity-map the same page so the second-pass code
+ * can keep executing after the kernel VA mapping is dropped.
+ */
+ map_tramp_page(kexec_tramp_p4d2, kexec_tramp_pud2,
+ kexec_tramp_pmd2, kexec_tramp_pte2, pa, pa);
+}
+
/*
* machine_kexec_prepare - Initialize kexec
*
@@ -73,6 +132,14 @@ machine_kexec_prepare(struct kimage *image)
/* Mark the control page executable */
set_memory_x((unsigned long) control_code_buffer, 1);
+ } else {
+ /*
+ * Crash kexec uses riscv_kexec_norelocate as a trampoline.
+ * Pre-build the trampoline page tables here so the panic
+ * path only has to switch satp and jump.
+ */
+ riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
+ __pa_symbol(__kexec_tramp_text_start));
}
return 0;
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 4/7] riscv: kexec: Switch to trampoline page table before norelocate
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
` (2 preceding siblings ...)
2026-05-26 12:50 ` [PATCH v2 3/7] riscv: kexec: Build trampoline page tables for crash kernel entry fangyu.yu
@ 2026-05-26 12:50 ` fangyu.yu
2026-05-26 12:50 ` [PATCH v2 5/7] riscv: kexec: Always build the trampoline page table fangyu.yu
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Make riscv_kexec_norelocate a two-pass trampoline so it can
drop the kernel page tables while still executing from a
mapped address.
On the first entry, t3 is initialized to 0 by machine_kexec().
Loads the physical address of riscv_kexec_norelocate and the
trampoline SATP value, switches to the trampoline page table,
and jumps to the trampoline VA(=PA).
On the second entry, t3 contains the physical address of
riscv_kexec_norelocate, so the PC comparison matches and
execution continues under trampoline VA(=PA).
Since the trampoline page table is already active, replace the
previous stvec-based handoff with a direct jump to the target
entry (jr a2).
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kernel/kexec_relocate.S | 32 ++++++++++++++++++----
arch/riscv/kernel/machine_kexec.c | 44 +++++++++++++++++++++++++++---
2 files changed, 67 insertions(+), 9 deletions(-)
diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index af6b99f5b0fd..2b9892bf04f2 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -147,13 +147,35 @@ riscv_kexec_relocate_end:
/* Used for jumping to crashkernel */
+.extern kexec_tramp_satp
+.extern riscv_kexec_norelocate_pa
.section ".kexec.tramp.text", "ax"
SYM_CODE_START(riscv_kexec_norelocate)
+ /*
+ * Two-pass entry:
+ * - 1st entry: t3 == 0 (initialized by machine_kexec()).
+ *
+ * - 2nd entry: t3 holds the physical address of
+ * riscv_kexec_norelocate, so auipc matches t3 and we fall through
+ * to label 1 to continue execution under trampoline VA(=PA).
+ */
+ auipc t0, 0
+ beq t0, t3, 1f
+
+ la t0, riscv_kexec_norelocate_pa
+ REG_L t3, 0(t0)
+ la t0, kexec_tramp_satp
+ REG_L t1, 0(t0)
+ csrw CSR_SATP, t1
+ sfence.vma x0, x0
+
+ jr t3
/*
* s0: (const) Phys address to jump to
* s1: (const) Phys address of the FDT image
* s2: (const) The hartid of the current hart
*/
+1:
mv s0, a1
mv s1, a2
mv s2, a3
@@ -199,13 +221,13 @@ SYM_CODE_START(riscv_kexec_norelocate)
csrw CSR_SSCRATCH, zero
/*
- * Switch to physical addressing
- * This will also trigger a jump to CSR_STVEC
- * which in this case is the address of the new
- * kernel.
+ * We are already executing from the trampoline VA with the trampoline
+ * page table installed, so there is no need to rely on the old flow
+ * of programming stvec and taking the implicit trap on SATP switch.
+ * Jump directly to the target entry instead.
*/
- csrw CSR_STVEC, a2
csrw CSR_SATP, zero
+ jr a2
SYM_CODE_END(riscv_kexec_norelocate)
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 9b4b495e7c15..00fdc42d650d 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -18,6 +18,8 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
+unsigned long kexec_tramp_satp;
+unsigned long riscv_kexec_norelocate_pa;
static pgd_t kexec_tramp_pgd[PTRS_PER_PGD] __aligned(PAGE_SIZE);
static p4d_t kexec_tramp_p4d[PTRS_PER_P4D] __aligned(PAGE_SIZE);
static pud_t kexec_tramp_pud[PTRS_PER_PUD] __aligned(PAGE_SIZE);
@@ -135,11 +137,17 @@ machine_kexec_prepare(struct kimage *image)
} else {
/*
* Crash kexec uses riscv_kexec_norelocate as a trampoline.
- * Pre-build the trampoline page tables here so the panic
- * path only has to switch satp and jump.
+ * Pre-build the trampoline page tables and capture the
+ * trampoline SATP value plus the physical address of
+ * riscv_kexec_norelocate so that the panic path only has
+ * to switch satp and jump.
*/
riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
__pa_symbol(__kexec_tramp_text_start));
+ WRITE_ONCE(riscv_kexec_norelocate_pa,
+ __pa_symbol(&riscv_kexec_norelocate));
+ WRITE_ONCE(kexec_tramp_satp,
+ PFN_DOWN(__pa_symbol(kexec_tramp_pgd)) | satp_mode);
}
return 0;
@@ -243,7 +251,35 @@ machine_kexec(struct kimage *image)
/* Jump to the relocation code */
pr_notice("Bye...\n");
- kexec_method(first_ind_entry, jump_addr, fdt_addr,
- this_hart_id, kernel_map.va_pa_offset);
+ /*
+ * Hand off to the trampoline. For KEXEC_TYPE_CRASH we go into
+ * riscv_kexec_norelocate, which uses t3 as the 1st/2nd-pass
+ * discriminator (must be 0 on first entry). A bare
+ * asm volatile ("li t3, 0" ::: "t3")
+ * before the C call only declares t3 *modified*; the compiler is
+ * free to use t3 as scratch when materialising args. Pin t3 = 0
+ * (and the args) via local register variables and perform the
+ * indirect jump inside the same inline asm so t3 == 0 is
+ * guaranteed at the moment control leaves machine_kexec().
+ */
+ {
+ register unsigned long a0_val asm("a0") = first_ind_entry;
+ register unsigned long a1_val asm("a1") = jump_addr;
+ register unsigned long a2_val asm("a2") = fdt_addr;
+ register unsigned long a3_val asm("a3") = this_hart_id;
+ register unsigned long a4_val asm("a4") = kernel_map.va_pa_offset;
+ register unsigned long t3_zero asm("t3") = 0;
+ register riscv_kexec_method m asm("t6") = kexec_method;
+
+ asm volatile (
+ "jr %[m]"
+ :
+ : "r" (a0_val), "r" (a1_val), "r" (a2_val),
+ "r" (a3_val), "r" (a4_val),
+ "r" (t3_zero),
+ [m] "r" (m)
+ : "memory"
+ );
+ }
unreachable();
}
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 5/7] riscv: kexec: Always build the trampoline page table
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
` (3 preceding siblings ...)
2026-05-26 12:50 ` [PATCH v2 4/7] riscv: kexec: Switch to trampoline page table before norelocate fangyu.yu
@ 2026-05-26 12:50 ` fangyu.yu
2026-05-26 12:50 ` [PATCH v2 6/7] riscv: kexec: Add the relocate-trampoline wrapper fangyu.yu
2026-05-26 12:50 ` [PATCH v2 7/7] riscv: kexec: Route normal kexec through the trampoline page table fangyu.yu
6 siblings, 0 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
The trampoline page table and the kexec_tramp_satp value are
currently built only on the crash path. A follow-up patch needs
the same infrastructure for the normal kexec path.
Pull the trampoline build and the WRITE_ONCE() that publishes the
SATP value out of the crash-only else branch in
machine_kexec_prepare(). The crash path keeps recording its own
riscv_kexec_norelocate_pa; the normal path keeps its existing
control_code_buffer copy.
No functional change.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kernel/machine_kexec.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 00fdc42d650d..556b76bcf96e 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -119,6 +119,16 @@ machine_kexec_prepare(struct kimage *image)
return -EINVAL;
}
+ /*
+ * Build the trampoline page table and capture its SATP value.
+ * The crash path consumes it today; the non-crash kexec path
+ * will use the same setup as well.
+ */
+ riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
+ __pa_symbol(__kexec_tramp_text_start));
+ WRITE_ONCE(kexec_tramp_satp,
+ PFN_DOWN(__pa_symbol(kexec_tramp_pgd)) | satp_mode);
+
/* Copy the assembler code for relocation to the control page */
if (image->type != KEXEC_TYPE_CRASH) {
control_code_buffer = page_address(image->control_code_page);
@@ -135,19 +145,8 @@ machine_kexec_prepare(struct kimage *image)
/* Mark the control page executable */
set_memory_x((unsigned long) control_code_buffer, 1);
} else {
- /*
- * Crash kexec uses riscv_kexec_norelocate as a trampoline.
- * Pre-build the trampoline page tables and capture the
- * trampoline SATP value plus the physical address of
- * riscv_kexec_norelocate so that the panic path only has
- * to switch satp and jump.
- */
- riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
- __pa_symbol(__kexec_tramp_text_start));
WRITE_ONCE(riscv_kexec_norelocate_pa,
__pa_symbol(&riscv_kexec_norelocate));
- WRITE_ONCE(kexec_tramp_satp,
- PFN_DOWN(__pa_symbol(kexec_tramp_pgd)) | satp_mode);
}
return 0;
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 6/7] riscv: kexec: Add the relocate-trampoline wrapper
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
` (4 preceding siblings ...)
2026-05-26 12:50 ` [PATCH v2 5/7] riscv: kexec: Always build the trampoline page table fangyu.yu
@ 2026-05-26 12:50 ` fangyu.yu
2026-05-26 12:50 ` [PATCH v2 7/7] riscv: kexec: Route normal kexec through the trampoline page table fangyu.yu
6 siblings, 0 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Add riscv_kexec_relocate_entry to .kexec.tramp.text and the two
asm-visible globals (riscv_kexec_relocate_entry_pa and
riscv_kexec_cc_buffer_pa) that the wrapper consumes.
The wrapper performs the same two-step transition used by the crash
path: switch to the trampoline pgd, jump to the PA of self, then drop
the MMU with PC already on a PA. It finally jumps to the PA of
control_code_buffer.
machine_kexec_prepare() publishes the wrapper PA and the
control_code_buffer PA via WRITE_ONCE for non-crash images.
Nothing routes to the wrapper yet; the switchover happens in the
follow-up patch.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/include/asm/kexec.h | 1 +
arch/riscv/kernel/kexec_relocate.S | 37 ++++++++++++++++++++++++++++++
arch/riscv/kernel/machine_kexec.c | 7 ++++++
3 files changed, 45 insertions(+)
diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h
index 6466c1f00d41..b75cab959e53 100644
--- a/arch/riscv/include/asm/kexec.h
+++ b/arch/riscv/include/asm/kexec.h
@@ -53,6 +53,7 @@ typedef void (*riscv_kexec_method)(unsigned long first_ind_entry,
unsigned long va_pa_off);
extern riscv_kexec_method riscv_kexec_norelocate;
+extern riscv_kexec_method riscv_kexec_relocate_entry;
#ifdef CONFIG_KEXEC_FILE
extern const struct kexec_file_ops elf_kexec_ops;
diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index 2b9892bf04f2..1baadad1b546 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -231,6 +231,43 @@ SYM_CODE_START(riscv_kexec_norelocate)
SYM_CODE_END(riscv_kexec_norelocate)
+.extern riscv_kexec_relocate_entry_pa
+.extern riscv_kexec_cc_buffer_pa
+.section ".kexec.tramp.text", "ax"
+SYM_CODE_START(riscv_kexec_relocate_entry)
+ /*
+ * Two-pass entry, identical in shape to riscv_kexec_norelocate:
+ * - 1st entry: t3 == 0 (initialized by machine_kexec()).
+ * - 2nd entry: t3 == PA of riscv_kexec_relocate_entry, so auipc
+ * matches t3 and we fall through to label 1.
+ * Args a0..a4 are passed through unchanged to riscv_kexec_relocate.
+ */
+ auipc t0, 0
+ beq t0, t3, 1f
+
+ la t0, riscv_kexec_relocate_entry_pa
+ REG_L t3, 0(t0)
+ la t0, kexec_tramp_satp
+ REG_L t1, 0(t0)
+ csrw CSR_SATP, t1
+ sfence.vma x0, x0
+
+ jr t3
+1:
+ /*
+ * Now executing at the PA of this wrapper with the trampoline pgd
+ * installed (identity-mapped). Drop the MMU; PC stays valid because
+ * it is already a PA.
+ */
+ csrw CSR_SATP, zero
+ sfence.vma x0, x0
+
+ /* Jump to the PA of control_code_buffer to run the relocate body. */
+ la t0, riscv_kexec_cc_buffer_pa
+ REG_L t0, 0(t0)
+ jr t0
+SYM_CODE_END(riscv_kexec_relocate_entry)
+
.section ".rodata"
SYM_DATA(riscv_kexec_relocate_size,
.long riscv_kexec_relocate_end - riscv_kexec_relocate)
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 556b76bcf96e..e3eb1e71920a 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -20,6 +20,8 @@
unsigned long kexec_tramp_satp;
unsigned long riscv_kexec_norelocate_pa;
+unsigned long riscv_kexec_relocate_entry_pa;
+unsigned long riscv_kexec_cc_buffer_pa;
static pgd_t kexec_tramp_pgd[PTRS_PER_PGD] __aligned(PAGE_SIZE);
static p4d_t kexec_tramp_p4d[PTRS_PER_P4D] __aligned(PAGE_SIZE);
static pud_t kexec_tramp_pud[PTRS_PER_PUD] __aligned(PAGE_SIZE);
@@ -144,6 +146,11 @@ machine_kexec_prepare(struct kimage *image)
/* Mark the control page executable */
set_memory_x((unsigned long) control_code_buffer, 1);
+
+ WRITE_ONCE(riscv_kexec_relocate_entry_pa,
+ __pa_symbol(&riscv_kexec_relocate_entry));
+ WRITE_ONCE(riscv_kexec_cc_buffer_pa,
+ __pa(control_code_buffer));
} else {
WRITE_ONCE(riscv_kexec_norelocate_pa,
__pa_symbol(&riscv_kexec_norelocate));
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 7/7] riscv: kexec: Route normal kexec through the trampoline page table
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
` (5 preceding siblings ...)
2026-05-26 12:50 ` [PATCH v2 6/7] riscv: kexec: Add the relocate-trampoline wrapper fangyu.yu
@ 2026-05-26 12:50 ` fangyu.yu
6 siblings, 0 replies; 8+ messages in thread
From: fangyu.yu @ 2026-05-26 12:50 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Anup Patel, Atish Patra, Nick Kossifidis
Cc: Song Shuai, Björn Töpel, Ard Biesheuvel, Conor Dooley,
Arnd Bergmann, Thomas Zimmermann, Richard Lyu, Nam Cao,
Jisheng Zhang, Nathan Chancellor, guoren, linux-riscv,
linux-kernel, kexec, kvm-riscv, kvm, Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
riscv_kexec_relocate (copied into control_code_buffer) uses an stvec
trick to drop the MMU and land on the PA of the next loop label.
Under VS-mode KVM cannot emulate this single-step transition and the
VCPU dies with "kvm run failed Operation not supported".
Route normal kexec through riscv_kexec_relocate_entry, the trampoline
wrapper added in the previous patch. It drops SATP with PC already on
a PA, then hands off to control_code_buffer where the relocate body
runs with SATP=0.
Drop the stvec trick from the relocate body and pass first_ind_entry
as a physical address since the body now starts with SATP=0. The
".align 2" plus filler "nop" that ensured the PA of the loop top was
4-byte aligned -- required because the legacy stvec trick wrote that
PA into stvec.BASE, whose low two bits are MODE and are discarded by
the hardware -- is no longer load-bearing and is removed as well.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kernel/kexec_relocate.S | 26 ++++++--------------------
arch/riscv/kernel/machine_kexec.c | 10 +++++++---
2 files changed, 13 insertions(+), 23 deletions(-)
diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index 1baadad1b546..29392f457f42 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -34,27 +34,13 @@ SYM_CODE_START(riscv_kexec_relocate)
csrw CSR_SIP, zero
/*
- * When we switch SATP.MODE to "Bare" we'll only
- * play with physical addresses. However the first time
- * we try to jump somewhere, the offset on the jump
- * will be relative to pc which will still be on VA. To
- * deal with this we set stvec to the physical address at
- * the start of the loop below so that we jump there in
- * any case.
+ * The trampoline wrapper (riscv_kexec_relocate_entry) has already
+ * dropped the MMU and handed control to us at this PA copy of the
+ * relocate code. From here on the entire loop runs with SATP=0 and
+ * every address (s0, s5, source/dest pointers) is a physical one.
*/
- la s6, 1f
- sub s6, s6, s4
- csrw CSR_STVEC, s6
-
- /*
- * With C-extension, here we get 42 Bytes and the next
- * .align directive would pad zeros here up to 44 Bytes.
- * So manually put a nop here to avoid zeros padding.
- */
- nop
/* Process entries in a loop */
-.align 2
1:
REG_L t0, 0(s0) /* t0 = *image->entry */
addi s0, s0, RISCV_SZPTR /* image->entry++ */
@@ -70,8 +56,8 @@ SYM_CODE_START(riscv_kexec_relocate)
andi t1, t0, 0x2
beqz t1, 2f
andi s0, t0, ~0x2
- csrw CSR_SATP, zero
- jr s6
+ /* MMU is already off; the entry wrapper handled the transition. */
+ j 1b
2:
/* IND_DONE entry ? -> jump to done label */
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index e3eb1e71920a..99cc251f971c 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -231,11 +231,15 @@ machine_kexec(struct kimage *image)
{
struct kimage_arch *internal = &image->arch;
unsigned long jump_addr = (unsigned long) image->start;
- unsigned long first_ind_entry = (unsigned long) &image->head;
+ /*
+ * The relocate body runs entirely with the MMU off (the wrapper
+ * drops SATP before jumping into control_code_buffer), so the very
+ * first entry must be a physical address.
+ */
+ unsigned long first_ind_entry = __pa(&image->head);
unsigned long this_cpu_id = __smp_processor_id();
unsigned long this_hart_id = cpuid_to_hartid_map(this_cpu_id);
unsigned long fdt_addr = internal->fdt_addr;
- void *control_code_buffer = page_address(image->control_code_page);
riscv_kexec_method kexec_method = NULL;
#ifdef CONFIG_SMP
@@ -244,7 +248,7 @@ machine_kexec(struct kimage *image)
#endif
if (image->type != KEXEC_TYPE_CRASH)
- kexec_method = control_code_buffer;
+ kexec_method = (riscv_kexec_method) &riscv_kexec_relocate_entry;
else
kexec_method = (riscv_kexec_method) &riscv_kexec_norelocate;
--
2.50.1
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-05-26 12:50 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-26 12:50 [PATCH v2 0/7] riscv: kexec: Fix VCPU crash on kexec/kdump under KVM fangyu.yu
2026-05-26 12:50 ` [PATCH v2 1/7] riscv: Add kexec trampoline text section to vmlinux.lds.S fangyu.yu
2026-05-26 12:50 ` [PATCH v2 2/7] riscv: kexec: Place norelocate trampoline into .kexec.tramp.text fangyu.yu
2026-05-26 12:50 ` [PATCH v2 3/7] riscv: kexec: Build trampoline page tables for crash kernel entry fangyu.yu
2026-05-26 12:50 ` [PATCH v2 4/7] riscv: kexec: Switch to trampoline page table before norelocate fangyu.yu
2026-05-26 12:50 ` [PATCH v2 5/7] riscv: kexec: Always build the trampoline page table fangyu.yu
2026-05-26 12:50 ` [PATCH v2 6/7] riscv: kexec: Add the relocate-trampoline wrapper fangyu.yu
2026-05-26 12:50 ` [PATCH v2 7/7] riscv: kexec: Route normal kexec through the trampoline page table fangyu.yu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®