# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
# Node ID 4a320d26fc24bc49ae24f31dec2bf006a9ddc7a8
# Parent 2041122e0c4a6df3cfce2691bf83d443dc2f698d
[TOOLS] Uncompress and allocate memory for gzipped kernel and initrd images on
the fly. We cannot rely on the length contained in the gzip trailer to determine
the length of the decompressed data because images have been observed which have
trailing junk.
Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
---
tools/libxc/xc_linux_build.c | 105 ++++++++++++++++++++++++-------------------
tools/libxc/xc_private.c | 22 ---------
tools/libxc/xg_private.c | 65 ++++++++++++++++++--------
tools/libxc/xg_private.h | 2
4 files changed, 106 insertions(+), 88 deletions(-)
diff -r 2041122e0c4a -r 4a320d26fc24 tools/libxc/xc_linux_build.c
--- a/tools/libxc/xc_linux_build.c Thu Oct 26 15:08:20 2006 +0100
+++ b/tools/libxc/xc_linux_build.c Thu Oct 26 16:56:16 2006 +0100
@@ -36,6 +36,11 @@
struct initrd_info {
enum { INITRD_none, INITRD_file, INITRD_mem } type;
+ /*
+ * .len must be filled in by the user for type==INITRD_mem. It is
+ * filled in by load_initrd() for INITRD_file and unused for
+ * INITRD_none.
+ */
unsigned long len;
union {
gzFile file_handle;
@@ -134,30 +139,42 @@ static int load_initrd(int xc_handle, do
xen_pfn_t *phys_to_mach)
{
char page[PAGE_SIZE];
- unsigned long pfn_start, pfn, nr_pages;
+ unsigned long pfn_start, pfn;
if ( initrd->type == INITRD_none )
return 0;
pfn_start = physbase >> PAGE_SHIFT;
- nr_pages = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
- for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
- {
- if ( initrd->type == INITRD_mem )
+
+ if ( initrd->type == INITRD_mem )
+ {
+ unsigned long nr_pages = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
{
xc_copy_to_domain_page(
xc_handle, dom, phys_to_mach[pfn],
&initrd->u.mem_addr[(pfn - pfn_start) << PAGE_SHIFT]);
}
- else
- {
- if ( gzread(initrd->u.file_handle, page, PAGE_SIZE) == -1 )
+ }
+ else
+ {
+ int readlen;
+
+ pfn = pfn_start;
+ initrd->len = 0;
+
+ /* gzread returns 0 on EOF */
+ while ( (readlen = gzread(initrd->u.file_handle, page, PAGE_SIZE)) )
+ {
+ if ( readlen < 0 )
{
PERROR("Error reading initrd image, could not");
return -EINVAL;
}
- xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn], page);
+
+ initrd->len += readlen;
+ xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn++], page);
}
}
@@ -485,10 +502,17 @@ static int setup_guest(int xc_handle,
if ( rc != 0 )
goto error_out;
- dsi.v_start = round_pgdown(dsi.v_start);
- vinitrd_start = round_pgup(dsi.v_end);
- vinitrd_end = vinitrd_start + initrd->len;
- v_end = round_pgup(vinitrd_end);
+ dsi.v_start = round_pgdown(dsi.v_start);
+ (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
+ &dsi);
+
+ vinitrd_start = round_pgup(dsi.v_end);
+ if ( load_initrd(xc_handle, dom, initrd,
+ vinitrd_start - dsi.v_start, page_array) )
+ goto error_out;
+
+ vinitrd_end = vinitrd_start + initrd->len;
+ v_end = round_pgup(vinitrd_end);
start_info_mpa = (nr_pages - 3) << PAGE_SHIFT;
/* Build firmware. */
@@ -524,13 +548,6 @@ static int setup_guest(int xc_handle,
_p(vinitrd_start), _p(vinitrd_end),
_p(dsi.v_start), _p(v_end));
IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
-
- (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
- &dsi);
-
- if ( load_initrd(xc_handle, dom, initrd,
- vinitrd_start - dsi.v_start, page_array) )
- goto error_out;
*pvke = dsi.v_kernentry;
@@ -728,6 +745,24 @@ static int setup_guest(int xc_handle,
shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap,
required_features);
+ if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
+ {
+ PERROR("Could not allocate memory");
+ goto error_out;
+ }
+
+ if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
+ {
+ PERROR("Could not get the page frame list");
+ goto error_out;
+ }
+
+ rc = (load_funcs.loadimage)(image, image_size,
+ xc_handle, dom, page_array,
+ &dsi);
+ if ( rc != 0 )
+ goto error_out;
+
/*
* Why do we need this? The number of page-table frames depends on the
* size of the bootstrap address space. But the size of the address space
@@ -741,9 +776,14 @@ static int setup_guest(int xc_handle,
ERROR("End of mapped kernel image too close to end of memory");
goto error_out;
}
+
vinitrd_start = v_end;
+ if ( load_initrd(xc_handle, dom, initrd,
+ vinitrd_start - dsi.v_start, page_array) )
+ goto error_out;
if ( !increment_ulong(&v_end, round_pgup(initrd->len)) )
goto error_out;
+
vphysmap_start = v_end;
if ( !increment_ulong(&v_end, round_pgup(nr_pages * sizeof(long))) )
goto error_out;
@@ -844,28 +884,6 @@ static int setup_guest(int xc_handle,
_p((v_end-dsi.v_start)>>20), nr_pages>>(20-PAGE_SHIFT));
goto error_out;
}
-
- if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
- {
- PERROR("Could not allocate memory");
- goto error_out;
- }
-
- if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
- {
- PERROR("Could not get the page frame list");
- goto error_out;
- }
-
- rc = (load_funcs.loadimage)(image, image_size,
- xc_handle, dom, page_array,
- &dsi);
- if ( rc != 0 )
- goto error_out;
-
- if ( load_initrd(xc_handle, dom, initrd,
- vinitrd_start - dsi.v_start, page_array) )
- goto error_out;
/* setup page tables */
#if defined(__i386__)
@@ -1350,7 +1368,6 @@ int xc_linux_build(int xc_handle,
goto error_out;
}
- initrd_info.len = xc_get_filesz(fd);
if ( (initrd_info.u.file_handle = gzdopen(fd, "rb")) == NULL )
{
PERROR("Could not allocate decompression state for initrd");
diff -r 2041122e0c4a -r 4a320d26fc24 tools/libxc/xc_private.c
--- a/tools/libxc/xc_private.c Thu Oct 26 15:08:20 2006 +0100
+++ b/tools/libxc/xc_private.c Thu Oct 26 16:56:16 2006 +0100
@@ -344,28 +344,6 @@ int xc_clear_domain_page(int xc_handle,
return 0;
}
-unsigned long xc_get_filesz(int fd)
-{
- uint16_t sig;
- uint32_t _sz = 0;
- unsigned long sz;
-
- lseek(fd, 0, SEEK_SET);
- if ( read(fd, &sig, sizeof(sig)) != sizeof(sig) )
- return 0;
- sz = lseek(fd, 0, SEEK_END);
- if ( sig == 0x8b1f ) /* GZIP signature? */
- {
- lseek(fd, -4, SEEK_END);
- if ( read(fd, &_sz, 4) != 4 )
- return 0;
- sz = _sz;
- }
- lseek(fd, 0, SEEK_SET);
-
- return sz;
-}
-
void xc_map_memcpy(unsigned long dst, const char *src, unsigned long size,
int xch, uint32_t dom, xen_pfn_t *parray,
unsigned long vstart)
diff -r 2041122e0c4a -r 4a320d26fc24 tools/libxc/xg_private.c
--- a/tools/libxc/xg_private.c Thu Oct 26 15:08:20 2006 +0100
+++ b/tools/libxc/xg_private.c Thu Oct 26 16:56:16 2006 +0100
@@ -31,7 +31,7 @@ char *xc_read_image(const char *filename
{
int kernel_fd = -1;
gzFile kernel_gfd = NULL;
- char *image = NULL;
+ char *image = NULL, *tmp;
unsigned int bytes;
if ( (filename == NULL) || (size == NULL) )
@@ -43,33 +43,58 @@ char *xc_read_image(const char *filename
goto out;
}
- if ( (*size = xc_get_filesz(kernel_fd)) == 0 )
- {
- PERROR("Could not read kernel image");
- goto out;
- }
-
if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
{
PERROR("Could not allocate decompression state for state file");
goto out;
}
- if ( (image = malloc(*size)) == NULL )
- {
- PERROR("Could not allocate memory for kernel image");
- goto out;
- }
-
- if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
- {
- PERROR("Error reading kernel image, could not"
- " read the whole image (%d != %ld).", bytes, *size);
- free(image);
- image = NULL;
- }
+ *size = 0;
+
+#define CHUNK 1*1024*1024
+ while(1)
+ {
+ if ( (tmp = realloc(image, *size + CHUNK)) == NULL )
+ {
+ PERROR("Could not allocate memory for kernel image");
+ free(image);
+ image = NULL;
+ goto out;
+ }
+ image = tmp;
+
+ bytes = gzread(kernel_gfd, image + *size, CHUNK);
+ switch (bytes)
+ {
+ case -1:
+ PERROR("Error reading kernel image");
+ free(image);
+ image = NULL;
+ goto out;
+ case 0: /* EOF */
+ goto out;
+ default:
+ *size += bytes;
+ break;
+ }
+ }
+#undef CHUNK
out:
+ if ( *size == 0 )
+ {
+ PERROR("Could not read kernel image");
+ free(image);
+ image = NULL;
+ }
+ else if ( image )
+ {
+ /* Shrink allocation to fit image. */
+ tmp = realloc(image, *size);
+ if ( tmp )
+ image = tmp;
+ }
+
if ( kernel_gfd != NULL )
gzclose(kernel_gfd);
else if ( kernel_fd >= 0 )
diff -r 2041122e0c4a -r 4a320d26fc24 tools/libxc/xg_private.h
--- a/tools/libxc/xg_private.h Thu Oct 26 15:08:20 2006 +0100
+++ b/tools/libxc/xg_private.h Thu Oct 26 16:56:16 2006 +0100
@@ -193,8 +193,6 @@ int xc_copy_to_domain_page(int xc_handle
int xc_copy_to_domain_page(int xc_handle, uint32_t domid,
unsigned long dst_pfn, const char *src_page);
-unsigned long xc_get_filesz(int fd);
-
void xc_map_memcpy(unsigned long dst, const char *src, unsigned long size,
int xch, uint32_t dom, xen_pfn_t *parray,
unsigned long vstart);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|