static int xc_dom_probe_zimage32_kernel(struct xc_dom_image *dom) { uint32_t *zimage; if ( dom->kernel_blob == NULL ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: no kernel image loaded", __FUNCTION__); return -EINVAL; } if ( dom->kernel_size < 0x30 /*sizeof(struct setup_header)*/ ) { xc_dom_printf(dom->xch, "%s: kernel image too small", __FUNCTION__); return -EINVAL; } zimage = (uint32_t *)dom->kernel_blob; if ( zimage[ZIMAGE32_MAGIC_OFFSET/4] != ZIMAGE32_MAGIC ) { xc_dom_printf(dom->xch, "%s: kernel is not an arm32 zImage", __FUNCTION__); return -EINVAL; } return 0; }
static int vcpu(struct xc_dom_image *dom, void *ptr) { vcpu_guest_context_t *ctxt = ptr; memset(ctxt, 0x55, sizeof(*ctxt)); ctxt->user_regs.pc = dom->parms.virt_entry; ctxt->user_regs.msr = 0; ctxt->user_regs.gprs[1] = 0; /* Linux uses its own stack */ ctxt->user_regs.gprs[3] = dom->devicetree_seg.pfn << PAGE_SHIFT; ctxt->user_regs.gprs[4] = dom->kernel_seg.pfn << PAGE_SHIFT; ctxt->user_regs.gprs[5] = 0; /* There is a buggy kernel that does not zero the "local_paca", so * we must make sure this register is 0 */ ctxt->user_regs.gprs[13] = 0; xc_dom_printf("%s: initial vcpu:\n", __FUNCTION__); xc_dom_printf(" pc 0x%016"PRIx64", msr 0x%016"PRIx64"\n" " r1-5 %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64 " %016"PRIx64"\n", ctxt->user_regs.pc, ctxt->user_regs.msr, ctxt->user_regs.gprs[1], ctxt->user_regs.gprs[2], ctxt->user_regs.gprs[3], ctxt->user_regs.gprs[4], ctxt->user_regs.gprs[5]); return 0; }
int xc_dom_mem_init(struct xc_dom_image *dom, unsigned int mem_mb) { unsigned int page_shift; xen_pfn_t nr_pages; dom->arch_hooks = xc_dom_find_arch_hooks(dom->guest_type); if ( dom->arch_hooks == NULL ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: arch hooks not set\n", __FUNCTION__); return -1; } page_shift = XC_DOM_PAGE_SHIFT(dom); nr_pages = mem_mb << (20 - page_shift); xc_dom_printf("%s: mem %d MB, pages 0x%" PRIpfn " pages, %dk each\n", __FUNCTION__, mem_mb, nr_pages, 1 << (page_shift-10)); dom->total_pages = nr_pages; xc_dom_printf("%s: 0x%" PRIpfn " pages\n", __FUNCTION__, dom->total_pages); return 0; }
static int set_mode(xc_interface *xch, domid_t domid, char *guest_type) { static const struct { char *guest; uint32_t size; } types[] = { { "xen-3.0-aarch64", 64 }, { "xen-3.0-armv7l", 32 }, }; DECLARE_DOMCTL; int i,rc; domctl.domain = domid; domctl.cmd = XEN_DOMCTL_set_address_size; for ( i = 0; i < sizeof(types)/sizeof(types[0]); i++ ) if ( !strcmp(types[i].guest, guest_type) ) domctl.u.address_size.size = types[i].size; if ( domctl.u.address_size.size == 0 ) { xc_dom_printf(xch, "%s: warning: unknown guest type %s", __FUNCTION__, guest_type); return -EINVAL; } xc_dom_printf(xch, "%s: guest %s, address size %" PRId32 "", __FUNCTION__, guest_type, domctl.u.address_size.size); rc = do_domctl(xch, &domctl); if ( rc != 0 ) xc_dom_printf(xch, "%s: warning: failed (rc=%d)", __FUNCTION__, rc); return rc; }
static int xc_dom_load_bin_kernel(struct xc_dom_image *dom) { struct xen_bin_image_table *image_info; char *image = dom->kernel_blob; char *dest; size_t image_size = dom->kernel_size; uint32_t start_addr; uint32_t load_end_addr; uint32_t bss_end_addr; uint32_t skip, text_size, bss_size; image_info = find_table(dom); if ( !image_info ) return -EINVAL; start_addr = image_info->header_addr - ((char *)image_info - image); load_end_addr = image_info->load_end_addr ?: start_addr + image_size; bss_end_addr = image_info->bss_end_addr ?: load_end_addr; /* It's possible that we need to skip the first part of the image */ skip = image_info->load_addr - start_addr; text_size = load_end_addr - image_info->load_addr; bss_size = bss_end_addr - load_end_addr; xc_dom_printf("%s: calculated sizes\n", __FUNCTION__); xc_dom_printf(" skip: 0x%" PRIx32 "\n", skip); xc_dom_printf(" text_size: 0x%" PRIx32 "\n", text_size); xc_dom_printf(" bss_size: 0x%" PRIx32 "\n", bss_size); dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart); memcpy(dest, image + skip, text_size); memset(dest + text_size, 0, bss_size); return 0; }
static int xc_dom_probe_zimage64_kernel(struct xc_dom_image *dom) { struct zimage64_hdr *zimage; if ( dom->kernel_blob == NULL ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: no kernel image loaded", __FUNCTION__); return -EINVAL; } if ( dom->kernel_size < sizeof(*zimage) ) { xc_dom_printf(dom->xch, "%s: kernel image too small", __FUNCTION__); return -EINVAL; } zimage = dom->kernel_blob; if ( zimage->magic0 != ZIMAGE64_MAGIC_V0 && zimage->magic1 != ZIMAGE64_MAGIC_V1 ) { xc_dom_printf(dom->xch, "%s: kernel is not an arm64 Image", __FUNCTION__); return -EINVAL; } return 0; }
static void print_mem(const char *name, size_t mem) { if ( mem > (32 * 1024 * 1024) ) xc_dom_printf("%-24s : %zd MB\n", name, mem / (1024 * 1024)); else if ( mem > (32 * 1024) ) xc_dom_printf("%-24s : %zd kB\n", name, mem / 1024); else xc_dom_printf("%-24s : %zd bytes\n", name, mem); }
void xc_dom_log_memory_footprint(struct xc_dom_image *dom) { xc_dom_printf("domain builder memory footprint\n"); xc_dom_printf(" allocated\n"); print_mem(" malloc", dom->alloc_malloc); print_mem(" anon mmap", dom->alloc_mem_map); xc_dom_printf(" mapped\n"); print_mem(" file mmap", dom->alloc_file_map); print_mem(" domU mmap", dom->alloc_domU_map); }
static int alloc_magic_pages(struct xc_dom_image *dom) { struct ft_cxt devtree; void *guest_devtree; unsigned long shadow_mb; int rma_pages; int rc; /* Allocate special pages from the end of the RMA. */ rma_pages = 1 << (dom->realmodearea_log - PAGE_SHIFT); dom->shared_info_pfn = --rma_pages; dom->console_pfn = --rma_pages; dom->xenstore_pfn = --rma_pages; /* Gather shadow allocation info for the device tree. */ rc = xc_shadow_control(dom->guest_xc, dom->guest_domid, XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION, NULL, 0, &shadow_mb, 0, NULL); if (rc < 0 || shadow_mb == 0) { xc_dom_printf("Couldn't get shadow allocation size or it was 0.\n"); return rc; } /* Build device tree. */ rc = make_devtree(&devtree, dom, shadow_mb); if (rc < 0) { xc_dom_printf("Failed to create flattened device tree.\n"); return rc; } /* Find a spot for it. */ rc = xc_dom_alloc_segment(dom, &dom->devicetree_seg, "devtree", 0, devtree.bph->totalsize); if (rc) goto out; /* Copy the device tree into place. */ guest_devtree = xc_dom_seg_to_ptr(dom, &dom->devicetree_seg); if (!guest_devtree) { xc_dom_printf("Couldn't map guest memory for device tree.\n"); rc = -1; goto out; } memcpy(guest_devtree, devtree.bph, devtree.bph->totalsize); out: free_devtree(&devtree); return rc; }
int xc_dom_do_gunzip(void *src, size_t srclen, void *dst, size_t dstlen) { z_stream zStream; int rc; memset(&zStream, 0, sizeof(zStream)); zStream.next_in = src; zStream.avail_in = srclen; zStream.next_out = dst; zStream.avail_out = dstlen; rc = inflateInit2(&zStream, (MAX_WBITS + 32)); /* +32 means "handle gzip" */ if ( rc != Z_OK ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: inflateInit2 failed (rc=%d)\n", __FUNCTION__, rc); return -1; } rc = inflate(&zStream, Z_FINISH); inflateEnd(&zStream); if ( rc != Z_STREAM_END ) { xc_dom_panic(XC_INTERNAL_ERROR, "%s: inflate failed (rc=%d)\n", __FUNCTION__, rc); return -1; } xc_dom_printf("%s: unzip ok, 0x%zx -> 0x%zx\n", __FUNCTION__, srclen, dstlen); return 0; }
int xc_dom_kernel_mem(struct xc_dom_image *dom, const void *mem, size_t memsize) { xc_dom_printf("%s: called\n", __FUNCTION__); dom->kernel_blob = (void *)mem; dom->kernel_size = memsize; return xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size); }
size_t xc_dom_check_gzip(xc_interface *xch, void *blob, size_t ziplen) { unsigned char *gzlen; size_t unziplen; if ( ziplen < 6 ) /* Too small. We need (i.e. the subsequent code relies on) * 2 bytes for the magic number plus 4 bytes length. */ return 0; if ( strncmp(blob, "\037\213", 2) ) /* not gzipped */ return 0; gzlen = blob + ziplen - 4; unziplen = (size_t)gzlen[3] << 24 | gzlen[2] << 16 | gzlen[1] << 8 | gzlen[0]; if ( unziplen > XC_DOM_DECOMPRESS_MAX ) { xc_dom_printf (xch, "%s: size (zip %zd, unzip %zd) looks insane, skip gunzip", __FUNCTION__, ziplen, unziplen); return 0; } return unziplen + 16; }
static int xc_try_lzma_decode( struct xc_dom_image *dom, void **blob, size_t *size) { xc_dom_printf("%s: LZMA decompress support unavailable\n", __FUNCTION__); return -1; }
int xc_dom_compat_check(struct xc_dom_image *dom) { xen_capabilities_info_t xen_caps; char *item, *ptr; int match, found = 0; strncpy(xen_caps, dom->xen_caps, XEN_CAPABILITIES_INFO_LEN - 1); xen_caps[XEN_CAPABILITIES_INFO_LEN - 1] = '\0'; for ( item = strtok_r(xen_caps, " ", &ptr); item != NULL ; item = strtok_r(NULL, " ", &ptr) ) { match = !strcmp(dom->guest_type, item); xc_dom_printf("%s: supported guest type: %s%s\n", __FUNCTION__, item, match ? " <= matches" : ""); if ( match ) found++; } if ( !found ) xc_dom_panic(XC_INVALID_KERNEL, "%s: guest type %s not supported by xen kernel, sorry\n", __FUNCTION__, dom->guest_type); return found; }
struct xc_dom_image *xc_dom_allocate(const char *cmdline, const char *features) { struct xc_dom_image *dom; xc_dom_printf("%s: cmdline=\"%s\", features=\"%s\"\n", __FUNCTION__, cmdline, features); dom = malloc(sizeof(*dom)); if ( !dom ) goto err; memset(dom, 0, sizeof(*dom)); if ( cmdline ) dom->cmdline = xc_dom_strdup(dom, cmdline); if ( features ) elf_xen_parse_features(features, dom->f_requested, NULL); dom->parms.virt_base = UNSET_ADDR; dom->parms.virt_entry = UNSET_ADDR; dom->parms.virt_hypercall = UNSET_ADDR; dom->parms.virt_hv_start_low = UNSET_ADDR; dom->parms.elf_paddr_offset = UNSET_ADDR; dom->alloc_malloc += sizeof(*dom); return dom; err: if ( dom ) xc_dom_release(dom); return NULL; }
static int ia64_setup_memmap(struct xc_dom_image *dom) { unsigned int page_size = XC_DOM_PAGE_SIZE(dom); unsigned long memmap_info_num_pages; unsigned long memmap_info_pfn; xen_ia64_memmap_info_t* memmap_info; unsigned int num_mds; efi_memory_desc_t *md; char* start_info; struct xen_ia64_boot_param* bp; /* setup memmap page */ memmap_info_num_pages = 1; memmap_info_pfn = dom->start_info_pfn - 1; xc_dom_printf("%s: memmap: mfn 0x%" PRIpfn " pages 0x%lx\n", __FUNCTION__, memmap_info_pfn, memmap_info_num_pages); memmap_info = xc_map_foreign_range(dom->guest_xc, dom->guest_domid, page_size * memmap_info_num_pages, PROT_READ | PROT_WRITE, memmap_info_pfn); if (NULL == memmap_info) return -1; /* [0, total_pages) */ memmap_info->efi_memdesc_size = sizeof(md[0]); memmap_info->efi_memdesc_version = EFI_MEMORY_DESCRIPTOR_VERSION; num_mds = 0; md = (efi_memory_desc_t*)&memmap_info->memdesc; md[num_mds].type = EFI_CONVENTIONAL_MEMORY; md[num_mds].pad = 0; md[num_mds].phys_addr = 0; md[num_mds].virt_addr = 0; md[num_mds].num_pages = dom->total_pages << (PAGE_SHIFT - EFI_PAGE_SHIFT); md[num_mds].attribute = EFI_MEMORY_WB; num_mds++; memmap_info->efi_memmap_size = num_mds * sizeof(md[0]); munmap(memmap_info, page_size * memmap_info_num_pages); assert(num_mds <= (page_size * memmap_info_num_pages - offsetof(typeof(*memmap_info), memdesc))/sizeof(*md)); /* * kludge: we need to pass memmap_info page's pfn and other magic pages * somehow. * we use xen_ia64_boot_param::efi_memmap::{efi_memmap, efi_memmap_size} * for this purpose */ start_info = xc_map_foreign_range(dom->guest_xc, dom->guest_domid, page_size, PROT_READ | PROT_WRITE, dom->start_info_pfn); if (NULL == start_info) return -1; bp = (struct xen_ia64_boot_param*)(start_info + sizeof(start_info_t)); memset(bp, 0, sizeof(*bp)); XEN_IA64_MEMMAP_INFO_NUM_PAGES(bp) = memmap_info_num_pages; XEN_IA64_MEMMAP_INFO_PFN(bp) = memmap_info_pfn; munmap(start_info, page_size); return 0; }
void xc_dom_release(struct xc_dom_image *dom) { xc_dom_printf("%s: called\n", __FUNCTION__); if ( dom->phys_pages ) xc_dom_unmap_all(dom); xc_dom_free_all(dom); free(dom); }
int xc_dom_kernel_file(struct xc_dom_image *dom, const char *filename) { xc_dom_printf("%s: filename=\"%s\"\n", __FUNCTION__, filename); dom->kernel_blob = xc_dom_malloc_filemap(dom, filename, &dom->kernel_size); if ( dom->kernel_blob == NULL ) return -1; return xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size); }
void xc_dom_loginit(void) { if ( xc_dom_logfile ) return; xc_dom_logfile = fopen("/var/log/xen/domain-builder-ng.log", "a"); setvbuf(xc_dom_logfile, NULL, _IONBF, 0); xc_dom_printf("### ----- xc domain builder logfile opened -----\n"); }
static struct xc_dom_loader *xc_dom_find_loader(struct xc_dom_image *dom) { struct xc_dom_loader *loader = first_loader; while ( loader != NULL ) { xc_dom_printf("%s: trying %s loader ... ", __FUNCTION__, loader->name); if ( loader->probe(dom) == 0 ) { xc_dom_printf("OK\n"); return loader; } xc_dom_printf("failed\n"); loader = loader->next; } xc_dom_panic(XC_INVALID_KERNEL, "%s: no loader found\n", __FUNCTION__); return NULL; }
static int shared_info(struct xc_dom_image *dom, void *ptr) { shared_info_t *shared_info = ptr; xc_dom_printf("%s: called\n", __FUNCTION__); memset(shared_info, 0, sizeof(*shared_info)); return 0; }
int xc_dom_ramdisk_mem(struct xc_dom_image *dom, const void *mem, size_t memsize) { xc_dom_printf("%s: called\n", __FUNCTION__); dom->ramdisk_blob = (void *)mem; dom->ramdisk_size = memsize; // return xc_dom_try_gunzip(dom, &dom->ramdisk_blob, &dom->ramdisk_size); return 0; }
static int xc_dom_probe_zimage_kernel(struct xc_dom_image *dom) { uint32_t *zimage; uint32_t end; if ( dom->kernel_blob == NULL ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: no kernel image loaded", __FUNCTION__); return -EINVAL; } if ( dom->kernel_size < 0x30 /*sizeof(struct setup_header)*/ ) { xc_dom_printf(dom->xch, "%s: kernel image too small", __FUNCTION__); return -EINVAL; } zimage = (uint32_t *)dom->kernel_blob; if ( zimage[ZIMAGE_MAGIC_OFFSET/4] != ZIMAGE_MAGIC ) { xc_dom_printf(dom->xch, "%s: kernel is not a bzImage", __FUNCTION__); return -EINVAL; } end = zimage[ZIMAGE_END_OFFSET/4]; /* * Check for an appended DTB. */ if ( end + sizeof(struct minimal_dtb_header) < dom->kernel_size ) { struct minimal_dtb_header *dtb_hdr; dtb_hdr = (struct minimal_dtb_header *)(dom->kernel_blob + end); if (ntohl/*be32_to_cpu*/(dtb_hdr->magic) == DTB_MAGIC) { xc_dom_printf(dom->xch, "%s: found an appended DTB", __FUNCTION__); end += ntohl/*be32_to_cpu*/(dtb_hdr->total_size); } } dom->kernel_size = end; return 0; }
static int launch_vm(xc_interface *xch, domid_t domid, vcpu_guest_context_any_t *ctxt) { int rc; xc_dom_printf(xch, "%s: called, ctxt=%p", __FUNCTION__, ctxt); rc = xc_vcpu_setcontext(xch, domid, 0, ctxt); if ( rc != 0 ) xc_dom_panic(xch, XC_INTERNAL_ERROR, "%s: SETVCPUCONTEXT failed (rc=%d)", __FUNCTION__, rc); return rc; }
int xc_dom_update_guest_p2m(struct xc_dom_image *dom) { uint32_t *p2m_32; uint64_t *p2m_64; xen_pfn_t i; if ( !dom->p2m_guest ) return 0; switch ( dom->arch_hooks->sizeof_pfn ) { case 4: xc_dom_printf("%s: dst 32bit, pages 0x%" PRIpfn " \n", __FUNCTION__, dom->total_pages); p2m_32 = dom->p2m_guest; for ( i = 0; i < dom->total_pages; i++ ) if ( dom->p2m_host[i] != INVALID_P2M_ENTRY ) p2m_32[i] = dom->p2m_host[i]; else p2m_32[i] = (uint32_t) - 1; break; case 8: xc_dom_printf("%s: dst 64bit, pages 0x%" PRIpfn " \n", __FUNCTION__, dom->total_pages); p2m_64 = dom->p2m_guest; for ( i = 0; i < dom->total_pages; i++ ) if ( dom->p2m_host[i] != INVALID_P2M_ENTRY ) p2m_64[i] = dom->p2m_host[i]; else p2m_64[i] = (uint64_t) - 1; break; default: xc_dom_panic(XC_INTERNAL_ERROR, "sizeof_pfn is invalid (is %d, can be 4 or 8)", dom->arch_hooks->sizeof_pfn); return -1; } return 0; }
static int shared_info_ia64(struct xc_dom_image *dom, void *ptr) { shared_info_ia64_t *shared_info = ptr; int i; xc_dom_printf("%s: called\n", __FUNCTION__); memset(shared_info, 0, sizeof(*shared_info)); for (i = 0; i < MAX_VIRT_CPUS; i++) shared_info->vcpu_info[i].evtchn_upcall_mask = 1; shared_info->arch.start_info_pfn = dom->start_info_pfn; shared_info->arch.memmap_info_num_pages = 1; //XXX shared_info->arch.memmap_info_pfn = dom->start_info_pfn - 1; return 0; }
int xc_dom_alloc_page(struct xc_dom_image *dom, char *name) { unsigned int page_size = XC_DOM_PAGE_SIZE(dom); xen_vaddr_t start; xen_pfn_t pfn; start = dom->virt_alloc_end; dom->virt_alloc_end += page_size; if (dom->allocate) dom->allocate(dom, dom->virt_alloc_end); pfn = (start - dom->parms.virt_base) / page_size; xc_dom_printf("%-20s: %-12s : 0x%" PRIx64 " (pfn 0x%" PRIpfn ")\n", __FUNCTION__, name, start, pfn); return pfn; }
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; }
static int launch_vm(int xc, domid_t domid, void *ctxt) { DECLARE_DOMCTL; int rc; xc_dom_printf("%s: called, ctxt=%p\n", __FUNCTION__, ctxt); memset(&domctl, 0, sizeof(domctl)); domctl.cmd = XEN_DOMCTL_setvcpucontext; domctl.domain = domid; domctl.u.vcpucontext.vcpu = 0; set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); rc = do_domctl(xc, &domctl); if ( rc != 0 ) xc_dom_panic(XC_INTERNAL_ERROR, "%s: SETVCPUCONTEXT failed (rc=%d)\n", __FUNCTION__, rc); return rc; }
int xc_dom_boot_mem_init(struct xc_dom_image *dom) { long rc; xc_dom_printf("%s: called\n", __FUNCTION__); rc = arch_setup_meminit(dom); if ( rc != 0 ) { xc_dom_panic(XC_OUT_OF_MEMORY, "%s: can't allocate low memory for domain\n", __FUNCTION__); return rc; } return 0; }