ia64/xen-unstable

view xen/common/kexec.c @ 17062:0769835cf50f

x86 shadow: Reduce scope of shadow lock.

emulate_map_dest doesn't require holding lock, since
only shadow related operation possibly involved is to
remove shadow which is less frequent and can acquire
lock inside. Rest are either guest table walk or
per-vcpu monitor table manipulation

Signed-off-by Kevin Tian <kevin.tian@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 14 10:33:12 2008 +0000 (2008-02-14)
parents 96f64f4c42f0
children 90ae3dfdd3cc
line source
1 /******************************************************************************
2 * kexec.c - Achitecture independent kexec code for Xen
3 *
4 * Xen port written by:
5 * - Simon 'Horms' Horman <horms@verge.net.au>
6 * - Magnus Damm <magnus@valinux.co.jp>
7 */
9 #include <xen/lib.h>
10 #include <xen/ctype.h>
11 #include <xen/errno.h>
12 #include <xen/guest_access.h>
13 #include <xen/sched.h>
14 #include <xen/types.h>
15 #include <xen/kexec.h>
16 #include <xen/keyhandler.h>
17 #include <public/kexec.h>
18 #include <xen/cpumask.h>
19 #include <asm/atomic.h>
20 #include <xen/spinlock.h>
21 #include <xen/version.h>
22 #include <xen/console.h>
23 #include <public/elfnote.h>
24 #include <xsm/xsm.h>
26 #ifndef COMPAT
28 typedef long ret_t;
30 static DEFINE_PER_CPU(void *, crash_notes);
32 static Elf_Note *xen_crash_note;
34 static cpumask_t crash_saved_cpus;
36 static xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR];
38 #define KEXEC_FLAG_DEFAULT_POS (KEXEC_IMAGE_NR + 0)
39 #define KEXEC_FLAG_CRASH_POS (KEXEC_IMAGE_NR + 1)
40 #define KEXEC_FLAG_IN_PROGRESS (KEXEC_IMAGE_NR + 2)
42 static unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */
44 static spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED;
46 xen_kexec_reserve_t kexec_crash_area;
48 static void __init parse_crashkernel(const char *str)
49 {
50 kexec_crash_area.size = parse_size_and_unit(str, &str);
51 if ( *str == '@' )
52 kexec_crash_area.start = parse_size_and_unit(str+1, NULL);
53 }
54 custom_param("crashkernel", parse_crashkernel);
56 static void one_cpu_only(void)
57 {
58 /* Only allow the first cpu to continue - force other cpus to spin */
59 if ( test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
60 for ( ; ; ) ;
61 }
63 /* Save the registers in the per-cpu crash note buffer. */
64 void kexec_crash_save_cpu(void)
65 {
66 int cpu = smp_processor_id();
67 Elf_Note *note = per_cpu(crash_notes, cpu);
68 ELF_Prstatus *prstatus;
69 crash_xen_core_t *xencore;
71 if ( cpu_test_and_set(cpu, crash_saved_cpus) )
72 return;
74 prstatus = (ELF_Prstatus *)ELFNOTE_DESC(note);
76 note = ELFNOTE_NEXT(note);
77 xencore = (crash_xen_core_t *)ELFNOTE_DESC(note);
79 elf_core_save_regs(&prstatus->pr_reg, xencore);
80 }
82 /* Set up the single Xen-specific-info crash note. */
83 crash_xen_info_t *kexec_crash_save_info(void)
84 {
85 int cpu = smp_processor_id();
86 crash_xen_info_t info;
87 crash_xen_info_t *out = (crash_xen_info_t *)ELFNOTE_DESC(xen_crash_note);
89 BUG_ON(!cpu_test_and_set(cpu, crash_saved_cpus));
91 memset(&info, 0, sizeof(info));
92 info.xen_major_version = xen_major_version();
93 info.xen_minor_version = xen_minor_version();
94 info.xen_extra_version = __pa(xen_extra_version());
95 info.xen_changeset = __pa(xen_changeset());
96 info.xen_compiler = __pa(xen_compiler());
97 info.xen_compile_date = __pa(xen_compile_date());
98 info.xen_compile_time = __pa(xen_compile_time());
99 info.tainted = tainted;
101 /* Copy from guaranteed-aligned local copy to possibly-unaligned dest. */
102 memcpy(out, &info, sizeof(info));
104 return out;
105 }
107 void kexec_crash(void)
108 {
109 int pos;
111 pos = (test_bit(KEXEC_FLAG_CRASH_POS, &kexec_flags) != 0);
112 if ( !test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags) )
113 return;
115 console_start_sync();
117 one_cpu_only();
118 kexec_crash_save_cpu();
119 machine_crash_shutdown();
121 machine_kexec(&kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]);
123 BUG();
124 }
126 static void do_crashdump_trigger(unsigned char key)
127 {
128 printk("'%c' pressed -> triggering crashdump\n", key);
129 kexec_crash();
130 printk(" * no crash kernel loaded!\n");
131 }
133 static __init int register_crashdump_trigger(void)
134 {
135 register_keyhandler('C', do_crashdump_trigger, "trigger a crashdump");
136 return 0;
137 }
138 __initcall(register_crashdump_trigger);
140 static void setup_note(Elf_Note *n, const char *name, int type, int descsz)
141 {
142 int l = strlen(name) + 1;
143 strlcpy(ELFNOTE_NAME(n), name, l);
144 n->namesz = l;
145 n->descsz = descsz;
146 n->type = type;
147 }
149 static int sizeof_note(const char *name, int descsz)
150 {
151 return (sizeof(Elf_Note) +
152 ELFNOTE_ALIGN(strlen(name)+1) +
153 ELFNOTE_ALIGN(descsz));
154 }
156 #define kexec_get(x) kexec_get_##x
158 #endif
160 static int kexec_get(reserve)(xen_kexec_range_t *range)
161 {
162 if ( kexec_crash_area.size > 0 && kexec_crash_area.start > 0) {
163 range->start = kexec_crash_area.start;
164 range->size = kexec_crash_area.size;
165 }
166 else
167 range->start = range->size = 0;
168 return 0;
169 }
171 static int kexec_get(xen)(xen_kexec_range_t *range)
172 {
173 #ifdef CONFIG_X86_64
174 range->start = xenheap_phys_start;
175 #else
176 range->start = virt_to_maddr(_start);
177 #endif
178 range->size = (unsigned long)xenheap_phys_end - (unsigned long)range->start;
179 return 0;
180 }
182 static int kexec_get(cpu)(xen_kexec_range_t *range)
183 {
184 int nr = range->nr;
185 int nr_bytes = 0;
187 if ( nr < 0 || nr >= num_present_cpus() )
188 return -EINVAL;
190 nr_bytes += sizeof_note("CORE", sizeof(ELF_Prstatus));
191 nr_bytes += sizeof_note("Xen", sizeof(crash_xen_core_t));
193 /* The Xen info note is included in CPU0's range. */
194 if ( nr == 0 )
195 nr_bytes += sizeof_note("Xen", sizeof(crash_xen_info_t));
197 if ( per_cpu(crash_notes, nr) == NULL )
198 {
199 Elf_Note *note;
201 note = per_cpu(crash_notes, nr) = xmalloc_bytes(nr_bytes);
203 if ( note == NULL )
204 return -ENOMEM;
206 /* Setup CORE note. */
207 setup_note(note, "CORE", NT_PRSTATUS, sizeof(ELF_Prstatus));
209 /* Setup Xen CORE note. */
210 note = ELFNOTE_NEXT(note);
211 setup_note(note, "Xen", XEN_ELFNOTE_CRASH_REGS, sizeof(crash_xen_core_t));
213 if (nr == 0)
214 {
215 /* Setup system wide Xen info note. */
216 xen_crash_note = note = ELFNOTE_NEXT(note);
217 setup_note(note, "Xen", XEN_ELFNOTE_CRASH_INFO, sizeof(crash_xen_info_t));
218 }
219 }
221 range->start = __pa((unsigned long)per_cpu(crash_notes, nr));
222 range->size = nr_bytes;
223 return 0;
224 }
226 static int kexec_get(range)(XEN_GUEST_HANDLE(void) uarg)
227 {
228 xen_kexec_range_t range;
229 int ret = -EINVAL;
231 if ( unlikely(copy_from_guest(&range, uarg, 1)) )
232 return -EFAULT;
234 switch ( range.range )
235 {
236 case KEXEC_RANGE_MA_CRASH:
237 ret = kexec_get(reserve)(&range);
238 break;
239 case KEXEC_RANGE_MA_XEN:
240 ret = kexec_get(xen)(&range);
241 break;
242 case KEXEC_RANGE_MA_CPU:
243 ret = kexec_get(cpu)(&range);
244 break;
245 }
247 if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) )
248 return -EFAULT;
250 return ret;
251 }
253 #ifndef COMPAT
255 static int kexec_load_get_bits(int type, int *base, int *bit)
256 {
257 switch ( type )
258 {
259 case KEXEC_TYPE_DEFAULT:
260 *base = KEXEC_IMAGE_DEFAULT_BASE;
261 *bit = KEXEC_FLAG_DEFAULT_POS;
262 break;
263 case KEXEC_TYPE_CRASH:
264 *base = KEXEC_IMAGE_CRASH_BASE;
265 *bit = KEXEC_FLAG_CRASH_POS;
266 break;
267 default:
268 return -1;
269 }
270 return 0;
271 }
273 #endif
275 static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
276 {
277 xen_kexec_load_t load;
278 xen_kexec_image_t *image;
279 int base, bit, pos;
280 int ret = 0;
282 if ( unlikely(copy_from_guest(&load, uarg, 1)) )
283 return -EFAULT;
285 if ( kexec_load_get_bits(load.type, &base, &bit) )
286 return -EINVAL;
288 pos = (test_bit(bit, &kexec_flags) != 0);
290 /* Load the user data into an unused image */
291 if ( op == KEXEC_CMD_kexec_load )
292 {
293 image = &kexec_image[base + !pos];
295 BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */
297 #ifndef COMPAT
298 memcpy(image, &load.image, sizeof(*image));
299 #else
300 XLAT_kexec_image(image, &load.image);
301 #endif
303 if ( !(ret = machine_kexec_load(load.type, base + !pos, image)) )
304 {
305 /* Set image present bit */
306 set_bit((base + !pos), &kexec_flags);
308 /* Make new image the active one */
309 change_bit(bit, &kexec_flags);
310 }
311 }
313 /* Unload the old image if present and load successful */
314 if ( ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
315 {
316 if ( test_and_clear_bit((base + pos), &kexec_flags) )
317 {
318 image = &kexec_image[base + pos];
319 machine_kexec_unload(load.type, base + pos, image);
320 }
321 }
323 return ret;
324 }
326 #ifndef COMPAT
328 static int kexec_exec(XEN_GUEST_HANDLE(void) uarg)
329 {
330 xen_kexec_exec_t exec;
331 xen_kexec_image_t *image;
332 int base, bit, pos;
334 if ( unlikely(copy_from_guest(&exec, uarg, 1)) )
335 return -EFAULT;
337 if ( kexec_load_get_bits(exec.type, &base, &bit) )
338 return -EINVAL;
340 pos = (test_bit(bit, &kexec_flags) != 0);
342 /* Only allow kexec/kdump into loaded images */
343 if ( !test_bit(base + pos, &kexec_flags) )
344 return -ENOENT;
346 switch (exec.type)
347 {
348 case KEXEC_TYPE_DEFAULT:
349 image = &kexec_image[base + pos];
350 one_cpu_only();
351 machine_reboot_kexec(image); /* Does not return */
352 break;
353 case KEXEC_TYPE_CRASH:
354 kexec_crash(); /* Does not return */
355 break;
356 }
358 return -EINVAL; /* never reached */
359 }
361 #endif
363 ret_t do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
364 {
365 unsigned long flags;
366 int ret = -EINVAL;
368 if ( !IS_PRIV(current->domain) )
369 return -EPERM;
371 ret = xsm_kexec();
372 if ( ret )
373 return ret;
375 switch ( op )
376 {
377 case KEXEC_CMD_kexec_get_range:
378 ret = kexec_get(range)(uarg);
379 break;
380 case KEXEC_CMD_kexec_load:
381 case KEXEC_CMD_kexec_unload:
382 spin_lock_irqsave(&kexec_lock, flags);
383 if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags))
384 {
385 ret = kexec_load_unload(op, uarg);
386 }
387 spin_unlock_irqrestore(&kexec_lock, flags);
388 break;
389 case KEXEC_CMD_kexec:
390 ret = kexec_exec(uarg);
391 break;
392 }
394 return ret;
395 }
397 #if defined(CONFIG_COMPAT) && !defined(COMPAT)
398 #include "compat/kexec.c"
399 #endif
401 /*
402 * Local variables:
403 * mode: C
404 * c-set-style: "BSD"
405 * c-basic-offset: 4
406 * tab-width: 4
407 * indent-tabs-mode: nil
408 * End:
409 */