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/types.h>
19 #include <xen/kexec.h>
20 #include <xen/guest_access.h>
21 #include <asm/fixmap.h>
22 #include <asm/hpet.h>
23 #include <asm/page.h>
24 #include <asm/machine_kexec.h>
25
26 /*
27 * Add a mapping for a page to the page tables used during kexec.
28 */
machine_kexec_add_page(struct kexec_image * image,unsigned long vaddr,unsigned long maddr)29 int machine_kexec_add_page(struct kexec_image *image, unsigned long vaddr,
30 unsigned long maddr)
31 {
32 struct page_info *l4_page;
33 struct page_info *l3_page;
34 struct page_info *l2_page;
35 struct page_info *l1_page;
36 l4_pgentry_t *l4 = NULL;
37 l3_pgentry_t *l3 = NULL;
38 l2_pgentry_t *l2 = NULL;
39 l1_pgentry_t *l1 = NULL;
40 int ret = -ENOMEM;
41
42 l4_page = image->aux_page;
43 if ( !l4_page )
44 {
45 l4_page = kimage_alloc_control_page(image, 0);
46 if ( !l4_page )
47 goto out;
48 image->aux_page = l4_page;
49 }
50
51 l4 = __map_domain_page(l4_page);
52 l4 += l4_table_offset(vaddr);
53 if ( !(l4e_get_flags(*l4) & _PAGE_PRESENT) )
54 {
55 l3_page = kimage_alloc_control_page(image, 0);
56 if ( !l3_page )
57 goto out;
58 l4e_write(l4, l4e_from_page(l3_page, __PAGE_HYPERVISOR));
59 }
60 else
61 l3_page = l4e_get_page(*l4);
62
63 l3 = __map_domain_page(l3_page);
64 l3 += l3_table_offset(vaddr);
65 if ( !(l3e_get_flags(*l3) & _PAGE_PRESENT) )
66 {
67 l2_page = kimage_alloc_control_page(image, 0);
68 if ( !l2_page )
69 goto out;
70 l3e_write(l3, l3e_from_page(l2_page, __PAGE_HYPERVISOR));
71 }
72 else
73 l2_page = l3e_get_page(*l3);
74
75 l2 = __map_domain_page(l2_page);
76 l2 += l2_table_offset(vaddr);
77 if ( !(l2e_get_flags(*l2) & _PAGE_PRESENT) )
78 {
79 l1_page = kimage_alloc_control_page(image, 0);
80 if ( !l1_page )
81 goto out;
82 l2e_write(l2, l2e_from_page(l1_page, __PAGE_HYPERVISOR));
83 }
84 else
85 l1_page = l2e_get_page(*l2);
86
87 l1 = __map_domain_page(l1_page);
88 l1 += l1_table_offset(vaddr);
89 l1e_write(l1, l1e_from_pfn(maddr >> PAGE_SHIFT, __PAGE_HYPERVISOR));
90
91 ret = 0;
92 out:
93 if ( l1 )
94 unmap_domain_page(l1);
95 if ( l2 )
96 unmap_domain_page(l2);
97 if ( l3 )
98 unmap_domain_page(l3);
99 if ( l4 )
100 unmap_domain_page(l4);
101 return ret;
102 }
103
machine_kexec_load(struct kexec_image * image)104 int machine_kexec_load(struct kexec_image *image)
105 {
106 void *code_page;
107 int ret;
108
109 switch ( image->arch )
110 {
111 case EM_386:
112 case EM_X86_64:
113 break;
114 default:
115 return -EINVAL;
116 }
117
118 code_page = __map_domain_page(image->control_code_page);
119 memcpy(code_page, kexec_reloc, kexec_reloc_size);
120 unmap_domain_page(code_page);
121
122 /*
123 * Add a mapping for the control code page to the same virtual
124 * address as kexec_reloc. This allows us to keep running after
125 * these page tables are loaded in kexec_reloc.
126 */
127 ret = machine_kexec_add_page(image, (unsigned long)kexec_reloc,
128 page_to_maddr(image->control_code_page));
129 if ( ret < 0 )
130 return ret;
131
132 return 0;
133 }
134
machine_kexec_unload(struct kexec_image * image)135 void machine_kexec_unload(struct kexec_image *image)
136 {
137 /* no-op. kimage_free() frees all control pages. */
138 }
139
machine_reboot_kexec(struct kexec_image * image)140 void machine_reboot_kexec(struct kexec_image *image)
141 {
142 BUG_ON(smp_processor_id() != 0);
143 smp_send_stop();
144 machine_kexec(image);
145 BUG();
146 }
147
machine_kexec(struct kexec_image * image)148 void machine_kexec(struct kexec_image *image)
149 {
150 int i;
151 unsigned long reloc_flags = 0;
152
153 /* We are about to permenantly jump out of the Xen context into the kexec
154 * purgatory code. We really dont want to be still servicing interupts.
155 */
156 local_irq_disable();
157
158 /* Now regular interrupts are disabled, we need to reduce the impact
159 * of interrupts not disabled by 'cli'.
160 *
161 * The NMI handlers have already been set up nmi_shootdown_cpus(). All
162 * pcpus other than us have the nmi_crash handler, while we have the nop
163 * handler.
164 *
165 * The MCE handlers touch extensive areas of Xen code and data. At this
166 * point, there is nothing we can usefully do, so set the nop handler.
167 */
168 for ( i = 0; i < nr_cpu_ids; i++ )
169 {
170 if ( idt_tables[i] == NULL )
171 continue;
172 _update_gate_addr_lower(&idt_tables[i][TRAP_machine_check], &trap_nop);
173 }
174
175 /* Explicitly enable NMIs on this CPU. Some crashdump kernels do
176 * not like running with NMIs disabled. */
177 enable_nmis();
178
179 if ( image->arch == EM_386 )
180 reloc_flags |= KEXEC_RELOC_FLAG_COMPAT;
181
182 kexec_reloc(page_to_maddr(image->control_code_page),
183 page_to_maddr(image->aux_page),
184 image->head, image->entry_maddr, reloc_flags);
185 }
186
machine_kexec_get(xen_kexec_range_t * range)187 int machine_kexec_get(xen_kexec_range_t *range)
188 {
189 if (range->range != KEXEC_RANGE_MA_XEN)
190 return -EINVAL;
191 return machine_kexec_get_xen(range);
192 }
193
arch_crash_save_vmcoreinfo(void)194 void arch_crash_save_vmcoreinfo(void)
195 {
196 VMCOREINFO_SYMBOL(dom_xen);
197 VMCOREINFO_SYMBOL(dom_io);
198
199 VMCOREINFO_SYMBOL_ALIAS(pgd_l4, idle_pg_table);
200 }
201
202 /*
203 * Local variables:
204 * mode: C
205 * c-file-style: "BSD"
206 * c-basic-offset: 4
207 * tab-width: 4
208 * indent-tabs-mode: nil
209 * End:
210 */
211