xref: /openbmc/linux/arch/parisc/kernel/kexec.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1fc697dc0SSven Schnelle // SPDX-License-Identifier: GPL-2.0
2fc697dc0SSven Schnelle 
3fc697dc0SSven Schnelle #include <linux/kernel.h>
4fc697dc0SSven Schnelle #include <linux/console.h>
5fc697dc0SSven Schnelle #include <linux/kexec.h>
6fc697dc0SSven Schnelle #include <linux/delay.h>
7*cc719a9cSSimon Horman #include <linux/reboot.h>
8*cc719a9cSSimon Horman 
9fc697dc0SSven Schnelle #include <asm/cacheflush.h>
10fc697dc0SSven Schnelle #include <asm/sections.h>
11fc697dc0SSven Schnelle 
12fc697dc0SSven Schnelle extern void relocate_new_kernel(unsigned long head,
13fc697dc0SSven Schnelle 				unsigned long start,
14fc697dc0SSven Schnelle 				unsigned long phys);
15fc697dc0SSven Schnelle 
16fc697dc0SSven Schnelle extern const unsigned int relocate_new_kernel_size;
17fc697dc0SSven Schnelle extern unsigned int kexec_initrd_start_offset;
18fc697dc0SSven Schnelle extern unsigned int kexec_initrd_end_offset;
19fc697dc0SSven Schnelle extern unsigned int kexec_cmdline_offset;
20fc697dc0SSven Schnelle extern unsigned int kexec_free_mem_offset;
21fc697dc0SSven Schnelle 
kexec_show_segment_info(const struct kimage * kimage,unsigned long n)22fc697dc0SSven Schnelle static void kexec_show_segment_info(const struct kimage *kimage,
23fc697dc0SSven Schnelle 				    unsigned long n)
24fc697dc0SSven Schnelle {
25fc697dc0SSven Schnelle 	pr_debug("    segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n",
26fc697dc0SSven Schnelle 			n,
27fc697dc0SSven Schnelle 			kimage->segment[n].mem,
28fc697dc0SSven Schnelle 			kimage->segment[n].mem + kimage->segment[n].memsz,
29fc697dc0SSven Schnelle 			(unsigned long)kimage->segment[n].memsz,
30fc697dc0SSven Schnelle 			(unsigned long)kimage->segment[n].memsz /  PAGE_SIZE);
31fc697dc0SSven Schnelle }
32fc697dc0SSven Schnelle 
kexec_image_info(const struct kimage * kimage)33fc697dc0SSven Schnelle static void kexec_image_info(const struct kimage *kimage)
34fc697dc0SSven Schnelle {
35fc697dc0SSven Schnelle 	unsigned long i;
36fc697dc0SSven Schnelle 
37fc697dc0SSven Schnelle 	pr_debug("kexec kimage info:\n");
38fc697dc0SSven Schnelle 	pr_debug("  type:        %d\n", kimage->type);
39fc697dc0SSven Schnelle 	pr_debug("  start:       %lx\n", kimage->start);
40fc697dc0SSven Schnelle 	pr_debug("  head:        %lx\n", kimage->head);
41fc697dc0SSven Schnelle 	pr_debug("  nr_segments: %lu\n", kimage->nr_segments);
42fc697dc0SSven Schnelle 
43fc697dc0SSven Schnelle 	for (i = 0; i < kimage->nr_segments; i++)
44fc697dc0SSven Schnelle 		kexec_show_segment_info(kimage, i);
451191cf49SSven Schnelle 
461191cf49SSven Schnelle #ifdef CONFIG_KEXEC_FILE
471191cf49SSven Schnelle 	if (kimage->file_mode) {
481191cf49SSven Schnelle 		pr_debug("cmdline: %.*s\n", (int)kimage->cmdline_buf_len,
491191cf49SSven Schnelle 			 kimage->cmdline_buf);
501191cf49SSven Schnelle 	}
511191cf49SSven Schnelle #endif
52fc697dc0SSven Schnelle }
53fc697dc0SSven Schnelle 
machine_kexec_cleanup(struct kimage * kimage)54fc697dc0SSven Schnelle void machine_kexec_cleanup(struct kimage *kimage)
55fc697dc0SSven Schnelle {
56fc697dc0SSven Schnelle }
57fc697dc0SSven Schnelle 
machine_crash_shutdown(struct pt_regs * regs)58fc697dc0SSven Schnelle void machine_crash_shutdown(struct pt_regs *regs)
59fc697dc0SSven Schnelle {
60fc697dc0SSven Schnelle }
61fc697dc0SSven Schnelle 
machine_shutdown(void)62fc697dc0SSven Schnelle void machine_shutdown(void)
63fc697dc0SSven Schnelle {
64fc697dc0SSven Schnelle 	smp_send_stop();
65fc697dc0SSven Schnelle 	while (num_online_cpus() > 1) {
66fc697dc0SSven Schnelle 		cpu_relax();
67fc697dc0SSven Schnelle 		mdelay(1);
68fc697dc0SSven Schnelle 	}
69fc697dc0SSven Schnelle }
70fc697dc0SSven Schnelle 
machine_kexec(struct kimage * image)71fc697dc0SSven Schnelle void machine_kexec(struct kimage *image)
72fc697dc0SSven Schnelle {
73fc697dc0SSven Schnelle #ifdef CONFIG_64BIT
74fc697dc0SSven Schnelle 	Elf64_Fdesc desc;
75fc697dc0SSven Schnelle #endif
76fc697dc0SSven Schnelle 	void (*reloc)(unsigned long head,
77fc697dc0SSven Schnelle 		      unsigned long start,
78fc697dc0SSven Schnelle 		      unsigned long phys);
79fc697dc0SSven Schnelle 
80fc697dc0SSven Schnelle 	unsigned long phys = page_to_phys(image->control_code_page);
81fc697dc0SSven Schnelle 	void *virt = (void *)__fix_to_virt(FIX_TEXT_KEXEC);
82fc697dc0SSven Schnelle 	struct kimage_arch *arch = &image->arch;
83fc697dc0SSven Schnelle 
84fc697dc0SSven Schnelle 	set_fixmap(FIX_TEXT_KEXEC, phys);
85fc697dc0SSven Schnelle 
86fc697dc0SSven Schnelle 	flush_cache_all();
87fc697dc0SSven Schnelle 
88fc697dc0SSven Schnelle #ifdef CONFIG_64BIT
89fc697dc0SSven Schnelle 	reloc = (void *)&desc;
90fc697dc0SSven Schnelle 	desc.addr = (long long)virt;
91fc697dc0SSven Schnelle #else
92fc697dc0SSven Schnelle 	reloc = (void *)virt;
93fc697dc0SSven Schnelle #endif
94fc697dc0SSven Schnelle 
95fc697dc0SSven Schnelle 	memcpy(virt, dereference_function_descriptor(relocate_new_kernel),
96fc697dc0SSven Schnelle 		relocate_new_kernel_size);
97fc697dc0SSven Schnelle 
98fc697dc0SSven Schnelle 	*(unsigned long *)(virt + kexec_cmdline_offset) = arch->cmdline;
99fc697dc0SSven Schnelle 	*(unsigned long *)(virt + kexec_initrd_start_offset) = arch->initrd_start;
100fc697dc0SSven Schnelle 	*(unsigned long *)(virt + kexec_initrd_end_offset) = arch->initrd_end;
101fc697dc0SSven Schnelle 	*(unsigned long *)(virt + kexec_free_mem_offset) = PAGE0->mem_free;
102fc697dc0SSven Schnelle 
103fc697dc0SSven Schnelle 	flush_cache_all();
104fc697dc0SSven Schnelle 	flush_tlb_all();
105fc697dc0SSven Schnelle 	local_irq_disable();
106fc697dc0SSven Schnelle 
107fc697dc0SSven Schnelle 	reloc(image->head & PAGE_MASK, image->start, phys);
108fc697dc0SSven Schnelle }
109fc697dc0SSven Schnelle 
machine_kexec_prepare(struct kimage * image)110fc697dc0SSven Schnelle int machine_kexec_prepare(struct kimage *image)
111fc697dc0SSven Schnelle {
112fc697dc0SSven Schnelle 	kexec_image_info(image);
113fc697dc0SSven Schnelle 	return 0;
114fc697dc0SSven Schnelle }
115