1 /******************************************************************************
2 * machine_kexec.c
3 *
4 * Copyright (C) 2013 Citrix Systems R&D Ltd.
5 *
6 * Portions derived from Linux's arch/x86/kernel/machine_kexec_64.c.
7 *
8 * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com>
9 *
10 * Xen port written by:
11 * - Simon 'Horms' Horman <horms@verge.net.au>
12 * - Magnus Damm <magnus@valinux.co.jp>
13 *
14 * This source code is licensed under the GNU General Public License,
15 * Version 2. See the file COPYING for more details.
16 */
17
18 #include <xen/domain_page.h>
19 #include <xen/elfstructs.h>
20 #include <xen/kexec.h>
21 #include <xen/types.h>
22
23 #include <asm/fixmap.h>
24 #include <asm/hpet.h>
25 #include <asm/idt.h>
26 #include <asm/machine_kexec.h>
27 #include <asm/msr.h>
28 #include <asm/page.h>
29
30 /*
31 * Add a mapping for a page to the page tables used during kexec.
32 */
machine_kexec_add_page(struct kexec_image * image,unsigned long vaddr,unsigned long maddr)33 int machine_kexec_add_page(struct kexec_image *image, unsigned long vaddr,
34 unsigned long maddr)
35 {
36 struct page_info *l4_page;
37 struct page_info *l3_page;
38 struct page_info *l2_page;
39 struct page_info *l1_page;
40 l4_pgentry_t *l4 = NULL;
41 l3_pgentry_t *l3 = NULL;
42 l2_pgentry_t *l2 = NULL;
43 l1_pgentry_t *l1 = NULL;
44 int ret = -ENOMEM;
45
46 l4_page = image->aux_page;
47 if ( !l4_page )
48 {
49 l4_page = kimage_alloc_control_page(image, 0);
50 if ( !l4_page )
51 goto out;
52 image->aux_page = l4_page;
53 }
54
55 l4 = __map_domain_page(l4_page);
56 l4 += l4_table_offset(vaddr);
57 if ( !(l4e_get_flags(*l4) & _PAGE_PRESENT) )
58 {
59 l3_page = kimage_alloc_control_page(image, 0);
60 if ( !l3_page )
61 goto out;
62 l4e_write(l4, l4e_from_page(l3_page, __PAGE_HYPERVISOR));
63 }
64 else
65 l3_page = l4e_get_page(*l4);
66
67 l3 = __map_domain_page(l3_page);
68 l3 += l3_table_offset(vaddr);
69 if ( !(l3e_get_flags(*l3) & _PAGE_PRESENT) )
70 {
71 l2_page = kimage_alloc_control_page(image, 0);
72 if ( !l2_page )
73 goto out;
74 l3e_write(l3, l3e_from_page(l2_page, __PAGE_HYPERVISOR));
75 }
76 else
77 l2_page = l3e_get_page(*l3);
78
79 l2 = __map_domain_page(l2_page);
80 l2 += l2_table_offset(vaddr);
81 if ( !(l2e_get_flags(*l2) & _PAGE_PRESENT) )
82 {
83 l1_page = kimage_alloc_control_page(image, 0);
84 if ( !l1_page )
85 goto out;
86 l2e_write(l2, l2e_from_page(l1_page, __PAGE_HYPERVISOR));
87 }
88 else
89 l1_page = l2e_get_page(*l2);
90
91 l1 = __map_domain_page(l1_page);
92 l1 += l1_table_offset(vaddr);
93 l1e_write(l1, l1e_from_pfn(maddr >> PAGE_SHIFT, __PAGE_HYPERVISOR));
94
95 ret = 0;
96 out:
97 if ( l1 )
98 unmap_domain_page(l1);
99 if ( l2 )
100 unmap_domain_page(l2);
101 if ( l3 )
102 unmap_domain_page(l3);
103 if ( l4 )
104 unmap_domain_page(l4);
105 return ret;
106 }
107
machine_kexec_load(struct kexec_image * image)108 int machine_kexec_load(struct kexec_image *image)
109 {
110 void *code_page;
111 int ret;
112
113 switch ( image->arch )
114 {
115 case EM_386:
116 case EM_X86_64:
117 break;
118 default:
119 return -EINVAL;
120 }
121
122 code_page = __map_domain_page(image->control_code_page);
123 memcpy(code_page, kexec_reloc, kexec_reloc_end - (char *)kexec_reloc);
124 unmap_domain_page(code_page);
125
126 /*
127 * Add a mapping for the control code page to the same virtual
128 * address as kexec_reloc. This allows us to keep running after
129 * these page tables are loaded in kexec_reloc.
130 */
131 ret = machine_kexec_add_page(image, (unsigned long)kexec_reloc,
132 page_to_maddr(image->control_code_page));
133 if ( ret < 0 )
134 return ret;
135
136 return 0;
137 }
138
machine_kexec_unload(struct kexec_image * image)139 void machine_kexec_unload(struct kexec_image *image)
140 {
141 /* no-op. kimage_free() frees all control pages. */
142 }
143
machine_reboot_kexec(struct kexec_image * image)144 void machine_reboot_kexec(struct kexec_image *image)
145 {
146 BUG_ON(smp_processor_id() != 0);
147 smp_send_stop();
148 machine_kexec(image);
149 BUG();
150 }
151
machine_kexec(struct kexec_image * image)152 void machine_kexec(struct kexec_image *image)
153 {
154 int i;
155 unsigned long reloc_flags = 0;
156
157 /* We are about to permenantly jump out of the Xen context into the kexec
158 * purgatory code. We really dont want to be still servicing interupts.
159 */
160 local_irq_disable();
161
162 /* Now regular interrupts are disabled, we need to reduce the impact
163 * of interrupts not disabled by 'cli'.
164 *
165 * The NMI handlers have already been set up nmi_shootdown_cpus(). All
166 * pcpus other than us have the nmi_crash handler, while we have the nop
167 * handler.
168 *
169 * The MCE handlers touch extensive areas of Xen code and data. At this
170 * point, there is nothing we can usefully do, so set the nop handler.
171 */
172 for ( i = 0; i < nr_cpu_ids; i++ )
173 {
174 idt_entry_t *idt = per_cpu(idt, i);
175
176 if ( !idt )
177 continue;
178
179 _update_gate_addr_lower(&idt[X86_EXC_MC], &trap_nop);
180 }
181
182 /* Reset CPUID masking and faulting to the host's default. */
183 ctxt_switch_levelling(NULL);
184
185 /* Disable CET. */
186 if ( read_cr4() & X86_CR4_CET )
187 {
188 wrmsrl(MSR_S_CET, 0);
189 write_cr4(read_cr4() & ~X86_CR4_CET);
190 }
191
192 /* Explicitly enable NMIs on this CPU. Some crashdump kernels do
193 * not like running with NMIs disabled. */
194 enable_nmis();
195
196 if ( image->arch == EM_386 )
197 reloc_flags |= KEXEC_RELOC_FLAG_COMPAT;
198
199 kexec_reloc(page_to_maddr(image->control_code_page),
200 page_to_maddr(image->aux_page),
201 image->head, image->entry_maddr, reloc_flags);
202 }
203
machine_kexec_get(xen_kexec_range_t * range)204 int machine_kexec_get(xen_kexec_range_t *range)
205 {
206 if (range->range != KEXEC_RANGE_MA_XEN)
207 return -EINVAL;
208 return machine_kexec_get_xen(range);
209 }
210
arch_crash_save_vmcoreinfo(void)211 void arch_crash_save_vmcoreinfo(void)
212 {
213 VMCOREINFO_SYMBOL(dom_xen);
214 VMCOREINFO_SYMBOL(dom_io);
215
216 VMCOREINFO_SYMBOL_ALIAS(pgd_l4, idle_pg_table);
217 }
218
219 /*
220 * Local variables:
221 * mode: C
222 * c-file-style: "BSD"
223 * c-basic-offset: 4
224 * tab-width: 4
225 * indent-tabs-mode: nil
226 * End:
227 */
228