Skip to content

Commit fba8a86

Browse files
mickflemmpalmer-dabbelt
authored andcommitted
RISC-V: Add kexec support
This patch adds support for kexec on RISC-V. On SMP systems it depends on HOTPLUG_CPU in order to be able to bring up all harts after kexec. It also needs a recent OpenSBI version that supports the HSM extension. I tested it on riscv64 QEMU on both an smp and a non-smp system. Signed-off-by: Nick Kossifidis <[email protected]> Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent d83e682 commit fba8a86

File tree

5 files changed

+412
-0
lines changed

5 files changed

+412
-0
lines changed

arch/riscv/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,21 @@ config RISCV_SBI_V01
391391
help
392392
This config allows kernel to use SBI v0.1 APIs. This will be
393393
deprecated in future once legacy M-mode software are no longer in use.
394+
395+
config KEXEC
396+
bool "Kexec system call"
397+
select KEXEC_CORE
398+
select HOTPLUG_CPU if SMP
399+
depends on MMU
400+
help
401+
kexec is a system call that implements the ability to shutdown your
402+
current kernel, and to start another kernel. It is like a reboot
403+
but it is independent of the system firmware. And like a reboot
404+
you can start any kernel with it, not just Linux.
405+
406+
The name comes from the similarity to the exec system call.
407+
408+
394409
endmenu
395410

396411
menu "Boot options"

arch/riscv/include/asm/kexec.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2019 FORTH-ICS/CARV
4+
* Nick Kossifidis <[email protected]>
5+
*/
6+
7+
#ifndef _RISCV_KEXEC_H
8+
#define _RISCV_KEXEC_H
9+
10+
#include <asm/page.h> /* For PAGE_SIZE */
11+
12+
/* Maximum physical address we can use pages from */
13+
#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
14+
15+
/* Maximum address we can reach in physical address mode */
16+
#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
17+
18+
/* Maximum address we can use for the control code buffer */
19+
#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
20+
21+
/* Reserve a page for the control code buffer */
22+
#define KEXEC_CONTROL_PAGE_SIZE PAGE_SIZE
23+
24+
#define KEXEC_ARCH KEXEC_ARCH_RISCV
25+
26+
static inline void
27+
crash_setup_regs(struct pt_regs *newregs,
28+
struct pt_regs *oldregs)
29+
{
30+
/* Dummy implementation for now */
31+
}
32+
33+
34+
#define ARCH_HAS_KIMAGE_ARCH
35+
36+
struct kimage_arch {
37+
unsigned long fdt_addr;
38+
};
39+
40+
const extern unsigned char riscv_kexec_relocate[];
41+
const extern unsigned int riscv_kexec_relocate_size;
42+
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+
49+
#endif

arch/riscv/kernel/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
99
CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE)
1010
endif
1111

12+
ifdef CONFIG_KEXEC
13+
AFLAGS_kexec_relocate.o := -mcmodel=medany -mno-relax
14+
endif
15+
1216
extra-y += head.o
1317
extra-y += vmlinux.lds
1418

@@ -54,6 +58,7 @@ obj-$(CONFIG_SMP) += cpu_ops_sbi.o
5458
endif
5559
obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o
5660
obj-$(CONFIG_KGDB) += kgdb.o
61+
obj-$(CONFIG_KEXEC) += kexec_relocate.o machine_kexec.o
5762

5863
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
5964

arch/riscv/kernel/kexec_relocate.S

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2019 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/page.h> /* For PAGE_SIZE */
10+
#include <linux/linkage.h> /* For SYM_* macros */
11+
12+
.section ".rodata"
13+
SYM_CODE_START(riscv_kexec_relocate)
14+
15+
/*
16+
* s0: Pointer to the current entry
17+
* s1: (const) Phys address to jump to after relocation
18+
* s2: (const) Phys address of the FDT image
19+
* s3: (const) The hartid of the current hart
20+
* s4: Pointer to the destination address for the relocation
21+
* s5: (const) Number of words per page
22+
* s6: (const) 1, used for subtraction
23+
* s7: (const) va_pa_offset, used when switching MMU off
24+
* s8: (const) Physical address of the main loop
25+
* s9: (debug) indirection page counter
26+
* s10: (debug) entry counter
27+
* s11: (debug) copied words counter
28+
*/
29+
mv s0, a0
30+
mv s1, a1
31+
mv s2, a2
32+
mv s3, a3
33+
mv s4, zero
34+
li s5, (PAGE_SIZE / RISCV_SZPTR)
35+
li s6, 1
36+
mv s7, a4
37+
mv s8, zero
38+
mv s9, zero
39+
mv s10, zero
40+
mv s11, zero
41+
42+
/* Disable / cleanup interrupts */
43+
csrw CSR_SIE, zero
44+
csrw CSR_SIP, zero
45+
46+
/*
47+
* When we switch SATP.MODE to "Bare" we'll only
48+
* play with physical addresses. However the first time
49+
* we try to jump somewhere, the offset on the jump
50+
* will be relative to pc which will still be on VA. To
51+
* deal with this we set stvec to the physical address at
52+
* the start of the loop below so that we jump there in
53+
* any case.
54+
*/
55+
la s8, 1f
56+
sub s8, s8, s7
57+
csrw CSR_STVEC, s8
58+
59+
/* Process entries in a loop */
60+
.align 2
61+
1:
62+
addi s10, s10, 1
63+
REG_L t0, 0(s0) /* t0 = *image->entry */
64+
addi s0, s0, RISCV_SZPTR /* image->entry++ */
65+
66+
/* IND_DESTINATION entry ? -> save destination address */
67+
andi t1, t0, 0x1
68+
beqz t1, 2f
69+
andi s4, t0, ~0x1
70+
j 1b
71+
72+
2:
73+
/* IND_INDIRECTION entry ? -> update next entry ptr (PA) */
74+
andi t1, t0, 0x2
75+
beqz t1, 2f
76+
andi s0, t0, ~0x2
77+
addi s9, s9, 1
78+
csrw CSR_SATP, zero
79+
jalr zero, s8, 0
80+
81+
2:
82+
/* IND_DONE entry ? -> jump to done label */
83+
andi t1, t0, 0x4
84+
beqz t1, 2f
85+
j 4f
86+
87+
2:
88+
/*
89+
* IND_SOURCE entry ? -> copy page word by word to the
90+
* destination address we got from IND_DESTINATION
91+
*/
92+
andi t1, t0, 0x8
93+
beqz t1, 1b /* Unknown entry type, ignore it */
94+
andi t0, t0, ~0x8
95+
mv t3, s5 /* i = num words per page */
96+
3: /* copy loop */
97+
REG_L t1, (t0) /* t1 = *src_ptr */
98+
REG_S t1, (s4) /* *dst_ptr = *src_ptr */
99+
addi t0, t0, RISCV_SZPTR /* stc_ptr++ */
100+
addi s4, s4, RISCV_SZPTR /* dst_ptr++ */
101+
sub t3, t3, s6 /* i-- */
102+
addi s11, s11, 1 /* c++ */
103+
beqz t3, 1b /* copy done ? */
104+
j 3b
105+
106+
4:
107+
/* Pass the arguments to the next kernel / Cleanup*/
108+
mv a0, s3
109+
mv a1, s2
110+
mv a2, s1
111+
112+
/* Cleanup */
113+
mv a3, zero
114+
mv a4, zero
115+
mv a5, zero
116+
mv a6, zero
117+
mv a7, zero
118+
119+
mv s0, zero
120+
mv s1, zero
121+
mv s2, zero
122+
mv s3, zero
123+
mv s4, zero
124+
mv s5, zero
125+
mv s6, zero
126+
mv s7, zero
127+
mv s8, zero
128+
mv s9, zero
129+
mv s10, zero
130+
mv s11, zero
131+
132+
mv t0, zero
133+
mv t1, zero
134+
mv t2, zero
135+
mv t3, zero
136+
mv t4, zero
137+
mv t5, zero
138+
mv t6, zero
139+
csrw CSR_SEPC, zero
140+
csrw CSR_SCAUSE, zero
141+
csrw CSR_SSCRATCH, zero
142+
143+
/*
144+
* Make sure the relocated code is visible
145+
* and jump to the new kernel
146+
*/
147+
fence.i
148+
149+
jalr zero, a2, 0
150+
151+
SYM_CODE_END(riscv_kexec_relocate)
152+
riscv_kexec_relocate_end:
153+
154+
.section ".rodata"
155+
SYM_DATA(riscv_kexec_relocate_size,
156+
.long riscv_kexec_relocate_end - riscv_kexec_relocate)
157+

0 commit comments

Comments
 (0)