ia64/linux-2.6.18-xen.hg

view arch/ia64/kernel/machine_kexec.c @ 451:11371d0e841b

kexec: read more iomem regions from hypervisor

This sets the location of the efi memmap and boot parameter
regions using information provided by the hypervisor,
overriding values derived by dom0 from the virtualised
efi memory regions.

It also creates a xen heap region and uses this as the parent
of per-cpu regions - they belong in hypervisor memory not
dom0 kernel memory.

The xen heap region is inserted into /proc/iomem_machine

* There is also a hypervisor portion of this patch.
* In order for the regions to show up after kexec patches
to kexec-tools are required. I have posted them
to the kexec mailing list and intend to merge them.

http://lists.infradead.org/pipermail/kexec/2008-February/001348.html

Signed-off-by: Simon Horman <horms@verge.net.au>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 28 10:54:55 2008 +0000 (2008-02-28)
parents b7f980c60a61
children
line source
1 /*
2 * arch/ia64/kernel/machine_kexec.c
3 *
4 * Handle transition of Linux booting another kernel
5 * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P.
6 * Copyright (C) 2005 Khalid Aziz <khalid.aziz@hp.com>
7 * Copyright (C) 2006 Intel Corp, Zou Nan hai <nanhai.zou@intel.com>
8 *
9 * This source code is licensed under the GNU General Public License,
10 * Version 2. See the file COPYING for more details.
11 */
13 #include <linux/mm.h>
14 #include <linux/kexec.h>
15 #include <linux/cpu.h>
16 #include <linux/irq.h>
17 #include <asm/mmu_context.h>
18 #include <asm/setup.h>
19 #include <asm/delay.h>
20 #include <asm/meminit.h>
21 #ifdef CONFIG_XEN
22 #include <xen/interface/kexec.h>
23 #include <asm/kexec.h>
24 #endif
26 typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long,
27 struct ia64_boot_param *, unsigned long);
29 struct kimage *ia64_kimage;
31 struct resource efi_memmap_res = {
32 .name = "EFI Memory Map",
33 .start = 0,
34 .end = 0,
35 .flags = IORESOURCE_BUSY | IORESOURCE_MEM
36 };
38 struct resource boot_param_res = {
39 .name = "Boot parameter",
40 .start = 0,
41 .end = 0,
42 .flags = IORESOURCE_BUSY | IORESOURCE_MEM
43 };
46 /*
47 * Do what every setup is needed on image and the
48 * reboot code buffer to allow us to avoid allocations
49 * later.
50 */
51 int machine_kexec_prepare(struct kimage *image)
52 {
53 void *control_code_buffer;
54 const unsigned long *func;
56 func = (unsigned long *)&relocate_new_kernel;
57 /* Pre-load control code buffer to minimize work in kexec path */
58 control_code_buffer = page_address(image->control_code_page);
59 memcpy((void *)control_code_buffer, (const void *)func[0],
60 relocate_new_kernel_size);
61 flush_icache_range((unsigned long)control_code_buffer,
62 (unsigned long)control_code_buffer + relocate_new_kernel_size);
63 ia64_kimage = image;
65 return 0;
66 }
68 void machine_kexec_cleanup(struct kimage *image)
69 {
70 }
72 #ifndef CONFIG_XEN
73 void machine_shutdown(void)
74 {
75 int cpu;
77 for_each_online_cpu(cpu) {
78 if (cpu != smp_processor_id())
79 cpu_down(cpu);
80 }
81 kexec_disable_iosapic();
82 }
84 /*
85 * Do not allocate memory (or fail in any way) in machine_kexec().
86 * We are past the point of no return, committed to rebooting now.
87 */
88 extern void *efi_get_pal_addr(void);
89 static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
90 {
91 struct kimage *image = arg;
92 relocate_new_kernel_t rnk;
93 void *pal_addr = efi_get_pal_addr();
94 unsigned long code_addr = (unsigned long)page_address(image->control_code_page);
95 unsigned long vector;
96 int ii;
98 if (image->type == KEXEC_TYPE_CRASH) {
99 crash_save_this_cpu();
100 current->thread.ksp = (__u64)info->sw - 16;
101 }
103 /* Interrupts aren't acceptable while we reboot */
104 local_irq_disable();
106 /* Mask CMC and Performance Monitor interrupts */
107 ia64_setreg(_IA64_REG_CR_PMV, 1 << 16);
108 ia64_setreg(_IA64_REG_CR_CMCV, 1 << 16);
110 /* Mask ITV and Local Redirect Registers */
111 ia64_set_itv(1 << 16);
112 ia64_set_lrr0(1 << 16);
113 ia64_set_lrr1(1 << 16);
115 /* terminate possible nested in-service interrupts */
116 for (ii = 0; ii < 16; ii++)
117 ia64_eoi();
119 /* unmask TPR and clear any pending interrupts */
120 ia64_setreg(_IA64_REG_CR_TPR, 0);
121 ia64_srlz_d();
122 vector = ia64_get_ivr();
123 while (vector != IA64_SPURIOUS_INT_VECTOR) {
124 ia64_eoi();
125 vector = ia64_get_ivr();
126 }
127 platform_kernel_launch_event();
128 rnk = (relocate_new_kernel_t)&code_addr;
129 (*rnk)(image->head, image->start, ia64_boot_param,
130 GRANULEROUNDDOWN((unsigned long) pal_addr));
131 BUG();
132 }
134 void machine_kexec(struct kimage *image)
135 {
136 unw_init_running(ia64_machine_kexec, image);
137 for(;;);
138 }
139 #else /* CONFIG_XEN */
140 void machine_kexec_setup_load_arg(xen_kexec_image_t *xki,struct kimage *image)
141 {
142 xki->reboot_code_buffer =
143 kexec_page_to_pfn(image->control_code_page) << PAGE_SHIFT;
144 }
146 static struct resource xen_hypervisor_heap_res;
148 int __init machine_kexec_setup_resources(struct resource *hypervisor,
149 struct resource *phys_cpus,
150 int nr_phys_cpus)
151 {
152 xen_kexec_range_t range;
153 int k;
155 /* fill in xen_hypervisor_heap_res with hypervisor heap
156 * machine address range
157 */
159 memset(&range, 0, sizeof(range));
160 range.range = KEXEC_RANGE_MA_XENHEAP;
162 if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
163 return -1;
165 xen_hypervisor_heap_res.name = "Hypervisor heap";
166 xen_hypervisor_heap_res.start = range.start;
167 xen_hypervisor_heap_res.end = range.start + range.size - 1;
168 xen_hypervisor_heap_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM;
170 /* The per-cpu crash note resources belong inside the
171 * hypervisor heap resource */
172 for (k = 0; k < nr_phys_cpus; k++)
173 request_resource(&xen_hypervisor_heap_res, phys_cpus + k);
175 /* fill in efi_memmap_res with EFI memmap machine address range */
177 memset(&range, 0, sizeof(range));
178 range.range = KEXEC_RANGE_MA_EFI_MEMMAP;
180 if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
181 return -1;
183 efi_memmap_res.start = range.start;
184 efi_memmap_res.end = range.start + range.size - 1;
186 /* fill in boot_param_res with boot parameter machine address range */
188 memset(&range, 0, sizeof(range));
189 range.range = KEXEC_RANGE_MA_BOOT_PARAM;
191 if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
192 return -1;
194 boot_param_res.start = range.start;
195 boot_param_res.end = range.start + range.size - 1;
197 return 0;
198 }
200 void machine_kexec_register_resources(struct resource *res)
201 {
202 request_resource(res, &xen_hypervisor_heap_res);
203 }
204 #endif /* CONFIG_XEN */