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