diff -r 1d36cca98fc3 tools/libxc/xc_hvm_build.c --- a/tools/libxc/xc_hvm_build.c Fri Feb 10 12:35:19 2006 +0100 +++ b/tools/libxc/xc_hvm_build.c Mon Feb 13 17:10:05 2006 -0500 @@ -339,24 +339,29 @@ static int setup_guest(int xc_handle, return -1; } -int xc_hvm_build(int xc_handle, - uint32_t domid, - int memsize, - const char *image_name, - unsigned int control_evtchn, - unsigned int vcpus, - unsigned int acpi, - unsigned int apic, - unsigned int store_evtchn, - unsigned long *store_mfn) +static int xc_hvm_build_internal(int xc_handle, + uint32_t domid, + int memsize, + unsigned char *image, + unsigned long image_size, + unsigned int control_evtchn, + unsigned int vcpus, + unsigned int acpi, + unsigned int apic, + unsigned int store_evtchn, + unsigned long *store_mfn) { dom0_op_t launch_op, op; int rc, i; vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt; unsigned long nr_pages; - char *image = NULL; - unsigned long image_size; xen_capabilities_info_t xen_caps; + + if ( (image == NULL) || (image_size == 0) ) + { + ERROR("Image required"); + goto error_out; + } if ( (rc = xc_version(xc_handle, XENVER_capabilities, &xen_caps)) != 0 ) { @@ -376,9 +381,6 @@ int xc_hvm_build(int xc_handle, PERROR("Could not find total pages for domain"); goto error_out; } - - if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL ) - goto error_out; if ( mlock(&st_ctxt, sizeof(st_ctxt) ) ) { @@ -398,15 +400,13 @@ int xc_hvm_build(int xc_handle, memset(ctxt, 0, sizeof(*ctxt)); ctxt->flags = VGCF_HVM_GUEST; - if ( setup_guest(xc_handle, domid, memsize, image, image_size, nr_pages, + if ( setup_guest(xc_handle, domid, memsize, (char *)image, image_size, nr_pages, ctxt, op.u.getdomaininfo.shared_info_frame, control_evtchn, vcpus, acpi, apic, store_evtchn, store_mfn) < 0) { ERROR("Error constructing guest OS"); goto error_out; } - - free(image); /* FPU is set up to default initial state. */ memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); @@ -451,7 +451,6 @@ int xc_hvm_build(int xc_handle, return rc; error_out: - free(image); return -1; } @@ -581,6 +580,92 @@ loadelfimage( return 0; } +/* xc_hvm_build + * + * Create a domain for a virtualized Linux, using files/filenames + * + */ + +int xc_hvm_build(int xc_handle, + uint32_t domid, + int memsize, + const char *image_name, + unsigned int control_evtchn, + unsigned int vcpus, + unsigned int acpi, + unsigned int apic, + unsigned int store_evtchn, + unsigned long *store_mfn) +{ + unsigned char *image; + int sts; + long image_size; + + /* Bring uncompressed image into memory */ + + if ( (image_name == NULL) || + ((image = (unsigned char *)xc_read_image(image_name, (unsigned long *)&image_size)) == NULL )) + return -1; + + sts = xc_hvm_build_internal(xc_handle, domid, memsize, + image, image_size, + control_evtchn, vcpus, acpi, + apic, store_evtchn, store_mfn); + free(image); + return sts; +} + +/* xc_hvm_build_mem + * + * Create a domain for a virtualized Linux, using buffers + * + */ + +int xc_hvm_build_mem(int xc_handle, + uint32_t domid, + int memsize, + unsigned char *image_buffer, + unsigned long image_size, + unsigned int control_evtchn, + unsigned int vcpus, + unsigned int acpi, + unsigned int apic, + unsigned int store_evtchn, + unsigned long *store_mfn) +{ + int sts; + unsigned long img_len; + unsigned char *img; + + /* Validate that there is a kernel buffer */ + + if ( (image_buffer == NULL) || (image_size == 0) ) + { + ERROR("kernel image buffer not present"); + return -EINVAL; + } + + img = xc_inflate_buffer(image_buffer, image_size, &img_len); + if (img == NULL) + { + ERROR("unable to inflate ram disk buffer"); + return -1; + } + + sts = xc_hvm_build_internal(xc_handle, domid, memsize, + img, img_len, + control_evtchn, vcpus, acpi, + apic, store_evtchn, store_mfn); + + /* xc_inflate_buffer may return the original buffer pointer (for + for already inflated buffers), so exercise some care in freeing */ + + if ( (img != NULL) && (img != image_buffer) ) + free(img); + + return sts; +} + /* * Local variables: * mode: C diff -r 1d36cca98fc3 tools/libxc/xc_ia64_stubs.c --- a/tools/libxc/xc_ia64_stubs.c Fri Feb 10 12:35:19 2006 +0100 +++ b/tools/libxc/xc_ia64_stubs.c Mon Feb 13 17:10:05 2006 -0500 @@ -645,7 +645,7 @@ int xc_hvm_build(int xc_handle, goto error_out; } - if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL ){ + if ( (image = xc_read_image(image_name, &image_size)) == NULL ){ PERROR("Could not read guest firmware image %s",image_name); goto error_out; } diff -r 1d36cca98fc3 tools/libxc/xc_linux_build.c --- a/tools/libxc/xc_linux_build.c Fri Feb 10 12:35:19 2006 +0100 +++ b/tools/libxc/xc_linux_build.c Mon Feb 13 17:10:05 2006 -0500 @@ -335,8 +335,8 @@ extern unsigned long xc_ia64_fpsr_defaul static int setup_guest(int xc_handle, uint32_t dom, - char *image, unsigned long image_size, - gzFile initrd_gfd, unsigned long initrd_len, + const unsigned char *image, unsigned long image_size, + unsigned char *initrd, unsigned long initrd_len, unsigned long nr_pages, unsigned long *pvsi, unsigned long *pvke, unsigned long *pvss, vcpu_guest_context_t *ctxt, @@ -400,23 +400,20 @@ static int setup_guest(int xc_handle, (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array, &dsi); - /* Load the initial ramdisk image. */ + /* Load the initial ramdisk image, if present */ if ( initrd_len != 0 ) { - for ( i = (vinitrd_start - dsi.v_start); - i < (vinitrd_end - dsi.v_start); i += PAGE_SIZE ) - { - char page[PAGE_SIZE]; - if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 ) + /* Pages are not contiguous, so do the copy one page at a time */ + + for ( i = (vinitrd_start - dsi.v_start), offset = 0; + i < (vinitrd_end - dsi.v_start); + i += PAGE_SIZE, offset += PAGE_SIZE ) { - PERROR("Error reading initrd image, could not"); - goto error_out; + xc_copy_to_domain_page(xc_handle, dom, + page_array[i>>PAGE_SHIFT], + &initrd[offset]); } - xc_copy_to_domain_page(xc_handle, dom, - page_array[i>>PAGE_SHIFT], page); - } - } - + } *pvke = dsi.v_kernentry; @@ -474,8 +471,8 @@ static int setup_guest(int xc_handle, #else /* x86 */ static int setup_guest(int xc_handle, uint32_t dom, - char *image, unsigned long image_size, - gzFile initrd_gfd, unsigned long initrd_len, + const unsigned char *image, unsigned long image_size, + unsigned char *initrd, unsigned long initrd_len, unsigned long nr_pages, unsigned long *pvsi, unsigned long *pvke, unsigned long *pvss, vcpu_guest_context_t *ctxt, @@ -518,13 +515,13 @@ static int setup_guest(int xc_handle, unsigned shadow_mode_enabled; unsigned long guest_store_mfn, guest_console_mfn, guest_shared_info_mfn; - rc = probeimageformat(image, image_size, &load_funcs); + rc = probeimageformat((char *)image, (unsigned long)image_size, &load_funcs); if ( rc != 0 ) goto error_out; memset(&dsi, 0, sizeof(struct domain_setup_info)); - rc = (load_funcs.parseimage)(image, image_size, &dsi); + rc = (load_funcs.parseimage)((char *)image, (unsigned long)image_size, &dsi); if ( rc != 0 ) goto error_out; @@ -634,24 +631,22 @@ static int setup_guest(int xc_handle, goto error_out; } - (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array, + (load_funcs.loadimage)((char *)image, image_size, xc_handle, dom, page_array, &dsi); - /* Load the initial ramdisk image. */ + /* Load the initial ramdisk image, if present */ if ( initrd_len != 0 ) { - for ( i = (vinitrd_start - dsi.v_start); - i < (vinitrd_end - dsi.v_start); i += PAGE_SIZE ) - { - char page[PAGE_SIZE]; - if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 ) - { - PERROR("Error reading initrd image, could not"); - goto error_out; - } + int offset; + + // Pages are not contiguous, so do the inflation a page at a time + + for ( i = (vinitrd_start - dsi.v_start), offset = 0; + i < (vinitrd_end - dsi.v_start); + i += PAGE_SIZE, offset += PAGE_SIZE ) xc_copy_to_domain_page(xc_handle, dom, - page_array[i>>PAGE_SHIFT], page); - } + page_array[i>>PAGE_SHIFT], + &initrd[offset]); } /* setup page tables */ @@ -865,52 +860,39 @@ static int setup_guest(int xc_handle, } #endif -int xc_linux_build(int xc_handle, - uint32_t domid, - const char *image_name, - const char *ramdisk_name, - const char *cmdline, - unsigned long flags, - unsigned int store_evtchn, - unsigned long *store_mfn, - unsigned int console_evtchn, - unsigned long *console_mfn) +/* xc_linux_build_internal + * + * Common routine to create a domain for a para-virtualized Linux. Always called with + * a buffer containing the uncompressed kernel. The RAMdisk is either a file, or a + * buffer with the potentially compressed RAMdisk. Figure out which, and make it all + * happen. + * + */ + +static int xc_linux_build_internal(int xc_handle, + uint32_t domid, + const unsigned char *image, + unsigned long image_size, + unsigned char *initrd, + unsigned long initrd_len, + const char *cmdline, + unsigned long flags, + unsigned int store_evtchn, + unsigned long *store_mfn, + unsigned int console_evtchn, + unsigned long *console_mfn) { dom0_op_t launch_op; DECLARE_DOM0_OP; - int initrd_fd = -1; - gzFile initrd_gfd = NULL; int rc, i; vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt; unsigned long nr_pages; - char *image = NULL; - unsigned long image_size, initrd_size=0; unsigned long vstartinfo_start, vkern_entry, vstack_start; if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 ) { PERROR("Could not find total pages for domain"); goto error_out; - } - - if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL ) - goto error_out; - - if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) ) - { - if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 ) - { - PERROR("Could not open the initial ramdisk image"); - goto error_out; - } - - initrd_size = xc_get_filesz(initrd_fd); - - if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL ) - { - PERROR("Could not allocate decompression state for initrd"); - goto error_out; - } } #ifdef VALGRIND @@ -935,7 +917,8 @@ int xc_linux_build(int xc_handle, memset(ctxt, 0, sizeof(*ctxt)); if ( setup_guest(xc_handle, domid, image, image_size, - initrd_gfd, initrd_size, nr_pages, + initrd, initrd_len, + nr_pages, &vstartinfo_start, &vkern_entry, &vstack_start, ctxt, cmdline, op.u.getdomaininfo.shared_info_frame, @@ -945,12 +928,6 @@ int xc_linux_build(int xc_handle, ERROR("Error constructing guest OS"); goto error_out; } - - if ( initrd_fd >= 0 ) - close(initrd_fd); - if ( initrd_gfd ) - gzclose(initrd_gfd); - free(image); #ifdef __ia64__ /* based on new_thread in xen/arch/ia64/domain.c */ @@ -1037,12 +1014,149 @@ int xc_linux_build(int xc_handle, return rc; error_out: - if ( initrd_gfd != NULL ) - gzclose(initrd_gfd); - else if ( initrd_fd >= 0 ) - close(initrd_fd); + return -1; +} + +/* xc_linux_build_mem + * + * Create a domain for a para-virtualized Linux, using buffers containing the kernel + * and, possibly, the ramdisk. This allows for use in situations where files may + * not be readily available. + * + */ + +int xc_linux_build_mem(int xc_handle, + uint32_t domid, + unsigned char *image_buffer, + unsigned long image_size, + unsigned char *initrd, + unsigned long initrd_len, + const char *cmdline, + unsigned long flags, + unsigned int store_evtchn, + unsigned long *store_mfn, + unsigned int console_evtchn, + unsigned long *console_mfn) +{ + int sts; + unsigned char *img_buf; + unsigned long img_len; + unsigned char *ram_buf; + unsigned long ram_len; + + /* A kernel buffer is required */ + + if ( (image_buffer == NULL) || (image_size == 0) ) + { + ERROR("kernel image buffer not present"); + return EINVAL; + } + + /* If it's gzipped, inflate it; otherwise, use as is */ + /* xc_inflate_buffer may return the same buffer pointer if */ + /* the buffer is already inflated */ + + img_buf = xc_inflate_buffer(image_buffer, image_size, &img_len); + if (img_buf == NULL) + { + ERROR("unable to inflate kernel image buffer"); + return EFAULT; + } + + /* RAM disks are optional; if we get one, inflate it */ + + if (initrd != NULL) + { + ram_buf = xc_inflate_buffer(initrd, initrd_len, &ram_len); + if (ram_buf == NULL) + { + ERROR("unable to inflate ram disk buffer"); + sts = -1; + goto out; + } + } + else + { + ram_buf = initrd; + ram_len = initrd_len; + } + + sts = xc_linux_build_internal(xc_handle, domid, img_buf, img_len, + ram_buf, ram_len, cmdline, flags, + store_evtchn, store_mfn, + console_evtchn, console_mfn); + + out: + /* The inflation routines may pass back the same buffer so be */ + /* sure that we have a buffer and that it's not the one passed in. */ + /* Don't unnecessarily annoy/surprise/confound the caller */ + + if ( (img_buf != NULL) && (img_buf != image_buffer) ) + free(img_buf); + if ( (ram_buf != NULL) && (ram_buf != initrd) ) + free(ram_buf); + + return sts; +} + +/* xc_linux_build + * + * Create a domain for a para-virtualized Linux, using files/filenames + * + */ + +int xc_linux_build(int xc_handle, + uint32_t domid, + const char *image_name, + const char *initrd_name, + const char *cmdline, + unsigned long flags, + unsigned int store_evtchn, + unsigned long *store_mfn, + unsigned int console_evtchn, + unsigned long *console_mfn) +{ + unsigned char *image; + long image_size; + unsigned char *ram; + unsigned long ram_size; + int sts; + + /* xc_linux_build_internal always takes uncompressed buffers of the */ + /* kernel image and ram disk, so read the files here and create them */ + + /* Bring uncompressed kernel image into memory */ + + if ( (image_name == NULL) || + ((image = (unsigned char *)xc_read_image(image_name, (unsigned long *)&image_size)) == NULL )) + return -1; + + /* The ramdisk is optional */ + + if ( (initrd_name != NULL) && (strlen(initrd_name) != 0) ) + { + ram = (unsigned char *)xc_read_image(initrd_name, &ram_size); + if (ram == NULL) + { + free(image); + return -1; + } + } + else + { + ram = NULL; + ram_size = 0; + } + + sts = xc_linux_build_internal(xc_handle, domid, image, image_size, + ram, ram_size, cmdline, flags, + store_evtchn, store_mfn, + console_evtchn, console_mfn); free(image); - return -1; + if (ram != NULL) + free(ram); + + return sts; } /* diff -r 1d36cca98fc3 tools/libxc/xenguest.h --- a/tools/libxc/xenguest.h Fri Feb 10 12:35:19 2006 +0100 +++ b/tools/libxc/xenguest.h Mon Feb 13 17:10:05 2006 -0500 @@ -42,6 +42,22 @@ int xc_linux_restore(int xc_handle, int unsigned long *store_mfn, unsigned int console_evtchn, unsigned long *console_mfn); +/** + * This function will create a domain for a paravirtualized Linux + * using file names pointing to kernel and ramdisk + * + * @parm xc_handle a handle to an open hypervisor interface + * @parm domid the id of the domain + * @param image_name name of the kernel image file + * @param ramdisk_name name of the ramdisk image file + * @parm cmdline command line string + * @parm flags domain creation flags + * @parm store_evtchn the store event channel for this domain to use + * @parm store_mfn returned with the mfn of the store page + * @parm console_evtchn the console event channel for this domain to use + * @parm conole_mfn returned with the mfn of the console page + * @return 0 on success, -1 on failure + */ int xc_linux_build(int xc_handle, uint32_t domid, const char *image_name, @@ -52,6 +68,37 @@ int xc_linux_build(int xc_handle, unsigned long *store_mfn, unsigned int console_evtchn, unsigned long *console_mfn); + +/** + * This function will create a domain for a paravirtualized Linux + * using buffers for kernel and initrd + * + * @param xc_handle a handle to an open hypervisor interface + * @param domid the id of the domain + * @param image_buffer buffer containing kernel image + * @param image_size size of the kernel image buffer + * @param initrd_buffer name of the ramdisk image file + * @param initrd_size size of the ramdisk buffer + * @param cmdline command line string + * @param flags domain creation flags + * @param store_evtchn the store event channel for this domain to use + * @param store_mfn returned with the mfn of the store page + * @param console_evtchn the console event channel for this domain to use + * @param conole_mfn returned with the mfn of the console page + * @return 0 on success, -1 on failure + */ +int xc_linux_build_mem(int xc_handle, + uint32_t domid, + unsigned char *image_buffer, + unsigned long image_size, + unsigned char *initrd_buffer, + unsigned long initrd_size, + const char *cmdline, + unsigned long flags, + unsigned int store_evtchn, + unsigned long *store_mfn, + unsigned int console_evtchn, + unsigned long *console_mfn); int xc_hvm_build(int xc_handle, uint32_t domid, @@ -64,4 +111,16 @@ int xc_hvm_build(int xc_handle, unsigned int store_evtchn, unsigned long *store_mfn); +int xc_hvm_build_mem(int xc_handle, + uint32_t domid, + int memsize, + unsigned char *image_buffer, + unsigned long image_size, + unsigned int control_evtchn, + unsigned int vcpus, + unsigned int acpi, + unsigned int apic, + unsigned int store_evtchn, + unsigned long *store_mfn); + #endif // XENGUEST_H diff -r 1d36cca98fc3 tools/libxc/xg_private.c --- a/tools/libxc/xg_private.c Fri Feb 10 12:35:19 2006 +0100 +++ b/tools/libxc/xg_private.c Mon Feb 13 17:10:05 2006 -0500 @@ -10,15 +10,21 @@ #include "xg_private.h" -char *xc_read_kernel_image(const char *filename, unsigned long *size) +char *xc_read_image(const char *filename, unsigned long *size) { int kernel_fd = -1; gzFile kernel_gfd = NULL; char *image = NULL; unsigned int bytes; - if ( filename == NULL ) - goto out; + + /* Check for non-null input. We could handle a NULL size, but it's */ + /* not clear what value it provides to not know the length on return, */ + /* especially since it's unconditionally updated just below. */ + /* Also, just return - we haven't done anything requiring cleanup */ + + if ( ( filename == NULL ) || (size == NULL) ) + return NULL; if ( (kernel_fd = open(filename, O_RDONLY)) < 0 ) { @@ -60,6 +66,59 @@ char *xc_read_kernel_image(const char *f return image; } +unsigned char *xc_inflate_buffer(unsigned char *in_buf, unsigned long in_size, + unsigned long *out_size) +{ + int sts; + z_stream zStream; + unsigned long out_len; + unsigned char *out_buf; + + if ( (in_buf[0] == 0x1F) && (in_buf[1] == 0x8B) ) + { + out_len = in_buf[in_size-4] + + (256 * (in_buf[in_size-3] + + (256 * (in_buf[in_size-2] + + (256 * in_buf[in_size-1]))))); + bzero(&zStream, sizeof(zStream)); + out_buf = malloc(out_len + 16); /* Leave a little extra space */ + if (out_buf == NULL) { + ERROR("Error mallocing buffer\n"); + return NULL; + } + + zStream.next_in = in_buf; + zStream.avail_in = in_size; + zStream.next_out = out_buf; + zStream.avail_out = out_len+16; + sts = inflateInit2(&zStream, (MAX_WBITS+32)); /* +32 means "handle gzip" */ + if (sts != Z_OK) + { + ERROR("inflateInit failed, sts %d\n", sts); + free(out_buf); + return NULL; + } + + /* Inflate in one pass/call */ + + sts = inflate(&zStream, Z_FINISH); + if (sts != Z_STREAM_END) + { + ERROR("inflate failed, sts %d\n", sts); + free(out_buf); + return NULL; + } + } else { + out_buf = in_buf; + out_len = in_size; + } + + if (out_size != NULL) + *out_size = out_len; + + return out_buf; +} + /*******************/ int pin_table( @@ -83,6 +142,11 @@ unsigned long csum_page (void * page) unsigned long *p = page; unsigned long long sum=0; + // Return 0 checksum for NULL input + + if (page == NULL) + return 0; + for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ ) sum += p[i]; diff -r 1d36cca98fc3 tools/libxc/xg_private.h --- a/tools/libxc/xg_private.h Fri Feb 10 12:35:19 2006 +0100 +++ b/tools/libxc/xg_private.h Mon Feb 13 17:10:05 2006 -0500 @@ -26,7 +26,11 @@ #endif -char *xc_read_kernel_image(const char *filename, unsigned long *size); +char *xc_read_image(const char *filename, unsigned long *size); +unsigned char *xc_inflate_buffer(unsigned char *in_buf, + unsigned long in_size, + unsigned long *out_size); + unsigned long csum_page (void * page); #define _PAGE_PRESENT 0x001