1 | /* |
---|
2 | * drivers/xen/core/machine_kexec.c |
---|
3 | * handle transition of Linux booting another kernel |
---|
4 | */ |
---|
5 | |
---|
6 | #include <linux/kexec.h> |
---|
7 | #include <xen/interface/kexec.h> |
---|
8 | #include <linux/mm.h> |
---|
9 | #include <linux/bootmem.h> |
---|
10 | |
---|
11 | extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, |
---|
12 | struct kimage *image); |
---|
13 | |
---|
14 | int xen_max_nr_phys_cpus; |
---|
15 | struct resource xen_hypervisor_res; |
---|
16 | struct resource *xen_phys_cpus; |
---|
17 | |
---|
18 | void xen_machine_kexec_setup_resources(void) |
---|
19 | { |
---|
20 | xen_kexec_range_t range; |
---|
21 | struct resource *res; |
---|
22 | int k = 0; |
---|
23 | |
---|
24 | if (!is_initial_xendomain()) |
---|
25 | return; |
---|
26 | |
---|
27 | /* determine maximum number of physical cpus */ |
---|
28 | |
---|
29 | while (1) { |
---|
30 | memset(&range, 0, sizeof(range)); |
---|
31 | range.range = KEXEC_RANGE_MA_CPU; |
---|
32 | range.nr = k; |
---|
33 | |
---|
34 | if(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
---|
35 | break; |
---|
36 | |
---|
37 | k++; |
---|
38 | } |
---|
39 | |
---|
40 | if (k == 0) |
---|
41 | return; |
---|
42 | |
---|
43 | xen_max_nr_phys_cpus = k; |
---|
44 | |
---|
45 | /* allocate xen_phys_cpus */ |
---|
46 | |
---|
47 | xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource)); |
---|
48 | BUG_ON(xen_phys_cpus == NULL); |
---|
49 | |
---|
50 | /* fill in xen_phys_cpus with per-cpu crash note information */ |
---|
51 | |
---|
52 | for (k = 0; k < xen_max_nr_phys_cpus; k++) { |
---|
53 | memset(&range, 0, sizeof(range)); |
---|
54 | range.range = KEXEC_RANGE_MA_CPU; |
---|
55 | range.nr = k; |
---|
56 | |
---|
57 | if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
---|
58 | goto err; |
---|
59 | |
---|
60 | res = xen_phys_cpus + k; |
---|
61 | |
---|
62 | memset(res, 0, sizeof(*res)); |
---|
63 | res->name = "Crash note"; |
---|
64 | res->start = range.start; |
---|
65 | res->end = range.start + range.size - 1; |
---|
66 | res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; |
---|
67 | } |
---|
68 | |
---|
69 | /* fill in xen_hypervisor_res with hypervisor machine address range */ |
---|
70 | |
---|
71 | memset(&range, 0, sizeof(range)); |
---|
72 | range.range = KEXEC_RANGE_MA_XEN; |
---|
73 | |
---|
74 | if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
---|
75 | goto err; |
---|
76 | |
---|
77 | xen_hypervisor_res.name = "Hypervisor code and data"; |
---|
78 | xen_hypervisor_res.start = range.start; |
---|
79 | xen_hypervisor_res.end = range.start + range.size - 1; |
---|
80 | xen_hypervisor_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM; |
---|
81 | |
---|
82 | /* fill in crashk_res if range is reserved by hypervisor */ |
---|
83 | |
---|
84 | memset(&range, 0, sizeof(range)); |
---|
85 | range.range = KEXEC_RANGE_MA_CRASH; |
---|
86 | |
---|
87 | if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
---|
88 | return; |
---|
89 | |
---|
90 | if (range.size) { |
---|
91 | crashk_res.start = range.start; |
---|
92 | crashk_res.end = range.start + range.size - 1; |
---|
93 | } |
---|
94 | |
---|
95 | return; |
---|
96 | |
---|
97 | err: |
---|
98 | /* |
---|
99 | * It isn't possible to free xen_phys_cpus this early in the |
---|
100 | * boot. Failure at this stage is unexpected and the amount of |
---|
101 | * memory is small therefore we tolerate the potential leak. |
---|
102 | */ |
---|
103 | xen_max_nr_phys_cpus = 0; |
---|
104 | return; |
---|
105 | } |
---|
106 | |
---|
107 | void xen_machine_kexec_register_resources(struct resource *res) |
---|
108 | { |
---|
109 | int k; |
---|
110 | |
---|
111 | request_resource(res, &xen_hypervisor_res); |
---|
112 | |
---|
113 | for (k = 0; k < xen_max_nr_phys_cpus; k++) |
---|
114 | request_resource(&xen_hypervisor_res, xen_phys_cpus + k); |
---|
115 | |
---|
116 | } |
---|
117 | |
---|
118 | static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) |
---|
119 | { |
---|
120 | machine_kexec_setup_load_arg(xki, image); |
---|
121 | |
---|
122 | xki->indirection_page = image->head; |
---|
123 | xki->start_address = image->start; |
---|
124 | } |
---|
125 | |
---|
126 | /* |
---|
127 | * Load the image into xen so xen can kdump itself |
---|
128 | * This might have been done in prepare, but prepare |
---|
129 | * is currently called too early. It might make sense |
---|
130 | * to move prepare, but for now, just add an extra hook. |
---|
131 | */ |
---|
132 | int xen_machine_kexec_load(struct kimage *image) |
---|
133 | { |
---|
134 | xen_kexec_load_t xkl; |
---|
135 | |
---|
136 | memset(&xkl, 0, sizeof(xkl)); |
---|
137 | xkl.type = image->type; |
---|
138 | setup_load_arg(&xkl.image, image); |
---|
139 | return HYPERVISOR_kexec_op(KEXEC_CMD_kexec_load, &xkl); |
---|
140 | } |
---|
141 | |
---|
142 | /* |
---|
143 | * Unload the image that was stored by machine_kexec_load() |
---|
144 | * This might have been done in machine_kexec_cleanup() but it |
---|
145 | * is called too late, and its possible xen could try and kdump |
---|
146 | * using resources that have been freed. |
---|
147 | */ |
---|
148 | void xen_machine_kexec_unload(struct kimage *image) |
---|
149 | { |
---|
150 | xen_kexec_load_t xkl; |
---|
151 | |
---|
152 | memset(&xkl, 0, sizeof(xkl)); |
---|
153 | xkl.type = image->type; |
---|
154 | HYPERVISOR_kexec_op(KEXEC_CMD_kexec_unload, &xkl); |
---|
155 | } |
---|
156 | |
---|
157 | /* |
---|
158 | * Do not allocate memory (or fail in any way) in machine_kexec(). |
---|
159 | * We are past the point of no return, committed to rebooting now. |
---|
160 | * |
---|
161 | * This has the hypervisor move to the prefered reboot CPU, |
---|
162 | * stop all CPUs and kexec. That is it combines machine_shutdown() |
---|
163 | * and machine_kexec() in Linux kexec terms. |
---|
164 | */ |
---|
165 | NORET_TYPE void machine_kexec(struct kimage *image) |
---|
166 | { |
---|
167 | xen_kexec_exec_t xke; |
---|
168 | |
---|
169 | memset(&xke, 0, sizeof(xke)); |
---|
170 | xke.type = image->type; |
---|
171 | HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke); |
---|
172 | panic("KEXEC_CMD_kexec hypercall should not return\n"); |
---|
173 | } |
---|
174 | |
---|
175 | void machine_shutdown(void) |
---|
176 | { |
---|
177 | /* do nothing */ |
---|
178 | } |
---|
179 | |
---|
180 | |
---|
181 | /* |
---|
182 | * Local variables: |
---|
183 | * c-file-style: "linux" |
---|
184 | * indent-tabs-mode: t |
---|
185 | * c-indent-level: 8 |
---|
186 | * c-basic-offset: 8 |
---|
187 | * tab-width: 8 |
---|
188 | * End: |
---|
189 | */ |
---|