debuggers.hg

view tools/libxc/xc_vmx_build.c @ 3643:a920f0ced90f

bitkeeper revision 1.1159.212.66 (42001b6f4kUEhmWXQmgg_vNH-AqiWQ)

Right now, the memory for the 1:1 physical mode page tables comes from the
VMX domain's memory. With this change, when the user asks for a domain with
M Megabytes of memory, we actually allocate M+N megabytes in xend, where
N is the memory for the page table pages.

This simplifies the code in the device models that maps guest memory (we
now map all of it) and the E820 map can also give the full M megabytes to
the guest.

Signed-off-by: Xin B Li <xin.b.li@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
Signed-off-by: ian.pratt@cl.cam.ac.uk
author iap10@labyrinth.cl.cam.ac.uk
date Wed Feb 02 00:14:39 2005 +0000 (2005-02-02)
parents 2c56c6b39a48
children 281346e5fc97
line source
1 /******************************************************************************
2 * xc_vmx_build.c
3 */
5 #include "xc_private.h"
6 #define ELFSIZE 32
7 #include "xc_elf.h"
8 #include <stdlib.h>
9 #include <zlib.h>
10 #include "linux_boot_params.h"
12 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
13 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
15 #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
16 #define round_pgdown(_p) ((_p)&PAGE_MASK)
18 #define LINUX_BOOT_PARAMS_ADDR 0x00090000
19 #define LINUX_KERNEL_ENTR_ADDR 0x00100000
20 #define LINUX_PAGE_OFFSET 0xC0000000
22 struct domain_setup_info
23 {
24 unsigned long v_start;
25 unsigned long v_end;
26 unsigned long v_kernstart;
27 unsigned long v_kernend;
28 unsigned long v_kernentry;
30 unsigned int use_writable_pagetables;
31 unsigned int load_bsd_symtab;
33 unsigned long symtab_addr;
34 unsigned long symtab_len;
35 };
37 static int
38 parseelfimage(
39 char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
40 static int
41 loadelfimage(
42 char *elfbase, int xch, u32 dom, unsigned long *parray,
43 unsigned long vstart);
44 static int
45 loadelfsymtab(
46 char *elfbase, int xch, u32 dom, unsigned long *parray,
47 struct domain_setup_info *dsi);
49 static int setup_guestos(int xc_handle,
50 u32 dom, int memsize,
51 char *image, unsigned long image_size,
52 gzFile initrd_gfd, unsigned long initrd_len,
53 unsigned long nr_pages,
54 full_execution_context_t *ctxt,
55 const char *cmdline,
56 unsigned long shared_info_frame,
57 unsigned int control_evtchn,
58 unsigned long flags,
59 struct mem_map * mem_mapp)
60 {
61 l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
62 l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
63 unsigned long *page_array = NULL;
64 unsigned long l2tab;
65 unsigned long l1tab;
66 unsigned long count, i;
67 shared_info_t *shared_info;
68 struct linux_boot_params * boot_paramsp;
69 __u16 * boot_gdtp;
70 mmu_t *mmu = NULL;
71 int rc;
73 unsigned long nr_pt_pages;
74 unsigned long ppt_alloc;
76 struct domain_setup_info dsi;
77 unsigned long vinitrd_start;
78 unsigned long vinitrd_end;
79 unsigned long vboot_params_start;
80 unsigned long vboot_params_end;
81 unsigned long vboot_gdt_start;
82 unsigned long vboot_gdt_end;
83 unsigned long vpt_start;
84 unsigned long vpt_end;
85 unsigned long v_end;
87 memset(&dsi, 0, sizeof(struct domain_setup_info));
89 rc = parseelfimage(image, image_size, &dsi);
90 if ( rc != 0 )
91 goto error_out;
93 if (dsi.use_writable_pagetables)
94 xc_domain_setvmassist(xc_handle, dom, VMASST_CMD_enable,
95 VMASST_TYPE_writable_pagetables);
97 if (dsi.load_bsd_symtab)
98 loadelfsymtab(image, xc_handle, dom, NULL, &dsi);
100 if ( (dsi.v_start & (PAGE_SIZE-1)) != 0 )
101 {
102 PERROR("Guest OS must load to a page boundary.\n");
103 goto error_out;
104 }
106 /*
107 * Why do we need this? The number of page-table frames depends on the
108 * size of the bootstrap address space. But the size of the address space
109 * depends on the number of page-table frames (since each one is mapped
110 * read-only). We have a pair of simultaneous equations in two unknowns,
111 * which we solve by exhaustive search.
112 */
113 vboot_params_start = LINUX_BOOT_PARAMS_ADDR;
114 vboot_params_end = vboot_params_start + PAGE_SIZE;
115 vboot_gdt_start = vboot_params_end;
116 vboot_gdt_end = vboot_gdt_start + PAGE_SIZE;
118 v_end = memsize << 20;
119 vinitrd_end = v_end - PAGE_SIZE; /* leaving the top 4k untouched for IO requests page use */
120 vinitrd_start = vinitrd_end - initrd_len;
121 vinitrd_start = vinitrd_start & (~(PAGE_SIZE - 1));
123 if(initrd_len == 0)
124 vinitrd_start = vinitrd_end = 0;
126 nr_pt_pages = 1 + ((memsize + 3) >> 2);
127 vpt_start = v_end;
128 vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
130 printf("VIRTUAL MEMORY ARRANGEMENT:\n"
131 " Boot_params: %08lx->%08lx\n"
132 " boot_gdt: %08lx->%08lx\n"
133 " Loaded kernel: %08lx->%08lx\n"
134 " Init. ramdisk: %08lx->%08lx\n"
135 " Page tables: %08lx->%08lx\n"
136 " TOTAL: %08lx->%08lx\n",
137 vboot_params_start, vboot_params_end,
138 vboot_gdt_start, vboot_gdt_end,
139 dsi.v_kernstart, dsi.v_kernend,
140 vinitrd_start, vinitrd_end,
141 vpt_start, vpt_end,
142 dsi.v_start, v_end);
143 printf(" ENTRY ADDRESS: %08lx\n", dsi.v_kernentry);
144 printf(" INITRD LENGTH: %08lx\n", initrd_len);
146 if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
147 {
148 printf("Initial guest OS requires too much space\n"
149 "(%luMB is greater than %luMB limit)\n",
150 (v_end-dsi.v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
151 goto error_out;
152 }
154 if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
155 {
156 PERROR("Could not allocate memory");
157 goto error_out;
158 }
160 if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
161 {
162 PERROR("Could not get the page frame list");
163 goto error_out;
164 }
166 loadelfimage(image, xc_handle, dom, page_array, dsi.v_start);
168 if (dsi.load_bsd_symtab)
169 loadelfsymtab(image, xc_handle, dom, page_array, &dsi);
171 /* Load the initial ramdisk image. */
172 if ( initrd_len != 0 )
173 {
174 for ( i = (vinitrd_start - dsi.v_start);
175 i < (vinitrd_end - dsi.v_start); i += PAGE_SIZE )
176 {
177 char page[PAGE_SIZE];
178 if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 )
179 {
180 PERROR("Error reading initrd image, could not");
181 goto error_out;
182 }
183 xc_copy_to_domain_page(xc_handle, dom,
184 page_array[i>>PAGE_SHIFT], page);
185 }
186 }
188 if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
189 goto error_out;
191 /* First allocate page for page dir. */
192 ppt_alloc = (vpt_start - dsi.v_start) >> PAGE_SHIFT;
193 l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
194 ctxt->pt_base = l2tab;
196 /* Initialise the page tables. */
197 if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
198 PROT_READ|PROT_WRITE,
199 l2tab >> PAGE_SHIFT)) == NULL )
200 goto error_out;
201 memset(vl2tab, 0, PAGE_SIZE);
202 vl2e = &vl2tab[l2_table_offset(dsi.v_start)];
203 for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++ )
204 {
205 if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
206 {
207 l1tab = page_array[ppt_alloc++] << PAGE_SHIFT;
208 if ( vl1tab != NULL )
209 munmap(vl1tab, PAGE_SIZE);
210 if ( (vl1tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
211 PROT_READ|PROT_WRITE,
212 l1tab >> PAGE_SHIFT)) == NULL )
213 {
214 munmap(vl2tab, PAGE_SIZE);
215 goto error_out;
216 }
217 memset(vl1tab, 0, PAGE_SIZE);
218 vl1e = &vl1tab[l1_table_offset(dsi.v_start + (count<<PAGE_SHIFT))];
219 *vl2e++ = l1tab | L2_PROT;
220 }
222 *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
223 vl1e++;
224 }
225 munmap(vl1tab, PAGE_SIZE);
226 munmap(vl2tab, PAGE_SIZE);
228 /*
229 * Pin down l2tab addr as page dir page - causes hypervisor to provide
230 * correct protection for the page
231 */
232 if ( add_mmu_update(xc_handle, mmu,
233 l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) )
234 goto error_out;
236 boot_paramsp = xc_map_foreign_range(
237 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
238 page_array[(vboot_params_start-dsi.v_start)>>PAGE_SHIFT]);
239 memset(boot_paramsp, 0, sizeof(*boot_paramsp));
241 strncpy(boot_paramsp->cmd_line, cmdline, 0x800);
242 boot_paramsp->cmd_line[0x800-1] = '\0';
243 boot_paramsp->cmd_line_ptr = ((unsigned long) vboot_params_start) + offsetof(struct linux_boot_params, cmd_line);
245 boot_paramsp->setup_sects = 0;
246 boot_paramsp->mount_root_rdonly = 1;
247 boot_paramsp->swapdev = 0x0;
248 boot_paramsp->ramdisk_flags = 0x0;
249 boot_paramsp->root_dev = 0x0; /* We must tell kernel root dev by kernel command line. */
251 /* we don't have a ps/2 mouse now.
252 * 0xAA means a aux mouse is there.
253 * See detect_auxiliary_port() in pc_keyb.c.
254 */
255 boot_paramsp->aux_device_info = 0x0;
257 boot_paramsp->header_magic[0] = 0x48; /* "H" */
258 boot_paramsp->header_magic[1] = 0x64; /* "d" */
259 boot_paramsp->header_magic[2] = 0x72; /* "r" */
260 boot_paramsp->header_magic[3] = 0x53; /* "S" */
262 boot_paramsp->protocol_version = 0x0203; /* 2.03 */
263 boot_paramsp->loader_type = 0x71; /* GRUB */
264 boot_paramsp->loader_flags = 0x1; /* loaded high */
265 boot_paramsp->code32_start = LINUX_KERNEL_ENTR_ADDR; /* 1MB */
266 boot_paramsp->initrd_start = vinitrd_start;
267 boot_paramsp->initrd_size = initrd_len;
269 i = ((memsize - 1) << 10) - 4;
270 boot_paramsp->alt_mem_k = i; /* alt_mem_k */
271 boot_paramsp->screen.overlap.ext_mem_k = i & 0xFFFF; /* ext_mem_k */
273 /*
274 * Stuff SCREAN_INFO
275 */
276 boot_paramsp->screen.info.orig_x = 0;
277 boot_paramsp->screen.info.orig_y = 0;
278 boot_paramsp->screen.info.orig_video_page = 8;
279 boot_paramsp->screen.info.orig_video_mode = 3;
280 boot_paramsp->screen.info.orig_video_cols = 80;
281 boot_paramsp->screen.info.orig_video_ega_bx = 0;
282 boot_paramsp->screen.info.orig_video_lines = 25;
283 boot_paramsp->screen.info.orig_video_isVGA = 1;
284 boot_paramsp->screen.info.orig_video_points = 0x0010;
286 /* seems we may NOT stuff boot_paramsp->apm_bios_info */
287 /* seems we may NOT stuff boot_paramsp->drive_info */
288 /* seems we may NOT stuff boot_paramsp->sys_desc_table */
289 *((unsigned short *) &boot_paramsp->drive_info.dummy[0]) = 800;
290 boot_paramsp->drive_info.dummy[2] = 4;
291 boot_paramsp->drive_info.dummy[14] = 32;
293 boot_paramsp->e820_map_nr = mem_mapp->nr_map;
294 for (i=0; i<mem_mapp->nr_map; i++) {
295 boot_paramsp->e820_map[i].addr = mem_mapp->map[i].addr;
296 boot_paramsp->e820_map[i].size = mem_mapp->map[i].size;
297 boot_paramsp->e820_map[i].type = mem_mapp->map[i].type;
298 }
299 munmap(boot_paramsp, PAGE_SIZE);
301 boot_gdtp = xc_map_foreign_range(
302 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
303 page_array[(vboot_gdt_start-dsi.v_start)>>PAGE_SHIFT]);
304 memset(boot_gdtp, 0, PAGE_SIZE);
305 boot_gdtp[12*4 + 0] = boot_gdtp[13*4 + 0] = 0xffff; /* limit */
306 boot_gdtp[12*4 + 1] = boot_gdtp[13*4 + 1] = 0x0000; /* base */
307 boot_gdtp[12*4 + 2] = 0x9a00; boot_gdtp[13*4 + 2] = 0x9200; /* perms */
308 boot_gdtp[12*4 + 3] = boot_gdtp[13*4 + 3] = 0x00cf; /* granu + top of limit */
309 munmap(boot_gdtp, PAGE_SIZE);
311 /* shared_info page starts its life empty. */
312 shared_info = xc_map_foreign_range(
313 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame);
314 memset(shared_info, 0, sizeof(shared_info_t));
315 /* Mask all upcalls... */
316 for ( i = 0; i < MAX_VIRT_CPUS; i++ )
317 shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
318 munmap(shared_info, PAGE_SIZE);
320 /* Send the page update requests down to the hypervisor. */
321 if ( finish_mmu_updates(xc_handle, mmu) )
322 goto error_out;
324 free(mmu);
325 free(page_array);
327 /*
328 * Initial register values:
329 */
330 ctxt->cpu_ctxt.ds = 0x68;
331 ctxt->cpu_ctxt.es = 0x0;
332 ctxt->cpu_ctxt.fs = 0x0;
333 ctxt->cpu_ctxt.gs = 0x0;
334 ctxt->cpu_ctxt.ss = 0x68;
335 ctxt->cpu_ctxt.cs = 0x60;
336 ctxt->cpu_ctxt.eip = dsi.v_kernentry;
337 ctxt->cpu_ctxt.edx = vboot_gdt_start;
338 ctxt->cpu_ctxt.eax = 0x800;
339 ctxt->cpu_ctxt.esp = vboot_gdt_end;
340 ctxt->cpu_ctxt.ebx = 0; /* startup_32 expects this to be 0 to signal boot cpu */
341 ctxt->cpu_ctxt.ecx = mem_mapp->nr_map;
342 ctxt->cpu_ctxt.esi = vboot_params_start;
343 ctxt->cpu_ctxt.edi = vboot_params_start + 0x2d0;
345 ctxt->cpu_ctxt.eflags = (1<<2);
347 return 0;
349 error_out:
350 if ( mmu != NULL )
351 free(mmu);
352 if ( page_array != NULL )
353 free(page_array);
354 return -1;
355 }
358 #define VMX_FEATURE_FLAG 0x20
360 int vmx_identify(void)
361 {
362 int eax, ecx;
364 __asm__ __volatile__ ("cpuid"
365 : "=a" (eax), "=c" (ecx)
366 : "0" (1)
367 : "bx", "dx");
368 if (!(ecx & VMX_FEATURE_FLAG)) {
369 return -1;
370 }
371 return 0;
372 }
374 int xc_vmx_build(int xc_handle,
375 u32 domid,
376 int memsize,
377 const char *image_name,
378 struct mem_map *mem_mapp,
379 const char *ramdisk_name,
380 const char *cmdline,
381 unsigned int control_evtchn,
382 unsigned long flags)
383 {
384 dom0_op_t launch_op, op;
385 int initrd_fd = -1;
386 gzFile initrd_gfd = NULL;
387 int rc, i;
388 full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
389 unsigned long nr_pages;
390 char *image = NULL;
391 unsigned long image_size, initrd_size=0;
393 if ( vmx_identify() < 0 )
394 {
395 PERROR("CPU doesn't support VMX Extensions");
396 goto error_out;
397 }
399 if ( (nr_pages = xc_get_tot_pages(xc_handle, domid)) < 0 )
400 {
401 PERROR("Could not find total pages for domain");
402 goto error_out;
403 }
405 if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL )
406 goto error_out;
408 if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) )
409 {
410 if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 )
411 {
412 PERROR("Could not open the initial ramdisk image");
413 goto error_out;
414 }
416 initrd_size = xc_get_filesz(initrd_fd);
418 if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL )
419 {
420 PERROR("Could not allocate decompression state for initrd");
421 goto error_out;
422 }
423 }
425 if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
426 {
427 PERROR("Unable to mlock ctxt");
428 return 1;
429 }
431 op.cmd = DOM0_GETDOMAININFO;
432 op.u.getdomaininfo.domain = (domid_t)domid;
433 op.u.getdomaininfo.exec_domain = 0;
434 op.u.getdomaininfo.ctxt = ctxt;
435 if ( (do_dom0_op(xc_handle, &op) < 0) ||
436 ((u16)op.u.getdomaininfo.domain != domid) )
437 {
438 PERROR("Could not get info on domain");
439 goto error_out;
440 }
441 if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) ||
442 (ctxt->pt_base != 0) )
443 {
444 ERROR("Domain is already constructed");
445 goto error_out;
446 }
448 if ( setup_guestos(xc_handle, domid, memsize, image, image_size,
449 initrd_gfd, initrd_size, nr_pages,
450 ctxt, cmdline,
451 op.u.getdomaininfo.shared_info_frame,
452 control_evtchn, flags, mem_mapp) < 0 )
453 {
454 ERROR("Error constructing guest OS");
455 goto error_out;
456 }
458 if ( initrd_fd >= 0 )
459 close(initrd_fd);
460 if ( initrd_gfd )
461 gzclose(initrd_gfd);
462 if ( image != NULL )
463 free(image);
465 ctxt->flags = ECF_VMX_GUEST;
466 /* FPU is set up to default initial state. */
467 memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
469 /* Virtual IDT is empty at start-of-day. */
470 for ( i = 0; i < 256; i++ )
471 {
472 ctxt->trap_ctxt[i].vector = i;
473 ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS;
474 }
475 ctxt->fast_trap_idx = 0;
477 /* No LDT. */
478 ctxt->ldt_ents = 0;
480 /* Use the default Xen-provided GDT. */
481 ctxt->gdt_ents = 0;
483 /* Ring 1 stack is the initial stack. */
484 /*
485 ctxt->guestos_ss = FLAT_GUESTOS_DS;
486 ctxt->guestos_esp = vstartinfo_start;
487 */
488 /* No debugging. */
489 memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
491 /* No callback handlers. */
492 ctxt->event_callback_cs = FLAT_GUESTOS_CS;
493 ctxt->event_callback_eip = 0;
494 ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
495 ctxt->failsafe_callback_eip = 0;
497 memset( &launch_op, 0, sizeof(launch_op) );
499 launch_op.u.builddomain.domain = (domid_t)domid;
500 launch_op.u.builddomain.ctxt = ctxt;
502 launch_op.cmd = DOM0_BUILDDOMAIN;
503 rc = do_dom0_op(xc_handle, &launch_op);
504 return rc;
506 error_out:
507 if ( initrd_gfd != NULL )
508 gzclose(initrd_gfd);
509 else if ( initrd_fd >= 0 )
510 close(initrd_fd);
511 if ( image != NULL )
512 free(image);
514 return -1;
515 }
517 static inline int is_loadable_phdr(Elf_Phdr *phdr)
518 {
519 return ((phdr->p_type == PT_LOAD) &&
520 ((phdr->p_flags & (PF_W|PF_X)) != 0));
521 }
523 static int parseelfimage(char *elfbase,
524 unsigned long elfsize,
525 struct domain_setup_info *dsi)
526 {
527 Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
528 Elf_Phdr *phdr;
529 Elf_Shdr *shdr;
530 unsigned long kernstart = ~0UL, kernend=0UL;
531 char *shstrtab;
532 int h;
534 if ( !IS_ELF(*ehdr) )
535 {
536 ERROR("Kernel image does not have an ELF header.");
537 return -EINVAL;
538 }
540 if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
541 {
542 ERROR("ELF program headers extend beyond end of image.");
543 return -EINVAL;
544 }
546 if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
547 {
548 ERROR("ELF section headers extend beyond end of image.");
549 return -EINVAL;
550 }
552 /* Find the section-header strings table. */
553 if ( ehdr->e_shstrndx == SHN_UNDEF )
554 {
555 ERROR("ELF image has no section-header strings table (shstrtab).");
556 return -EINVAL;
557 }
558 shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
559 (ehdr->e_shstrndx*ehdr->e_shentsize));
560 shstrtab = elfbase + shdr->sh_offset;
562 for ( h = 0; h < ehdr->e_phnum; h++ )
563 {
564 phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
565 if ( !is_loadable_phdr(phdr) )
566 continue;
567 if ( phdr->p_vaddr < kernstart )
568 kernstart = phdr->p_vaddr;
569 if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
570 kernend = phdr->p_vaddr + phdr->p_memsz;
571 }
573 if ( (kernstart > kernend) ||
574 (ehdr->e_entry < kernstart) ||
575 (ehdr->e_entry > kernend) )
576 {
577 ERROR("Malformed ELF image.");
578 return -EINVAL;
579 }
581 dsi->v_start = 0x00000000;
582 dsi->use_writable_pagetables = 0;
583 dsi->load_bsd_symtab = 0;
585 dsi->v_kernstart = kernstart - LINUX_PAGE_OFFSET;
586 dsi->v_kernend = kernend - LINUX_PAGE_OFFSET;
587 dsi->v_kernentry = LINUX_KERNEL_ENTR_ADDR;
589 dsi->v_end = dsi->v_kernend;
591 return 0;
592 }
594 static int
595 loadelfimage(
596 char *elfbase, int xch, u32 dom, unsigned long *parray,
597 unsigned long vstart)
598 {
599 Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
600 Elf_Phdr *phdr;
601 int h;
603 char *va;
604 unsigned long pa, done, chunksz;
606 for ( h = 0; h < ehdr->e_phnum; h++ )
607 {
608 phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
609 if ( !is_loadable_phdr(phdr) )
610 continue;
612 for ( done = 0; done < phdr->p_filesz; done += chunksz )
613 {
614 pa = (phdr->p_vaddr + done) - vstart - LINUX_PAGE_OFFSET;
615 va = xc_map_foreign_range(
616 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
617 chunksz = phdr->p_filesz - done;
618 if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
619 chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
620 memcpy(va + (pa & (PAGE_SIZE-1)),
621 elfbase + phdr->p_offset + done, chunksz);
622 munmap(va, PAGE_SIZE);
623 }
625 for ( ; done < phdr->p_memsz; done += chunksz )
626 {
627 pa = (phdr->p_vaddr + done) - vstart - LINUX_PAGE_OFFSET;
628 va = xc_map_foreign_range(
629 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
630 chunksz = phdr->p_memsz - done;
631 if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
632 chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
633 memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
634 munmap(va, PAGE_SIZE);
635 }
636 }
638 return 0;
639 }
642 #define ELFROUND (ELFSIZE / 8)
644 static int
645 loadelfsymtab(
646 char *elfbase, int xch, u32 dom, unsigned long *parray,
647 struct domain_setup_info *dsi)
648 {
649 Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase, *sym_ehdr;
650 Elf_Shdr *shdr;
651 unsigned long maxva, symva;
652 char *p;
653 int h, i;
655 p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
656 ehdr->e_shnum * sizeof(Elf_Shdr));
657 if (p == NULL)
658 return 0;
660 maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
661 symva = maxva;
662 maxva += sizeof(int);
663 dsi->symtab_addr = maxva;
664 dsi->symtab_len = 0;
665 maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
666 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
668 shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
669 memcpy(shdr, elfbase + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
671 for ( h = 0; h < ehdr->e_shnum; h++ )
672 {
673 if ( shdr[h].sh_type == SHT_STRTAB )
674 {
675 /* Look for a strtab @i linked to symtab @h. */
676 for ( i = 0; i < ehdr->e_shnum; i++ )
677 if ( (shdr[i].sh_type == SHT_SYMTAB) &&
678 (shdr[i].sh_link == h) )
679 break;
680 /* Skip symtab @h if we found no corresponding strtab @i. */
681 if ( i == ehdr->e_shnum )
682 {
683 shdr[h].sh_offset = 0;
684 continue;
685 }
686 }
688 if ( (shdr[h].sh_type == SHT_STRTAB) ||
689 (shdr[h].sh_type == SHT_SYMTAB) )
690 {
691 if ( parray != NULL )
692 xc_map_memcpy(maxva, elfbase + shdr[h].sh_offset, shdr[h].sh_size,
693 xch, dom, parray, dsi->v_start);
695 /* Mangled to be based on ELF header location. */
696 shdr[h].sh_offset = maxva - dsi->symtab_addr;
698 dsi->symtab_len += shdr[h].sh_size;
699 maxva += shdr[h].sh_size;
700 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
701 }
703 shdr[h].sh_name = 0; /* Name is NULL. */
704 }
706 if ( dsi->symtab_len == 0 )
707 {
708 dsi->symtab_addr = 0;
709 goto out;
710 }
712 if ( parray != NULL )
713 {
714 *(int *)p = maxva - dsi->symtab_addr;
715 sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
716 memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
717 sym_ehdr->e_phoff = 0;
718 sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
719 sym_ehdr->e_phentsize = 0;
720 sym_ehdr->e_phnum = 0;
721 sym_ehdr->e_shstrndx = SHN_UNDEF;
723 /* Copy total length, crafted ELF header and section header table */
724 xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
725 ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
726 dsi->v_start);
727 }
729 dsi->symtab_len = maxva - dsi->symtab_addr;
730 dsi->v_end = round_pgup(maxva);
732 out:
733 if ( p != NULL )
734 free(p);
736 return 0;
737 }