ia64/xen-unstable

changeset 12023:4a320d26fc24

[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@xensource.com>
author Ian Campbell <ian.campbell@xensource.com>
date Thu Oct 26 16:56:16 2006 +0100 (2006-10-26)
parents 2041122e0c4a
children 1940ee13f9d6
files tools/libxc/xc_linux_build.c tools/libxc/xc_private.c tools/libxc/xg_private.c tools/libxc/xg_private.h
line diff
     1.1 --- a/tools/libxc/xc_linux_build.c	Thu Oct 26 15:08:20 2006 +0100
     1.2 +++ b/tools/libxc/xc_linux_build.c	Thu Oct 26 16:56:16 2006 +0100
     1.3 @@ -36,6 +36,11 @@
     1.4  
     1.5  struct initrd_info {
     1.6      enum { INITRD_none, INITRD_file, INITRD_mem } type;
     1.7 +    /*
     1.8 +     * .len must be filled in by the user for type==INITRD_mem. It is
     1.9 +     * filled in by load_initrd() for INITRD_file and unused for
    1.10 +     * INITRD_none.
    1.11 +     */
    1.12      unsigned long len;
    1.13      union {
    1.14          gzFile file_handle;
    1.15 @@ -134,30 +139,42 @@ static int load_initrd(int xc_handle, do
    1.16                  xen_pfn_t *phys_to_mach)
    1.17  {
    1.18      char page[PAGE_SIZE];
    1.19 -    unsigned long pfn_start, pfn, nr_pages;
    1.20 +    unsigned long pfn_start, pfn;
    1.21  
    1.22      if ( initrd->type == INITRD_none )
    1.23          return 0;
    1.24  
    1.25      pfn_start = physbase >> PAGE_SHIFT;
    1.26 -    nr_pages  = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
    1.27  
    1.28 -    for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
    1.29 +    if ( initrd->type == INITRD_mem )
    1.30      {
    1.31 -        if ( initrd->type == INITRD_mem )
    1.32 +        unsigned long nr_pages  = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
    1.33 +
    1.34 +        for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
    1.35          {
    1.36              xc_copy_to_domain_page(
    1.37                  xc_handle, dom, phys_to_mach[pfn],
    1.38                  &initrd->u.mem_addr[(pfn - pfn_start) << PAGE_SHIFT]);
    1.39          }
    1.40 -        else
    1.41 +    }
    1.42 +    else
    1.43 +    {
    1.44 +        int readlen;
    1.45 +
    1.46 +        pfn = pfn_start;
    1.47 +        initrd->len = 0;
    1.48 +
    1.49 +        /* gzread returns 0 on EOF */
    1.50 +        while ( (readlen = gzread(initrd->u.file_handle, page, PAGE_SIZE)) )
    1.51          {
    1.52 -            if ( gzread(initrd->u.file_handle, page, PAGE_SIZE) == -1 )
    1.53 +            if ( readlen < 0 )
    1.54              {
    1.55                  PERROR("Error reading initrd image, could not");
    1.56                  return -EINVAL;
    1.57              }
    1.58 -            xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn], page);
    1.59 +
    1.60 +            initrd->len += readlen;
    1.61 +            xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn++], page);
    1.62          }
    1.63      }
    1.64  
    1.65 @@ -485,10 +502,17 @@ static int setup_guest(int xc_handle,
    1.66      if ( rc != 0 )
    1.67          goto error_out;
    1.68  
    1.69 -    dsi.v_start      = round_pgdown(dsi.v_start);
    1.70 -    vinitrd_start    = round_pgup(dsi.v_end);
    1.71 -    vinitrd_end      = vinitrd_start + initrd->len;
    1.72 -    v_end            = round_pgup(vinitrd_end);
    1.73 +    dsi.v_start = round_pgdown(dsi.v_start);
    1.74 +    (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
    1.75 +                           &dsi);
    1.76 +
    1.77 +    vinitrd_start = round_pgup(dsi.v_end);
    1.78 +    if ( load_initrd(xc_handle, dom, initrd,
    1.79 +                     vinitrd_start - dsi.v_start, page_array) )
    1.80 +        goto error_out;
    1.81 +
    1.82 +    vinitrd_end    = vinitrd_start + initrd->len;
    1.83 +    v_end          = round_pgup(vinitrd_end);
    1.84      start_info_mpa = (nr_pages - 3) << PAGE_SHIFT;
    1.85  
    1.86      /* Build firmware.  */
    1.87 @@ -525,13 +549,6 @@ static int setup_guest(int xc_handle,
    1.88             _p(dsi.v_start),     _p(v_end));
    1.89      IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
    1.90  
    1.91 -    (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
    1.92 -                           &dsi);
    1.93 -
    1.94 -    if ( load_initrd(xc_handle, dom, initrd,
    1.95 -                     vinitrd_start - dsi.v_start, page_array) )
    1.96 -        goto error_out;
    1.97 -
    1.98      *pvke = dsi.v_kernentry;
    1.99  
   1.100      /* Now need to retrieve machine pfn for system pages:
   1.101 @@ -728,6 +745,24 @@ static int setup_guest(int xc_handle,
   1.102      shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap,
   1.103                                             required_features);
   1.104  
   1.105 +    if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
   1.106 +    {
   1.107 +        PERROR("Could not allocate memory");
   1.108 +        goto error_out;
   1.109 +    }
   1.110 +
   1.111 +    if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
   1.112 +    {
   1.113 +        PERROR("Could not get the page frame list");
   1.114 +        goto error_out;
   1.115 +    }
   1.116 +
   1.117 +    rc = (load_funcs.loadimage)(image, image_size,
   1.118 +                           xc_handle, dom, page_array,
   1.119 +                           &dsi);
   1.120 +    if ( rc != 0 )
   1.121 +        goto error_out;
   1.122 +
   1.123      /*
   1.124       * Why do we need this? The number of page-table frames depends on the
   1.125       * size of the bootstrap address space. But the size of the address space
   1.126 @@ -741,9 +776,14 @@ static int setup_guest(int xc_handle,
   1.127          ERROR("End of mapped kernel image too close to end of memory");
   1.128          goto error_out;
   1.129      }
   1.130 +
   1.131      vinitrd_start = v_end;
   1.132 +    if ( load_initrd(xc_handle, dom, initrd,
   1.133 +                     vinitrd_start - dsi.v_start, page_array) )
   1.134 +        goto error_out;
   1.135      if ( !increment_ulong(&v_end, round_pgup(initrd->len)) )
   1.136          goto error_out;
   1.137 +
   1.138      vphysmap_start = v_end;
   1.139      if ( !increment_ulong(&v_end, round_pgup(nr_pages * sizeof(long))) )
   1.140          goto error_out;
   1.141 @@ -845,28 +885,6 @@ static int setup_guest(int xc_handle,
   1.142          goto error_out;
   1.143      }
   1.144  
   1.145 -    if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
   1.146 -    {
   1.147 -        PERROR("Could not allocate memory");
   1.148 -        goto error_out;
   1.149 -    }
   1.150 -
   1.151 -    if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
   1.152 -    {
   1.153 -        PERROR("Could not get the page frame list");
   1.154 -        goto error_out;
   1.155 -    }
   1.156 -
   1.157 -    rc = (load_funcs.loadimage)(image, image_size,
   1.158 -                           xc_handle, dom, page_array,
   1.159 -                           &dsi);
   1.160 -    if ( rc != 0 )
   1.161 -        goto error_out;
   1.162 -
   1.163 -    if ( load_initrd(xc_handle, dom, initrd,
   1.164 -                     vinitrd_start - dsi.v_start, page_array) )
   1.165 -        goto error_out;
   1.166 -
   1.167      /* setup page tables */
   1.168  #if defined(__i386__)
   1.169      if (dsi.pae_kernel != PAEKERN_no)
   1.170 @@ -1350,7 +1368,6 @@ int xc_linux_build(int xc_handle,
   1.171              goto error_out;
   1.172          }
   1.173  
   1.174 -        initrd_info.len = xc_get_filesz(fd);
   1.175          if ( (initrd_info.u.file_handle = gzdopen(fd, "rb")) == NULL )
   1.176          {
   1.177              PERROR("Could not allocate decompression state for initrd");
     2.1 --- a/tools/libxc/xc_private.c	Thu Oct 26 15:08:20 2006 +0100
     2.2 +++ b/tools/libxc/xc_private.c	Thu Oct 26 16:56:16 2006 +0100
     2.3 @@ -344,28 +344,6 @@ int xc_clear_domain_page(int xc_handle,
     2.4      return 0;
     2.5  }
     2.6  
     2.7 -unsigned long xc_get_filesz(int fd)
     2.8 -{
     2.9 -    uint16_t sig;
    2.10 -    uint32_t _sz = 0;
    2.11 -    unsigned long sz;
    2.12 -
    2.13 -    lseek(fd, 0, SEEK_SET);
    2.14 -    if ( read(fd, &sig, sizeof(sig)) != sizeof(sig) )
    2.15 -        return 0;
    2.16 -    sz = lseek(fd, 0, SEEK_END);
    2.17 -    if ( sig == 0x8b1f ) /* GZIP signature? */
    2.18 -    {
    2.19 -        lseek(fd, -4, SEEK_END);
    2.20 -        if ( read(fd, &_sz, 4) != 4 )
    2.21 -            return 0;
    2.22 -        sz = _sz;
    2.23 -    }
    2.24 -    lseek(fd, 0, SEEK_SET);
    2.25 -
    2.26 -    return sz;
    2.27 -}
    2.28 -
    2.29  void xc_map_memcpy(unsigned long dst, const char *src, unsigned long size,
    2.30                     int xch, uint32_t dom, xen_pfn_t *parray,
    2.31                     unsigned long vstart)
     3.1 --- a/tools/libxc/xg_private.c	Thu Oct 26 15:08:20 2006 +0100
     3.2 +++ b/tools/libxc/xg_private.c	Thu Oct 26 16:56:16 2006 +0100
     3.3 @@ -31,7 +31,7 @@ char *xc_read_image(const char *filename
     3.4  {
     3.5      int kernel_fd = -1;
     3.6      gzFile kernel_gfd = NULL;
     3.7 -    char *image = NULL;
     3.8 +    char *image = NULL, *tmp;
     3.9      unsigned int bytes;
    3.10  
    3.11      if ( (filename == NULL) || (size == NULL) )
    3.12 @@ -43,33 +43,58 @@ char *xc_read_image(const char *filename
    3.13          goto out;
    3.14      }
    3.15  
    3.16 -    if ( (*size = xc_get_filesz(kernel_fd)) == 0 )
    3.17 -    {
    3.18 -        PERROR("Could not read kernel image");
    3.19 -        goto out;
    3.20 -    }
    3.21 -
    3.22      if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
    3.23      {
    3.24          PERROR("Could not allocate decompression state for state file");
    3.25          goto out;
    3.26      }
    3.27  
    3.28 -    if ( (image = malloc(*size)) == NULL )
    3.29 +    *size = 0;
    3.30 +
    3.31 +#define CHUNK 1*1024*1024
    3.32 +    while(1)
    3.33      {
    3.34 -        PERROR("Could not allocate memory for kernel image");
    3.35 -        goto out;
    3.36 +	    if ( (tmp = realloc(image, *size + CHUNK)) == NULL )
    3.37 +	    {
    3.38 +		    PERROR("Could not allocate memory for kernel image");
    3.39 +		    free(image);
    3.40 +		    image = NULL;
    3.41 +		    goto out;
    3.42 +	    }
    3.43 +	    image = tmp;
    3.44 +
    3.45 +	    bytes = gzread(kernel_gfd, image + *size, CHUNK);
    3.46 +	    switch (bytes)
    3.47 +	    {
    3.48 +	    case -1:
    3.49 +		    PERROR("Error reading kernel image");
    3.50 +		    free(image);
    3.51 +		    image = NULL;
    3.52 +		    goto out;
    3.53 +	    case 0: /* EOF */
    3.54 +		    goto out;
    3.55 +	    default:
    3.56 +		    *size += bytes;
    3.57 +		    break;
    3.58 +	    }
    3.59 +    }
    3.60 +#undef CHUNK
    3.61 +
    3.62 + out:
    3.63 +    if ( *size == 0 )
    3.64 +    {
    3.65 +	    PERROR("Could not read kernel image");
    3.66 +	    free(image);
    3.67 +	    image = NULL;
    3.68 +    }
    3.69 +    else if ( image )
    3.70 +    {
    3.71 +	    /* Shrink allocation to fit image. */
    3.72 +	    tmp = realloc(image, *size);
    3.73 +	    if ( tmp )
    3.74 +		    image = tmp;
    3.75      }
    3.76  
    3.77 -    if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
    3.78 -    {
    3.79 -        PERROR("Error reading kernel image, could not"
    3.80 -               " read the whole image (%d != %ld).", bytes, *size);
    3.81 -        free(image);
    3.82 -        image = NULL;
    3.83 -    }
    3.84 -
    3.85 - out:
    3.86      if ( kernel_gfd != NULL )
    3.87          gzclose(kernel_gfd);
    3.88      else if ( kernel_fd >= 0 )
     4.1 --- a/tools/libxc/xg_private.h	Thu Oct 26 15:08:20 2006 +0100
     4.2 +++ b/tools/libxc/xg_private.h	Thu Oct 26 16:56:16 2006 +0100
     4.3 @@ -193,8 +193,6 @@ typedef struct mfn_mapper {
     4.4  int xc_copy_to_domain_page(int xc_handle, uint32_t domid,
     4.5                              unsigned long dst_pfn, const char *src_page);
     4.6  
     4.7 -unsigned long xc_get_filesz(int fd);
     4.8 -
     4.9  void xc_map_memcpy(unsigned long dst, const char *src, unsigned long size,
    4.10                     int xch, uint32_t dom, xen_pfn_t *parray,
    4.11                     unsigned long vstart);