[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v7 2/2] xen/arm: support gzip compressed kernels
Free the memory used for the compressed kernel and update the relative mod->start and mod->size parameters with the uncompressed ones. To decompress the kernel, allocate memory from dommheap, because freeing the modules is done by calling init_heap_pages, which frees to domheap. Map these pages using vmap, because they might not be in the linear 1:1 map. Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx> CC: ian.campbell@xxxxxxxxxx --- Changes in v7: - move vunmap and mod->start,size assignments earlier Changes in v6: - use vmap to map pages - free old module and update mod->start and mod->size from kernel_decompress 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 | 88 ++++++++++++++++++++++++++++++++++++++----- xen/arch/arm/setup.c | 2 +- xen/include/asm-arm/setup.h | 2 + 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index f641b12..8ad5440 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,73 @@ 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 bootmodule *mod) +{ + char *output, *input; + char magic[2]; + int rc; + unsigned kernel_order_out; + paddr_t output_size; + struct page_info *pages; + mfn_t mfn; + int i; + paddr_t addr = mod->start; + paddr_t size = mod->size; + + 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; + } + mfn = _mfn(page_to_mfn(pages)); + output = __vmap(&mfn, 1 << kernel_order_out, 1, 1, PAGE_HYPERVISOR); + + rc = perform_gunzip(output, input, size); + clean_dcache_va_range(output, output_size); + iounmap(input); + vunmap(output); + + mod->start = page_to_maddr(pages); + mod->size = output_size; + + /* + * Need to free pages after output_size here because they won't be + * freed by discard_initial_modules + */ + i = (output_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + for ( ; i < (1 << kernel_order_out); i++ ) + free_domheap_page(pages + i); + + /* + * Free the original kernel, update the pointers to the + * decompressed kernel + */ + dt_unreserved_regions(addr, addr + size, init_domheap_pages, 0); + + return 0; +} + #ifdef CONFIG_ARM_64 /* * Check if the image is a 64-bit Image. @@ -444,8 +513,6 @@ int kernel_probe(struct kernel_info *info) struct bootmodule *mod = boot_module_find_by_kind(BOOTMOD_KERNEL); int rc; - paddr_t start, size; - if ( !mod || !mod->size ) { printk(XENLOG_ERR "Missing kernel boot module?\n"); @@ -453,25 +520,28 @@ int kernel_probe(struct kernel_info *info) } info->kernel_bootmodule = mod; - start = mod->start; - size = mod->size; - printk("Loading kernel from boot module @ %"PRIpaddr"\n", start); + printk("Loading kernel from boot module @ %"PRIpaddr"\n", mod->start); info->initrd_bootmodule = boot_module_find_by_kind(BOOTMOD_RAMDISK); if ( info->initrd_bootmodule ) 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(mod); + if (rc < 0 && rc != -EINVAL) + return rc; + #ifdef CONFIG_ARM_64 - rc = kernel_zimage64_probe(info, start, size); + rc = kernel_zimage64_probe(info, mod->start, mod->size); if (rc < 0) #endif - rc = kernel_uimage_probe(info, start, size); + rc = kernel_uimage_probe(info, mod->start, mod->size); if (rc < 0) - rc = kernel_zimage32_probe(info, start, size); + rc = kernel_zimage32_probe(info, mod->start, mod->size); if (rc < 0) - rc = kernel_elf_probe(info, start, size); + rc = kernel_elf_probe(info, mod->start, mod->size); return rc; } diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 6626eba..109c71c 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -165,7 +165,7 @@ static void __init processor_id(void) processor_setup(); } -static void dt_unreserved_regions(paddr_t s, paddr_t e, +void dt_unreserved_regions(paddr_t s, paddr_t e, void (*cb)(paddr_t, paddr_t), int first) { int i, nr = fdt_num_mem_rsv(device_tree_flattened); diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h index 81bb3da..30ac53b 100644 --- a/xen/include/asm-arm/setup.h +++ b/xen/include/asm-arm/setup.h @@ -54,6 +54,8 @@ void copy_from_paddr(void *dst, paddr_t paddr, unsigned long len); int construct_dom0(struct domain *d); void discard_initial_modules(void); +void dt_unreserved_regions(paddr_t s, paddr_t e, + void (*cb)(paddr_t, paddr_t), int first); size_t __init boot_fdt_info(const void *fdt, paddr_t paddr); const char __init *boot_fdt_cmdline(const void *fdt); -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |