diff options
author | Sven Schnelle <svens@stackframe.org> | 2019-09-08 05:33:04 -0400 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2019-09-08 09:37:04 -0400 |
commit | fc697dc0c26a5908d467454e49440862d7fe96d0 (patch) | |
tree | 89a0cc633b00b294644143b4a11a78bf18c77e0d /arch/parisc | |
parent | 507efd63d98c4437d62bbfa932b322e72723e1fc (diff) |
parisc: add kexec syscall support
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Signed-off-by: Helge Deller <deller@gmx.de>
Diffstat (limited to 'arch/parisc')
-rw-r--r-- | arch/parisc/Kconfig | 13 | ||||
-rw-r--r-- | arch/parisc/include/asm/fixmap.h | 1 | ||||
-rw-r--r-- | arch/parisc/include/asm/kexec.h | 37 | ||||
-rw-r--r-- | arch/parisc/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/parisc/kernel/kexec.c | 105 | ||||
-rw-r--r-- | arch/parisc/kernel/relocate_kernel.S | 149 |
6 files changed, 306 insertions, 0 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index ee59171edffe..548c767f4358 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -346,6 +346,19 @@ config NR_CPUS | |||
346 | depends on SMP | 346 | depends on SMP |
347 | default "4" | 347 | default "4" |
348 | 348 | ||
349 | config KEXEC | ||
350 | bool "Kexec system call" | ||
351 | select KEXEC_CORE | ||
352 | help | ||
353 | kexec is a system call that implements the ability to shutdown your | ||
354 | current kernel, and to start another kernel. It is like a reboot | ||
355 | but it is independent of the system firmware. And like a reboot | ||
356 | you can start any kernel with it, not just Linux. | ||
357 | |||
358 | It is an ongoing process to be certain the hardware in a machine | ||
359 | shutdown, so do not be surprised if this code does not | ||
360 | initially work for you. | ||
361 | |||
349 | endmenu | 362 | endmenu |
350 | 363 | ||
351 | 364 | ||
diff --git a/arch/parisc/include/asm/fixmap.h b/arch/parisc/include/asm/fixmap.h index 288da73d4cc0..e480b2c05407 100644 --- a/arch/parisc/include/asm/fixmap.h +++ b/arch/parisc/include/asm/fixmap.h | |||
@@ -30,6 +30,7 @@ | |||
30 | enum fixed_addresses { | 30 | enum fixed_addresses { |
31 | /* Support writing RO kernel text via kprobes, jump labels, etc. */ | 31 | /* Support writing RO kernel text via kprobes, jump labels, etc. */ |
32 | FIX_TEXT_POKE0, | 32 | FIX_TEXT_POKE0, |
33 | FIX_TEXT_KEXEC, | ||
33 | FIX_BITMAP_COUNT | 34 | FIX_BITMAP_COUNT |
34 | }; | 35 | }; |
35 | 36 | ||
diff --git a/arch/parisc/include/asm/kexec.h b/arch/parisc/include/asm/kexec.h new file mode 100644 index 000000000000..a99ea747d7ed --- /dev/null +++ b/arch/parisc/include/asm/kexec.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef _ASM_PARISC_KEXEC_H | ||
3 | #define _ASM_PARISC_KEXEC_H | ||
4 | |||
5 | #ifdef CONFIG_KEXEC | ||
6 | |||
7 | /* Maximum physical address we can use pages from */ | ||
8 | #define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) | ||
9 | /* Maximum address we can reach in physical address mode */ | ||
10 | #define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) | ||
11 | /* Maximum address we can use for the control code buffer */ | ||
12 | #define KEXEC_CONTROL_MEMORY_LIMIT (-1UL) | ||
13 | |||
14 | #define KEXEC_CONTROL_PAGE_SIZE 4096 | ||
15 | |||
16 | #define KEXEC_ARCH KEXEC_ARCH_PARISC | ||
17 | #define ARCH_HAS_KIMAGE_ARCH | ||
18 | |||
19 | #ifndef __ASSEMBLY__ | ||
20 | |||
21 | struct kimage_arch { | ||
22 | unsigned long initrd_start; | ||
23 | unsigned long initrd_end; | ||
24 | unsigned long cmdline; | ||
25 | }; | ||
26 | |||
27 | static inline void crash_setup_regs(struct pt_regs *newregs, | ||
28 | struct pt_regs *oldregs) | ||
29 | { | ||
30 | /* Dummy implementation for now */ | ||
31 | } | ||
32 | |||
33 | #endif /* __ASSEMBLY__ */ | ||
34 | |||
35 | #endif /* CONFIG_KEXEC */ | ||
36 | |||
37 | #endif /* _ASM_PARISC_KEXEC_H */ | ||
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index c232266b517c..487cf88866a8 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile | |||
@@ -37,3 +37,4 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | |||
37 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o | 37 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
38 | obj-$(CONFIG_KGDB) += kgdb.o | 38 | obj-$(CONFIG_KGDB) += kgdb.o |
39 | obj-$(CONFIG_KPROBES) += kprobes.o | 39 | obj-$(CONFIG_KPROBES) += kprobes.o |
40 | obj-$(CONFIG_KEXEC) += kexec.o relocate_kernel.o | ||
diff --git a/arch/parisc/kernel/kexec.c b/arch/parisc/kernel/kexec.c new file mode 100644 index 000000000000..a92d265a2261 --- /dev/null +++ b/arch/parisc/kernel/kexec.c | |||
@@ -0,0 +1,105 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/console.h> | ||
5 | #include <linux/kexec.h> | ||
6 | #include <linux/delay.h> | ||
7 | #include <asm/cacheflush.h> | ||
8 | #include <asm/sections.h> | ||
9 | |||
10 | extern void relocate_new_kernel(unsigned long head, | ||
11 | unsigned long start, | ||
12 | unsigned long phys); | ||
13 | |||
14 | extern const unsigned int relocate_new_kernel_size; | ||
15 | extern unsigned int kexec_initrd_start_offset; | ||
16 | extern unsigned int kexec_initrd_end_offset; | ||
17 | extern unsigned int kexec_cmdline_offset; | ||
18 | extern unsigned int kexec_free_mem_offset; | ||
19 | |||
20 | static void kexec_show_segment_info(const struct kimage *kimage, | ||
21 | unsigned long n) | ||
22 | { | ||
23 | pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n", | ||
24 | n, | ||
25 | kimage->segment[n].mem, | ||
26 | kimage->segment[n].mem + kimage->segment[n].memsz, | ||
27 | (unsigned long)kimage->segment[n].memsz, | ||
28 | (unsigned long)kimage->segment[n].memsz / PAGE_SIZE); | ||
29 | } | ||
30 | |||
31 | static void kexec_image_info(const struct kimage *kimage) | ||
32 | { | ||
33 | unsigned long i; | ||
34 | |||
35 | pr_debug("kexec kimage info:\n"); | ||
36 | pr_debug(" type: %d\n", kimage->type); | ||
37 | pr_debug(" start: %lx\n", kimage->start); | ||
38 | pr_debug(" head: %lx\n", kimage->head); | ||
39 | pr_debug(" nr_segments: %lu\n", kimage->nr_segments); | ||
40 | |||
41 | for (i = 0; i < kimage->nr_segments; i++) | ||
42 | kexec_show_segment_info(kimage, i); | ||
43 | } | ||
44 | |||
45 | void machine_kexec_cleanup(struct kimage *kimage) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | void machine_crash_shutdown(struct pt_regs *regs) | ||
50 | { | ||
51 | } | ||
52 | |||
53 | void machine_shutdown(void) | ||
54 | { | ||
55 | smp_send_stop(); | ||
56 | while (num_online_cpus() > 1) { | ||
57 | cpu_relax(); | ||
58 | mdelay(1); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | void machine_kexec(struct kimage *image) | ||
63 | { | ||
64 | #ifdef CONFIG_64BIT | ||
65 | Elf64_Fdesc desc; | ||
66 | #endif | ||
67 | void (*reloc)(unsigned long head, | ||
68 | unsigned long start, | ||
69 | unsigned long phys); | ||
70 | |||
71 | unsigned long phys = page_to_phys(image->control_code_page); | ||
72 | void *virt = (void *)__fix_to_virt(FIX_TEXT_KEXEC); | ||
73 | struct kimage_arch *arch = &image->arch; | ||
74 | |||
75 | set_fixmap(FIX_TEXT_KEXEC, phys); | ||
76 | |||
77 | flush_cache_all(); | ||
78 | |||
79 | #ifdef CONFIG_64BIT | ||
80 | reloc = (void *)&desc; | ||
81 | desc.addr = (long long)virt; | ||
82 | #else | ||
83 | reloc = (void *)virt; | ||
84 | #endif | ||
85 | |||
86 | memcpy(virt, dereference_function_descriptor(relocate_new_kernel), | ||
87 | relocate_new_kernel_size); | ||
88 | |||
89 | *(unsigned long *)(virt + kexec_cmdline_offset) = arch->cmdline; | ||
90 | *(unsigned long *)(virt + kexec_initrd_start_offset) = arch->initrd_start; | ||
91 | *(unsigned long *)(virt + kexec_initrd_end_offset) = arch->initrd_end; | ||
92 | *(unsigned long *)(virt + kexec_free_mem_offset) = PAGE0->mem_free; | ||
93 | |||
94 | flush_cache_all(); | ||
95 | flush_tlb_all(); | ||
96 | local_irq_disable(); | ||
97 | |||
98 | reloc(image->head & PAGE_MASK, image->start, phys); | ||
99 | } | ||
100 | |||
101 | int machine_kexec_prepare(struct kimage *image) | ||
102 | { | ||
103 | kexec_image_info(image); | ||
104 | return 0; | ||
105 | } | ||
diff --git a/arch/parisc/kernel/relocate_kernel.S b/arch/parisc/kernel/relocate_kernel.S new file mode 100644 index 000000000000..2561e52b8d9b --- /dev/null +++ b/arch/parisc/kernel/relocate_kernel.S | |||
@@ -0,0 +1,149 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #include <linux/linkage.h> | ||
3 | #include <linux/kexec.h> | ||
4 | |||
5 | #include <asm/assembly.h> | ||
6 | #include <asm/asm-offsets.h> | ||
7 | #include <asm/page.h> | ||
8 | #include <asm/setup.h> | ||
9 | #include <asm/psw.h> | ||
10 | |||
11 | .level PA_ASM_LEVEL | ||
12 | |||
13 | .macro kexec_param name | ||
14 | .align 8 | ||
15 | ENTRY(kexec\()_\name) | ||
16 | #ifdef CONFIG_64BIT | ||
17 | .dword 0 | ||
18 | #else | ||
19 | .word 0 | ||
20 | #endif | ||
21 | |||
22 | ENTRY(kexec\()_\name\()_offset) | ||
23 | .word kexec\()_\name - relocate_new_kernel | ||
24 | .endm | ||
25 | |||
26 | .text | ||
27 | |||
28 | /* args: | ||
29 | * r26 - kimage->head | ||
30 | * r25 - start address of kernel | ||
31 | * r24 - physical address of relocate code | ||
32 | */ | ||
33 | |||
34 | ENTRY_CFI(relocate_new_kernel) | ||
35 | 0: copy %arg1, %rp | ||
36 | /* disable I and Q bit, so we are allowed to execute RFI */ | ||
37 | rsm PSW_SM_I, %r0 | ||
38 | nop | ||
39 | nop | ||
40 | nop | ||
41 | nop | ||
42 | nop | ||
43 | nop | ||
44 | nop | ||
45 | |||
46 | rsm PSW_SM_Q, %r0 | ||
47 | nop | ||
48 | nop | ||
49 | nop | ||
50 | nop | ||
51 | nop | ||
52 | nop | ||
53 | nop | ||
54 | |||
55 | /* | ||
56 | * After return-from-interrupt, we want to run without Code/Data | ||
57 | * translation enabled just like on a normal boot. | ||
58 | */ | ||
59 | |||
60 | /* calculate new physical execution address */ | ||
61 | ldo 1f-0b(%arg2), %r1 | ||
62 | mtctl %r0, %cr17 /* IIASQ */ | ||
63 | mtctl %r0, %cr17 /* IIASQ */ | ||
64 | mtctl %r1, %cr18 /* IIAOQ */ | ||
65 | ldo 4(%r1),%r1 | ||
66 | mtctl %r1, %cr18 /* IIAOQ */ | ||
67 | #ifdef CONFIG_64BIT | ||
68 | depdi,z 1, PSW_W_BIT, 1, %r1 | ||
69 | mtctl %r1, %cr22 /* IPSW */ | ||
70 | #else | ||
71 | mtctl %r0, %cr22 /* IPSW */ | ||
72 | #endif | ||
73 | /* lets go... */ | ||
74 | rfi | ||
75 | 1: nop | ||
76 | nop | ||
77 | |||
78 | .Lloop: | ||
79 | LDREG,ma REG_SZ(%arg0), %r3 | ||
80 | /* If crash kernel, no copy needed */ | ||
81 | cmpib,COND(=),n 0,%r3,boot | ||
82 | |||
83 | bb,<,n %r3, 31 - IND_DONE_BIT, boot | ||
84 | bb,>=,n %r3, 31 - IND_INDIRECTION_BIT, .Lnotind | ||
85 | /* indirection, load and restart */ | ||
86 | movb %r3, %arg0, .Lloop | ||
87 | depi 0, 31, PAGE_SHIFT, %arg0 | ||
88 | |||
89 | .Lnotind: | ||
90 | bb,>=,n %r3, 31 - IND_DESTINATION_BIT, .Lnotdest | ||
91 | b .Lloop | ||
92 | copy %r3, %r20 | ||
93 | |||
94 | .Lnotdest: | ||
95 | bb,>= %r3, 31 - IND_SOURCE_BIT, .Lloop | ||
96 | depi 0, 31, PAGE_SHIFT, %r3 | ||
97 | copy %r3, %r21 | ||
98 | |||
99 | /* copy page */ | ||
100 | copy %r0, %r18 | ||
101 | zdepi 1, 31 - PAGE_SHIFT, 1, %r18 | ||
102 | add %r20, %r18, %r17 | ||
103 | |||
104 | depi 0, 31, PAGE_SHIFT, %r20 | ||
105 | .Lcopy: | ||
106 | copy %r20, %r12 | ||
107 | LDREG,ma REG_SZ(%r21), %r8 | ||
108 | LDREG,ma REG_SZ(%r21), %r9 | ||
109 | LDREG,ma REG_SZ(%r21), %r10 | ||
110 | LDREG,ma REG_SZ(%r21), %r11 | ||
111 | STREG,ma %r8, REG_SZ(%r20) | ||
112 | STREG,ma %r9, REG_SZ(%r20) | ||
113 | STREG,ma %r10, REG_SZ(%r20) | ||
114 | STREG,ma %r11, REG_SZ(%r20) | ||
115 | |||
116 | #ifndef CONFIG_64BIT | ||
117 | LDREG,ma REG_SZ(%r21), %r8 | ||
118 | LDREG,ma REG_SZ(%r21), %r9 | ||
119 | LDREG,ma REG_SZ(%r21), %r10 | ||
120 | LDREG,ma REG_SZ(%r21), %r11 | ||
121 | STREG,ma %r8, REG_SZ(%r20) | ||
122 | STREG,ma %r9, REG_SZ(%r20) | ||
123 | STREG,ma %r10, REG_SZ(%r20) | ||
124 | STREG,ma %r11, REG_SZ(%r20) | ||
125 | #endif | ||
126 | |||
127 | fdc %r0(%r12) | ||
128 | cmpb,COND(<<) %r20,%r17,.Lcopy | ||
129 | fic (%sr4, %r12) | ||
130 | b,n .Lloop | ||
131 | |||
132 | boot: | ||
133 | mtctl %r0, %cr15 | ||
134 | |||
135 | LDREG kexec_free_mem-0b(%arg2), %arg0 | ||
136 | LDREG kexec_cmdline-0b(%arg2), %arg1 | ||
137 | LDREG kexec_initrd_end-0b(%arg2), %arg3 | ||
138 | LDREG kexec_initrd_start-0b(%arg2), %arg2 | ||
139 | bv,n %r0(%rp) | ||
140 | |||
141 | ENDPROC_CFI(relocate_new_kernel); | ||
142 | |||
143 | ENTRY(relocate_new_kernel_size) | ||
144 | .word relocate_new_kernel_size - relocate_new_kernel | ||
145 | |||
146 | kexec_param cmdline | ||
147 | kexec_param initrd_start | ||
148 | kexec_param initrd_end | ||
149 | kexec_param free_mem | ||