1
2
3
4
5
6
7
8
9#include <linux/mm.h>
10#include <linux/kexec.h>
11#include <linux/delay.h>
12#include <linux/init.h>
13#include <linux/numa.h>
14#include <linux/ftrace.h>
15#include <linux/suspend.h>
16
17#include <asm/pgtable.h>
18#include <asm/pgalloc.h>
19#include <asm/tlbflush.h>
20#include <asm/mmu_context.h>
21#include <asm/io.h>
22#include <asm/apic.h>
23#include <asm/cpufeature.h>
24#include <asm/desc.h>
25#include <asm/system.h>
26#include <asm/cacheflush.h>
27
28#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
29static u32 kexec_pgd[1024] PAGE_ALIGNED;
30#ifdef CONFIG_X86_PAE
31static u32 kexec_pmd0[1024] PAGE_ALIGNED;
32static u32 kexec_pmd1[1024] PAGE_ALIGNED;
33#endif
34static u32 kexec_pte0[1024] PAGE_ALIGNED;
35static u32 kexec_pte1[1024] PAGE_ALIGNED;
36
37static void set_idt(void *newidt, __u16 limit)
38{
39 struct desc_ptr curidt;
40
41
42 curidt.size = limit;
43 curidt.address = (unsigned long)newidt;
44
45 load_idt(&curidt);
46}
47
48
49static void set_gdt(void *newgdt, __u16 limit)
50{
51 struct desc_ptr curgdt;
52
53
54 curgdt.size = limit;
55 curgdt.address = (unsigned long)newgdt;
56
57 load_gdt(&curgdt);
58}
59
60static void load_segments(void)
61{
62#define __STR(X) #X
63#define STR(X) __STR(X)
64
65 __asm__ __volatile__ (
66 "\tljmp $"STR(__KERNEL_CS)",$1f\n"
67 "\t1:\n"
68 "\tmovl $"STR(__KERNEL_DS)",%%eax\n"
69 "\tmovl %%eax,%%ds\n"
70 "\tmovl %%eax,%%es\n"
71 "\tmovl %%eax,%%fs\n"
72 "\tmovl %%eax,%%gs\n"
73 "\tmovl %%eax,%%ss\n"
74 ::: "eax", "memory");
75#undef STR
76#undef __STR
77}
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92int machine_kexec_prepare(struct kimage *image)
93{
94 if (nx_enabled)
95 set_pages_x(image->control_code_page, 1);
96 return 0;
97}
98
99
100
101
102
103void machine_kexec_cleanup(struct kimage *image)
104{
105 if (nx_enabled)
106 set_pages_nx(image->control_code_page, 1);
107}
108
109
110
111
112
113void machine_kexec(struct kimage *image)
114{
115 unsigned long page_list[PAGES_NR];
116 void *control_page;
117 int save_ftrace_enabled;
118 asmlinkage unsigned long
119 (*relocate_kernel_ptr)(unsigned long indirection_page,
120 unsigned long control_page,
121 unsigned long start_address,
122 unsigned int has_pae,
123 unsigned int preserve_context);
124
125#ifdef CONFIG_KEXEC_JUMP
126 if (kexec_image->preserve_context)
127 save_processor_state();
128#endif
129
130 save_ftrace_enabled = __ftrace_enabled_save();
131
132
133 local_irq_disable();
134
135 if (image->preserve_context) {
136#ifdef CONFIG_X86_IO_APIC
137
138
139
140
141
142
143 disable_IO_APIC();
144#endif
145 }
146
147 control_page = page_address(image->control_code_page);
148 memcpy(control_page, relocate_kernel, KEXEC_CONTROL_CODE_MAX_SIZE);
149
150 relocate_kernel_ptr = control_page;
151 page_list[PA_CONTROL_PAGE] = __pa(control_page);
152 page_list[VA_CONTROL_PAGE] = (unsigned long)control_page;
153 page_list[PA_PGD] = __pa(kexec_pgd);
154 page_list[VA_PGD] = (unsigned long)kexec_pgd;
155#ifdef CONFIG_X86_PAE
156 page_list[PA_PMD_0] = __pa(kexec_pmd0);
157 page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
158 page_list[PA_PMD_1] = __pa(kexec_pmd1);
159 page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
160#endif
161 page_list[PA_PTE_0] = __pa(kexec_pte0);
162 page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
163 page_list[PA_PTE_1] = __pa(kexec_pte1);
164 page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
165
166 if (image->type == KEXEC_TYPE_DEFAULT)
167 page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page)
168 << PAGE_SHIFT);
169
170
171
172
173
174
175
176
177
178
179 load_segments();
180
181
182
183 set_gdt(phys_to_virt(0),0);
184 set_idt(phys_to_virt(0),0);
185
186
187 image->start = relocate_kernel_ptr((unsigned long)image->head,
188 (unsigned long)page_list,
189 image->start, cpu_has_pae,
190 image->preserve_context);
191
192#ifdef CONFIG_KEXEC_JUMP
193 if (kexec_image->preserve_context)
194 restore_processor_state();
195#endif
196
197 __ftrace_enabled_restore(save_ftrace_enabled);
198}
199
200void arch_crash_save_vmcoreinfo(void)
201{
202#ifdef CONFIG_NUMA
203 VMCOREINFO_SYMBOL(node_data);
204 VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
205#endif
206#ifdef CONFIG_X86_PAE
207 VMCOREINFO_CONFIG(X86_PAE);
208#endif
209}
210
211