ia64/xen-unstable

view tools/libxc/xc_ppc_linux_build.c @ 10836:80e2c1b3f9b1

[powerpc] domain building fixes for linux kexec model
The following updates are included:
- No stack allocation is necessary
- Some buggy kernels require r13 to be zeroed
- the DTB must be loaded from a fixed address, we are using
"/root/DomU.dtb" until we have the tools build the DTB on their
own.
- Though we give the PFN of the store and console pages to the new
domain we must make sure the MFN is given to the tools.

Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
author Jimi Xenidis <jimix@watson.ibm.com>
date Wed Jul 26 14:24:09 2006 -0400 (2006-07-26)
parents 050de6b53961
children c8870f1aa5ca
line source
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * Copyright (C) IBM Corporation 2006
17 *
18 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
19 */
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <inttypes.h>
30 #include <xen/dom0_ops.h>
31 #include <xen/memory.h>
32 #include <xc_private.h>
33 #include <xg_private.h>
34 #include <xenctrl.h>
36 /* XXX 64M hack */
37 #define MEMSIZE (64UL << 20)
38 #define INITRD_ADDR (24UL << 20)
40 int verbose;
41 #define VERBOSE(stuff, ...) \
42 if (verbose) \
43 stuff __VA_ARGS__;
45 #define ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
47 #define max(x,y) ({ \
48 const typeof(x) _x = (x); \
49 const typeof(y) _y = (y); \
50 (void) (&_x == &_y); \
51 _x > _y ? _x : _y; })
53 static void *load_file(const char *path, unsigned long *filesize)
54 {
55 void *img;
56 ssize_t size;
57 int fd;
59 VERBOSE(printf("load_file(%s)\n", path));
61 fd = open(path, O_RDONLY);
62 if (fd < 0) {
63 perror(path);
64 return NULL;
65 }
67 size = lseek(fd, 0, SEEK_END);
68 if (size < 0) {
69 perror(path);
70 close(fd);
71 return NULL;
72 }
73 lseek(fd, 0, SEEK_SET);
75 img = malloc(size);
76 if (img == NULL) {
77 perror(path);
78 close(fd);
79 return NULL;
80 }
82 size = read(fd, img, size);
83 if (size <= 0) {
84 perror(path);
85 close(fd);
86 free(img);
87 return NULL;
88 }
90 if (filesize)
91 *filesize = size;
92 close(fd);
93 return img;
94 }
96 static int init_boot_vcpu(
97 int xc_handle,
98 int domid,
99 struct domain_setup_info *dsi,
100 unsigned long dtb,
101 unsigned long kaddr)
102 {
103 vcpu_guest_context_t ctxt;
104 int rc;
106 memset(&ctxt.user_regs, 0x55, sizeof(ctxt.user_regs));
107 ctxt.user_regs.pc = dsi->v_kernentry;
108 ctxt.user_regs.msr = 0;
109 ctxt.user_regs.gprs[1] = 0; /* Linux uses its own stack */
110 ctxt.user_regs.gprs[3] = dtb;
111 ctxt.user_regs.gprs[4] = kaddr;
112 ctxt.user_regs.gprs[5] = 0;
113 /* There is a buggy kernel that does not zero the "local_paca", so
114 * we must make sure this register is 0 */
115 ctxt.user_regs.gprs[13] = 0;
117 VERBOSE(printf("xc_vcpu_setvcpucontext:\n"
118 " pc 0x%"PRIx64", msr 0x016%"PRIx64"\n"
119 " r1-5 %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64
120 " %016"PRIx64"\n",
121 ctxt.user_regs.pc, ctxt.user_regs.msr,
122 ctxt.user_regs.gprs[1],
123 ctxt.user_regs.gprs[2],
124 ctxt.user_regs.gprs[3],
125 ctxt.user_regs.gprs[4],
126 ctxt.user_regs.gprs[5]));
127 rc = xc_vcpu_setcontext(xc_handle, domid, 0, &ctxt);
128 if (rc < 0)
129 perror("setdomaininfo");
131 return rc;
132 }
134 static int install_image(
135 int xc_handle,
136 int domid,
137 xen_pfn_t *page_array,
138 void *image,
139 unsigned long paddr,
140 unsigned long size)
141 {
142 uint8_t *img = image;
143 int i;
144 int rc = 0;
146 if (paddr & ~PAGE_MASK) {
147 printf("*** unaligned address\n");
148 return -1;
149 }
151 for (i = 0; i < size; i += PAGE_SIZE) {
152 void *page = img + i;
153 xen_pfn_t pfn = (paddr + i) >> PAGE_SHIFT;
154 xen_pfn_t mfn = page_array[pfn];
156 rc = xc_copy_to_domain_page(xc_handle, domid, mfn, page);
157 if (rc < 0) {
158 perror("xc_copy_to_domain_page");
159 break;
160 }
161 }
162 return rc;
163 }
165 /* XXX be more flexible about placement in memory */
166 static int load_dtb(
167 int xc_handle,
168 int domid,
169 const char *dtb_path,
170 unsigned long dtb_addr,
171 struct domain_setup_info *dsi,
172 xen_pfn_t *page_array)
173 {
174 uint8_t *img;
175 unsigned long dtb_size;
176 int rc = 0;
178 img = load_file(dtb_path, &dtb_size);
179 if (img == NULL) {
180 rc = -1;
181 goto out;
182 }
184 VERBOSE(printf("copying device tree to 0x%lx[0x%lx]\n",
185 dtb_addr, dtb_size));
186 rc = install_image(xc_handle, domid, page_array, img, dtb_addr, dtb_size);
188 out:
189 free(img);
190 return rc;
191 }
193 unsigned long spin_list[] = {
194 #if 0
195 0x100,
196 0x200,
197 0x300,
198 0x380,
199 0x400,
200 0x480,
201 0x500,
202 0x700,
203 0x900,
204 0xc00,
205 #endif
206 0
207 };
209 /* XXX yes, this is a hack */
210 static void hack_kernel_img(char *img)
211 {
212 const off_t file_offset = 0x10000;
213 unsigned long *addr = spin_list;
215 while (*addr) {
216 uint32_t *instruction = (uint32_t *)(img + *addr + file_offset);
217 printf("installing spin loop at %lx (%x)\n", *addr, *instruction);
218 *instruction = 0x48000000;
219 addr++;
220 }
221 }
223 static int load_kernel(
224 int xc_handle,
225 int domid,
226 const char *kernel_path,
227 struct domain_setup_info *dsi,
228 xen_pfn_t *page_array)
229 {
230 struct load_funcs load_funcs;
231 char *kernel_img;
232 unsigned long kernel_size;
233 int rc;
235 /* load the kernel ELF file */
236 kernel_img = load_file(kernel_path, &kernel_size);
237 if (kernel_img == NULL) {
238 rc = -1;
239 goto out;
240 }
242 hack_kernel_img(kernel_img);
244 VERBOSE(printf("probe_elf\n"));
245 rc = probe_elf(kernel_img, kernel_size, &load_funcs);
246 if (rc < 0) {
247 rc = -1;
248 printf("%s is not an ELF file\n", kernel_path);
249 goto out;
250 }
252 VERBOSE(printf("parseimage\n"));
253 rc = (load_funcs.parseimage)(kernel_img, kernel_size, dsi);
254 if (rc < 0) {
255 rc = -1;
256 goto out;
257 }
259 VERBOSE(printf("loadimage\n"));
260 (load_funcs.loadimage)(kernel_img, kernel_size, xc_handle, domid,
261 page_array, dsi);
263 VERBOSE(printf(" v_start %016"PRIx64"\n", dsi->v_start));
264 VERBOSE(printf(" v_end %016"PRIx64"\n", dsi->v_end));
265 VERBOSE(printf(" v_kernstart %016"PRIx64"\n", dsi->v_kernstart));
266 VERBOSE(printf(" v_kernend %016"PRIx64"\n", dsi->v_kernend));
267 VERBOSE(printf(" v_kernentry %016"PRIx64"\n", dsi->v_kernentry));
269 out:
270 free(kernel_img);
271 return rc;
272 }
274 static int load_initrd(
275 int xc_handle,
276 int domid,
277 xen_pfn_t *page_array,
278 const char *initrd_path,
279 unsigned long *base,
280 unsigned long *len)
281 {
282 uint8_t *initrd_img;
283 int rc = -1;
285 /* load the initrd file */
286 initrd_img = load_file(initrd_path, len);
287 if (initrd_img == NULL)
288 return -1;
290 VERBOSE(printf("copying initrd to 0x%lx[0x%lx]\n", INITRD_ADDR, *len));
291 if (install_image(xc_handle, domid, page_array, initrd_img, INITRD_ADDR,
292 *len))
293 goto out;
295 *base = INITRD_ADDR;
296 rc = 0;
298 out:
299 free(initrd_img);
300 return rc;
301 }
303 static unsigned long create_start_info(start_info_t *si,
304 unsigned int console_evtchn, unsigned int store_evtchn)
305 {
306 unsigned long eomem;
307 unsigned long si_addr;
309 memset(si, 0, sizeof(*si));
310 snprintf(si->magic, sizeof(si->magic), "xen-%d.%d-powerpc64HV", 3, 0);
312 eomem = MEMSIZE;
313 si->nr_pages = eomem >> PAGE_SHIFT;
314 si->shared_info = eomem - (PAGE_SIZE * 1);
315 si->store_mfn = si->nr_pages - 2;
316 si->store_evtchn = store_evtchn;
317 si->console_mfn = si->nr_pages - 3;
318 si->console_evtchn = console_evtchn;
319 si_addr = eomem - (PAGE_SIZE * 4);
321 return si_addr;
322 }
324 static int get_page_array(int xc_handle, int domid, xen_pfn_t **page_array)
325 {
326 int nr_pages;
327 int rc;
329 VERBOSE(printf("xc_get_tot_pages\n"));
330 nr_pages = xc_get_tot_pages(xc_handle, domid);
331 VERBOSE(printf(" 0x%x\n", nr_pages));
333 *page_array = malloc(nr_pages * sizeof(xen_pfn_t));
334 if (*page_array == NULL) {
335 perror("malloc");
336 return -1;
337 }
339 VERBOSE(printf("xc_get_pfn_list\n"));
340 rc = xc_get_pfn_list(xc_handle, domid, *page_array, nr_pages);
341 if (rc != nr_pages) {
342 perror("Could not get the page frame list");
343 return -1;
344 }
346 return 0;
347 }
351 int xc_linux_build(int xc_handle,
352 uint32_t domid,
353 const char *image_name,
354 const char *initrd_name,
355 const char *cmdline,
356 const char *features,
357 unsigned long flags,
358 unsigned int store_evtchn,
359 unsigned long *store_mfn,
360 unsigned int console_evtchn,
361 unsigned long *console_mfn)
362 {
363 struct domain_setup_info dsi;
364 xen_pfn_t *page_array = NULL;
365 unsigned long kern_addr;
366 unsigned long dtb_addr;
367 unsigned long si_addr;
368 unsigned long initrd_base = 0;
369 unsigned long initrd_len = 0;
370 start_info_t si;
371 int rc = 0;
373 if (get_page_array(xc_handle, domid, &page_array)) {
374 rc = -1;
375 goto out;
376 }
378 if (load_kernel(xc_handle, domid, image_name, &dsi, page_array)) {
379 rc = -1;
380 goto out;
381 }
382 kern_addr = 0;
384 if (initrd_name && initrd_name[0] != '\0' &&
385 load_initrd(xc_handle, domid, page_array, initrd_name, &initrd_base,
386 &initrd_len)) {
387 rc = -1;
388 goto out;
389 }
390 /* XXX install initrd addr/len into device tree */
392 dtb_addr = (16 << 20);
393 if (load_dtb(xc_handle, domid, "/root/DomU.dtb", dtb_addr, &dsi, page_array)) {
394 dtb_addr = 0;
395 }
397 si_addr = create_start_info(&si, store_evtchn, console_evtchn);
398 *console_mfn = page_array[si.console_mfn];
399 *store_mfn = page_array[si.store_mfn];
401 if (install_image(xc_handle, domid, page_array, &si, si_addr,
402 sizeof(start_info_t))) {
403 rc = -1;
404 goto out;
405 }
407 if (init_boot_vcpu(xc_handle, domid, &dsi, dtb_addr, kern_addr)) {
408 rc = -1;
409 goto out;
410 }
412 out:
413 return rc;
414 }