mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/common: dom0less: introduce common kernel.c
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 don't provide 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> Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
This commit is contained in:
1 parent
a03848f23b
commit
a7ee73f581
6 files changed
+267
-216
No files matched your search
@@ -11,6 +11,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
|
||||
|
||||
+6
-215
@@ -162,105 +162,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
|
||||
*/
|
||||
@@ -273,8 +174,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 */
|
||||
@@ -504,130 +405,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
|
||||
|
||||
+4
-1
@@ -14,13 +14,16 @@ config CORE_PARKING
|
||||
|
||||
config DOM0LESS_BOOT
|
||||
bool "Dom0less boot support" if EXPERT
|
||||
depends on HAS_DOM0LESS && HAS_DEVICE_TREE
|
||||
depends on HAS_DOM0LESS && HAS_DEVICE_TREE && DOMAIN_BUILD_HELPERS
|
||||
default y
|
||||
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
|
||||
|
||||
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
|
||||
@@ -0,0 +1,242 @@
|
||||
#include <xen/bootfdt.h>
|
||||
#include <xen/device_tree.h>
|
||||
#include <xen/fdt-kernel.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/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);
|
||||
}
|
||||
@@ -120,6 +120,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 /* __XEN_FDT_KERNEL_H__ */
|
||||
|
||||
/*
|
||||
|
||||