ia64/xen-unstable

view xen/common/kexec.c @ 12772:b08b870770f9

[PATCH 02/02] Kexec / Kdump: Don't declare _end

_end is already declared in xen/include/asm/config.h, so don't declare
it twice. This solves a powerpc/ia64 build problem where _end is declared
as char _end[] compared to unsigned long _end on x86.

Signed-Off-By: Magnus Damm <magnus@valinux.co.jp>
author Ian Campbell <ian.campbell@xensource.com>
date Mon Dec 04 09:08:47 2006 +0000 (2006-12-04)
parents 5091a9a55d86
children 58284e749407
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 <asm/kexec.h>
10 #include <xen/lib.h>
11 #include <xen/ctype.h>
12 #include <xen/errno.h>
13 #include <xen/guest_access.h>
14 #include <xen/sched.h>
15 #include <xen/types.h>
16 #include <xen/kexec.h>
17 #include <xen/keyhandler.h>
18 #include <public/kexec.h>
19 #include <xen/cpumask.h>
20 #include <asm/atomic.h>
21 #include <xen/spinlock.h>
22 #include <xen/version.h>
23 #include <public/elfnote.h>
25 DEFINE_PER_CPU (crash_note_t, crash_notes);
26 cpumask_t crash_saved_cpus;
27 int crashing_cpu;
29 xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR];
31 #define KEXEC_FLAG_DEFAULT_POS (KEXEC_IMAGE_NR + 0)
32 #define KEXEC_FLAG_CRASH_POS (KEXEC_IMAGE_NR + 1)
33 #define KEXEC_FLAG_IN_PROGRESS (KEXEC_IMAGE_NR + 2)
35 unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */
37 spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED;
39 xen_kexec_reserve_t kexec_crash_area;
41 static void __init parse_crashkernel(char *str)
42 {
43 unsigned long start, size;
45 size = parse_size_and_unit(str, &str);
46 if ( *str == '@' )
47 start = parse_size_and_unit(str+1, NULL);
48 else
49 start = 0;
51 if ( start && size )
52 {
53 kexec_crash_area.start = start;
54 kexec_crash_area.size = size;
55 }
56 }
57 custom_param("crashkernel", parse_crashkernel);
59 static void one_cpu_only(void)
60 {
61 /* Only allow the first cpu to continue - force other cpus to spin */
62 if ( test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
63 {
64 while (1);
65 }
66 }
68 /* Save the registers in the per-cpu crash note buffer */
70 void machine_crash_save_cpu(void)
71 {
72 int cpu = smp_processor_id();
73 crash_note_t *cntp;
75 if ( !cpu_test_and_set(cpu, crash_saved_cpus) )
76 {
77 cntp = &per_cpu(crash_notes, cpu);
78 elf_core_save_regs(&cntp->core.desc.desc.pr_reg,
79 &cntp->xen_regs.desc.desc);
81 /* setup crash "CORE" note */
82 setup_crash_note(cntp, core, CORE_STR, CORE_STR_LEN, NT_PRSTATUS);
84 /* setup crash note "Xen", XEN_ELFNOTE_CRASH_REGS */
85 setup_crash_note(cntp, xen_regs, XEN_STR, XEN_STR_LEN,
86 XEN_ELFNOTE_CRASH_REGS);
87 }
88 }
90 /* Setup the single Xen specific info crash note */
92 crash_xen_info_t *machine_crash_save_info(void)
93 {
94 int cpu = smp_processor_id();
95 crash_note_t *cntp;
96 crash_xen_info_t *info;
98 BUG_ON(!cpu_test_and_set(cpu, crash_saved_cpus));
100 cntp = &per_cpu(crash_notes, cpu);
102 /* setup crash note "Xen", XEN_ELFNOTE_CRASH_INFO */
103 setup_crash_note(cntp, xen_info, XEN_STR, XEN_STR_LEN,
104 XEN_ELFNOTE_CRASH_INFO);
106 info = &cntp->xen_info.desc.desc;
108 info->xen_major_version = xen_major_version();
109 info->xen_minor_version = xen_minor_version();
110 info->xen_extra_version = __pa(xen_extra_version());
111 info->xen_changeset = __pa(xen_changeset());
112 info->xen_compiler = __pa(xen_compiler());
113 info->xen_compile_date = __pa(xen_compile_date());
114 info->xen_compile_time = __pa(xen_compile_time());
115 info->tainted = tainted;
117 return info;
118 }
120 void machine_crash_kexec(void)
121 {
122 int pos;
123 xen_kexec_image_t *image;
125 one_cpu_only();
127 machine_crash_save_cpu();
128 crashing_cpu = smp_processor_id();
130 machine_crash_shutdown();
132 pos = (test_bit(KEXEC_FLAG_CRASH_POS, &kexec_flags) != 0);
134 if ( test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags) )
135 {
136 image = &kexec_image[KEXEC_IMAGE_CRASH_BASE + pos];
137 machine_kexec(image); /* Does not return */
138 }
139 }
141 static void do_crashdump_trigger(unsigned char key)
142 {
143 printk("triggering crashdump\n");
144 machine_crash_kexec();
145 }
147 static __init int register_crashdump_trigger(void)
148 {
149 register_keyhandler('c', do_crashdump_trigger, "trigger a crashdump");
150 return 0;
151 }
152 __initcall(register_crashdump_trigger);
154 static int kexec_get_reserve(xen_kexec_range_t *range)
155 {
156 range->start = kexec_crash_area.start;
157 range->size = kexec_crash_area.size;
158 return 0;
159 }
161 extern unsigned long _text;
163 static int kexec_get_xen(xen_kexec_range_t *range, int get_ma)
164 {
165 if ( get_ma )
166 range->start = virt_to_maddr(&_text);
167 else
168 range->start = (unsigned long) &_text;
170 range->size = (unsigned long)&_end - (unsigned long)&_text;
171 return 0;
172 }
174 static int kexec_get_cpu(xen_kexec_range_t *range)
175 {
176 if ( range->nr < 0 || range->nr >= num_present_cpus() )
177 return -EINVAL;
179 range->start = __pa((unsigned long)&per_cpu(crash_notes, range->nr));
180 range->size = sizeof(crash_note_t);
181 return 0;
182 }
184 static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg)
185 {
186 xen_kexec_range_t range;
187 int ret = -EINVAL;
189 if ( unlikely(copy_from_guest(&range, uarg, 1)) )
190 return -EFAULT;
192 switch ( range.range )
193 {
194 case KEXEC_RANGE_MA_CRASH:
195 ret = kexec_get_reserve(&range);
196 break;
197 case KEXEC_RANGE_MA_XEN:
198 ret = kexec_get_xen(&range, 1);
199 break;
200 case KEXEC_RANGE_VA_XEN:
201 ret = kexec_get_xen(&range, 0);
202 break;
203 case KEXEC_RANGE_MA_CPU:
204 ret = kexec_get_cpu(&range);
205 break;
206 }
208 if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) )
209 return -EFAULT;
211 return ret;
212 }
214 static int kexec_load_get_bits(int type, int *base, int *bit)
215 {
216 switch ( type )
217 {
218 case KEXEC_TYPE_DEFAULT:
219 *base = KEXEC_IMAGE_DEFAULT_BASE;
220 *bit = KEXEC_FLAG_DEFAULT_POS;
221 break;
222 case KEXEC_TYPE_CRASH:
223 *base = KEXEC_IMAGE_CRASH_BASE;
224 *bit = KEXEC_FLAG_CRASH_POS;
225 break;
226 default:
227 return -1;
228 }
229 return 0;
230 }
232 static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
233 {
234 xen_kexec_load_t load;
235 xen_kexec_image_t *image;
236 int base, bit, pos;
237 int ret = 0;
239 if ( unlikely(copy_from_guest(&load, uarg, 1)) )
240 return -EFAULT;
242 if ( kexec_load_get_bits(load.type, &base, &bit) )
243 return -EINVAL;
245 pos = (test_bit(bit, &kexec_flags) != 0);
247 /* Load the user data into an unused image */
248 if ( op == KEXEC_CMD_kexec_load )
249 {
250 image = &kexec_image[base + !pos];
252 BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */
254 memcpy(image, &load.image, sizeof(*image));
256 if ( !(ret = machine_kexec_load(load.type, base + !pos, image)) )
257 {
258 /* Set image present bit */
259 set_bit((base + !pos), &kexec_flags);
261 /* Make new image the active one */
262 change_bit(bit, &kexec_flags);
263 }
264 }
266 /* Unload the old image if present and load successful */
267 if ( ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
268 {
269 if ( test_and_clear_bit((base + pos), &kexec_flags) )
270 {
271 image = &kexec_image[base + pos];
272 machine_kexec_unload(load.type, base + pos, image);
273 }
274 }
276 return ret;
277 }
279 static int kexec_exec(XEN_GUEST_HANDLE(void) uarg)
280 {
281 xen_kexec_exec_t exec;
282 xen_kexec_image_t *image;
283 int base, bit, pos;
285 if ( unlikely(copy_from_guest(&exec, uarg, 1)) )
286 return -EFAULT;
288 if ( kexec_load_get_bits(exec.type, &base, &bit) )
289 return -EINVAL;
291 pos = (test_bit(bit, &kexec_flags) != 0);
293 /* Only allow kexec/kdump into loaded images */
294 if ( !test_bit(base + pos, &kexec_flags) )
295 return -ENOENT;
297 switch (exec.type)
298 {
299 case KEXEC_TYPE_DEFAULT:
300 image = &kexec_image[base + pos];
301 one_cpu_only();
302 machine_reboot_kexec(image); /* Does not return */
303 break;
304 case KEXEC_TYPE_CRASH:
305 machine_crash_kexec(); /* Does not return */
306 break;
307 }
309 return -EINVAL; /* never reached */
310 }
312 long do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
313 {
314 unsigned long flags;
315 int ret = -EINVAL;
317 if ( !IS_PRIV(current->domain) )
318 return -EPERM;
320 switch ( op )
321 {
322 case KEXEC_CMD_kexec_get_range:
323 ret = kexec_get_range(uarg);
324 break;
325 case KEXEC_CMD_kexec_load:
326 case KEXEC_CMD_kexec_unload:
327 spin_lock_irqsave(&kexec_lock, flags);
328 if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags))
329 {
330 ret = kexec_load_unload(op, uarg);
331 }
332 spin_unlock_irqrestore(&kexec_lock, flags);
333 break;
334 case KEXEC_CMD_kexec:
335 ret = kexec_exec(uarg);
336 break;
337 }
339 return ret;
340 }
342 /*
343 * Local variables:
344 * mode: C
345 * c-set-style: "BSD"
346 * c-basic-offset: 4
347 * tab-width: 4
348 * indent-tabs-mode: nil
349 * End:
350 */