[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 10/18] x86: introduce the domain builder
This commit introduces the domain builder configuration FDT parser along with the domain builder core for domain creation. To enable domain builder to be a cross architecture internal API, a new arch domain creation call is introduced for use by the domain builder. Signed-off-by: Daniel P. Smith <dpsmith@xxxxxxxxxxxxxxxxxxxx> Reviewed-by: Christopher Clark <christopher.clark@xxxxxxxxxx> --- xen/arch/x86/setup.c | 9 + xen/common/Makefile | 1 + xen/common/domain-builder/Makefile | 2 + xen/common/domain-builder/core.c | 96 ++++++++++ xen/common/domain-builder/fdt.c | 295 +++++++++++++++++++++++++++++ xen/common/domain-builder/fdt.h | 7 + xen/include/xen/bootinfo.h | 16 ++ xen/include/xen/domain_builder.h | 1 + 8 files changed, 427 insertions(+) create mode 100644 xen/common/domain-builder/Makefile create mode 100644 xen/common/domain-builder/core.c create mode 100644 xen/common/domain-builder/fdt.c create mode 100644 xen/common/domain-builder/fdt.h diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index e4060d6219..28dbfcd209 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1,4 +1,6 @@ +#include <xen/bootdomain.h> #include <xen/bootinfo.h> +#include <xen/domain_builder.h> #include <xen/init.h> #include <xen/lib.h> #include <xen/err.h> @@ -826,6 +828,13 @@ static struct domain *__init create_dom0(const struct boot_info *bi) return d; } +void __init arch_create_dom( + const struct boot_info *bi, struct boot_domain *bd) +{ + if ( builder_is_initdom(bd) ) + create_dom0(bi); +} + /* How much of the directmap is prebuilt at compile time. */ #define PREBUILT_MAP_LIMIT (1 << L2_PAGETABLE_SHIFT) diff --git a/xen/common/Makefile b/xen/common/Makefile index ebd3e2d659..eb108fa107 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -72,6 +72,7 @@ extra-y := symbols-dummy.o obj-$(CONFIG_COVERAGE) += coverage/ obj-y += sched/ obj-$(CONFIG_UBSAN) += ubsan/ +obj-y += domain-builder/ obj-$(CONFIG_NEEDS_LIBELF) += libelf/ obj-$(CONFIG_CORE_DEVICE_TREE) += libfdt/ diff --git a/xen/common/domain-builder/Makefile b/xen/common/domain-builder/Makefile new file mode 100644 index 0000000000..9561602502 --- /dev/null +++ b/xen/common/domain-builder/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_BUILDER_FDT) += fdt.o +obj-y += core.o diff --git a/xen/common/domain-builder/core.c b/xen/common/domain-builder/core.c new file mode 100644 index 0000000000..b030b07d71 --- /dev/null +++ b/xen/common/domain-builder/core.c @@ -0,0 +1,96 @@ +#include <xen/bootdomain.h> +#include <xen/bootinfo.h> +#include <xen/domain_builder.h> +#include <xen/init.h> +#include <xen/types.h> + +#include <asm/bzimage.h> +#include <asm/setup.h> + +#include "fdt.h" + +static struct domain_builder __initdata builder; + +void __init builder_init(struct boot_info *info) +{ + struct boot_domain *d = NULL; + + info->builder = &builder; + + if ( IS_ENABLED(CONFIG_BUILDER_FDT) ) + { + /* fdt is required to be module 0 */ + switch ( check_fdt(info, __va(info->mods[0].start)) ) + { + case 0: + printk("Domain Builder: initialized from config\n"); + info->builder->fdt_enabled = true; + return; + case -EINVAL: + info->builder->fdt_enabled = false; + break; + case -ENODATA: + default: + panic("%s: error occured processing DTB\n", __func__); + } + } + + /* + * No FDT config support or an FDT wasn't present, do an initial + * domain construction + */ + printk("Domain Builder: falling back to initial domain build\n"); + info->builder->nr_doms = 1; + d = &info->builder->domains[0]; + + d->mode = opt_dom0_pvh ? 0 : BUILD_MODE_PARAVIRTUALIZED; + + d->kernel = &info->mods[0]; + d->kernel->kind = BOOTMOD_KERNEL; + + d->permissions = BUILD_PERMISSION_CONTROL | BUILD_PERMISSION_HARDWARE; + d->functions = BUILD_FUNCTION_CONSOLE | BUILD_FUNCTION_XENSTORE | + BUILD_FUNCTION_INITIAL_DOM; + + d->kernel->arch->headroom = bzimage_headroom(bootstrap_map(d->kernel), + d->kernel->size); + bootstrap_map(NULL); + + if ( d->kernel->string.len ) + d->kernel->string.kind = BOOTSTR_CMDLINE; +} + +uint32_t __init builder_create_domains(struct boot_info *info) +{ + uint32_t build_count = 0, functions_built = 0; + int i; + + for ( i = 0; i < info->builder->nr_doms; i++ ) + { + struct boot_domain *d = &info->builder->domains[i]; + + if ( ! IS_ENABLED(CONFIG_MULTIDOM_BUILDER) && + ! builder_is_initdom(d) && + functions_built & BUILD_FUNCTION_INITIAL_DOM ) + continue; + + if ( d->kernel == NULL ) + { + if ( builder_is_initdom(d) ) + panic("%s: intial domain missing kernel\n", __func__); + + printk(XENLOG_ERR "%s:Dom%d definiton has no kernel\n", __func__, + d->domid); + continue; + } + + arch_create_dom(info, d); + if ( d->domain ) + { + functions_built |= d->functions; + build_count++; + } + } + + return build_count; +} diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c new file mode 100644 index 0000000000..937cc61e7a --- /dev/null +++ b/xen/common/domain-builder/fdt.c @@ -0,0 +1,295 @@ +#include <xen/bootdomain.h> +#include <xen/bootinfo.h> +#include <xen/domain_builder.h> +#include <xen/fdt.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/libfdt/libfdt.h> +#include <xen/page-size.h> +#include <xen/pfn.h> +#include <xen/types.h> + +#include <asm/bzimage.h> +#include <asm/setup.h> + +#include "fdt.h" + +#define BUILDER_FDT_TARGET_UNK 0 +#define BUILDER_FDT_TARGET_X86 1 +#define BUILDER_FDT_TARGET_ARM 2 +static int __initdata target_arch = BUILDER_FDT_TARGET_UNK; + +static struct boot_module *read_module( + const void *fdt, int node, uint32_t address_cells, uint32_t size_cells, + struct boot_info *info) +{ + const struct fdt_property *prop; + const __be32 *cell; + struct boot_module *bm; + bootmodule_kind kind = BOOTMOD_UNKNOWN; + int len; + + if ( device_tree_node_compatible(fdt, node, "module,kernel") ) + kind = BOOTMOD_KERNEL; + + if ( device_tree_node_compatible(fdt, node, "module,ramdisk") ) + kind = BOOTMOD_RAMDISK; + + if ( device_tree_node_compatible(fdt, node, "module,microcode") ) + kind = BOOTMOD_UCODE; + + if ( device_tree_node_compatible(fdt, node, "module,xsm-policy") ) + kind = BOOTMOD_XSM; + + if ( device_tree_node_compatible(fdt, node, "module,config") ) + kind = BOOTMOD_GUEST_CONF; + + if ( device_tree_node_compatible(fdt, node, "module,index") ) + { + uint32_t idx; + + idx = (uint32_t)device_tree_get_u32(fdt, node, "module-index", 0); + if ( idx == 0 ) + return NULL; + + bm = &info->mods[idx]; + + bm->kind = kind; + + return bm; + } + + if ( device_tree_node_compatible(fdt, node, "module,addr") ) + { + uint64_t addr, size; + + prop = fdt_get_property(fdt, node, "module-addr", &len); + if ( !prop ) + return NULL; + + if ( len < dt_cells_to_size(address_cells + size_cells) ) + return NULL; + + cell = (const __be32 *)prop->data; + device_tree_get_reg( + &cell, address_cells, size_cells, &addr, &size); + + bm = bootmodule_next_by_addr(info, addr, NULL); + + bm->kind = kind; + + return bm; + } + + printk(XENLOG_WARNING + "builder fdt: module node %d, no index or addr provided\n", + node); + + return NULL; +} + +static int process_config_node( + const void *fdt, int node, const char *name, int depth, + uint32_t address_cells, uint32_t size_cells, void *data) +{ + struct boot_info *info = (struct boot_info *)data; + int node_next; + + if ( !info ) + return -1; + + for ( node_next = fdt_first_subnode(fdt, node); + node_next > 0; + node_next = fdt_next_subnode(fdt, node_next)) + read_module(fdt, node_next, address_cells, size_cells, info); + + return 0; +} + +static int process_domain_node( + const void *fdt, int node, const char *name, int depth, + uint32_t address_cells, uint32_t size_cells, void *data) +{ + struct boot_info *info = (struct boot_info *)data; + const struct fdt_property *prop; + struct boot_domain *domain; + int node_next, i, plen; + + if ( !info ) + return -1; + + if ( info->builder->nr_doms >= BUILD_MAX_BOOT_DOMAINS ) + return -1; + + domain = &info->builder->domains[info->builder->nr_doms]; + + domain->domid = (domid_t)device_tree_get_u32(fdt, node, "domid", 0); + domain->permissions = device_tree_get_u32(fdt, node, "permissions", 0); + domain->functions = device_tree_get_u32(fdt, node, "functions", 0); + domain->mode = device_tree_get_u32(fdt, node, "mode", 0); + + prop = fdt_get_property(fdt, node, "domain-uuid", &plen); + if ( prop ) + for ( i=0; i < sizeof(domain->uuid) % sizeof(uint32_t); i++ ) + *(domain->uuid + i) = fdt32_to_cpu((uint32_t)prop->data[i]); + + domain->ncpus = device_tree_get_u32(fdt, node, "cpus", 1); + + if ( target_arch == BUILDER_FDT_TARGET_X86 ) + { + prop = fdt_get_property(fdt, node, "memory", &plen); + if ( prop ) + { + int sz = fdt32_to_cpu(prop->len); + char s[64]; + unsigned long val; + + if ( sz >= 64 ) + panic("node %s invalid `memory' property\n", name); + + memcpy(s, prop->data, sz); + s[sz] = '\0'; + val = parse_size_and_unit(s, NULL); + + domain->meminfo.mem_size.nr_pages = PFN_UP(val); + domain->meminfo.mem_max.nr_pages = PFN_UP(val); + } + else + panic("node %s missing `memory' property\n", name); + } + else + panic("%s: only x86 memory parsing supported\n", __func__); + + prop = fdt_get_property(fdt, node, "security-id", + &plen); + if ( prop ) + { + int sz = fdt32_to_cpu(prop->len); + sz = sz > BUILD_MAX_SECID_LEN ? BUILD_MAX_SECID_LEN : sz; + memcpy(domain->secid, prop->data, sz); + } + + for ( node_next = fdt_first_subnode(fdt, node); + node_next > 0; + node_next = fdt_next_subnode(fdt, node_next)) + { + struct boot_module *bm = read_module(fdt, node_next, address_cells, + size_cells, info); + + switch ( bm->kind ) + { + case BOOTMOD_KERNEL: + /* kernel was already found */ + if ( domain->kernel != NULL ) + continue; + + bm->arch->headroom = bzimage_headroom(bootstrap_map(bm), bm->size); + bootstrap_map(NULL); + + if ( bm->string.len ) + bm->string.kind = BOOTSTR_CMDLINE; + else + { + prop = fdt_get_property(fdt, node_next, "bootargs", &plen); + if ( prop ) + { + int size = fdt32_to_cpu(prop->len); + size = size > BOOTMOD_MAX_STRING ? + BOOTMOD_MAX_STRING : size; + memcpy(bm->string.bytes, prop->data, size); + bm->string.kind = BOOTSTR_CMDLINE; + } + } + + domain->kernel = bm; + + break; + case BOOTMOD_RAMDISK: + /* ramdisk was already found */ + if ( domain->ramdisk != NULL ) + continue; + + domain->ramdisk = bm; + + break; + case BOOTMOD_GUEST_CONF: + /* guest config was already found */ + if ( domain->configs[BUILD_DOM_CONF_IDX] != NULL ) + continue; + + domain->configs[BUILD_DOM_CONF_IDX] = bm; + + break; + default: + continue; + } + } + + info->builder->nr_doms++; + + return 0; +} + +static int __init scan_node( + const void *fdt, int node, const char *name, int depth, u32 address_cells, + u32 size_cells, void *data) +{ + int rc = -1; + + /* skip nodes that are not direct children of the hyperlaunch node */ + if ( depth > 1 ) + return 0; + + if ( device_tree_node_compatible(fdt, node, "xen,config") ) + rc = process_config_node(fdt, node, name, depth, + address_cells, size_cells, data); + else if ( device_tree_node_compatible(fdt, node, "xen,domain") ) + rc = process_domain_node(fdt, node, name, depth, + address_cells, size_cells, data); + + if ( rc < 0 ) + printk("hyperlaunch fdt: node `%s'failed to parse\n", name); + + return rc; +} + +/* check_fdt + * Attempts to initialize hyperlaunch config + * + * Returns: + * -EINVAL: Not a valid DTB + * -ENODATA: Valid DTB but not a valid hyperlaunch device tree + * 0: Valid hyperlaunch device tree + */ +int __init check_fdt(struct boot_info *info, void *fdt) +{ + int hv_node, ret; + + ret = fdt_check_header(fdt); + if ( ret < 0 ) + return -EINVAL; + + hv_node = fdt_path_offset(fdt, "/chosen/hypervisor"); + if ( hv_node < 0 ) + return -ENODATA; + + if ( !device_tree_node_compatible(fdt, hv_node, "hypervisor,xen") ) + return -EINVAL; + + if ( IS_ENABLED(CONFIG_X86) && + device_tree_node_compatible(fdt, hv_node, "xen,x86") ) + target_arch = BUILDER_FDT_TARGET_X86; + else if ( IS_ENABLED(CONFIG_ARM) && + device_tree_node_compatible(fdt, hv_node, "xen,arm") ) + target_arch = BUILDER_FDT_TARGET_ARM; + + if ( target_arch != BUILDER_FDT_TARGET_X86 && + target_arch != BUILDER_FDT_TARGET_ARM ) + return -EINVAL; + + ret = device_tree_for_each_node(fdt, hv_node, scan_node, boot_info); + if ( ret > 0 ) + return -ENODATA; + + return 0; +} diff --git a/xen/common/domain-builder/fdt.h b/xen/common/domain-builder/fdt.h new file mode 100644 index 0000000000..b185718412 --- /dev/null +++ b/xen/common/domain-builder/fdt.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef COMMON_BUILDER_FDT_H +#define COMMON_BUILDER_FDT_H + +int __init check_fdt(struct boot_info *info, void *fdt); +#endif diff --git a/xen/include/xen/bootinfo.h b/xen/include/xen/bootinfo.h index 1d76d99a40..07b151e318 100644 --- a/xen/include/xen/bootinfo.h +++ b/xen/include/xen/bootinfo.h @@ -101,6 +101,22 @@ static inline struct boot_module *bootmodule_next_by_kind( return NULL; } +static inline struct boot_module *bootmodule_next_by_addr( + const struct boot_info *bi, paddr_t addr, struct boot_module *start) +{ + /* point end at the entry for xen */ + struct boot_module *end = &bi->mods[bi->nr_mods]; + + if ( !start ) + start = bi->mods; + + for ( ; start < end; start++ ) + if ( start->start == addr ) + return start; + + return NULL; +} + static inline void bootmodule_update_start(struct boot_module *b, paddr_t new_start) { b->start = new_start; diff --git a/xen/include/xen/domain_builder.h b/xen/include/xen/domain_builder.h index 79785ef251..c0d997f7bd 100644 --- a/xen/include/xen/domain_builder.h +++ b/xen/include/xen/domain_builder.h @@ -51,5 +51,6 @@ static inline struct domain *builder_get_hwdom(struct boot_info *info) void builder_init(struct boot_info *info); uint32_t builder_create_domains(struct boot_info *info); +void arch_create_dom(const struct boot_info *bi, struct boot_domain *bd); #endif /* XEN_DOMAIN_BUILDER_H */ -- 2.20.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |