Skip to content

Commit e53d281

Browse files
mickflemmpalmer-dabbelt
authored andcommitted
RISC-V: Add kdump support
This patch adds support for kdump, the kernel will reserve a region for the crash kernel and jump there on panic. In order for userspace tools (kexec-tools) to prepare the crash kernel kexec image, we also need to expose some information on /proc/iomem for the memory regions used by the kernel and for the region reserved for crash kernel. Note that on userspace the device tree is used to determine the system's memory layout so the "System RAM" on /proc/iomem is ignored. I tested this on riscv64 qemu and works as expected, you may test it by triggering a crash through /proc/sysrq_trigger: echo c > /proc/sysrq_trigger Signed-off-by: Nick Kossifidis <[email protected]> Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent ffe0e52 commit e53d281

File tree

8 files changed

+249
-27
lines changed

8 files changed

+249
-27
lines changed

arch/riscv/include/asm/elf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,10 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
8181
int uses_interp);
8282
#endif /* CONFIG_MMU */
8383

84+
#define ELF_CORE_COPY_REGS(dest, regs) \
85+
do { \
86+
*(struct user_regs_struct *)&(dest) = \
87+
*(struct user_regs_struct *)regs; \
88+
} while (0);
89+
8490
#endif /* _ASM_RISCV_ELF_H */

arch/riscv/include/asm/kexec.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@
2323

2424
#define KEXEC_ARCH KEXEC_ARCH_RISCV
2525

26+
extern void riscv_crash_save_regs(struct pt_regs *newregs);
27+
2628
static inline void
2729
crash_setup_regs(struct pt_regs *newregs,
2830
struct pt_regs *oldregs)
2931
{
30-
/* Dummy implementation for now */
32+
if (oldregs)
33+
memcpy(newregs, oldregs, sizeof(struct pt_regs));
34+
else
35+
riscv_crash_save_regs(newregs);
3136
}
3237

3338

@@ -40,10 +45,12 @@ struct kimage_arch {
4045
const extern unsigned char riscv_kexec_relocate[];
4146
const extern unsigned int riscv_kexec_relocate_size;
4247

43-
typedef void (*riscv_kexec_do_relocate)(unsigned long first_ind_entry,
44-
unsigned long jump_addr,
45-
unsigned long fdt_addr,
46-
unsigned long hartid,
47-
unsigned long va_pa_off);
48+
typedef void (*riscv_kexec_method)(unsigned long first_ind_entry,
49+
unsigned long jump_addr,
50+
unsigned long fdt_addr,
51+
unsigned long hartid,
52+
unsigned long va_pa_off);
53+
54+
extern riscv_kexec_method riscv_kexec_norelocate;
4855

4956
#endif

arch/riscv/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ obj-$(CONFIG_SMP) += cpu_ops_sbi.o
5858
endif
5959
obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o
6060
obj-$(CONFIG_KGDB) += kgdb.o
61-
obj-$(CONFIG_KEXEC) += kexec_relocate.o machine_kexec.o
61+
obj-$(CONFIG_KEXEC) += kexec_relocate.o crash_save_regs.o machine_kexec.o
6262

6363
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
6464

arch/riscv/kernel/crash_save_regs.S

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2020 FORTH-ICS/CARV
4+
* Nick Kossifidis <[email protected]>
5+
*/
6+
7+
#include <asm/asm.h> /* For RISCV_* and REG_* macros */
8+
#include <asm/csr.h> /* For CSR_* macros */
9+
#include <asm/asm-offsets.h> /* For offsets on pt_regs */
10+
#include <linux/linkage.h> /* For SYM_* macros */
11+
12+
.section ".text"
13+
SYM_CODE_START(riscv_crash_save_regs)
14+
REG_S ra, PT_RA(a0) /* x1 */
15+
REG_S sp, PT_SP(a0) /* x2 */
16+
REG_S gp, PT_GP(a0) /* x3 */
17+
REG_S tp, PT_TP(a0) /* x4 */
18+
REG_S t0, PT_T0(a0) /* x5 */
19+
REG_S t1, PT_T1(a0) /* x6 */
20+
REG_S t2, PT_T2(a0) /* x7 */
21+
REG_S s0, PT_S0(a0) /* x8/fp */
22+
REG_S s1, PT_S1(a0) /* x9 */
23+
REG_S a0, PT_A0(a0) /* x10 */
24+
REG_S a1, PT_A1(a0) /* x11 */
25+
REG_S a2, PT_A2(a0) /* x12 */
26+
REG_S a3, PT_A3(a0) /* x13 */
27+
REG_S a4, PT_A4(a0) /* x14 */
28+
REG_S a5, PT_A5(a0) /* x15 */
29+
REG_S a6, PT_A6(a0) /* x16 */
30+
REG_S a7, PT_A7(a0) /* x17 */
31+
REG_S s2, PT_S2(a0) /* x18 */
32+
REG_S s3, PT_S3(a0) /* x19 */
33+
REG_S s4, PT_S4(a0) /* x20 */
34+
REG_S s5, PT_S5(a0) /* x21 */
35+
REG_S s6, PT_S6(a0) /* x22 */
36+
REG_S s7, PT_S7(a0) /* x23 */
37+
REG_S s8, PT_S8(a0) /* x24 */
38+
REG_S s9, PT_S9(a0) /* x25 */
39+
REG_S s10, PT_S10(a0) /* x26 */
40+
REG_S s11, PT_S11(a0) /* x27 */
41+
REG_S t3, PT_T3(a0) /* x28 */
42+
REG_S t4, PT_T4(a0) /* x29 */
43+
REG_S t5, PT_T5(a0) /* x30 */
44+
REG_S t6, PT_T6(a0) /* x31 */
45+
46+
csrr t1, CSR_STATUS
47+
csrr t2, CSR_EPC
48+
csrr t3, CSR_TVAL
49+
csrr t4, CSR_CAUSE
50+
51+
REG_S t1, PT_STATUS(a0)
52+
REG_S t2, PT_EPC(a0)
53+
REG_S t3, PT_BADADDR(a0)
54+
REG_S t4, PT_CAUSE(a0)
55+
ret
56+
SYM_CODE_END(riscv_crash_save_regs)

arch/riscv/kernel/kexec_relocate.S

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,73 @@ SYM_CODE_START(riscv_kexec_relocate)
151151
SYM_CODE_END(riscv_kexec_relocate)
152152
riscv_kexec_relocate_end:
153153

154-
.section ".rodata"
154+
155+
/* Used for jumping to crashkernel */
156+
.section ".text"
157+
SYM_CODE_START(riscv_kexec_norelocate)
158+
/*
159+
* s0: (const) Phys address to jump to
160+
* s1: (const) Phys address of the FDT image
161+
* s2: (const) The hartid of the current hart
162+
* s3: (const) va_pa_offset, used when switching MMU off
163+
*/
164+
mv s0, a1
165+
mv s1, a2
166+
mv s2, a3
167+
mv s3, a4
168+
169+
/* Disable / cleanup interrupts */
170+
csrw CSR_SIE, zero
171+
csrw CSR_SIP, zero
172+
173+
/* Switch to physical addressing */
174+
la s4, 1f
175+
sub s4, s4, s3
176+
csrw CSR_STVEC, s4
177+
csrw CSR_SATP, zero
178+
179+
.align 2
180+
1:
181+
/* Pass the arguments to the next kernel / Cleanup*/
182+
mv a0, s2
183+
mv a1, s1
184+
mv a2, s0
185+
186+
/* Cleanup */
187+
mv a3, zero
188+
mv a4, zero
189+
mv a5, zero
190+
mv a6, zero
191+
mv a7, zero
192+
193+
mv s0, zero
194+
mv s1, zero
195+
mv s2, zero
196+
mv s3, zero
197+
mv s4, zero
198+
mv s5, zero
199+
mv s6, zero
200+
mv s7, zero
201+
mv s8, zero
202+
mv s9, zero
203+
mv s10, zero
204+
mv s11, zero
205+
206+
mv t0, zero
207+
mv t1, zero
208+
mv t2, zero
209+
mv t3, zero
210+
mv t4, zero
211+
mv t5, zero
212+
mv t6, zero
213+
csrw CSR_SEPC, zero
214+
csrw CSR_SCAUSE, zero
215+
csrw CSR_SSCRATCH, zero
216+
217+
jalr zero, a2, 0
218+
SYM_CODE_END(riscv_kexec_norelocate)
219+
220+
.section ".rodata"
155221
SYM_DATA(riscv_kexec_relocate_size,
156222
.long riscv_kexec_relocate_end - riscv_kexec_relocate)
157223

arch/riscv/kernel/machine_kexec.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,6 @@ machine_kexec_prepare(struct kimage *image)
5959

6060
kexec_image_info(image);
6161

62-
if (image->type == KEXEC_TYPE_CRASH) {
63-
pr_warn("Loading a crash kernel is unsupported for now.\n");
64-
return -EINVAL;
65-
}
66-
6762
/* Find the Flattened Device Tree and save its physical address */
6863
for (i = 0; i < image->nr_segments; i++) {
6964
if (image->segment[i].memsz <= sizeof(fdt))
@@ -85,17 +80,21 @@ machine_kexec_prepare(struct kimage *image)
8580
}
8681

8782
/* Copy the assembler code for relocation to the control page */
88-
control_code_buffer = page_address(image->control_code_page);
89-
control_code_buffer_sz = page_size(image->control_code_page);
90-
if (unlikely(riscv_kexec_relocate_size > control_code_buffer_sz)) {
91-
pr_err("Relocation code doesn't fit within a control page\n");
92-
return -EINVAL;
93-
}
94-
memcpy(control_code_buffer, riscv_kexec_relocate,
95-
riscv_kexec_relocate_size);
83+
if (image->type != KEXEC_TYPE_CRASH) {
84+
control_code_buffer = page_address(image->control_code_page);
85+
control_code_buffer_sz = page_size(image->control_code_page);
9686

97-
/* Mark the control page executable */
98-
set_memory_x((unsigned long) control_code_buffer, 1);
87+
if (unlikely(riscv_kexec_relocate_size > control_code_buffer_sz)) {
88+
pr_err("Relocation code doesn't fit within a control page\n");
89+
return -EINVAL;
90+
}
91+
92+
memcpy(control_code_buffer, riscv_kexec_relocate,
93+
riscv_kexec_relocate_size);
94+
95+
/* Mark the control page executable */
96+
set_memory_x((unsigned long) control_code_buffer, 1);
97+
}
9998

10099
return 0;
101100
}
@@ -147,6 +146,9 @@ void machine_shutdown(void)
147146
void
148147
machine_crash_shutdown(struct pt_regs *regs)
149148
{
149+
crash_save_cpu(regs, smp_processor_id());
150+
machine_shutdown();
151+
pr_info("Starting crashdump kernel...\n");
150152
}
151153

152154
/**
@@ -169,7 +171,12 @@ machine_kexec(struct kimage *image)
169171
unsigned long this_hart_id = raw_smp_processor_id();
170172
unsigned long fdt_addr = internal->fdt_addr;
171173
void *control_code_buffer = page_address(image->control_code_page);
172-
riscv_kexec_do_relocate do_relocate = control_code_buffer;
174+
riscv_kexec_method kexec_method = NULL;
175+
176+
if (image->type != KEXEC_TYPE_CRASH)
177+
kexec_method = control_code_buffer;
178+
else
179+
kexec_method = (riscv_kexec_method) &riscv_kexec_norelocate;
173180

174181
pr_notice("Will call new kernel at %08lx from hart id %lx\n",
175182
jump_addr, this_hart_id);
@@ -180,7 +187,7 @@ machine_kexec(struct kimage *image)
180187

181188
/* Jump to the relocation code */
182189
pr_notice("Bye...\n");
183-
do_relocate(first_ind_entry, jump_addr, fdt_addr,
184-
this_hart_id, va_pa_offset);
190+
kexec_method(first_ind_entry, jump_addr, fdt_addr,
191+
this_hart_id, va_pa_offset);
185192
unreachable();
186193
}

arch/riscv/kernel/setup.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/swiotlb.h>
2121
#include <linux/smp.h>
2222
#include <linux/efi.h>
23+
#include <linux/crash_dump.h>
2324

2425
#include <asm/cpu_ops.h>
2526
#include <asm/early_ioremap.h>
@@ -160,6 +161,14 @@ static void __init init_resources(void)
160161
if (ret < 0)
161162
goto error;
162163

164+
#ifdef CONFIG_KEXEC_CORE
165+
if (crashk_res.start != crashk_res.end) {
166+
ret = add_resource(&iomem_resource, &crashk_res);
167+
if (ret < 0)
168+
goto error;
169+
}
170+
#endif
171+
163172
for_each_reserved_mem_region(region) {
164173
res = &mem_res[res_idx--];
165174

@@ -252,7 +261,6 @@ void __init setup_arch(char **cmdline_p)
252261
efi_init();
253262
setup_bootmem();
254263
paging_init();
255-
init_resources();
256264
#if IS_ENABLED(CONFIG_BUILTIN_DTB)
257265
unflatten_and_copy_device_tree();
258266
#else
@@ -263,6 +271,7 @@ void __init setup_arch(char **cmdline_p)
263271
#endif
264272
misc_mem_init();
265273

274+
init_resources();
266275
sbi_init();
267276

268277
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) {

0 commit comments

Comments
 (0)