[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v5 2/2] xen/arm: support gzip compressed kernels



On Tue, 8 Sep 2015, Ian Campbell wrote:
> On Mon, 2015-09-07 at 15:25 +0100, Stefano Stabellini wrote:
> > Free the memory used for the compressed kernel and update the relative
> > mod->start and mod->size parameters with the uncompressed ones.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
> > Reviewed-by: Julien Grall <julien.grall@xxxxxxxxxx>
> > CC: ian.campbell@xxxxxxxxxx
> > 
> > ---
> > 
> > Changes in v5:
> > - code style
> > 
> > Changes in v4:
> > - return uint32_t from output_length
> > - __init kernel_decompress
> > - code style
> > - add comment
> > - if kernel_decompress fails with error, return
> > 
> > Changes in v3:
> > - better error checks in kernel_decompress
> > - free unneeded pages between output_size and kernel_order_out
> > - alloc pages from domheap
> > 
> > Changes in v2:
> > - use gzip_check
> > - avoid useless casts
> > - free original kernel image and update the mod with the new address and
> > size
> > - remove changes to common Makefile
> > - remove CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> > ---
> >  xen/arch/arm/kernel.c       |   75
> > +++++++++++++++++++++++++++++++++++++++++++
> >  xen/arch/arm/setup.c        |    2 +-
> >  xen/include/asm-arm/setup.h |    2 ++
> >  3 files changed, 78 insertions(+), 1 deletion(-)
> > 
> > diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
> > index f641b12..baa5717 100644
> > --- a/xen/arch/arm/kernel.c
> > +++ b/xen/arch/arm/kernel.c
> > @@ -13,6 +13,8 @@
> >  #include <asm/byteorder.h>
> >  #include <asm/setup.h>
> >  #include <xen/libfdt/libfdt.h>
> > +#include <xen/gunzip.h>
> > +#include <xen/vmap.h>
> >  
> >  #include "kernel.h"
> >  
> > @@ -257,6 +259,63 @@ static int kernel_uimage_probe(struct kernel_info
> > *info,
> >      return 0;
> >  }
> >  
> > +static __init uint32_t output_length(char *image, unsigned long
> > image_len)
> > +{
> > +    return *(uint32_t *)&image[image_len - 4];
> > +}
> > +
> > +static __init int kernel_decompress(struct kernel_info *info,
> > +                             paddr_t *addr, paddr_t *size)
> > +{
> > +    char *output, *input, *end;
> > +    char magic[2];
> > +    int rc;
> > +    unsigned kernel_order_out;
> > +    paddr_t output_size;
> > +    struct page_info *pages;
> > +
> > +    if ( *size < 2 )
> > +        return -EINVAL;
> > +
> > +    copy_from_paddr(magic, *addr, sizeof(magic));
> > +
> > +    /* only gzip is supported */
> > +    if ( !gzip_check(magic, *size) )
> > +        return -EINVAL;
> > +
> > +    input = ioremap_cache(*addr, *size);
> > +    if ( input == NULL )
> > +        return -EFAULT;
> > +
> > +    output_size = output_length(input, *size);
> > +    kernel_order_out = get_order_from_bytes(output_size);
> > +    pages = alloc_domheap_pages(NULL, kernel_order_out, 0);
> > +    if ( pages == NULL )
> > +    {
> > +        iounmap(input);
> > +        return -ENOMEM;
> > +    }
> > +    output = page_to_virt(pages);
> > +
> > +    rc = perform_gunzip(output, input, *size);
> > +    clean_dcache_va_range(output, output_size);
> > +    iounmap(input);
> > +
> > +    *addr = virt_to_maddr(output);
> 
> I don't think virt_to_maddr is strictly speaking valid (at the arch
> interface level, our actual implementation may happen to cope) for domheap
> pages, it's only valid for things which are in the linear 1:1 map (~=
> xenheap).
> 
> I think you need page_to_maddr(pages) instead.
> 
> 
> > +    *size = output_size;
> > +
> > +    end = output + (1 << (kernel_order_out + PAGE_SHIFT));
> > +    /* 
> > +     * Need to free pages after output_size here because they won't be
> > +     * freed by discard_initial_modules
> > +     */
> > +    output += (output_size + PAGE_SIZE - 1) & PAGE_MASK;
> > +    for ( ; output < end; output += PAGE_SIZE )
> > +        free_domheap_page(virt_to_page(output));
> 
> And here again I don't think you can use virt_to_page.

I replaced it all with vmap/vunmap.


> > +
> > +    return 0;
> > +}
> > +
> >  #ifdef CONFIG_ARM_64
> >  /*
> >   * Check if the image is a 64-bit Image.
> > @@ -463,6 +522,22 @@ int kernel_probe(struct kernel_info *info)
> >          printk("Loading ramdisk from boot module @ %"PRIpaddr"\n",
> >                 info->initrd_bootmodule->start);
> >  
> > +    /* if it is a gzip'ed image, 32bit or 64bit, uncompress it */
> > +    rc = kernel_decompress(info, &start, &size);
> > +    if (rc < 0 && rc != -EINVAL)
> 
> IMHO kernel_decompress should return success when the decompress is a nop
> (as represented by EINVAL here) and an error only when the thing needs to
> be decompressed but cannot be.

That mean collapsing the "nothing to do" and the "decompression
successful" cases into a single return value, which I think is not a
good idea. We would be losing information compared to what we have now.
I am quite happy to replace EINVAL with any other return value you think
is most appropriate though.


> That would mean putting the free of the original kernel and the updates of
> mod->* into kernel_decompress. But I think that also makes more sense
> because it confines the "ol' switcheroo" to the one place instead of mostly
> up there and then the tail end cleanup down here. i.e. you call
> kernel_decompress with everything in a consistent and valid state and
> return with everything also in a (possibly different) consistent and valid
> state.
> 
> I wouldn't have bothered commenting on this if I weren't already commenting
> on the above, since it's not a huge deal if you think this is the wrong
> direction.
> 
> Ian.
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.