@@ -12,6 +12,7 @@ config ARM_64
config ARM
def_bool y
+ select DOMAIN_BUILD_HELPERS
select FUNCTION_ALIGNMENT_4B
select GENERIC_UART_INIT
select HAS_ALTERNATIVE if HAS_VMAP
@@ -160,105 +160,6 @@ static void __init kernel_zimage_load(struct kernel_info *info)
iounmap(kernel);
}
-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, uint32_t offset)
-{
- char *output, *input;
- char magic[2];
- int rc;
- unsigned int 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 < offset )
- return -EINVAL;
-
- /*
- * It might be that gzip header does not appear at the start address
- * (e.g. in case of compressed uImage) so take into account offset to
- * gzip header.
- */
- addr += offset;
- size -= offset;
-
- 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 = page_to_mfn(pages);
- output = vmap_contig(mfn, 1 << kernel_order_out);
-
- rc = perform_gunzip(output, input, size);
- clean_dcache_va_range(output, output_size);
- iounmap(input);
- vunmap(output);
-
- if ( rc )
- {
- free_domheap_pages(pages, kernel_order_out);
- return rc;
- }
-
- 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 = PFN_UP(output_size);
- for ( ; i < (1 << kernel_order_out); i++ )
- free_domheap_page(pages + i);
-
- /*
- * When using static heap feature, don't give bootmodules memory back to
- * the heap allocator
- */
- if ( using_static_heap )
- return 0;
-
- /*
- * When freeing the kernel, we need to pass the module start address and
- * size as they were before taking an offset to gzip header into account,
- * so that the entire region will be freed.
- */
- addr -= offset;
- size += offset;
-
- /*
- * Free the original kernel, update the pointers to the
- * decompressed kernel
- */
- fw_unreserved_regions(addr, addr + size, init_domheap_pages, 0);
-
- return 0;
-}
-
/*
* Uimage CPU Architecture Codes
*/
@@ -271,8 +172,8 @@ static __init int kernel_decompress(struct bootmodule *mod, uint32_t offset)
/*
* Check if the image is a uImage and setup kernel_info
*/
-static int __init kernel_uimage_probe(struct kernel_info *info,
- struct bootmodule *mod)
+int __init kernel_uimage_probe(struct kernel_info *info,
+ struct bootmodule *mod)
{
struct {
__be32 magic; /* Image Header Magic Number */
@@ -502,130 +403,20 @@ static int __init kernel_zimage32_probe(struct kernel_info *info,
return 0;
}
-int __init kernel_probe(struct kernel_info *info,
- const struct dt_device_node *domain)
+int __init kernel_zimage_probe(struct kernel_info *info, paddr_t addr,
+ paddr_t size)
{
- struct bootmodule *mod = NULL;
- struct bootcmdline *cmd = NULL;
- struct dt_device_node *node;
- u64 kernel_addr, initrd_addr, dtb_addr, size;
int rc;
- /*
- * We need to initialize start to 0. This field may be populated during
- * kernel_xxx_probe() if the image has a fixed entry point (for e.g.
- * uimage.ep).
- * We will use this to determine if the image has a fixed entry point or
- * the load address should be used as the start address.
- */
- info->entry = 0;
-
- /* domain is NULL only for the hardware domain */
- if ( domain == NULL )
- {
- ASSERT(is_hardware_domain(info->d));
-
- mod = boot_module_find_by_kind(BOOTMOD_KERNEL);
-
- info->kernel_bootmodule = mod;
- info->initrd_bootmodule = boot_module_find_by_kind(BOOTMOD_RAMDISK);
-
- cmd = boot_cmdline_find_by_kind(BOOTMOD_KERNEL);
- if ( cmd )
- info->cmdline = &cmd->cmdline[0];
- }
- else
- {
- const char *name = NULL;
-
- dt_for_each_child_node(domain, node)
- {
- if ( dt_device_is_compatible(node, "multiboot,kernel") )
- {
- u32 len;
- const __be32 *val;
-
- val = dt_get_property(node, "reg", &len);
- dt_get_range(&val, node, &kernel_addr, &size);
- mod = boot_module_find_by_addr_and_kind(
- BOOTMOD_KERNEL, kernel_addr);
- info->kernel_bootmodule = mod;
- }
- else if ( dt_device_is_compatible(node, "multiboot,ramdisk") )
- {
- u32 len;
- const __be32 *val;
-
- val = dt_get_property(node, "reg", &len);
- dt_get_range(&val, node, &initrd_addr, &size);
- info->initrd_bootmodule = boot_module_find_by_addr_and_kind(
- BOOTMOD_RAMDISK, initrd_addr);
- }
- else if ( dt_device_is_compatible(node, "multiboot,device-tree") )
- {
- uint32_t len;
- const __be32 *val;
-
- val = dt_get_property(node, "reg", &len);
- if ( val == NULL )
- continue;
- dt_get_range(&val, node, &dtb_addr, &size);
- info->dtb_bootmodule = boot_module_find_by_addr_and_kind(
- BOOTMOD_GUEST_DTB, dtb_addr);
- }
- else
- continue;
- }
- name = dt_node_name(domain);
- cmd = boot_cmdline_find_by_name(name);
- if ( cmd )
- info->cmdline = &cmd->cmdline[0];
- }
- if ( !mod || !mod->size )
- {
- printk(XENLOG_ERR "Missing kernel boot module?\n");
- return -ENOENT;
- }
-
- printk("Loading %pd kernel from boot module @ %"PRIpaddr"\n",
- info->d, info->kernel_bootmodule->start);
- if ( info->initrd_bootmodule )
- printk("Loading ramdisk from boot module @ %"PRIpaddr"\n",
- info->initrd_bootmodule->start);
-
- /*
- * uImage header always appears at the top of the image (even compressed),
- * so it needs to be probed first. Note that in case of compressed uImage,
- * kernel_decompress is called from kernel_uimage_probe making the function
- * self-containing (i.e. fall through only in case of a header not found).
- */
- rc = kernel_uimage_probe(info, mod);
- if ( rc != -ENOENT )
- return rc;
-
- /*
- * If it is a gzip'ed image, 32bit or 64bit, uncompress it.
- * At this point, gzip header appears (if at all) at the top of the image,
- * so pass 0 as an offset.
- */
- rc = kernel_decompress(mod, 0);
- if ( rc && rc != -EINVAL )
- return rc;
-
#ifdef CONFIG_ARM_64
- rc = kernel_zimage64_probe(info, mod->start, mod->size);
+ rc = kernel_zimage64_probe(info, addr, size);
if (rc < 0)
#endif
- rc = kernel_zimage32_probe(info, mod->start, mod->size);
+ rc = kernel_zimage32_probe(info, addr, size);
return rc;
}
-void __init kernel_load(struct kernel_info *info)
-{
- info->load(info);
-}
-
/*
* Local variables:
* mode: C
@@ -14,13 +14,20 @@ config CORE_PARKING
config DOM0LESS_BOOT
bool "Dom0less boot support" if EXPERT
- depends on ARM
- default ARM
+ depends on DOMAIN_BUILD_HELPERS
+ default DOMAIN_BUILD_HELPERS
help
Dom0less boot support enables Xen to create and start domU guests during
Xen boot without the need of a control domain (Dom0), which could be
present anyway.
+config DOMAIN_BUILD_HELPERS
+ bool
+ help
+ Introduce functions necessary for working with domain creation, kernel,
+ etc. As an examples, these type of functions are going to be used by
+ CONFIG_DOM0LESS_BOOT.
+
config GRANT_TABLE
bool "Grant table support" if EXPERT
default y
@@ -4,3 +4,4 @@ obj-y += device-tree.o
obj-$(CONFIG_DOM0LESS_BOOT) += dom0less-build.o
obj-$(CONFIG_OVERLAY_DTB) += dt-overlay.o
obj-y += intc.o
+obj-$(CONFIG_DOMAIN_BUILD_HELPERS) += kernel.o
new file mode 100644
@@ -0,0 +1,242 @@
+#include <xen/bootfdt.h>
+#include <xen/device_tree.h>
+#include <xen/errno.h>
+#include <xen/gunzip.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/pfn.h>
+#include <xen/sched.h>
+#include <xen/types.h>
+#include <xen/vmap.h>
+
+#include <asm/kernel.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+
+static uint32_t __init output_length(char *image, unsigned long image_len)
+{
+ return *(uint32_t *)&image[image_len - 4];
+}
+
+int __init kernel_decompress(struct bootmodule *mod, uint32_t offset)
+{
+ char *output, *input;
+ char magic[2];
+ int rc;
+ unsigned int 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 < offset )
+ return -EINVAL;
+
+ /*
+ * It might be that gzip header does not appear at the start address
+ * (e.g. in case of compressed uImage) so take into account offset to
+ * gzip header.
+ */
+ addr += offset;
+ size -= offset;
+
+ 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 = page_to_mfn(pages);
+ output = vmap_contig(mfn, 1 << kernel_order_out);
+
+ rc = perform_gunzip(output, input, size);
+ clean_dcache_va_range(output, output_size);
+ iounmap(input);
+ vunmap(output);
+
+ if ( rc )
+ {
+ free_domheap_pages(pages, kernel_order_out);
+ return rc;
+ }
+
+ 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 = PFN_UP(output_size);
+ for ( ; i < (1 << kernel_order_out); i++ )
+ free_domheap_page(pages + i);
+
+ /*
+ * When using static heap feature, don't give bootmodules memory back to
+ * the heap allocator
+ */
+ if ( using_static_heap )
+ return 0;
+
+ /*
+ * When freeing the kernel, we need to pass the module start address and
+ * size as they were before taking an offset to gzip header into account,
+ * so that the entire region will be freed.
+ */
+ addr -= offset;
+ size += offset;
+
+ /*
+ * Free the original kernel, update the pointers to the
+ * decompressed kernel
+ */
+ fw_unreserved_regions(addr, addr + size, init_domheap_pages, 0);
+
+ return 0;
+}
+
+int __init kernel_probe(struct kernel_info *info,
+ const struct dt_device_node *domain)
+{
+ struct bootmodule *mod = NULL;
+ struct bootcmdline *cmd = NULL;
+ struct dt_device_node *node;
+ u64 kernel_addr, initrd_addr, dtb_addr, size;
+ int rc;
+
+ /*
+ * We need to initialize start to 0. This field may be populated during
+ * kernel_xxx_probe() if the image has a fixed entry point (for e.g.
+ * uimage.ep).
+ * We will use this to determine if the image has a fixed entry point or
+ * the load address should be used as the start address.
+ */
+ info->entry = 0;
+
+ /* domain is NULL only for the hardware domain */
+ if ( domain == NULL )
+ {
+ ASSERT(is_hardware_domain(info->d));
+
+ mod = boot_module_find_by_kind(BOOTMOD_KERNEL);
+
+ info->kernel_bootmodule = mod;
+ info->initrd_bootmodule = boot_module_find_by_kind(BOOTMOD_RAMDISK);
+
+ cmd = boot_cmdline_find_by_kind(BOOTMOD_KERNEL);
+ if ( cmd )
+ info->cmdline = &cmd->cmdline[0];
+ }
+ else
+ {
+ const char *name = NULL;
+
+ dt_for_each_child_node(domain, node)
+ {
+ if ( dt_device_is_compatible(node, "multiboot,kernel") )
+ {
+ u32 len;
+ const __be32 *val;
+
+ val = dt_get_property(node, "reg", &len);
+ dt_get_range(&val, node, &kernel_addr, &size);
+ mod = boot_module_find_by_addr_and_kind(
+ BOOTMOD_KERNEL, kernel_addr);
+ info->kernel_bootmodule = mod;
+ }
+ else if ( dt_device_is_compatible(node, "multiboot,ramdisk") )
+ {
+ u32 len;
+ const __be32 *val;
+
+ val = dt_get_property(node, "reg", &len);
+ dt_get_range(&val, node, &initrd_addr, &size);
+ info->initrd_bootmodule = boot_module_find_by_addr_and_kind(
+ BOOTMOD_RAMDISK, initrd_addr);
+ }
+ else if ( dt_device_is_compatible(node, "multiboot,device-tree") )
+ {
+ uint32_t len;
+ const __be32 *val;
+
+ val = dt_get_property(node, "reg", &len);
+ if ( val == NULL )
+ continue;
+ dt_get_range(&val, node, &dtb_addr, &size);
+ info->dtb_bootmodule = boot_module_find_by_addr_and_kind(
+ BOOTMOD_GUEST_DTB, dtb_addr);
+ }
+ else
+ continue;
+ }
+ name = dt_node_name(domain);
+ cmd = boot_cmdline_find_by_name(name);
+ if ( cmd )
+ info->cmdline = &cmd->cmdline[0];
+ }
+ if ( !mod || !mod->size )
+ {
+ printk(XENLOG_ERR "Missing kernel boot module?\n");
+ return -ENOENT;
+ }
+
+ printk("Loading %pd kernel from boot module @ %"PRIpaddr"\n",
+ info->d, info->kernel_bootmodule->start);
+ if ( info->initrd_bootmodule )
+ printk("Loading ramdisk from boot module @ %"PRIpaddr"\n",
+ info->initrd_bootmodule->start);
+
+ /*
+ * uImage isn't really used nowadays thereby leave kernel_uimage_probe()
+ * call here just for compatability with Arm code.
+ */
+#ifdef CONFIG_ARM
+ /*
+ * uImage header always appears at the top of the image (even compressed),
+ * so it needs to be probed first. Note that in case of compressed uImage,
+ * kernel_decompress is called from kernel_uimage_probe making the function
+ * self-containing (i.e. fall through only in case of a header not found).
+ */
+ rc = kernel_uimage_probe(info, mod);
+ if ( rc != -ENOENT )
+ return rc;
+#endif
+
+ /*
+ * If it is a gzip'ed image, 32bit or 64bit, uncompress it.
+ * At this point, gzip header appears (if at all) at the top of the image,
+ * so pass 0 as an offset.
+ */
+ rc = kernel_decompress(mod, 0);
+ if ( rc && rc != -EINVAL )
+ return rc;
+
+ rc = kernel_zimage_probe(info, mod->start, mod->size);
+
+ return rc;
+}
+
+void __init kernel_load(struct kernel_info *info)
+{
+ ASSERT(info && info->load);
+
+ info->load(info);
+}
@@ -134,6 +134,19 @@ int kernel_probe(struct kernel_info *info, const struct dt_device_node *domain);
*/
void kernel_load(struct kernel_info *info);
+int kernel_decompress(struct bootmodule *mod, uint32_t offset);
+
+int kernel_zimage_probe(struct kernel_info *info, paddr_t addr, paddr_t size);
+
+/*
+ * uImage isn't really used nowadays thereby leave kernel_uimage_probe()
+ * call here just for compatability with Arm code.
+ */
+#ifdef CONFIG_ARM
+struct bootmodule;
+int kernel_uimage_probe(struct kernel_info *info, struct bootmodule *mod);
+#endif
+
#endif /*__ASM_GENERIC_KERNEL_H__ */
/*
The following functions don't have arch specific things so it is moved to common: - kernel_prboe() - kernel_load() - output_length() Functions necessary for dom0less are only moved. The following changes are done: - Swap __init and return type of kernel_decompress() function to be consistent with defintions of functions in other files. The same for output_length(). - Wrap by "ifdef CONFIG_ARM" the call of kernel_uimage_probe() in kernel_probe() as uImage isn't really used nowadays thereby leave kernel_uimage_probe() call here just for compatability with Arm code. - Introduce kernel_zimage_probe() to cover the case that arch can have different zimage header. - Add ASSERT() for kernel_load() to check that it argument isn't NULL. - Make kernel_uimage_probe() non-static in Arm's code as it is used in common/kernel.c. Introduce CONFIG_DOMAIN_BUILD_HELPERS to not provide stubs for archs which doesn't provice enough functionality to enable it. Select CONFIG_DOMAIN_BUILD_HELPERS for CONFIG_ARM as only Arm supports it, at the moment. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- xen/arch/arm/Kconfig | 1 + xen/arch/arm/kernel.c | 221 +--------------------------- xen/common/Kconfig | 11 +- xen/common/device-tree/Makefile | 1 + xen/common/device-tree/kernel.c | 242 +++++++++++++++++++++++++++++++ xen/include/asm-generic/kernel.h | 13 ++ 6 files changed, 272 insertions(+), 217 deletions(-) create mode 100644 xen/common/device-tree/kernel.c