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