|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v6 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>
Reviewed-by: Julien Grall <julien.grall@xxxxxxxxxx>
CC: ian.campbell@xxxxxxxxxx
---
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 | 89 ++++++++++++++++++++++++++++++++++++++-----
xen/arch/arm/setup.c | 2 +-
xen/include/asm-arm/setup.h | 2 +
3 files changed, 83 insertions(+), 10 deletions(-)
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index f641b12..ad7e6bc 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,74 @@ 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);
+
+ /*
+ * 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);
+
+ vunmap(output);
+
+ /*
+ * Free the original kernel, update the pointers to the
+ * decompressed kernel
+ */
+ dt_unreserved_regions(mod->start, mod->start + mod->size,
+ init_domheap_pages, 0);
+ mod->start = page_to_maddr(pages);
+ mod->size = output_size;
+
+ return 0;
+}
+
#ifdef CONFIG_ARM_64
/*
* Check if the image is a 64-bit Image.
@@ -444,8 +514,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 +521,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 |