int arch_setup_meminit(struct xc_dom_image *dom) { int rc; xen_pfn_t pfn, allocsz, i; dom->shadow_enabled = 1; dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * dom->total_pages); if ( dom->p2m_host == NULL ) return -EINVAL; /* setup initial p2m */ for ( pfn = 0; pfn < dom->total_pages; pfn++ ) dom->p2m_host[pfn] = pfn + dom->rambase_pfn; /* allocate guest memory */ for ( i = rc = allocsz = 0; (i < dom->total_pages) && !rc; i += allocsz ) { allocsz = dom->total_pages - i; if ( allocsz > 1024*1024 ) allocsz = 1024*1024; rc = xc_domain_populate_physmap_exact( dom->xch, dom->guest_domid, allocsz, 0, 0, &dom->p2m_host[i]); } return 0; }
char *xc_dom_strdup(struct xc_dom_image *dom, const char *str) { size_t len = strlen(str) + 1; char *nstr = xc_dom_malloc(dom, len); if ( nstr == NULL ) return NULL; memcpy(nstr, str, len); return nstr; }
static int xc_dom_parse_elf_kernel(struct xc_dom_image *dom) { struct elf_binary *elf; int rc; rc = check_elf_kernel(dom, 1); if ( rc != 0 ) return rc; elf = xc_dom_malloc(dom, sizeof(*elf)); dom->private_loader = elf; rc = elf_init(elf, dom->kernel_blob, dom->kernel_size); xc_elf_set_logfile(dom->xch, elf, 1); if ( rc != 0 ) { xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: corrupted ELF image", __FUNCTION__); return rc; } /* Find the section-header strings table. */ if ( elf->sec_strtab == NULL ) { xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: ELF image" " has no shstrtab", __FUNCTION__); return -EINVAL; } /* parse binary and get xen meta info */ elf_parse_binary(elf); if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 ) return rc; if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) ) { xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not" " support unprivileged (DomU) operation", __FUNCTION__); return -EINVAL; } /* find kernel segment */ dom->kernel_seg.vstart = dom->parms.virt_kstart; dom->kernel_seg.vend = dom->parms.virt_kend; if ( dom->parms.bsd_symtab ) xc_dom_load_elf_symtab(dom, elf, 0); dom->guest_type = xc_dom_guest_type(dom, elf); DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "", __FUNCTION__, dom->guest_type, dom->kernel_seg.vstart, dom->kernel_seg.vend); return 0; }
void *xc_dom_boot_domU_map(struct xc_dom_image *dom, xen_pfn_t pfn, xen_pfn_t count) { int page_shift = XC_DOM_PAGE_SHIFT(dom); privcmd_mmap_entry_t *entries; void *ptr; int i, rc; int err; entries = xc_dom_malloc(dom, count * sizeof(privcmd_mmap_entry_t)); if ( entries == NULL ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn " [malloc]\n", __FUNCTION__, pfn, count); return NULL; } ptr = mmap(NULL, count << page_shift, PROT_READ | PROT_WRITE, MAP_SHARED, dom->guest_xc, 0); if ( ptr == MAP_FAILED ) { err = errno; xc_dom_panic(XC_INTERNAL_ERROR, "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn " [mmap, errno=%i (%s)]\n", __FUNCTION__, pfn, count, err, strerror(err)); return NULL; } for ( i = 0; i < count; i++ ) { entries[i].va = (uintptr_t) ptr + (i << page_shift); entries[i].mfn = xc_dom_p2m_host(dom, pfn + i); entries[i].npages = 1; } rc = xc_map_foreign_ranges(dom->guest_xc, dom->guest_domid, entries, count); if ( rc < 0 ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn " [xenctl, rc=%d]\n", __FUNCTION__, pfn, count, rc); return NULL; } return ptr; }
int arch_setup_meminit(struct xc_dom_image *dom) { xen_pfn_t pfn; int rc; /* setup initial p2m */ dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * dom->total_pages); for ( pfn = 0; pfn < dom->total_pages; pfn++ ) dom->p2m_host[pfn] = pfn; /* allocate guest memory */ rc = xc_domain_memory_populate_physmap(dom->guest_xc, dom->guest_domid, dom->total_pages, 0, 0, dom->p2m_host); return rc; }
static int xc_dom_parse_elf_kernel(struct xc_dom_image *dom) { struct elf_binary *elf; int rc; rc = check_elf_kernel(dom, 1); if ( rc != 0 ) return rc; elf = xc_dom_malloc(dom, sizeof(*elf)); dom->private_loader = elf; rc = elf_init(elf, dom->kernel_blob, dom->kernel_size); if ( xc_dom_logfile ) elf_set_logfile(elf, xc_dom_logfile, 1); if ( rc != 0 ) { xc_dom_panic(XC_INVALID_KERNEL, "%s: corrupted ELF image\n", __FUNCTION__); return rc; } /* Find the section-header strings table. */ if ( elf->sec_strtab == NULL ) { xc_dom_panic(XC_INVALID_KERNEL, "%s: ELF image has no shstrtab\n", __FUNCTION__); return -EINVAL; } /* parse binary and get xen meta info */ elf_parse_binary(elf); if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 ) return rc; /* find kernel segment */ dom->kernel_seg.vstart = dom->parms.virt_kstart; dom->kernel_seg.vend = dom->parms.virt_kend; if ( dom->parms.bsd_symtab ) xc_dom_load_elf_symtab(dom, elf, 0); dom->guest_type = xc_dom_guest_type(dom, elf); xc_dom_printf("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", __FUNCTION__, dom->guest_type, dom->kernel_seg.vstart, dom->kernel_seg.vend); return 0; }
int xc_dom_try_gunzip(struct xc_dom_image *dom, void **blob, size_t * size) { void *unzip; size_t unziplen; unziplen = xc_dom_check_gzip(*blob, *size); if ( unziplen == 0 ) return 0; unzip = xc_dom_malloc(dom, unziplen); if ( unzip == NULL ) return -1; if ( xc_dom_do_gunzip(*blob, *size, unzip, unziplen) == -1 ) return -1; *blob = unzip; *size = unziplen; return 0; }
void *xc_dom_boot_domU_map(struct xc_dom_image *dom, xen_pfn_t pfn, xen_pfn_t count) { int page_shift = XC_DOM_PAGE_SHIFT(dom); privcmd_mmap_entry_t *entries; void *ptr; int i; int err; entries = xc_dom_malloc(dom, count * sizeof(privcmd_mmap_entry_t)); if ( entries == NULL ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn " [malloc]", __FUNCTION__, pfn, count); return NULL; } for ( i = 0; i < count; i++ ) entries[i].mfn = xc_dom_p2m_host(dom, pfn + i); ptr = xc_map_foreign_ranges(dom->xch, dom->guest_domid, count << page_shift, PROT_READ | PROT_WRITE, 1 << page_shift, entries, count); if ( ptr == NULL ) { err = errno; xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: failed to mmap domU pages 0x%" PRIpfn "+0x%" PRIpfn " [mmap, errno=%i (%s)]", __FUNCTION__, pfn, count, err, strerror(err)); return NULL; } return ptr; }
void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t pfn, xen_pfn_t count) { struct xc_dom_phys *phys; unsigned int page_shift = XC_DOM_PAGE_SHIFT(dom); char *mode = "unset"; if ( pfn > dom->total_pages ) { xc_dom_printf("%s: pfn out of range (0x%" PRIpfn " > 0x%" PRIpfn ")\n", __FUNCTION__, pfn, dom->total_pages); return NULL; } /* already allocated? */ for ( phys = dom->phys_pages; phys != NULL; phys = phys->next ) { if ( pfn >= (phys->first + phys->count) ) continue; if ( count ) { /* size given: must be completely within the already allocated block */ if ( (pfn + count) <= phys->first ) continue; if ( (pfn < phys->first) || ((pfn + count) > (phys->first + phys->count)) ) { xc_dom_printf("%s: request overlaps allocated block" " (req 0x%" PRIpfn "+0x%" PRIpfn "," " blk 0x%" PRIpfn "+0x%" PRIpfn ")\n", __FUNCTION__, pfn, count, phys->first, phys->count); return NULL; } } else { /* no size given: block must be allocated already, just hand out a pointer to it */ if ( pfn < phys->first ) continue; } return phys->ptr + ((pfn - phys->first) << page_shift); } /* allocating is allowed with size specified only */ if ( count == 0 ) { xc_dom_printf("%s: no block found, no size given," " can't malloc (pfn 0x%" PRIpfn ")\n", __FUNCTION__, pfn); return NULL; } /* not found, no overlap => allocate */ phys = xc_dom_malloc(dom, sizeof(*phys)); if ( phys == NULL ) return NULL; memset(phys, 0, sizeof(*phys)); phys->first = pfn; phys->count = count; if ( dom->guest_domid ) { mode = "domU mapping"; phys->ptr = xc_dom_boot_domU_map(dom, phys->first, phys->count); if ( phys->ptr == NULL ) return NULL; dom->alloc_domU_map += phys->count << page_shift; } else { int err; mode = "anonymous memory"; phys->ptr = mmap(NULL, phys->count << page_shift, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if ( phys->ptr == MAP_FAILED ) { err = errno; xc_dom_panic(XC_OUT_OF_MEMORY, "%s: oom: can't allocate 0x%" PRIpfn " pages" " [mmap, errno=%i (%s)]\n", __FUNCTION__, count, err, strerror(err)); return NULL; } dom->alloc_mem_map += phys->count << page_shift; } #if 1 xc_dom_printf("%s: %s: pfn 0x%" PRIpfn "+0x%" PRIpfn " at %p\n", __FUNCTION__, mode, phys->first, phys->count, phys->ptr); #endif phys->next = dom->phys_pages; dom->phys_pages = phys; return phys->ptr; }
static int xc_dom_load_elf_symtab(struct xc_dom_image *dom, struct elf_binary *elf, int load) { struct elf_binary syms; const elf_shdr *shdr, *shdr2; xen_vaddr_t symtab, maxaddr; char *hdr; size_t size; int h, count, type, i, tables = 0; if ( elf_swap(elf) ) { xc_dom_printf("%s: non-native byte order, bsd symtab not supported\n", __FUNCTION__); return 0; } if ( load ) { if ( !dom->bsd_symtab_start ) return 0; size = dom->kernel_seg.vend - dom->bsd_symtab_start; hdr = xc_dom_vaddr_to_ptr(dom, dom->bsd_symtab_start); *(int *)hdr = size - sizeof(int); } else { size = sizeof(int) + elf_size(elf, elf->ehdr) + elf_shdr_count(elf) * elf_size(elf, shdr); hdr = xc_dom_malloc(dom, size); if ( hdr == NULL ) return 0; dom->bsd_symtab_start = elf_round_up(&syms, dom->kernel_seg.vend); } memcpy(hdr + sizeof(int), elf->image, elf_size(elf, elf->ehdr)); memcpy(hdr + sizeof(int) + elf_size(elf, elf->ehdr), elf->image + elf_uval(elf, elf->ehdr, e_shoff), elf_shdr_count(elf) * elf_size(elf, shdr)); if ( elf_64bit(elf) ) { Elf64_Ehdr *ehdr = (Elf64_Ehdr *)(hdr + sizeof(int)); ehdr->e_phoff = 0; ehdr->e_phentsize = 0; ehdr->e_phnum = 0; ehdr->e_shoff = elf_size(elf, elf->ehdr); ehdr->e_shstrndx = SHN_UNDEF; } else { Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(hdr + sizeof(int)); ehdr->e_phoff = 0; ehdr->e_phentsize = 0; ehdr->e_phnum = 0; ehdr->e_shoff = elf_size(elf, elf->ehdr); ehdr->e_shstrndx = SHN_UNDEF; } if ( elf_init(&syms, hdr + sizeof(int), size - sizeof(int)) ) return -1; if ( xc_dom_logfile ) elf_set_logfile(&syms, xc_dom_logfile, 1); symtab = dom->bsd_symtab_start + sizeof(int); maxaddr = elf_round_up(&syms, symtab + elf_size(&syms, syms.ehdr) + elf_shdr_count(&syms) * elf_size(&syms, shdr)); xc_dom_printf("%s/%s: bsd_symtab_start=%" PRIx64 ", kernel.end=0x%" PRIx64 " -- symtab=0x%" PRIx64 ", maxaddr=0x%" PRIx64 "\n", __FUNCTION__, load ? "load" : "parse", dom->bsd_symtab_start, dom->kernel_seg.vend, symtab, maxaddr); count = elf_shdr_count(&syms); for ( h = 0; h < count; h++ ) { shdr = elf_shdr_by_index(&syms, h); type = elf_uval(&syms, shdr, sh_type); if ( type == SHT_STRTAB ) { /* Look for a strtab @i linked to symtab @h. */ for ( i = 0; i < count; i++ ) { shdr2 = elf_shdr_by_index(&syms, i); if ( (elf_uval(&syms, shdr2, sh_type) == SHT_SYMTAB) && (elf_uval(&syms, shdr2, sh_link) == h) ) break; } /* Skip symtab @h if we found no corresponding strtab @i. */ if ( i == count ) { if ( elf_64bit(&syms) ) *(Elf64_Off*)(&shdr->e64.sh_offset) = 0; else *(Elf32_Off*)(&shdr->e32.sh_offset) = 0; continue; } } if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) ) { /* Mangled to be based on ELF header location. */ if ( elf_64bit(&syms) ) *(Elf64_Off*)(&shdr->e64.sh_offset) = maxaddr - symtab; else *(Elf32_Off*)(&shdr->e32.sh_offset) = maxaddr - symtab; size = elf_uval(&syms, shdr, sh_size); maxaddr = elf_round_up(&syms, maxaddr + size); tables++; xc_dom_printf("%s: h=%d %s, size=0x%zx, maxaddr=0x%" PRIx64 "\n", __FUNCTION__, h, type == SHT_SYMTAB ? "symtab" : "strtab", size, maxaddr); if ( load ) { shdr2 = elf_shdr_by_index(elf, h); memcpy((void*)elf_section_start(&syms, shdr), elf_section_start(elf, shdr2), size); } } /* Name is NULL. */ if ( elf_64bit(&syms) ) *(Elf64_Half*)(&shdr->e64.sh_name) = 0; else *(Elf32_Word*)(&shdr->e32.sh_name) = 0; } if ( tables == 0 ) { xc_dom_printf("%s: no symbol table present\n", __FUNCTION__); dom->bsd_symtab_start = 0; return 0; } if ( !load ) dom->kernel_seg.vend = maxaddr; return 0; }
if ( hdr_ptr == NULL ) { DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->bsd_symtab_start" " => NULL", __FUNCTION__); return -1; } elf->caller_xdest_base = hdr_ptr; elf->caller_xdest_size = allow_size; hdr = ELF_REALPTR2PTRVAL(hdr_ptr); elf_store_val(elf, unsigned, hdr, size - sizeof(unsigned)); } else { char *hdr_ptr; hdr_ptr = xc_dom_malloc(dom, size); if ( hdr_ptr == NULL ) return 0; elf->caller_xdest_base = hdr_ptr; elf->caller_xdest_size = size; hdr = ELF_REALPTR2PTRVAL(hdr_ptr); dom->bsd_symtab_start = elf_round_up(elf, dom->kernel_seg.vend); dom->kernel_seg.vend = elf_round_up(elf, dom->bsd_symtab_start + size); return 0; } elf_memcpy_safe(elf, hdr + sizeof(unsigned), ELF_IMAGE_BASE(elf), elf_size(elf, elf->ehdr)); elf_memcpy_safe(elf, hdr + sizeof(unsigned) + elf_size(elf, elf->ehdr), ELF_IMAGE_BASE(elf) + elf_uval(elf, elf->ehdr, e_shoff),
int xc_dom_boot_image(struct xc_dom_image *dom) { DECLARE_DOMCTL; void *ctxt; int rc; xc_dom_printf("%s: called\n", __FUNCTION__); /* misc ia64 stuff*/ if ( (rc = arch_setup_bootearly(dom)) != 0 ) return rc; /* collect some info */ domctl.cmd = XEN_DOMCTL_getdomaininfo; domctl.domain = dom->guest_domid; rc = do_domctl(dom->guest_xc, &domctl); if ( rc != 0 ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: getdomaininfo failed (rc=%d)\n", __FUNCTION__, rc); return rc; } if ( domctl.domain != dom->guest_domid ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: Huh? domid mismatch (%d != %d)\n", __FUNCTION__, domctl.domain, dom->guest_domid); return -1; } dom->shared_info_mfn = domctl.u.getdomaininfo.shared_info_frame; /* sanity checks */ if ( !xc_dom_compat_check(dom) ) return -1; /* initial mm setup */ if ( (rc = xc_dom_update_guest_p2m(dom)) != 0 ) return rc; if ( dom->arch_hooks->setup_pgtables ) if ( (rc = dom->arch_hooks->setup_pgtables(dom)) != 0 ) return rc; if ( (rc = clear_page(dom, dom->console_pfn)) != 0 ) return rc; if ( (rc = clear_page(dom, dom->xenstore_pfn)) != 0 ) return rc; /* start info page */ if ( dom->arch_hooks->start_info ) dom->arch_hooks->start_info(dom); /* hypercall page */ if ( (rc = setup_hypercall_page(dom)) != 0 ) return rc; xc_dom_log_memory_footprint(dom); /* misc x86 stuff */ if ( (rc = arch_setup_bootlate(dom)) != 0 ) return rc; /* let the vm run */ ctxt = xc_dom_malloc(dom, PAGE_SIZE * 2 /* FIXME */ ); memset(ctxt, 0, PAGE_SIZE * 2); if ( (rc = dom->arch_hooks->vcpu(dom, ctxt)) != 0 ) return rc; xc_dom_unmap_all(dom); rc = launch_vm(dom->guest_xc, dom->guest_domid, ctxt); return rc; }
int arch_setup_meminit(struct xc_dom_image *dom) { int rc; xen_pfn_t pfn, allocsz, i; uint64_t modbase; /* Convenient */ const uint64_t rambase = dom->rambase_pfn << XC_PAGE_SHIFT; const uint64_t ramsize = dom->total_pages << XC_PAGE_SHIFT; const uint64_t ramend = rambase + ramsize; const uint64_t kernbase = dom->kernel_seg.vstart; const uint64_t kernend = ROUNDUP(dom->kernel_seg.vend, 21/*2MB*/); const uint64_t kernsize = kernend - kernbase; const uint64_t dtb_size = dom->devicetree_blob ? ROUNDUP(dom->devicetree_size, XC_PAGE_SHIFT) : 0; const uint64_t ramdisk_size = dom->ramdisk_blob ? ROUNDUP(dom->ramdisk_size, XC_PAGE_SHIFT) : 0; const uint64_t modsize = dtb_size + ramdisk_size; const uint64_t ram128mb = rambase + (128<<20); if ( modsize + kernsize > ramsize ) { DOMPRINTF("%s: Not enough memory for the kernel+dtb+initrd", __FUNCTION__); return -1; } if ( ramsize > GUEST_RAM_SIZE - NR_MAGIC_PAGES*XC_PAGE_SIZE ) { DOMPRINTF("%s: ram size is too large for guest address space: " "%"PRIx64" > %llx", __FUNCTION__, ramsize, GUEST_RAM_SIZE - NR_MAGIC_PAGES*XC_PAGE_SIZE); return -1; } rc = set_mode(dom->xch, dom->guest_domid, dom->guest_type); if ( rc ) return rc; dom->shadow_enabled = 1; dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * dom->total_pages); if ( dom->p2m_host == NULL ) return -EINVAL; /* setup initial p2m */ for ( pfn = 0; pfn < dom->total_pages; pfn++ ) dom->p2m_host[pfn] = pfn + dom->rambase_pfn; /* allocate guest memory */ for ( i = rc = allocsz = 0; (i < dom->total_pages) && !rc; i += allocsz ) { allocsz = dom->total_pages - i; if ( allocsz > 1024*1024 ) allocsz = 1024*1024; rc = xc_domain_populate_physmap_exact( dom->xch, dom->guest_domid, allocsz, 0, 0, &dom->p2m_host[i]); } /* * We try to place dtb+initrd at 128MB or if we have less RAM * as high as possible. If there is no space then fallback to * just before the kernel. * * If changing this then consider * xen/arch/arm/kernel.c:place_modules as well. */ if ( ramend >= ram128mb + modsize && kernend < ram128mb ) modbase = ram128mb; else if ( ramend - modsize > kernend ) modbase = ramend - modsize; else if (kernbase - rambase > modsize ) modbase = kernbase - modsize; else return -1; DOMPRINTF("%s: placing boot modules at 0x%" PRIx64, __FUNCTION__, modbase); /* * Must map DTB *after* initrd, to satisfy order of calls to * xc_dom_alloc_segment in xc_dom_build_image, which must map * things at monotonolically increasing addresses. */ if ( ramdisk_size ) { dom->ramdisk_seg.vstart = modbase; dom->ramdisk_seg.vend = modbase + ramdisk_size; DOMPRINTF("%s: ramdisk: 0x%" PRIx64 " -> 0x%" PRIx64 "", __FUNCTION__, dom->ramdisk_seg.vstart, dom->ramdisk_seg.vend); modbase += ramdisk_size; } if ( dtb_size ) { dom->devicetree_seg.vstart = modbase; dom->devicetree_seg.vend = modbase + dtb_size; DOMPRINTF("%s: devicetree: 0x%" PRIx64 " -> 0x%" PRIx64 "", __FUNCTION__, dom->devicetree_seg.vstart, dom->devicetree_seg.vend); modbase += dtb_size; } return 0; }