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