:p
atchew
Login
The Hyperlaunch device tree for dom0 series is the second split out for the introduction of the Hyperlaunch domain builder logic. These changes focus on introducing the ability to express a domain configuration that is then used to populate the struct boot_domain structure for dom0. This ability to express a domain configuration provides the next step towards a general domain builder. The splitting of Hyperlaunch into a set of series are twofold, to reduce the effort in reviewing a much larger series, and to reduce the effort in handling the knock-on effects to the construction logic from requested review changes. Much thanks to AMD for supporting this work. Documentation on Hyperlaunch: https://wiki.xenproject.org/wiki/Hyperlaunch Original Hyperlaunch v1 patch series: https://lists.xenproject.org/archives/html/xen-devel/2022-07/msg00345.html V/r, Daniel P. Smith Daniel P. Smith (15): x86/boot: introduce boot domain x86/boot: introduce domid field to struct boot_domain x86/boot: add cmdline to struct boot_domain kconfig: introduce option to independently enable libfdt kconfig: introduce domain builder config option x86/hyperlaunch: introduce the domain builder x86/hyperlaunch: initial support for hyperlaunch device tree x86/hyperlaunch: locate dom0 kernel with hyperlaunch x86/hyperlaunch: obtain cmdline from device tree x86/hyperlaunch: locate dom0 initrd with hyperlaunch x86/hyperlaunch: add domain id parsing to domain config x86/hyperlaunch: specify dom0 mode with device tree x86/hyperlaunch: add memory parsing to domain config x86/hyperlaunch: add max vcpu parsing of hyperlaunch device tree x86/hyperlaunch: add capabilities to boot domain xen/arch/x86/Kconfig | 2 + xen/arch/x86/Makefile | 2 + xen/arch/x86/dom0_build.c | 19 +- xen/arch/x86/domain_builder/Kconfig | 15 + xen/arch/x86/domain_builder/Makefile | 3 + xen/arch/x86/domain_builder/core.c | 109 +++++++ xen/arch/x86/domain_builder/fdt.c | 395 +++++++++++++++++++++++ xen/arch/x86/domain_builder/fdt.h | 94 ++++++ xen/arch/x86/hvm/dom0_build.c | 23 +- xen/arch/x86/include/asm/bootdomain.h | 53 +++ xen/arch/x86/include/asm/bootinfo.h | 15 +- xen/arch/x86/include/asm/dom0_build.h | 6 +- xen/arch/x86/include/asm/domainbuilder.h | 12 + xen/arch/x86/include/asm/setup.h | 4 +- xen/arch/x86/pv/dom0_build.c | 28 +- xen/arch/x86/setup.c | 140 +++++--- xen/common/Kconfig | 4 + xen/common/Makefile | 2 +- 18 files changed, 836 insertions(+), 90 deletions(-) create mode 100644 xen/arch/x86/domain_builder/Kconfig create mode 100644 xen/arch/x86/domain_builder/Makefile create mode 100644 xen/arch/x86/domain_builder/core.c create mode 100644 xen/arch/x86/domain_builder/fdt.c create mode 100644 xen/arch/x86/domain_builder/fdt.h create mode 100644 xen/arch/x86/include/asm/bootdomain.h create mode 100644 xen/arch/x86/include/asm/domainbuilder.h -- 2.30.2
To begin moving toward allowing the hypervisor to construct more than one domain at boot, a container is needed for a domain's build information. Introduce a new header, <xen/asm/bootdomain.h>, that contains the initial struct boot_domain that encapsulate the build information for a domain. Add a kernel and ramdisk boot module reference along with a struct domain reference to the new struct boot_domain. This allows a struct boot_domain reference to be the only parameter necessary to pass down through the domain construction call chain. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> --- Changes since boot modules v9 - dropped unlikely Changes since v8: - code style correction --- xen/arch/x86/dom0_build.c | 8 ++++--- xen/arch/x86/hvm/dom0_build.c | 17 +++++---------- xen/arch/x86/include/asm/bootdomain.h | 31 +++++++++++++++++++++++++++ xen/arch/x86/include/asm/bootinfo.h | 5 +++++ xen/arch/x86/include/asm/dom0_build.h | 6 +++--- xen/arch/x86/include/asm/setup.h | 4 ++-- xen/arch/x86/pv/dom0_build.c | 24 +++++++-------------- xen/arch/x86/setup.c | 24 +++++++++------------ 8 files changed, 69 insertions(+), 50 deletions(-) create mode 100644 xen/arch/x86/include/asm/bootdomain.h diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -XXX,XX +XXX,XX @@ #include <xen/softirq.h> #include <asm/amd.h> +#include <asm/bootinfo.h> #include <asm/dom0_build.h> #include <asm/guest.h> #include <asm/hpet.h> @@ -XXX,XX +XXX,XX @@ int __init dom0_setup_permissions(struct domain *d) return rc; } -int __init construct_dom0(struct boot_info *bi, struct domain *d) +int __init construct_dom0(struct boot_domain *bd) { int rc; + const struct domain *d = bd->d; /* Sanity! */ BUG_ON(!pv_shim && d->domain_id != 0); @@ -XXX,XX +XXX,XX @@ int __init construct_dom0(struct boot_info *bi, struct domain *d) process_pending_softirqs(); if ( is_hvm_domain(d) ) - rc = dom0_construct_pvh(bi, d); + rc = dom0_construct_pvh(bd); else if ( is_pv_domain(d) ) - rc = dom0_construct_pv(bi, d); + rc = dom0_construct_pv(bd); else panic("Cannot construct Dom0. No guest interface available\n"); diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -XXX,XX +XXX,XX @@ static void __hwdom_init pvh_setup_mmcfg(struct domain *d) } } -int __init dom0_construct_pvh(struct boot_info *bi, struct domain *d) +int __init dom0_construct_pvh(struct boot_domain *bd) { paddr_t entry, start_info; - struct boot_module *image; - struct boot_module *initrd = NULL; - unsigned int idx; + struct boot_module *image = bd->kernel; + struct boot_module *initrd = bd->ramdisk; + struct domain *d = bd->d; int rc; printk(XENLOG_INFO "*** Building a PVH Dom%d ***\n", d->domain_id); - idx = first_boot_module_index(bi, BOOTMOD_KERNEL); - if ( idx >= bi->nr_modules ) + if ( image == NULL ) panic("Missing kernel boot module for %pd construction\n", d); - image = &bi->mods[idx]; - - idx = first_boot_module_index(bi, BOOTMOD_RAMDISK); - if ( idx < bi->nr_modules ) - initrd = &bi->mods[idx]; - if ( is_hardware_domain(d) ) { /* diff --git a/xen/arch/x86/include/asm/bootdomain.h b/xen/arch/x86/include/asm/bootdomain.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/x86/include/asm/bootdomain.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Apertus Solutions, LLC + * Author: Daniel P. Smith <dpsmith@apertussolutions.com> + * Copyright (c) 2024 Christopher Clark <christopher.w.clark@gmail.com> + */ + +#ifndef __XEN_X86_BOOTDOMAIN_H__ +#define __XEN_X86_BOOTDOMAIN_H__ + +struct boot_module; +struct domain; + +struct boot_domain { + struct boot_module *kernel; + struct boot_module *ramdisk; + + struct domain *d; +}; + +#endif + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -XXX,XX +XXX,XX @@ #include <xen/init.h> #include <xen/multiboot.h> #include <xen/types.h> +#include <asm/bootdomain.h> /* Max number of boot modules a bootloader can provide in addition to Xen */ #define MAX_NR_BOOTMODS 63 +/* Max number of boot domains that Xen can construct */ +#define MAX_NR_BOOTDOMS 1 + /* Boot module binary type / purpose */ enum bootmod_type { BOOTMOD_UNKNOWN, @@ -XXX,XX +XXX,XX @@ struct boot_info { unsigned int nr_modules; struct boot_module mods[MAX_NR_BOOTMODS + 1]; + struct boot_domain domains[MAX_NR_BOOTDOMS]; }; /* diff --git a/xen/arch/x86/include/asm/dom0_build.h b/xen/arch/x86/include/asm/dom0_build.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/dom0_build.h +++ b/xen/arch/x86/include/asm/dom0_build.h @@ -XXX,XX +XXX,XX @@ unsigned long dom0_compute_nr_pages(struct domain *d, unsigned long initrd_len); int dom0_setup_permissions(struct domain *d); -struct boot_info; -int dom0_construct_pv(struct boot_info *bi, struct domain *d); -int dom0_construct_pvh(struct boot_info *bi, struct domain *d); +struct boot_domain; +int dom0_construct_pv(struct boot_domain *bd); +int dom0_construct_pvh(struct boot_domain *bd); unsigned long dom0_paging_pages(const struct domain *d, unsigned long nr_pages); diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/setup.h +++ b/xen/arch/x86/include/asm/setup.h @@ -XXX,XX +XXX,XX @@ void subarch_init_memory(void); void init_IRQ(void); -struct boot_info; -int construct_dom0(struct boot_info *bi, struct domain *d); +struct boot_domain; +int construct_dom0(struct boot_domain *bd); void setup_io_bitmap(struct domain *d); diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/pv/dom0_build.c +++ b/xen/arch/x86/pv/dom0_build.c @@ -XXX,XX +XXX,XX @@ static struct page_info * __init alloc_chunk(struct domain *d, return page; } -static int __init dom0_construct(struct boot_info *bi, struct domain *d) +static int __init dom0_construct(struct boot_domain *bd) { unsigned int i; int rc, order, machine; @@ -XXX,XX +XXX,XX @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) struct page_info *page = NULL; unsigned int flush_flags = 0; start_info_t *si; + struct domain *d = bd->d; struct vcpu *v = d->vcpu[0]; - struct boot_module *image; - struct boot_module *initrd = NULL; + struct boot_module *image = bd->kernel; + struct boot_module *initrd = bd->ramdisk; void *image_base; unsigned long image_len; void *image_start; - unsigned long initrd_len = 0; + unsigned long initrd_len = initrd ? initrd->size : 0; l4_pgentry_t *l4tab = NULL, *l4start = NULL; l3_pgentry_t *l3tab = NULL, *l3start = NULL; @@ -XXX,XX +XXX,XX @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) printk(XENLOG_INFO "*** Building a PV Dom%d ***\n", d->domain_id); - i = first_boot_module_index(bi, BOOTMOD_KERNEL); - if ( i >= bi->nr_modules ) + if ( !image ) panic("Missing kernel boot module for %pd construction\n", d); - image = &bi->mods[i]; image_base = bootstrap_map_bm(image); image_len = image->size; image_start = image_base + image->headroom; - i = first_boot_module_index(bi, BOOTMOD_RAMDISK); - if ( i < bi->nr_modules ) - { - initrd = &bi->mods[i]; - initrd_len = initrd->size; - } - d->max_pages = ~0U; if ( (rc = bzimage_parse(image_base, &image_start, &image_len)) != 0 ) @@ -XXX,XX +XXX,XX @@ out: return rc; } -int __init dom0_construct_pv(struct boot_info *bi, struct domain *d) +int __init dom0_construct_pv(struct boot_domain *bd) { unsigned long cr4 = read_cr4(); int rc; @@ -XXX,XX +XXX,XX @@ int __init dom0_construct_pv(struct boot_info *bi, struct domain *d) write_cr4(cr4 & ~X86_CR4_SMAP); } - rc = dom0_construct(bi, d); + rc = dom0_construct(bd); if ( cr4 & X86_CR4_SMAP ) { diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0, }, }; + struct boot_domain *bd = &bi->domains[0]; struct domain *d; domid_t domid; - struct boot_module *image; - unsigned int idx; - - idx = first_boot_module_index(bi, BOOTMOD_KERNEL); - if ( idx >= bi->nr_modules ) - panic("Missing kernel boot module for building domain\n"); - - image = &bi->mods[idx]; if ( opt_dom0_pvh ) { @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) panic("Error creating d%uv0\n", domid); /* Grab the DOM0 command line. */ - if ( image->cmdline_pa || bi->kextra ) + if ( bd->kernel->cmdline_pa || bi->kextra ) { - if ( image->cmdline_pa ) - safe_strcpy( - cmdline, cmdline_cook(__va(image->cmdline_pa), bi->loader)); + if ( bd->kernel->cmdline_pa ) + safe_strcpy(cmdline, + cmdline_cook(__va(bd->kernel->cmdline_pa), bi->loader)); if ( bi->kextra ) /* kextra always includes exactly one leading space. */ @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) safe_strcat(cmdline, acpi_param); } - image->cmdline_pa = __pa(cmdline); + bd->kernel->cmdline_pa = __pa(cmdline); } - if ( construct_dom0(bi, d) != 0 ) + bd->d = d; + if ( construct_dom0(bd) != 0 ) panic("Could not construct domain 0\n"); return d; @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) /* Dom0 kernel is always first */ bi->mods[0].type = BOOTMOD_KERNEL; + bi->domains[0].kernel = &bi->mods[0]; if ( pvh_boot ) { @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) if ( initrdidx < MAX_NR_BOOTMODS ) { bi->mods[initrdidx].type = BOOTMOD_RAMDISK; + bi->domains[0].ramdisk = &bi->mods[initrdidx]; if ( first_boot_module_index(bi, BOOTMOD_UNKNOWN) < MAX_NR_BOOTMODS ) printk(XENLOG_WARNING "Multiple initrd candidates, picking module #%u\n", -- 2.30.2
Add a domid field to struct boot_domain to hold the assigned domain id for the domain. During initialization, ensure all instances of struct boot_domain have the invalid domid to ensure that the domid must be set either by convention or configuration. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> --- Changes since v9 boot modules - missing include for domid_t def --- xen/arch/x86/include/asm/bootdomain.h | 4 ++++ xen/arch/x86/setup.c | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/include/asm/bootdomain.h b/xen/arch/x86/include/asm/bootdomain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootdomain.h +++ b/xen/arch/x86/include/asm/bootdomain.h @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2024 Christopher Clark <christopher.w.clark@gmail.com> */ +#include <public/xen.h> + #ifndef __XEN_X86_BOOTDOMAIN_H__ #define __XEN_X86_BOOTDOMAIN_H__ @@ -XXX,XX +XXX,XX @@ struct boot_module; struct domain; struct boot_domain { + domid_t domid; + struct boot_module *kernel; struct boot_module *ramdisk; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static struct boot_info *__init multiboot_fill_boot_info( /* Variable 'i' should be one entry past the last module. */ bi->mods[i].type = BOOTMOD_XEN; + for ( i = 0; i < MAX_NR_BOOTDOMS; i++ ) + bi->domains[i].domid = DOMID_INVALID; + return bi; } @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) }; struct boot_domain *bd = &bi->domains[0]; struct domain *d; - domid_t domid; if ( opt_dom0_pvh ) { @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu; /* Create initial domain. Not d0 for pvshim. */ - domid = get_initial_domain_id(); - d = domain_create(domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged); + bd->domid = get_initial_domain_id(); + d = domain_create(bd->domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged); if ( IS_ERR(d) ) - panic("Error creating d%u: %ld\n", domid, PTR_ERR(d)); + panic("Error creating d%u: %ld\n", bd->domid, PTR_ERR(d)); init_dom0_cpuid_policy(d); if ( alloc_dom0_vcpu0(d) == NULL ) - panic("Error creating d%uv0\n", domid); + panic("Error creating d%uv0\n", bd->domid); /* Grab the DOM0 command line. */ if ( bd->kernel->cmdline_pa || bi->kextra ) -- 2.30.2
Add a container for the "cooked" command line for a domain. This provides for the backing memory to be directly associated with the domain being constructed. This is done in anticipation that the domain construction path may need to be invoked multiple times, thus ensuring each instance had a distinct memory allocation. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- Changes since v9 boot modules: - convert pvh_load_kernel to boot domain to directly use cmdline - adjustments to domain_cmdline_size - remove ASSERT and return 0 instead - use strlen() of values instead of hardcoded sizes - update cmdline parsing check to inspect multiboot string and not just pointer - add goto to skip cmdline processing if domain_cmdline_size returns 0 - drop updating cmdline_pa with dynamic buffer with change of its last consumer pvh_load_kernel Changes since v8: - switch to a dynamically allocated buffer - dropped local cmdline var in pv dom0_construct() Changes since v7: - updated commit message to expand on intent and purpose --- xen/arch/x86/hvm/dom0_build.c | 12 +++--- xen/arch/x86/include/asm/bootdomain.h | 2 + xen/arch/x86/pv/dom0_build.c | 4 +- xen/arch/x86/setup.c | 54 ++++++++++++++++++++++----- 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -XXX,XX +XXX,XX @@ static bool __init check_and_adjust_load_address( } static int __init pvh_load_kernel( - struct domain *d, struct boot_module *image, struct boot_module *initrd, - paddr_t *entry, paddr_t *start_info_addr) + struct boot_domain *bd, paddr_t *entry, paddr_t *start_info_addr) { + struct domain *d = bd->d; + struct boot_module *image = bd->kernel; + struct boot_module *initrd = bd->ramdisk; void *image_base = bootstrap_map_bm(image); void *image_start = image_base + image->headroom; unsigned long image_len = image->size; @@ -XXX,XX +XXX,XX @@ static void __hwdom_init pvh_setup_mmcfg(struct domain *d) int __init dom0_construct_pvh(struct boot_domain *bd) { paddr_t entry, start_info; - struct boot_module *image = bd->kernel; - struct boot_module *initrd = bd->ramdisk; struct domain *d = bd->d; int rc; printk(XENLOG_INFO "*** Building a PVH Dom%d ***\n", d->domain_id); - if ( image == NULL ) + if ( bd->kernel == NULL ) panic("Missing kernel boot module for %pd construction\n", d); if ( is_hardware_domain(d) ) @@ -XXX,XX +XXX,XX @@ int __init dom0_construct_pvh(struct boot_domain *bd) return rc; } - rc = pvh_load_kernel(d, image, initrd, &entry, &start_info); + rc = pvh_load_kernel(bd, &entry, &start_info); if ( rc ) { printk("Failed to load Dom0 kernel\n"); diff --git a/xen/arch/x86/include/asm/bootdomain.h b/xen/arch/x86/include/asm/bootdomain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootdomain.h +++ b/xen/arch/x86/include/asm/bootdomain.h @@ -XXX,XX +XXX,XX @@ struct boot_module; struct domain; struct boot_domain { + const char *cmdline; + domid_t domid; struct boot_module *kernel; diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/pv/dom0_build.c +++ b/xen/arch/x86/pv/dom0_build.c @@ -XXX,XX +XXX,XX @@ static int __init dom0_construct(struct boot_domain *bd) } memset(si->cmd_line, 0, sizeof(si->cmd_line)); - if ( image->cmdline_pa ) - strlcpy((char *)si->cmd_line, __va(image->cmdline_pa), sizeof(si->cmd_line)); + if ( bd->cmdline ) + strlcpy((char *)si->cmd_line, bd->cmdline, sizeof(si->cmd_line)); #ifdef CONFIG_VIDEO if ( !pv_shim && fill_console_start_info((void *)(si + 1)) ) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static unsigned int __init copy_bios_e820(struct e820entry *map, unsigned int li return n; } -static struct domain *__init create_dom0(struct boot_info *bi) +static size_t __init domain_cmdline_size( + struct boot_info *bi, struct boot_domain *bd) { - static char __initdata cmdline[MAX_GUEST_CMDLINE]; + size_t s = bi->kextra ? strlen(bi->kextra) : 0; + + s += bd->kernel->cmdline_pa ? strlen(__va(bd->kernel->cmdline_pa)) : 0; + + if ( s == 0 ) + return s; + + /* + * Certain parameters from the Xen command line may be added to the dom0 + * command line. Add additional space for the possible cases along with one + * extra char to hold \0. + */ + s += strlen(" noapic") + strlen(" acpi=") + sizeof(acpi_param) + 1; + + return s; +} +static struct domain *__init create_dom0(struct boot_info *bi) +{ + char *cmdline = NULL; struct xen_domctl_createdomain dom0_cfg = { .flags = IS_ENABLED(CONFIG_TBOOT) ? XEN_DOMCTL_CDF_s3_integrity : 0, .max_evtchn_port = -1, @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) panic("Error creating d%uv0\n", bd->domid); /* Grab the DOM0 command line. */ - if ( bd->kernel->cmdline_pa || bi->kextra ) + if ( (bd->kernel->cmdline_pa && + ((char *)__va(bd->kernel->cmdline_pa))[0]) || + bi->kextra ) { + size_t cmdline_size = domain_cmdline_size(bi, bd); + + if ( cmdline_size == 0 ) + goto skip_cmdline; + + if ( !(cmdline = xzalloc_array(char, cmdline_size)) ) + panic("Error allocating cmdline buffer for %pd\n", d); + if ( bd->kernel->cmdline_pa ) - safe_strcpy(cmdline, - cmdline_cook(__va(bd->kernel->cmdline_pa), bi->loader)); + strlcpy(cmdline, + cmdline_cook(__va(bd->kernel->cmdline_pa),bi->loader), + cmdline_size); if ( bi->kextra ) /* kextra always includes exactly one leading space. */ - safe_strcat(cmdline, bi->kextra); + strlcat(cmdline, bi->kextra, cmdline_size); /* Append any extra parameters. */ if ( skip_ioapic_setup && !strstr(cmdline, "noapic") ) - safe_strcat(cmdline, " noapic"); + strlcat(cmdline, " noapic", cmdline_size); if ( (strlen(acpi_param) == 0) && acpi_disabled ) { @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) if ( (strlen(acpi_param) != 0) && !strstr(cmdline, "acpi=") ) { - safe_strcat(cmdline, " acpi="); - safe_strcat(cmdline, acpi_param); + strlcat(cmdline, " acpi=", cmdline_size); + strlcat(cmdline, acpi_param, cmdline_size); } - bd->kernel->cmdline_pa = __pa(cmdline); + bd->cmdline = cmdline; } + skip_cmdline: bd->d = d; if ( construct_dom0(bd) != 0 ) panic("Could not construct domain 0\n"); + if ( cmdline ) + xfree(cmdline); + return d; } -- 2.30.2
Currently the inclusion of libfdt is controlled by the CONFIG_HAS_DEVICE_TREE kconfig flag. This flag also changes behvaior in a few places, such as boot module processing for XSM. To support the ability to include libfdt without changing these behaviors, introduce CONFIG_LIB_DEVICE_TREE. The inclusion of libfdt is then moved under CONFIG_LIB_DEVICE_TREE. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/common/Kconfig | 4 ++++ xen/common/Makefile | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ config HAS_ALTERNATIVE config HAS_COMPAT bool +config LIB_DEVICE_TREE + bool + config HAS_DEVICE_TREE bool + select LIB_DEVICE_TREE config HAS_DIT # Data Independent Timing bool diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += sched/ obj-$(CONFIG_UBSAN) += ubsan/ obj-$(CONFIG_NEEDS_LIBELF) += libelf/ -obj-$(CONFIG_HAS_DEVICE_TREE) += libfdt/ +obj-$(CONFIG_LIB_DEVICE_TREE) += libfdt/ CONF_FILE := $(if $(patsubst /%,,$(KCONFIG_CONFIG)),$(objtree)/)$(KCONFIG_CONFIG) $(obj)/config.gz: $(CONF_FILE) -- 2.30.2
Hyperlaunch domain builder will be the consolidated boot time domain building logic framework. Introduces the config option to enable this domain builder to and turn on the ability to load the domain configuration via a flattened device tree. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/Kconfig | 2 ++ xen/arch/x86/domain_builder/Kconfig | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 xen/arch/x86/domain_builder/Kconfig diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/Kconfig +++ b/xen/arch/x86/Kconfig @@ -XXX,XX +XXX,XX @@ config ALTP2M If unsure, stay with defaults. +source "arch/x86/domain_builder/Kconfig" + endmenu source "common/Kconfig" diff --git a/xen/arch/x86/domain_builder/Kconfig b/xen/arch/x86/domain_builder/Kconfig new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/x86/domain_builder/Kconfig @@ -XXX,XX +XXX,XX @@ + +menu "Domain Builder Features" + +config DOMAIN_BUILDER + bool "Domain builder (UNSUPPORTED)" if UNSUPPORTED + select LIB_DEVICE_TREE + help + Enables the domain builder capability to configure boot domain + construction using a flattened device tree. + + This feature is currently experimental. + + If unsure, say N. + +endmenu -- 2.30.2
Introduce the domain builder which is capable of consuming a device tree as the first boot module. If it finds a device tree as the first boot module, it will set its type to BOOTMOD_FDT. This change only detects the boot module and continues to boot with slight change to the boot convention that the dom0 kernel is no longer first boot module but is the second. No functional change intended. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/Makefile | 2 + xen/arch/x86/domain_builder/Makefile | 3 ++ xen/arch/x86/domain_builder/core.c | 55 ++++++++++++++++++++++++ xen/arch/x86/domain_builder/fdt.c | 38 ++++++++++++++++ xen/arch/x86/domain_builder/fdt.h | 21 +++++++++ xen/arch/x86/include/asm/bootinfo.h | 3 ++ xen/arch/x86/include/asm/domainbuilder.h | 8 ++++ xen/arch/x86/setup.c | 18 +++++--- 8 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 xen/arch/x86/domain_builder/Makefile create mode 100644 xen/arch/x86/domain_builder/core.c create mode 100644 xen/arch/x86/domain_builder/fdt.c create mode 100644 xen/arch/x86/domain_builder/fdt.h create mode 100644 xen/arch/x86/include/asm/domainbuilder.h diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_COMPAT) += x86_64/platform_hypercall.o obj-y += sysctl.o endif +obj-y += domain_builder/ + extra-y += asm-macros.i extra-y += xen.lds diff --git a/xen/arch/x86/domain_builder/Makefile b/xen/arch/x86/domain_builder/Makefile new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/x86/domain_builder/Makefile @@ -XXX,XX +XXX,XX @@ +obj-$(CONFIG_DOMAIN_BUILDER) += fdt.init.o +obj-y += core.init.o + diff --git a/xen/arch/x86/domain_builder/core.c b/xen/arch/x86/domain_builder/core.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/x86/domain_builder/core.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024, Apertus Solutions, LLC + */ +#include <xen/err.h> +#include <xen/init.h> +#include <xen/kconfig.h> +#include <xen/lib.h> + +#include <asm/bootinfo.h> + +#include "fdt.h" + +void __init builder_init(struct boot_info *bi) +{ + if ( IS_ENABLED(CONFIG_DOMAIN_BUILDER) ) + { + int ret; + + switch ( ret = has_hyperlaunch_fdt(bi) ) + { + case 0: + printk("Hyperlaunch device tree detected\n"); + bi->hyperlaunch_enabled = true; + bi->mods[0].type = BOOTMOD_FDT; + break; + case -EINVAL: + printk("Hyperlaunch device tree was not detected\n"); + bi->hyperlaunch_enabled = false; + break; + case -ENOENT: + fallthrough; + case -ENODATA: + printk("Device tree found, but not hyperlaunch (%d)\n", ret); + bi->hyperlaunch_enabled = false; + bi->mods[0].type = BOOTMOD_FDT; + break; + default: + printk("Unknown error (%d) occured checking for hyperlaunch device tree\n", + ret); + bi->hyperlaunch_enabled = false; + } + + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024, Apertus Solutions, LLC + */ +#include <xen/err.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/libfdt/libfdt.h> +#include <xen/rangeset.h> /* required for asm/setup.h */ + +#include <asm/bootinfo.h> +#include <asm/page.h> +#include <asm/setup.h> + +#include "fdt.h" + +int __init has_hyperlaunch_fdt(struct boot_info *bi) +{ + int ret = 0; + void *fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + + if ( fdt_check_header(fdt) < 0 ) + ret = -EINVAL; + + bootstrap_unmap(); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/domain_builder/fdt.h b/xen/arch/x86/domain_builder/fdt.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/x86/domain_builder/fdt.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +#ifndef __XEN_X86_FDT_H__ +#define __XEN_X86_FDT_H__ + +#include <xen/init.h> + +#include <asm/bootinfo.h> + +/* hyperlaunch fdt is required to be module 0 */ +#define HYPERLAUNCH_MODULE_IDX 0 + +#ifdef CONFIG_DOMAIN_BUILDER +int has_hyperlaunch_fdt(struct boot_info *bi); +#else +static inline int __init has_hyperlaunch_fdt(struct boot_info *bi) +{ + return -EINVAL; +} +#endif + +#endif /* __XEN_X86_FDT_H__ */ diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -XXX,XX +XXX,XX @@ enum bootmod_type { BOOTMOD_RAMDISK, BOOTMOD_MICROCODE, BOOTMOD_XSM_POLICY, + BOOTMOD_FDT, }; struct boot_module { @@ -XXX,XX +XXX,XX @@ struct boot_info { paddr_t memmap_addr; size_t memmap_length; + bool hyperlaunch_enabled; + unsigned int nr_modules; struct boot_module mods[MAX_NR_BOOTMODS + 1]; struct boot_domain domains[MAX_NR_BOOTDOMS]; diff --git a/xen/arch/x86/include/asm/domainbuilder.h b/xen/arch/x86/include/asm/domainbuilder.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/x86/include/asm/domainbuilder.h @@ -XXX,XX +XXX,XX @@ +#ifndef __XEN_X86_DOMBUILDER_H__ +#define __XEN_X86_DOMBUILDER_H__ + +#include <asm/bootinfo.h> + +void builder_init(struct boot_info *bi); + +#endif diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ #endif #include <xen/bitops.h> #include <asm/bootinfo.h> +#include <asm/domainbuilder.h> #include <asm/smp.h> #include <asm/processor.h> #include <asm/mpspec.h> @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) bi->nr_modules); } - /* Dom0 kernel is always first */ - bi->mods[0].type = BOOTMOD_KERNEL; - bi->domains[0].kernel = &bi->mods[0]; + builder_init(bi); + + /* Find first unknown boot module to use as Dom0 kernel */ + i = first_boot_module_index(bi, BOOTMOD_UNKNOWN); + bi->mods[i].type = BOOTMOD_KERNEL; + bi->domains[0].kernel = &bi->mods[i]; if ( pvh_boot ) { @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) xen->size = __2M_rwdata_end - _stext; } - bi->mods[0].headroom = - bzimage_headroom(bootstrap_map_bm(&bi->mods[0]), bi->mods[0].size); + i = first_boot_module_index(bi, BOOTMOD_KERNEL); + bi->mods[i].headroom = + bzimage_headroom(bootstrap_map_bm(&bi->mods[i]), bi->mods[i].size); bootstrap_unmap(); #ifndef highmem_start @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) #endif } - if ( bi->mods[0].headroom && !bi->mods[0].relocated ) + i = first_boot_module_index(bi, BOOTMOD_KERNEL); + if ( bi->mods[i].headroom && !bi->mods[0].relocated ) panic("Not enough memory to relocate the dom0 kernel image\n"); for ( i = 0; i < bi->nr_modules; ++i ) { -- 2.30.2
Add the ability to detect both a formal hyperlaunch device tree or a dom0less device tree. If the hyperlaunch device tree is found, then count the number of domain entries, reporting if more than one is found. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/domain_builder/core.c | 14 +++++++ xen/arch/x86/domain_builder/fdt.c | 64 ++++++++++++++++++++++++++++- xen/arch/x86/domain_builder/fdt.h | 5 +++ xen/arch/x86/include/asm/bootinfo.h | 1 + 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/domain_builder/core.c b/xen/arch/x86/domain_builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/core.c +++ b/xen/arch/x86/domain_builder/core.c @@ -XXX,XX +XXX,XX @@ void __init builder_init(struct boot_info *bi) ret); bi->hyperlaunch_enabled = false; } + } + + if ( bi->hyperlaunch_enabled ) + { + int ret; + + printk(XENLOG_INFO "Hyperlauch configuration:\n"); + if ( (ret = walk_hyperlaunch_fdt(bi)) < 0 ) + { + printk(XENLOG_INFO " walk of device tree failed (%d)\n", ret); + bi->hyperlaunch_enabled = false; + return; + } + printk(XENLOG_INFO " Number of domains: %d\n", bi->nr_domains); } } diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ #include "fdt.h" +static int __init find_hyperlaunch_node(void *fdt) +{ + int hv_node = fdt_path_offset(fdt, "/chosen/hypervisor"); + if ( hv_node >= 0 ) + { + /* Anything other than zero indicates no match */ + if ( fdt_node_check_compatible(fdt, hv_node, "hypervisor,xen") ) + return -ENODATA; + else + return hv_node; + } + else + { + /* Lood for dom0less config */ + int node, chosen_node = fdt_path_offset(fdt, "/chosen"); + if ( chosen_node < 0 ) + return -ENOENT; + + fdt_for_each_subnode(node, fdt, chosen_node) + { + if ( fdt_node_check_compatible(fdt, node, "xen,domain") == 0 ) + return chosen_node; + } + } + + return -ENODATA; +} + int __init has_hyperlaunch_fdt(struct boot_info *bi) { int ret = 0; void *fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); - if ( fdt_check_header(fdt) < 0 ) + if ( !fdt || fdt_check_header(fdt) < 0 ) ret = -EINVAL; + else + ret = find_hyperlaunch_node(fdt); + + bootstrap_unmap(); + + return ret < 0 ? ret : 0; +} + +int __init walk_hyperlaunch_fdt(struct boot_info *bi) +{ + int ret = 0, hv_node, node; + void *fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + + if ( unlikely(!fdt) ) + return -EINVAL; + + hv_node = find_hyperlaunch_node(fdt); + if ( hv_node < 0 ) + { + ret = hv_node; + goto err_out; + } + + fdt_for_each_subnode(node, fdt, hv_node) + { + ret = fdt_node_check_compatible(fdt, node, "xen,domain"); + if ( ret == 0 ) + bi->nr_domains++; + } + + /* Until multi-domain construction is added, throw an error */ + if ( !bi->nr_domains || bi->nr_domains > 1 ) + printk(XENLOG_ERR "Hyperlaunch only supports dom0 construction\n"); + err_out: bootstrap_unmap(); return ret; diff --git a/xen/arch/x86/domain_builder/fdt.h b/xen/arch/x86/domain_builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.h +++ b/xen/arch/x86/domain_builder/fdt.h @@ -XXX,XX +XXX,XX @@ #ifdef CONFIG_DOMAIN_BUILDER int has_hyperlaunch_fdt(struct boot_info *bi); +int walk_hyperlaunch_fdt(struct boot_info *bi); #else static inline int __init has_hyperlaunch_fdt(struct boot_info *bi) { return -EINVAL; } +static int __init walk_hyperlaunch_fdt(struct boot_info *bi) +{ + return -EINVAL; +} #endif #endif /* __XEN_X86_FDT_H__ */ diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -XXX,XX +XXX,XX @@ struct boot_info { bool hyperlaunch_enabled; unsigned int nr_modules; + unsigned int nr_domains; struct boot_module mods[MAX_NR_BOOTMODS + 1]; struct boot_domain domains[MAX_NR_BOOTDOMS]; }; -- 2.30.2
Look for a subnode of type `multiboot,kernel` within a domain node. If found, process the reg property for the MB1 module index. If the bootargs property is present and there was not an MB1 string, then use the command line from the device tree definition. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/domain_builder/core.c | 12 +++ xen/arch/x86/domain_builder/fdt.c | 126 +++++++++++++++++++++++++++++ xen/arch/x86/domain_builder/fdt.h | 17 ++++ xen/arch/x86/setup.c | 5 -- 4 files changed, 155 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/domain_builder/core.c b/xen/arch/x86/domain_builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/core.c +++ b/xen/arch/x86/domain_builder/core.c @@ -XXX,XX +XXX,XX @@ void __init builder_init(struct boot_info *bi) printk(XENLOG_INFO " Number of domains: %d\n", bi->nr_domains); } + else + { + int i; + + /* Find first unknown boot module to use as Dom0 kernel */ + printk("Falling back to using first boot module as dom0\n"); + i = first_boot_module_index(bi, BOOTMOD_UNKNOWN); + bi->mods[i].type = BOOTMOD_KERNEL; + bi->domains[0].kernel = &bi->mods[i]; + bi->nr_domains = 1; + } + } /* diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ #include "fdt.h" +static inline int __init fdt_get_prop_as_reg( + const void *fdt, int node, const char *name, unsigned int ssize, + unsigned int asize, uint64_t *size, uint64_t *addr) +{ + int ret; + const struct fdt_property *prop; + fdt32_t *cell; + + /* FDT spec max size is 4 (128bit int), but largest arch int size is 64 */ + if ( ssize > 2 || asize > 2 ) + return -EINVAL; + + prop = fdt_get_property(fdt, node, name, &ret); + if ( !prop || ret < sizeof(u32) ) + return ret < 0 ? ret : -EINVAL; + + /* read address field */ + cell = (fdt32_t *)prop->data; + + if ( asize == 1 ) + { + uint32_t val; + fdt_cell_as_u32(cell, &val); + *addr = (uint64_t)val; + } + else + fdt_cell_as_u64(cell, addr); + + /* read size field */ + cell += asize; + + if ( ssize == 1 ) + { + uint32_t val; + fdt_cell_as_u32(cell, &val); + *size = (uint64_t)val; + } + else + fdt_cell_as_u64(cell, size); + + return 0; +} + +static int __init dom0less_module_node( + void *fdt, int node, int size_size, int address_size) +{ + uint64_t size, addr; + int ret = fdt_get_prop_as_reg(fdt, node, "reg", size_size, address_size, + &size, &addr); + /* An FDT error value may have been returned, translate to -EINVAL */ + if ( ret < 0 ) + return -EINVAL; + + if ( size != 0 ) + return -EOPNOTSUPP; + + if ( addr > MAX_NR_BOOTMODS ) + return -ERANGE; + + /* + * MAX_NR_BOOTMODS cannot exceed the max for MB1, represented by a u32, + * thus the cast down to a u32 will be safe due to the prior check. + */ + return (int)addr; +} + +static int __init process_domain_node( + struct boot_info *bi, void *fdt, int dom_node) +{ + int node; + struct boot_domain *bd = &bi->domains[bi->nr_domains]; + const char *name = fdt_get_name(fdt, dom_node, NULL); + int address_size = fdt_address_cells(fdt, dom_node); + int size_size = fdt_size_cells(fdt, dom_node); + + if ( address_size < 0 || size_size < 0 ) + { + printk(" failed processing #address or #size for domain %s)\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + + fdt_for_each_subnode(node, fdt, dom_node) + { + if ( fdt_node_check_compatible(fdt, node, "multiboot,kernel") == 0 ) + { + int idx = dom0less_module_node(fdt, node, size_size, address_size); + if ( idx < 0 ) + { + printk(" failed processing kernel module for domain %s)\n", + name == NULL ? "unknown" : name); + return idx; + } + + if ( idx > bi->nr_modules ) + { + printk(" invalid kernel module index for domain node (%d)\n", + bi->nr_domains); + return -EINVAL; + } + + printk(" kernel: boot module %d\n", idx); + bi->mods[idx].type = BOOTMOD_KERNEL; + bd->kernel = &bi->mods[idx]; + } + } + + if ( !bd->kernel ) + { + printk(XENLOG_ERR "ERR: no kernel assigned to domain\n"); + return -EFAULT; + } + + return 0; +} + static int __init find_hyperlaunch_node(void *fdt) { int hv_node = fdt_path_offset(fdt, "/chosen/hypervisor"); @@ -XXX,XX +XXX,XX @@ int __init walk_hyperlaunch_fdt(struct boot_info *bi) fdt_for_each_subnode(node, fdt, hv_node) { + if ( bi->nr_domains >= MAX_NR_BOOTDOMS ) + { + printk(XENLOG_WARNING "WARN: more domains defined than max allowed"); + break; + } + ret = fdt_node_check_compatible(fdt, node, "xen,domain"); if ( ret == 0 ) + { + if ( (ret = process_domain_node(bi, fdt, node)) < 0 ) + break; bi->nr_domains++; + } } /* Until multi-domain construction is added, throw an error */ diff --git a/xen/arch/x86/domain_builder/fdt.h b/xen/arch/x86/domain_builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.h +++ b/xen/arch/x86/domain_builder/fdt.h @@ -XXX,XX +XXX,XX @@ #define __XEN_X86_FDT_H__ #include <xen/init.h> +#include <xen/libfdt/libfdt.h> #include <asm/bootinfo.h> @@ -XXX,XX +XXX,XX @@ #define HYPERLAUNCH_MODULE_IDX 0 #ifdef CONFIG_DOMAIN_BUILDER + +static inline int __init fdt_cell_as_u32(const fdt32_t *cell, uint32_t *val) +{ + *val = fdt32_to_cpu(*cell); + + return 0; +} + +static inline int __init fdt_cell_as_u64(const fdt32_t *cell, uint64_t *val) +{ + *val = ((uint64_t)fdt32_to_cpu(cell[0]) << 32) | + (uint64_t)fdt32_to_cpu(cell[1]); + + return 0; +} + int has_hyperlaunch_fdt(struct boot_info *bi); int walk_hyperlaunch_fdt(struct boot_info *bi); #else diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) builder_init(bi); - /* Find first unknown boot module to use as Dom0 kernel */ - i = first_boot_module_index(bi, BOOTMOD_UNKNOWN); - bi->mods[i].type = BOOTMOD_KERNEL; - bi->domains[0].kernel = &bi->mods[i]; - if ( pvh_boot ) { /* pvh_init() already filled in e820_raw */ -- 2.30.2
If a command line is not provided through the bootloader's mechanism, e.g. muiltboot module string field, then use one from the device tree if present. The device tree command line is located in the bootargs property of the `multiboot,kernel` node. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/domain_builder/core.c | 28 +++++++++++++++++++ xen/arch/x86/domain_builder/fdt.c | 34 ++++++++++++++++++++++++ xen/arch/x86/domain_builder/fdt.h | 24 +++++++++++++++++ xen/arch/x86/include/asm/bootinfo.h | 6 +++-- xen/arch/x86/include/asm/domainbuilder.h | 4 +++ xen/arch/x86/setup.c | 10 +++++-- 6 files changed, 102 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/domain_builder/core.c b/xen/arch/x86/domain_builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/core.c +++ b/xen/arch/x86/domain_builder/core.c @@ -XXX,XX +XXX,XX @@ #include <xen/lib.h> #include <asm/bootinfo.h> +#include <asm/setup.h> #include "fdt.h" +size_t __init builder_get_cmdline_size(struct boot_info *bi, int offset) +{ +#ifdef CONFIG_DOMAIN_BUILDER + const void *fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + int size = fdt_cmdline_prop_size(fdt, offset); + + bootstrap_unmap(); + return size < 0 ? 0 : (size_t) size; +#else + return 0; +#endif +} + +int __init builder_get_cmdline( + struct boot_info *bi, int offset, char *cmdline, size_t size) +{ +#ifdef CONFIG_DOMAIN_BUILDER + const void *fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + int ret = fdt_cmdline_prop_copy(fdt, offset, cmdline, size); + + bootstrap_unmap(); + return ret; +#else + return 0; +#endif +} + void __init builder_init(struct boot_info *bi) { if ( IS_ENABLED(CONFIG_DOMAIN_BUILDER) ) diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ static inline int __init fdt_get_prop_as_reg( return 0; } +static int __init fdt_get_prop_as_offset( + const void *fdt, int node, const char *name, unsigned long *a) +{ + int ret, poffset; + const char *pname; + size_t nsize = strlen(name); + + fdt_for_each_property_offset(poffset, fdt, node) + { + fdt_getprop_by_offset(fdt, poffset, &pname, &ret); + + if ( ret < 0 || strlen(pname) != nsize ) + continue; + + if ( !strncmp(pname, name, nsize) ) + { + *a = poffset; + return nsize; + } + } + + return -ENOENT; +} + static int __init dom0less_module_node( void *fdt, int node, int size_size, int address_size) { @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( printk(" kernel: boot module %d\n", idx); bi->mods[idx].type = BOOTMOD_KERNEL; bd->kernel = &bi->mods[idx]; + + /* If bootloader didn't set cmdline, see if FDT provides one. */ + if ( bd->kernel->cmdline_pa && + !((char *)__va(bd->kernel->cmdline_pa))[0] ) + { + int ret = fdt_get_prop_as_offset( + fdt, node, "bootargs", &bd->kernel->cmdline_pa); + if ( ret > 0 ) + bd->kernel->fdt_cmdline = true; + } } } diff --git a/xen/arch/x86/domain_builder/fdt.h b/xen/arch/x86/domain_builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.h +++ b/xen/arch/x86/domain_builder/fdt.h @@ -XXX,XX +XXX,XX @@ static inline int __init fdt_cell_as_u64(const fdt32_t *cell, uint64_t *val) return 0; } +static inline int __init fdt_cmdline_prop_size(const void *fdt, int offset) +{ + int ret; + + fdt_get_property_by_offset(fdt, offset, &ret); + + return ret; +} + +static inline int __init fdt_cmdline_prop_copy( + const void *fdt, int offset, char *cmdline, size_t size) +{ + int ret; + const struct fdt_property *prop = + fdt_get_property_by_offset(fdt, offset, &ret); + + if ( ret < 0 ) + return ret; + + ASSERT(size > ret); + + return strlcpy(cmdline, prop->data, ret); +} + int has_hyperlaunch_fdt(struct boot_info *bi); int walk_hyperlaunch_fdt(struct boot_info *bi); #else diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -XXX,XX +XXX,XX @@ struct boot_module { /* * Module State Flags: - * relocated: indicates module has been relocated in memory. - * released: indicates module's pages have been freed. + * relocated: indicates module has been relocated in memory. + * released: indicates module's pages have been freed. + * fdt_cmdline: indicates module's cmdline is in the FDT. */ bool relocated:1; bool released:1; + bool fdt_cmdline:1; /* * A boot module may need decompressing by Xen. Headroom is an estimate of diff --git a/xen/arch/x86/include/asm/domainbuilder.h b/xen/arch/x86/include/asm/domainbuilder.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/domainbuilder.h +++ b/xen/arch/x86/include/asm/domainbuilder.h @@ -XXX,XX +XXX,XX @@ #include <asm/bootinfo.h> +size_t __init builder_get_cmdline_size(struct boot_info *bi, int offset); +int __init builder_get_cmdline( + struct boot_info *bi, int offset, char *cmdline, size_t size); + void builder_init(struct boot_info *bi); #endif diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static size_t __init domain_cmdline_size( { size_t s = bi->kextra ? strlen(bi->kextra) : 0; - s += bd->kernel->cmdline_pa ? strlen(__va(bd->kernel->cmdline_pa)) : 0; + if ( bd->kernel->fdt_cmdline ) + s += builder_get_cmdline_size(bi, bd->kernel->cmdline_pa); + else + s += strlen(__va(bd->kernel->cmdline_pa)); if ( s == 0 ) return s; @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) if ( !(cmdline = xzalloc_array(char, cmdline_size)) ) panic("Error allocating cmdline buffer for %pd\n", d); - if ( bd->kernel->cmdline_pa ) + if ( bd->kernel->fdt_cmdline ) + builder_get_cmdline( + bi, bd->kernel->cmdline_pa, cmdline, cmdline_size); + else strlcpy(cmdline, cmdline_cook(__va(bd->kernel->cmdline_pa),bi->loader), cmdline_size); -- 2.30.2
Look for a subnode of type `multiboot,ramdisk` within a domain node. If found, process the reg property for the MB1 module index. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/domain_builder/fdt.c | 25 ++++++++++++++++++++++ xen/arch/x86/setup.c | 35 +++++++++++++++++-------------- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( if ( ret > 0 ) bd->kernel->fdt_cmdline = true; } + + continue; + } + if ( fdt_node_check_compatible(fdt, node, "multiboot,ramdisk") == 0 ) + { + int idx = dom0less_module_node(fdt, node, size_size, address_size); + if ( idx < 0 ) + { + printk(" failed processing ramdisk module for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + + if ( idx > bi->nr_modules ) + { + printk(" invalid ramdisk module index for domain node (%d)\n", + bi->nr_domains); + return -EINVAL; + } + + printk(" ramdisk: boot module %d\n", idx); + bi->mods[idx].type = BOOTMOD_RAMDISK; + bd->ramdisk = &bi->mods[idx]; + + continue; } } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) char *kextra; void *bsp_stack; struct cpu_info *info = get_cpu_info(), *bsp_info; - unsigned int initrdidx, num_parked = 0; + unsigned int num_parked = 0; struct boot_info *bi; unsigned long nr_pages, raw_max_page; int i, j, e820_warn = 0, bytes = 0; @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) cpu_has_nx ? XENLOG_INFO : XENLOG_WARNING "Warning: ", cpu_has_nx ? "" : "not "); - /* - * At this point all capabilities that consume boot modules should have - * claimed their boot modules. Find the first unclaimed boot module and - * claim it as the initrd ramdisk. Do a second search to see if there are - * any remaining unclaimed boot modules, and report them as unusued initrd - * candidates. - */ - initrdidx = first_boot_module_index(bi, BOOTMOD_UNKNOWN); - if ( initrdidx < MAX_NR_BOOTMODS ) + if ( !bi->hyperlaunch_enabled ) { - bi->mods[initrdidx].type = BOOTMOD_RAMDISK; - bi->domains[0].ramdisk = &bi->mods[initrdidx]; - if ( first_boot_module_index(bi, BOOTMOD_UNKNOWN) < MAX_NR_BOOTMODS ) - printk(XENLOG_WARNING - "Multiple initrd candidates, picking module #%u\n", - initrdidx); + /* + * At this point all capabilities that consume boot modules should have + * claimed their boot modules. Find the first unclaimed boot module and + * claim it as the initrd ramdisk. Do a second search to see if there are + * any remaining unclaimed boot modules, and report them as unusued initrd + * candidates. + */ + unsigned int initrdidx = first_boot_module_index(bi, BOOTMOD_UNKNOWN); + if ( initrdidx < MAX_NR_BOOTMODS ) + { + bi->mods[initrdidx].type = BOOTMOD_RAMDISK; + bi->domains[0].ramdisk = &bi->mods[initrdidx]; + if ( first_boot_module_index(bi, BOOTMOD_UNKNOWN) < MAX_NR_BOOTMODS ) + printk(XENLOG_WARNING + "Multiple initrd candidates, picking module #%u\n", + initrdidx); + } } /* -- 2.30.2
Introduce the ability to specify the desired domain id for the domain definition. The domain id will be populated in the domid property of the domain node in the device tree configuration. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/domain_builder/fdt.c | 31 ++++++++++++++++++++++++++++++- xen/arch/x86/domain_builder/fdt.h | 18 ++++++++++++++++++ xen/arch/x86/setup.c | 3 ++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ #include <xen/rangeset.h> /* required for asm/setup.h */ #include <asm/bootinfo.h> +#include <asm/guest.h> #include <asm/page.h> #include <asm/setup.h> @@ -XXX,XX +XXX,XX @@ static int __init dom0less_module_node( static int __init process_domain_node( struct boot_info *bi, void *fdt, int dom_node) { - int node; + int node, property; struct boot_domain *bd = &bi->domains[bi->nr_domains]; const char *name = fdt_get_name(fdt, dom_node, NULL); int address_size = fdt_address_cells(fdt, dom_node); @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( return -EINVAL; } + fdt_for_each_property_offset(property, fdt, dom_node) + { + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, property, NULL); + if ( !prop ) + continue; /* silently skip */ + + if ( match_fdt_property(fdt, prop, "domid" ) ) + { + uint32_t val = DOMID_INVALID; + if ( fdt_prop_as_u32(prop, &val) != 0 ) + { + printk(" failed processing domain id for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + bd->domid = (domid_t)val; + printk(" domid: %d\n", bd->domid); + } + } + fdt_for_each_subnode(node, fdt, dom_node) { if ( fdt_node_check_compatible(fdt, node, "multiboot,kernel") == 0 ) @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( return -EFAULT; } + if ( bd->domid == DOMID_INVALID ) + bd->domid = get_initial_domain_id(); + else + if ( bd->domid != get_initial_domain_id() ) + printk(XENLOG_WARNING "WARN: unsuported booting not using initial domid\n"); + return 0; } diff --git a/xen/arch/x86/domain_builder/fdt.h b/xen/arch/x86/domain_builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.h +++ b/xen/arch/x86/domain_builder/fdt.h @@ -XXX,XX +XXX,XX @@ static inline int __init fdt_cell_as_u64(const fdt32_t *cell, uint64_t *val) return 0; } +static inline int __init fdt_prop_as_u32( + const struct fdt_property *prop, uint32_t *val) +{ + if ( !prop || fdt32_to_cpu(prop->len) < sizeof(u32) ) + return -EINVAL; + + return fdt_cell_as_u32((fdt32_t *)prop->data, val); +} + +static inline bool __init match_fdt_property( + const void *fdt, const struct fdt_property *prop, const char *s) +{ + int slen, len = strlen(s); + const char *p = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff), &slen); + + return p && (slen == len) && (memcmp(p, s, len) == 0); +} + static inline int __init fdt_cmdline_prop_size(const void *fdt, int offset) { int ret; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu; /* Create initial domain. Not d0 for pvshim. */ - bd->domid = get_initial_domain_id(); + if ( bd->domid == DOMID_INVALID ) + bd->domid = get_initial_domain_id(); d = domain_create(bd->domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged); if ( IS_ERR(d) ) panic("Error creating d%u: %ld\n", bd->domid, PTR_ERR(d)); -- 2.30.2
Enable selecting the mode in which the domain will be built and ran. This includes: - whether it will be either a 32/64 bit domain - if it will be run as a PV or HVM domain - and if it will require a device model (not applicable for dom0) In the device tree, this will be represented as a bit map that will be carried through into struct boot_domain. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/domain_builder/fdt.c | 19 +++++++++++++++++++ xen/arch/x86/include/asm/bootdomain.h | 6 ++++++ xen/arch/x86/setup.c | 3 ++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( bd->domid = (domid_t)val; printk(" domid: %d\n", bd->domid); } + if ( match_fdt_property(fdt, prop, "mode" ) ) + { + if ( fdt_prop_as_u32(prop, &bd->mode) != 0 ) + { + printk(" failed processing mode for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + + printk(" mode: "); + if ( !(bd->mode & BUILD_MODE_PARAVIRT) ) { + if ( bd->mode & BUILD_MODE_ENABLE_DM ) + printk("HVM\n"); + else + printk("PVH\n"); + } + else + printk("PV\n"); + } } fdt_for_each_subnode(node, fdt, dom_node) diff --git a/xen/arch/x86/include/asm/bootdomain.h b/xen/arch/x86/include/asm/bootdomain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootdomain.h +++ b/xen/arch/x86/include/asm/bootdomain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { domid_t domid; + /* On | Off */ +#define BUILD_MODE_PARAVIRT (1 << 0) /* PV | PVH/HVM */ +#define BUILD_MODE_ENABLE_DM (1 << 1) /* HVM | PVH */ +#define BUILD_MODE_LONG (1 << 2) /* 64 BIT | 32 BIT */ + uint32_t mode; + struct boot_module *kernel; struct boot_module *ramdisk; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) struct boot_domain *bd = &bi->domains[0]; struct domain *d; - if ( opt_dom0_pvh ) + if ( opt_dom0_pvh || + (bi->hyperlaunch_enabled && !(bd->mode & BUILD_MODE_PARAVIRT)) ) { dom0_cfg.flags |= (XEN_DOMCTL_CDF_hvm | ((hvm_hap_supported() && !opt_dom0_shadow) ? -- 2.30.2
Add three properties, memory, mem-min, and mem-max, to the domain node device tree parsing to define the memory allocation for a domain. All three fields are expressed in kb and written as a u64 in the device tree entries. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/dom0_build.c | 8 ++++++ xen/arch/x86/domain_builder/fdt.c | 37 +++++++++++++++++++++++++++ xen/arch/x86/domain_builder/fdt.h | 9 +++++++ xen/arch/x86/include/asm/bootdomain.h | 4 +++ 4 files changed, 58 insertions(+) diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -XXX,XX +XXX,XX @@ int __init construct_dom0(struct boot_domain *bd) process_pending_softirqs(); + /* If param dom0_size was not set and HL config provided memory size */ + if ( !get_memsize(&dom0_size, LONG_MAX) && bd->mem_pages ) + dom0_size.nr_pages = bd->mem_pages; + if ( !get_memsize(&dom0_min_size, LONG_MAX) && bd->min_pages ) + dom0_size.nr_pages = bd->min_pages; + if ( !get_memsize(&dom0_max_size, LONG_MAX) && bd->max_pages ) + dom0_size.nr_pages = bd->max_pages; + if ( is_hvm_domain(d) ) rc = dom0_construct_pvh(bd); else if ( is_pv_domain(d) ) diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ #include <xen/lib.h> #include <xen/libfdt/libfdt.h> #include <xen/rangeset.h> /* required for asm/setup.h */ +#include <xen/sizes.h> #include <asm/bootinfo.h> #include <asm/guest.h> @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( else printk("PV\n"); } + if ( match_fdt_property(fdt, prop, "memory" ) ) + { + uint64_t kb; + if ( fdt_prop_as_u64(prop, &kb) != 0 ) + { + printk(" failed processing memory for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + bd->mem_pages = PFN_DOWN(kb * SZ_1K); + printk(" memory: %ld\n", bd->mem_pages << PAGE_SHIFT); + } + if ( match_fdt_property(fdt, prop, "mem-min" ) ) + { + uint64_t kb; + if ( fdt_prop_as_u64(prop, &kb) != 0 ) + { + printk(" failed processing memory for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + bd->min_pages = PFN_DOWN(kb * SZ_1K); + printk(" min memory: %ld\n", bd->min_pages << PAGE_SHIFT); + } + if ( match_fdt_property(fdt, prop, "mem-max" ) ) + { + uint64_t kb; + if ( fdt_prop_as_u64(prop, &kb) != 0 ) + { + printk(" failed processing memory for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + bd->max_pages = PFN_DOWN(kb * SZ_1K); + printk(" max memory: %ld\n", bd->max_pages << PAGE_SHIFT); + } } fdt_for_each_subnode(node, fdt, dom_node) diff --git a/xen/arch/x86/domain_builder/fdt.h b/xen/arch/x86/domain_builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.h +++ b/xen/arch/x86/domain_builder/fdt.h @@ -XXX,XX +XXX,XX @@ static inline int __init fdt_prop_as_u32( return fdt_cell_as_u32((fdt32_t *)prop->data, val); } +static inline int __init fdt_prop_as_u64( + const struct fdt_property *prop, uint64_t *val) +{ + if ( !prop || fdt32_to_cpu(prop->len) < sizeof(u64) ) + return -EINVAL; + + return fdt_cell_as_u64((fdt32_t *)prop->data, val); +} + static inline bool __init match_fdt_property( const void *fdt, const struct fdt_property *prop, const char *s) { diff --git a/xen/arch/x86/include/asm/bootdomain.h b/xen/arch/x86/include/asm/bootdomain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootdomain.h +++ b/xen/arch/x86/include/asm/bootdomain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { #define BUILD_MODE_LONG (1 << 2) /* 64 BIT | 32 BIT */ uint32_t mode; + unsigned long mem_pages; + unsigned long min_pages; + unsigned long max_pages; + struct boot_module *kernel; struct boot_module *ramdisk; -- 2.30.2
Introduce the `cpus` property, named as such for dom0less compatibility, that represents the maximum number of vpcus to allocate for a domain. In the device tree, it will be encoded as a u32 value. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/dom0_build.c | 3 +++ xen/arch/x86/domain_builder/fdt.c | 12 ++++++++++++ xen/arch/x86/include/asm/bootdomain.h | 2 ++ 3 files changed, 17 insertions(+) diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -XXX,XX +XXX,XX @@ int __init construct_dom0(struct boot_domain *bd) if ( !get_memsize(&dom0_max_size, LONG_MAX) && bd->max_pages ) dom0_size.nr_pages = bd->max_pages; + if ( opt_dom0_max_vcpus_max == UINT_MAX && bd->max_vcpus ) + opt_dom0_max_vcpus_max = bd->max_vcpus; + if ( is_hvm_domain(d) ) rc = dom0_construct_pvh(bd); else if ( is_pv_domain(d) ) diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( bd->max_pages = PFN_DOWN(kb * SZ_1K); printk(" max memory: %ld\n", bd->max_pages << PAGE_SHIFT); } + if ( match_fdt_property(fdt, prop, "cpus" ) ) + { + uint32_t val = UINT_MAX; + if ( fdt_prop_as_u32(prop, &val) != 0 ) + { + printk(" failed processing max_vcpus for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + bd->max_vcpus = val; + printk(" max vcpus: %d\n", bd->max_vcpus); + } } fdt_for_each_subnode(node, fdt, dom_node) diff --git a/xen/arch/x86/include/asm/bootdomain.h b/xen/arch/x86/include/asm/bootdomain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootdomain.h +++ b/xen/arch/x86/include/asm/bootdomain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { unsigned long min_pages; unsigned long max_pages; + unsigned int max_vcpus; + struct boot_module *kernel; struct boot_module *ramdisk; -- 2.30.2
Introduce the ability to assign capabilities to a domain via its definition in device tree. The first capability enabled to select is the control domain capability. The capability property is a bitfield in both the device tree and `struct boot_domain`. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> --- xen/arch/x86/domain_builder/core.c | 2 +- xen/arch/x86/domain_builder/fdt.c | 13 +++++++++++++ xen/arch/x86/include/asm/bootdomain.h | 4 ++++ xen/arch/x86/setup.c | 6 +++++- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/domain_builder/core.c b/xen/arch/x86/domain_builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/core.c +++ b/xen/arch/x86/domain_builder/core.c @@ -XXX,XX +XXX,XX @@ void __init builder_init(struct boot_info *bi) i = first_boot_module_index(bi, BOOTMOD_UNKNOWN); bi->mods[i].type = BOOTMOD_KERNEL; bi->domains[0].kernel = &bi->mods[i]; + bi->domains[0].capabilities |= BUILD_CAPS_CONTROL; bi->nr_domains = 1; } - } /* diff --git a/xen/arch/x86/domain_builder/fdt.c b/xen/arch/x86/domain_builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain_builder/fdt.c +++ b/xen/arch/x86/domain_builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( bd->max_vcpus = val; printk(" max vcpus: %d\n", bd->max_vcpus); } + if ( match_fdt_property(fdt, prop, "capabilities" ) ) + { + if ( fdt_prop_as_u32(prop, &bd->capabilities) != 0 ) + { + printk(" failed processing domain id for domain %s\n", + name == NULL ? "unknown" : name); + return -EINVAL; + } + printk(" caps: "); + if ( bd->capabilities & BUILD_CAPS_CONTROL ) + printk("c"); + printk("\n"); + } } fdt_for_each_subnode(node, fdt, dom_node) diff --git a/xen/arch/x86/include/asm/bootdomain.h b/xen/arch/x86/include/asm/bootdomain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootdomain.h +++ b/xen/arch/x86/include/asm/bootdomain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { domid_t domid; +#define BUILD_CAPS_NONE (0) +#define BUILD_CAPS_CONTROL (1 << 0) + uint32_t capabilities; + /* On | Off */ #define BUILD_MODE_PARAVIRT (1 << 0) /* PV | PVH/HVM */ #define BUILD_MODE_ENABLE_DM (1 << 1) /* HVM | PVH */ diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static size_t __init domain_cmdline_size( static struct domain *__init create_dom0(struct boot_info *bi) { char *cmdline = NULL; + int create_flags = 0; struct xen_domctl_createdomain dom0_cfg = { .flags = IS_ENABLED(CONFIG_TBOOT) ? XEN_DOMCTL_CDF_s3_integrity : 0, .max_evtchn_port = -1, @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) /* Create initial domain. Not d0 for pvshim. */ if ( bd->domid == DOMID_INVALID ) bd->domid = get_initial_domain_id(); - d = domain_create(bd->domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged); + if ( bd->capabilities & BUILD_CAPS_CONTROL ) + create_flags |= CDF_privileged; + d = domain_create(bd->domid, &dom0_cfg, + pv_shim ? 0 : create_flags); if ( IS_ERR(d) ) panic("Error creating d%u: %ld\n", bd->domid, PTR_ERR(d)); -- 2.30.2
Hi, Here's a new version. Took a while to integrate all the feedback, but here it is. v4 pipeline: https://gitlab.com/xen-project/people/agvallejo/xen/-/pipelines/1772300721 v3: https://lore.kernel.org/xen-devel/20250408160802.49870-1-agarciav@amd.com/ v2: https://lore.kernel.org/xen-devel/20241226165740.29812-1-dpsmith@apertussolutions.com/ v1: https://lore.kernel.org/xen-devel/20241123182044.30687-1-dpsmith@apertussolutions.com/ Cheers, Alejandro ========= Original cover letter: The Hyperlaunch device tree for dom0 series is the second split out for the introduction of the Hyperlaunch domain builder logic. These changes focus on introducing the ability to express a domain configuration that is then used to populate the struct boot_domain structure for dom0. This ability to express a domain configuration provides the next step towards a general domain builder. The splitting of Hyperlaunch into a set of series are twofold, to reduce the effort in reviewing a much larger series, and to reduce the effort in handling the knock-on effects to the construction logic from requested review changes. Alejandro Vallejo (1): x86/hyperlaunch: Add helpers to locate multiboot modules Daniel P. Smith (12): x86/boot: add cmdline to struct boot_domain kconfig: introduce domain builder config options common/hyperlaunch: introduce the domain builder x86/hyperlaunch: initial support for hyperlaunch device tree x86/hyperlaunch: locate dom0 kernel with hyperlaunch x86/hyperlaunch: obtain cmdline from device tree x86/hyperlaunch: locate dom0 initrd with hyperlaunch x86/hyperlaunch: add domain id parsing to domain config x86/hyperlaunch: specify dom0 mode with device tree x86/hyperlaunch: add memory parsing to domain config x86/hyperlaunch: add max vcpu parsing of hyperlaunch device tree x86/hyperlaunch: add capabilities to boot domain xen/arch/x86/Kconfig | 1 + xen/arch/x86/dom0_build.c | 11 + xen/arch/x86/hvm/dom0_build.c | 31 +- xen/arch/x86/include/asm/boot-domain.h | 17 + xen/arch/x86/include/asm/bootinfo.h | 10 +- xen/arch/x86/pv/dom0_build.c | 4 +- xen/arch/x86/setup.c | 91 +++-- xen/common/Kconfig | 5 + xen/common/Makefile | 1 + xen/common/domain-builder/Kconfig | 18 + xen/common/domain-builder/Makefile | 2 + xen/common/domain-builder/core.c | 110 ++++++ xen/common/domain-builder/fdt.c | 488 +++++++++++++++++++++++++ xen/common/domain-builder/fdt.h | 39 ++ xen/include/xen/domain-builder.h | 13 + xen/include/xen/libfdt/libfdt-xen.h | 44 +++ 16 files changed, 839 insertions(+), 46 deletions(-) create mode 100644 xen/common/domain-builder/Kconfig 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 create mode 100644 xen/include/xen/domain-builder.h -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Add a container for the "cooked" command line for a domain. This provides for the backing memory to be directly associated with the domain being constructed. This is done in anticipation that the domain construction path may need to be invoked multiple times, thus ensuring each instance had a distinct memory allocation. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Manually nullify bd->cmdline before xfree()ing cmdline. * const-ify arguments of domain_cmdline_size() * Add cmdline_len to pvh_load_kernel() --- xen/arch/x86/hvm/dom0_build.c | 31 ++++++++-------- xen/arch/x86/include/asm/boot-domain.h | 1 + xen/arch/x86/pv/dom0_build.c | 4 +- xen/arch/x86/setup.c | 51 ++++++++++++++++++++------ 4 files changed, 57 insertions(+), 30 deletions(-) diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -XXX,XX +XXX,XX @@ static int __init pvh_load_kernel( void *image_start = image_base + image->headroom; unsigned long image_len = image->size; unsigned long initrd_len = initrd ? initrd->size : 0; - const char *cmdline = image->cmdline_pa ? __va(image->cmdline_pa) : NULL; + unsigned long cmdline_len = bd->cmdline ? strlen(bd->cmdline) + 1 : 0; const char *initrd_cmdline = NULL; struct elf_binary elf; struct elf_dom_parms parms; @@ -XXX,XX +XXX,XX @@ static int __init pvh_load_kernel( initrd = NULL; } - if ( cmdline ) - extra_space += elf_round_up(&elf, strlen(cmdline) + 1); + extra_space += elf_round_up(&elf, cmdline_len); last_addr = find_memory(d, &elf, extra_space); if ( last_addr == INVALID_PADDR ) @@ -XXX,XX +XXX,XX @@ static int __init pvh_load_kernel( /* Free temporary buffers. */ free_boot_modules(); - if ( cmdline != NULL ) + rc = hvm_copy_to_guest_phys(last_addr, bd->cmdline, cmdline_len, v); + if ( rc ) { - rc = hvm_copy_to_guest_phys(last_addr, cmdline, strlen(cmdline) + 1, v); - if ( rc ) - { - printk("Unable to copy guest command line\n"); - return rc; - } - start_info.cmdline_paddr = last_addr; - /* - * Round up to 32/64 bits (depending on the guest kernel bitness) so - * the modlist/start_info is aligned. - */ - last_addr += elf_round_up(&elf, strlen(cmdline) + 1); + printk("Unable to copy guest command line\n"); + return rc; } + + start_info.cmdline_paddr = cmdline_len ? last_addr : 0; + + /* + * Round up to 32/64 bits (depending on the guest kernel bitness) so + * the modlist/start_info is aligned. + */ + last_addr += elf_round_up(&elf, cmdline_len); + if ( initrd != NULL ) { rc = hvm_copy_to_guest_phys(last_addr, &mod, sizeof(mod), v); diff --git a/xen/arch/x86/include/asm/boot-domain.h b/xen/arch/x86/include/asm/boot-domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/boot-domain.h +++ b/xen/arch/x86/include/asm/boot-domain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { struct boot_module *kernel; struct boot_module *module; + const char *cmdline; struct domain *d; }; diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/pv/dom0_build.c +++ b/xen/arch/x86/pv/dom0_build.c @@ -XXX,XX +XXX,XX @@ static int __init dom0_construct(const struct boot_domain *bd) } memset(si->cmd_line, 0, sizeof(si->cmd_line)); - if ( image->cmdline_pa ) - strlcpy((char *)si->cmd_line, __va(image->cmdline_pa), sizeof(si->cmd_line)); + if ( bd->cmdline ) + strlcpy((char *)si->cmd_line, bd->cmdline, sizeof(si->cmd_line)); #ifdef CONFIG_VIDEO if ( !pv_shim && fill_console_start_info((void *)(si + 1)) ) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static unsigned int __init copy_bios_e820(struct e820entry *map, unsigned int li return n; } -static struct domain *__init create_dom0(struct boot_info *bi) +static size_t __init domain_cmdline_size(const struct boot_info *bi, + const struct boot_domain *bd) { - static char __initdata cmdline[MAX_GUEST_CMDLINE]; + size_t s = bi->kextra ? strlen(bi->kextra) : 0; + + s += bd->kernel->cmdline_pa ? strlen(__va(bd->kernel->cmdline_pa)) : 0; + if ( s == 0 ) + return s; + + /* + * Certain parameters from the Xen command line may be added to the dom0 + * command line. Add additional space for the possible cases along with one + * extra char to hold \0. + */ + s += strlen(" noapic") + strlen(" acpi=") + sizeof(acpi_param) + 1; + + return s; +} + +static struct domain *__init create_dom0(struct boot_info *bi) +{ + char *cmdline = NULL; + size_t cmdline_size; struct xen_domctl_createdomain dom0_cfg = { .flags = IS_ENABLED(CONFIG_TBOOT) ? XEN_DOMCTL_CDF_s3_integrity : 0, .max_evtchn_port = -1, @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) if ( alloc_dom0_vcpu0(d) == NULL ) panic("Error creating %pdv0\n", d); - /* Grab the DOM0 command line. */ - if ( bd->kernel->cmdline_pa || bi->kextra ) + cmdline_size = domain_cmdline_size(bi, bd); + if ( cmdline_size ) { + if ( !(cmdline = xzalloc_array(char, cmdline_size)) ) + panic("Error allocating cmdline buffer for %pd\n", d); + if ( bd->kernel->cmdline_pa ) - safe_strcpy(cmdline, - cmdline_cook(__va(bd->kernel->cmdline_pa), bi->loader)); + strlcpy(cmdline, + cmdline_cook(__va(bd->kernel->cmdline_pa), bi->loader), + cmdline_size); if ( bi->kextra ) /* kextra always includes exactly one leading space. */ - safe_strcat(cmdline, bi->kextra); + strlcat(cmdline, bi->kextra, cmdline_size); /* Append any extra parameters. */ if ( skip_ioapic_setup && !strstr(cmdline, "noapic") ) - safe_strcat(cmdline, " noapic"); + strlcat(cmdline, " noapic", cmdline_size); if ( (strlen(acpi_param) == 0) && acpi_disabled ) { @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) if ( (strlen(acpi_param) != 0) && !strstr(cmdline, "acpi=") ) { - safe_strcat(cmdline, " acpi="); - safe_strcat(cmdline, acpi_param); + strlcat(cmdline, " acpi=", cmdline_size); + strlcat(cmdline, acpi_param, cmdline_size); } - - bd->kernel->cmdline_pa = __pa(cmdline); + bd->kernel->cmdline_pa = 0; + bd->cmdline = cmdline; } bd->d = d; if ( construct_dom0(bd) != 0 ) panic("Could not construct domain 0\n"); + bd->cmdline = NULL; + xfree(cmdline); + return d; } -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Hyperlaunch domain builder will be the consolidated boot time domain building logic framework. Introduces the config option to enable this domain builder to eventually turn on the ability to load the domain configuration via a flattened device tree. This is common code, but it's tightly integrated with boot_info, so the whole builder is gated on CONFIG_HAS_BOOT_INFO, autoselected on x86 only for the time being. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Moved from arch/x86 to common/ * Present the domain builder submenu for X86 only. * s/LIB_DEVICE_TREE/LIBFDT/ * Reworded Kconfig to be a bit more user-friendly. * Dropped Jason's R-by, due to the new Kconfig option. --- xen/arch/x86/Kconfig | 1 + xen/common/Kconfig | 5 +++++ xen/common/domain-builder/Kconfig | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 xen/common/domain-builder/Kconfig diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/Kconfig +++ b/xen/arch/x86/Kconfig @@ -XXX,XX +XXX,XX @@ config X86 select FUNCTION_ALIGNMENT_16B select GENERIC_BUG_FRAME select HAS_ALTERNATIVE + select HAS_BOOT_INFO select HAS_COMPAT select HAS_CPUFREQ select HAS_DIT diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ config GENERIC_BUG_FRAME config HAS_ALTERNATIVE bool +config HAS_BOOT_INFO + bool + config HAS_COMPAT bool @@ -XXX,XX +XXX,XX @@ config STATIC_MEMORY If unsure, say N. +source "common/domain-builder/Kconfig" + menu "Speculative hardening" config INDIRECT_THUNK diff --git a/xen/common/domain-builder/Kconfig b/xen/common/domain-builder/Kconfig new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/domain-builder/Kconfig @@ -XXX,XX +XXX,XX @@ + +menu "Domain Builder Features" +depends on HAS_BOOT_INFO + +config DOMAIN_BUILDER + bool "Domain builder (UNSUPPORTED)" if UNSUPPORTED + select LIBFDT + help + Xen has a built-in mechanisms to automatically construct domains + (like dom0) during the boot phase. The domain builder is an enhanced + form of that mechanism to enable constructing predefined domains + described on a flattened device tree. + + This feature is currently experimental. + + If unsure, say N. + +endmenu -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Introduce the domain builder which is capable of consuming a device tree as the first boot module. If it finds a device tree as the first boot module, it will set its type to BOOTMOD_FDT. This change only detects the boot module and continues to boot with slight change to the boot convention that the dom0 kernel is no longer first boot module but is the second. No functional change intended. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Moved from arch/x86/ to common/ * gated all of domain-builder/ on CONFIG_BOOT_INFO * Hide the domain builder submenu for !X86 * Factor out the "hyperlaunch_enabled = false" toggle core.c * Removed stub inline, as DCE makes it unnecessary * Adjusted printks. --- xen/arch/x86/include/asm/bootinfo.h | 3 ++ xen/arch/x86/setup.c | 17 +++++---- xen/common/Makefile | 1 + xen/common/domain-builder/Makefile | 2 ++ xen/common/domain-builder/core.c | 56 +++++++++++++++++++++++++++++ xen/common/domain-builder/fdt.c | 37 +++++++++++++++++++ xen/common/domain-builder/fdt.h | 12 +++++++ xen/include/xen/domain-builder.h | 9 +++++ 8 files changed, 131 insertions(+), 6 deletions(-) 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 create mode 100644 xen/include/xen/domain-builder.h diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -XXX,XX +XXX,XX @@ enum bootmod_type { BOOTMOD_RAMDISK, BOOTMOD_MICROCODE, BOOTMOD_XSM_POLICY, + BOOTMOD_FDT, }; struct boot_module { @@ -XXX,XX +XXX,XX @@ struct boot_info { paddr_t memmap_addr; size_t memmap_length; + bool hyperlaunch_enabled; + unsigned int nr_modules; struct boot_module mods[MAX_NR_BOOTMODS + 1]; struct boot_domain domains[MAX_NR_BOOTDOMS]; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/cpuidle.h> #include <xen/dmi.h> #include <xen/domain.h> +#include <xen/domain-builder.h> #include <xen/domain_page.h> #include <xen/efi.h> #include <xen/err.h> @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) bi->nr_modules); } - /* Dom0 kernel is always first */ - bi->mods[0].type = BOOTMOD_KERNEL; - bi->domains[0].kernel = &bi->mods[0]; + builder_init(bi); + + /* Find first unknown boot module to use as dom0 kernel */ + i = first_boot_module_index(bi, BOOTMOD_UNKNOWN); + bi->mods[i].type = BOOTMOD_KERNEL; + bi->domains[0].kernel = &bi->mods[i]; if ( pvh_boot ) { @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) xen->size = __2M_rwdata_end - _stext; } - bi->mods[0].headroom = - bzimage_headroom(bootstrap_map_bm(&bi->mods[0]), bi->mods[0].size); + bi->domains[0].kernel->headroom = + bzimage_headroom(bootstrap_map_bm(bi->domains[0].kernel), + bi->domains[0].kernel->size); bootstrap_unmap(); #ifndef highmem_start @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) #endif } - if ( bi->mods[0].headroom && !bi->mods[0].relocated ) + if ( bi->domains[0].kernel->headroom && !bi->domains[0].kernel->relocated ) panic("Not enough memory to relocate the dom0 kernel image\n"); for ( i = 0; i < bi->nr_modules; ++i ) { diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(filter-out $(CONFIG_X86),$(CONFIG_ACPI)) += device.o obj-$(CONFIG_HAS_DEVICE_TREE) += device-tree/ obj-$(CONFIG_IOREQ_SERVER) += dm.o obj-y += domain.o +obj-$(CONFIG_HAS_BOOT_INFO) += domain-builder/ obj-y += event_2l.o obj-y += event_channel.o obj-$(CONFIG_EVTCHN_FIFO) += event_fifo.o diff --git a/xen/common/domain-builder/Makefile b/xen/common/domain-builder/Makefile new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/domain-builder/Makefile @@ -XXX,XX +XXX,XX @@ +obj-$(CONFIG_DOMAIN_BUILDER) += fdt.init.o +obj-y += core.init.o diff --git a/xen/common/domain-builder/core.c b/xen/common/domain-builder/core.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/domain-builder/core.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024, Apertus Solutions, LLC + */ +#include <xen/err.h> +#include <xen/init.h> +#include <xen/kconfig.h> +#include <xen/lib.h> + +#include <asm/bootinfo.h> + +#include "fdt.h" + +void __init builder_init(struct boot_info *bi) +{ + bi->hyperlaunch_enabled = false; + + if ( IS_ENABLED(CONFIG_DOMAIN_BUILDER) ) + { + int ret; + + switch ( ret = has_hyperlaunch_fdt(bi) ) + { + case 0: + printk(XENLOG_DEBUG "DT found: hyperlaunch\n"); + bi->hyperlaunch_enabled = true; + bi->mods[0].type = BOOTMOD_FDT; + break; + + case -EINVAL: + /* No DT found */ + break; + + case -ENOENT: + case -ENODATA: + printk(XENLOG_DEBUG "DT found: non-hyperlaunch (%d)\n", ret); + bi->mods[0].type = BOOTMOD_FDT; + break; + + default: + printk(XENLOG_ERR "unknown error (%d) checking hyperlaunch DT\n", + ret); + break; + } + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024, Apertus Solutions, LLC + */ +#include <xen/err.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/libfdt/libfdt.h> + +#include <asm/bootinfo.h> +#include <asm/page.h> +#include <asm/setup.h> + +#include "fdt.h" + +int __init has_hyperlaunch_fdt(const struct boot_info *bi) +{ + int ret = 0; + const void *fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + + if ( !fdt || fdt_check_header(fdt) < 0 ) + ret = -EINVAL; + + bootstrap_unmap(); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/domain-builder/fdt.h b/xen/common/domain-builder/fdt.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/domain-builder/fdt.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __XEN_DOMAIN_BUILDER_FDT_H__ +#define __XEN_DOMAIN_BUILDER_FDT_H__ + +struct boot_info; + +/* hyperlaunch fdt is required to be module 0 */ +#define HYPERLAUNCH_MODULE_IDX 0 + +int has_hyperlaunch_fdt(const struct boot_info *bi); + +#endif /* __XEN_DOMAIN_BUILDER_FDT_H__ */ diff --git a/xen/include/xen/domain-builder.h b/xen/include/xen/domain-builder.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/domain-builder.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __XEN_DOMAIN_BUILDER_H__ +#define __XEN_DOMAIN_BUILDER_H__ + +struct boot_info; + +void builder_init(struct boot_info *bi); + +#endif /* __XEN_DOMAIN_BUILDER_H__ */ -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Add the ability to detect both a formal hyperlaunch device tree or a dom0less device tree. If the hyperlaunch device tree is found, then count the number of domain entries, reporting an error if more than one is found. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Panic if we're booting on hyperlaunch, but walking the DTB fails. * Remove inconsequential "else" clause in fdt.c * Remove stub, as it's not required due to DCE * Use min() rather than open-code it --- xen/arch/x86/include/asm/bootinfo.h | 1 + xen/common/domain-builder/core.c | 11 +++++ xen/common/domain-builder/fdt.c | 63 +++++++++++++++++++++++++++++ xen/common/domain-builder/fdt.h | 1 + 4 files changed, 76 insertions(+) diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -XXX,XX +XXX,XX @@ struct boot_info { bool hyperlaunch_enabled; unsigned int nr_modules; + unsigned int nr_domains; struct boot_module mods[MAX_NR_BOOTMODS + 1]; struct boot_domain domains[MAX_NR_BOOTDOMS]; }; diff --git a/xen/common/domain-builder/core.c b/xen/common/domain-builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/core.c +++ b/xen/common/domain-builder/core.c @@ -XXX,XX +XXX,XX @@ void __init builder_init(struct boot_info *bi) break; } } + + if ( bi->hyperlaunch_enabled ) + { + int ret; + + printk(XENLOG_INFO "Hyperlaunch configuration:\n"); + if ( (ret = walk_hyperlaunch_fdt(bi)) < 0 ) + panic("Walk of device tree failed (%d)\n", ret); + + printk(XENLOG_INFO " number of domains: %u\n", bi->nr_domains); + } } /* diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ #include "fdt.h" +static int __init find_hyperlaunch_node(const void *fdt) +{ + int hv_node = fdt_path_offset(fdt, "/chosen/hypervisor"); + + if ( hv_node >= 0 ) + { + /* Anything other than zero indicates no match */ + if ( fdt_node_check_compatible(fdt, hv_node, "hypervisor,xen") ) + return -ENODATA; + + return hv_node; + } + else + { + /* Look for dom0less config */ + int node, chosen_node = fdt_path_offset(fdt, "/chosen"); + + if ( chosen_node < 0 ) + return -ENOENT; + + fdt_for_each_subnode(node, fdt, chosen_node) + { + if ( !fdt_node_check_compatible(fdt, node, "xen,domain") ) + return chosen_node; + } + } + + return -ENODATA; +} + int __init has_hyperlaunch_fdt(const struct boot_info *bi) { int ret = 0; @@ -XXX,XX +XXX,XX @@ int __init has_hyperlaunch_fdt(const struct boot_info *bi) if ( !fdt || fdt_check_header(fdt) < 0 ) ret = -EINVAL; + else + ret = find_hyperlaunch_node(fdt); + + bootstrap_unmap(); + + return min(0, ret); +} + +int __init walk_hyperlaunch_fdt(struct boot_info *bi) +{ + int ret = 0, hv_node, node; + const void *fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + + if ( unlikely(!fdt) ) + return -EINVAL; + + hv_node = find_hyperlaunch_node(fdt); + if ( hv_node < 0 ) + { + ret = hv_node; + goto err_out; + } + + fdt_for_each_subnode(node, fdt, hv_node) + { + if ( !fdt_node_check_compatible(fdt, node, "xen,domain") ) + bi->nr_domains++; + } + + /* Until multi-domain construction is added, throw an error */ + if ( bi->nr_domains != 1 ) + printk(XENLOG_ERR "hyperlaunch only supports dom0 construction\n"); + err_out: bootstrap_unmap(); return ret; diff --git a/xen/common/domain-builder/fdt.h b/xen/common/domain-builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.h +++ b/xen/common/domain-builder/fdt.h @@ -XXX,XX +XXX,XX @@ struct boot_info; #define HYPERLAUNCH_MODULE_IDX 0 int has_hyperlaunch_fdt(const struct boot_info *bi); +int walk_hyperlaunch_fdt(struct boot_info *bi); #endif /* __XEN_DOMAIN_BUILDER_FDT_H__ */ -- 2.43.0
Hyperlaunch mandates either a reg or module-index DT prop on nodes that contain `multiboot,module" under their "compatible" prop. This patch introduces a helper to generically find such index, appending the module to the list of modules if it wasn't already (i.e: because it's given via the "reg" prop). Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Remove stray reg prop parser in libfdt-xen.h. * Remove fdt32_as_uX accessors. * Brough fdt_prop_as_u32() accesor from later patches. * So it can be used in place of a hardcoded fdt32_as_u32(). * Limited MAX_NR_BOOTMODS to INT_MAX. * Preserved BOOTMOD_XEN on module append logic. * Add missing bounds check to module-index parsed in multiboot module helper. * Converted idx variable to uint32_t for better bounds checking. * Braces from switch statement to conform to coding style. * Added missing XENLOG_X. * Print address_cells and size_cells on error parsing reg properties. * Added (transient) missing declaration for extern helper. * becomes static on the next patch. --- xen/common/domain-builder/fdt.c | 162 ++++++++++++++++++++++++++++ xen/common/domain-builder/fdt.h | 2 + xen/include/xen/domain-builder.h | 3 + xen/include/xen/libfdt/libfdt-xen.h | 11 ++ 4 files changed, 178 insertions(+) diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ #include "fdt.h" +/* + * Unpacks a "reg" property into its address and size constituents. + * + * @param prop Pointer to an FDT "reg" property. + * @param address_cells Number of 4-octet cells that make up an "address". + * @param size_cells Number of 4-octet cells that make up a "size". + * @param p_addr[out] Address encoded in the property. + * @param p_size[out] Size encoded in the property. + * @returns -EINVAL on malformed property, 0 otherwise. + */ +static int __init read_fdt_prop_as_reg(const struct fdt_property *prop, + int address_cells, int size_cells, + uint64_t *p_addr, uint64_t *p_size) +{ + const fdt32_t *cell = (const fdt32_t *)prop->data; + uint64_t addr, size; + + if ( fdt32_to_cpu(prop->len) != + (address_cells + size_cells) * sizeof(*cell) ) + { + printk(XENLOG_ERR " cannot read reg %lu+%lu from prop len %u\n", + address_cells * sizeof(*cell), size_cells * sizeof(*cell), + fdt32_to_cpu(prop->len)); + return -EINVAL; + } + + switch ( address_cells ) + { + case 1: + addr = fdt32_to_cpu(*cell); + break; + case 2: + addr = fdt64_to_cpu(*(const fdt64_t *)cell); + break; + default: + printk(XENLOG_ERR " unsupported address_cells=%d\n", address_cells); + return -EINVAL; + } + + cell += address_cells; + switch ( size_cells ) + { + case 1: + size = fdt32_to_cpu(*cell); + break; + case 2: + size = fdt64_to_cpu(*(const fdt64_t *)cell); + break; + default: + printk(XENLOG_ERR " unsupported size_cells=%d\n", size_cells); + return -EINVAL; + } + + *p_addr = addr; + *p_size = size; + + return 0; +} + +/* + * Locate a multiboot module given its node offset in the FDT. + * + * The module location may be given via either FDT property: + * * reg = <address, size> + * * Mutates `bi` to append the module. + * * module-index = <idx> + * * Leaves `bi` unchanged. + * + * @param fdt Pointer to the full FDT. + * @param node Offset for the module node. + * @param address_cells Number of 4-octet cells that make up an "address". + * @param size_cells Number of 4-octet cells that make up a "size". + * @param bi[inout] Xen's representation of the boot parameters. + * @return -EINVAL on malformed nodes, otherwise + * index inside `bi->mods` + */ +int __init fdt_read_multiboot_module(const void *fdt, int node, + int address_cells, int size_cells, + struct boot_info *bi) +{ + const struct fdt_property *prop; + uint64_t addr, size; + int ret; + uint32_t idx; + + if ( fdt_node_check_compatible(fdt, node, "multiboot,module") ) + { + printk(XENLOG_ERR " bad module. multiboot,module not found"); + return -ENODATA; + } + + /* Location given as a `module-index` property. */ + if ( (prop = fdt_get_property(fdt, node, "module-index", NULL)) ) + { + if ( fdt_get_property(fdt, node, "reg", NULL) ) + { + printk(XENLOG_ERR " found both reg and module-index for module\n"); + return -EINVAL; + } + if ( (ret = fdt_prop_as_u32(prop, &idx)) ) + { + printk(XENLOG_ERR " bad module-index prop\n"); + return ret; + } + if ( idx >= MAX_NR_BOOTMODS ) + { + printk(XENLOG_ERR " module-index overflow. %s=%u\n", + STR(MAX_NR_BOOTMODS), MAX_NR_BOOTMODS); + return -EINVAL; + } + + return idx; + } + + /* Otherwise location given as a `reg` property. */ + if ( !(prop = fdt_get_property(fdt, node, "reg", NULL)) ) + { + printk(XENLOG_ERR " no location for multiboot,module\n"); + return -EINVAL; + } + if ( fdt_get_property(fdt, node, "module-index", NULL) ) + { + printk(XENLOG_ERR " found both reg and module-index for module\n"); + return -EINVAL; + } + + ret = read_fdt_prop_as_reg(prop, address_cells, size_cells, &addr, &size); + if ( ret < 0 ) + { + printk(XENLOG_ERR " failed reading reg for multiboot,module\n"); + return -EINVAL; + } + + idx = bi->nr_modules; + if ( idx > MAX_NR_BOOTMODS ) + { + /* + * MAX_NR_BOOTMODS must fit in 31 bits so it's representable in the + * positive side of an int; for the return value. + */ + BUILD_BUG_ON(MAX_NR_BOOTMODS > (uint64_t)INT_MAX); + printk(XENLOG_ERR " idx=%u exceeds len=%u\n", idx, MAX_NR_BOOTMODS); + return -EINVAL; + } + + /* + * Append new module to the existing list + * + * Note that bi->nr_modules points to Xen itself, so we must shift it first + */ + bi->nr_modules++; + bi->mods[bi->nr_modules] = bi->mods[idx]; + bi->mods[idx] = (struct boot_module){ + .start = addr, + .size = size, + }; + + printk(XENLOG_INFO " module[%u]: addr %lx size %lx\n", idx, addr, size); + + return idx; +} + static int __init find_hyperlaunch_node(const void *fdt) { int hv_node = fdt_path_offset(fdt, "/chosen/hypervisor"); diff --git a/xen/common/domain-builder/fdt.h b/xen/common/domain-builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.h +++ b/xen/common/domain-builder/fdt.h @@ -XXX,XX +XXX,XX @@ #ifndef __XEN_DOMAIN_BUILDER_FDT_H__ #define __XEN_DOMAIN_BUILDER_FDT_H__ +#include <xen/libfdt/libfdt-xen.h> + struct boot_info; /* hyperlaunch fdt is required to be module 0 */ diff --git a/xen/include/xen/domain-builder.h b/xen/include/xen/domain-builder.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/domain-builder.h +++ b/xen/include/xen/domain-builder.h @@ -XXX,XX +XXX,XX @@ struct boot_info; void builder_init(struct boot_info *bi); +int fdt_read_multiboot_module(const void *fdt, int node, + int address_cells, int size_cells, + struct boot_info *bi) #endif /* __XEN_DOMAIN_BUILDER_H__ */ diff --git a/xen/include/xen/libfdt/libfdt-xen.h b/xen/include/xen/libfdt/libfdt-xen.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/libfdt/libfdt-xen.h +++ b/xen/include/xen/libfdt/libfdt-xen.h @@ -XXX,XX +XXX,XX @@ #define LIBFDT_XEN_H #include <xen/libfdt/libfdt.h> +#include <xen/errno.h> + +static inline int __init fdt_prop_as_u32( + const struct fdt_property *prop, uint32_t *val) +{ + if ( !prop || fdt32_to_cpu(prop->len) < sizeof(u32) ) + return -EINVAL; + + *val = fdt32_to_cpu(*(const fdt32_t *)prop->data); + return 0; +} static inline int fdt_get_mem_rsv_paddr(const void *fdt, int n, paddr_t *address, -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Look for a subnode of type `multiboot,kernel` within a domain node. If found, locate it using the multiboot module helper to generically ensure it lives in the module list. If the bootargs property is present and there was not an MB1 string, then use the command line from the device tree definition. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Stop printing on the fallback path of builder_init(). It's in fact the most common path and just adds noise. * Add missing XENLOG_X. * Simplified check to log error on nr_domains != 1. * s/XENLOG_ERR/XENLOG_WARNING/ on duplicate kernel. * Turned foo == 0 into !foo in the "multiboot,kernel" check --- xen/arch/x86/setup.c | 5 --- xen/common/domain-builder/core.c | 9 +++++ xen/common/domain-builder/fdt.c | 64 ++++++++++++++++++++++++++++++-- xen/include/xen/domain-builder.h | 3 -- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) builder_init(bi); - /* Find first unknown boot module to use as dom0 kernel */ - i = first_boot_module_index(bi, BOOTMOD_UNKNOWN); - bi->mods[i].type = BOOTMOD_KERNEL; - bi->domains[0].kernel = &bi->mods[i]; - if ( pvh_boot ) { /* pvh_init() already filled in e820_raw */ diff --git a/xen/common/domain-builder/core.c b/xen/common/domain-builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/core.c +++ b/xen/common/domain-builder/core.c @@ -XXX,XX +XXX,XX @@ void __init builder_init(struct boot_info *bi) printk(XENLOG_INFO " number of domains: %u\n", bi->nr_domains); } + else + { + /* Find first unknown boot module to use as dom0 kernel */ + unsigned int i = first_boot_module_index(bi, BOOTMOD_UNKNOWN); + + bi->mods[i].type = BOOTMOD_KERNEL; + bi->domains[0].kernel = &bi->mods[i]; + bi->nr_domains = 1; + } } /* diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init read_fdt_prop_as_reg(const struct fdt_property *prop, * @return -EINVAL on malformed nodes, otherwise * index inside `bi->mods` */ -int __init fdt_read_multiboot_module(const void *fdt, int node, - int address_cells, int size_cells, - struct boot_info *bi) +static int __init fdt_read_multiboot_module(const void *fdt, int node, + int address_cells, int size_cells, + struct boot_info *bi) { const struct fdt_property *prop; uint64_t addr, size; @@ -XXX,XX +XXX,XX @@ int __init fdt_read_multiboot_module(const void *fdt, int node, return idx; } +static int __init process_domain_node( + struct boot_info *bi, const void *fdt, int dom_node) +{ + int node; + struct boot_domain *bd = &bi->domains[bi->nr_domains]; + const char *name = fdt_get_name(fdt, dom_node, NULL) ?: "unknown"; + int address_cells = fdt_address_cells(fdt, dom_node); + int size_cells = fdt_size_cells(fdt, dom_node); + + fdt_for_each_subnode(node, fdt, dom_node) + { + if ( !fdt_node_check_compatible(fdt, node, "multiboot,kernel") ) + { + int idx; + + if ( bd->kernel ) + { + printk(XENLOG_WARNING + " duplicate kernel for domain %s\n", name); + continue; + } + + idx = fdt_read_multiboot_module(fdt, node, address_cells, + size_cells, bi); + if ( idx < 0 ) + { + printk(XENLOG_ERR + " failed processing kernel for domain %s\n", name); + return idx; + } + + printk(XENLOG_INFO " kernel: multiboot-index=%d\n", idx); + bi->mods[idx].type = BOOTMOD_KERNEL; + bd->kernel = &bi->mods[idx]; + } + } + + if ( !bd->kernel ) + { + printk(XENLOG_ERR "error: no kernel assigned to domain\n"); + return -ENODATA; + } + + return 0; +} + static int __init find_hyperlaunch_node(const void *fdt) { int hv_node = fdt_path_offset(fdt, "/chosen/hypervisor"); @@ -XXX,XX +XXX,XX @@ int __init walk_hyperlaunch_fdt(struct boot_info *bi) fdt_for_each_subnode(node, fdt, hv_node) { + if ( bi->nr_domains >= MAX_NR_BOOTDOMS ) + { + printk(XENLOG_WARNING "warning: only creating first %u domains\n", + MAX_NR_BOOTDOMS); + break; + } + if ( !fdt_node_check_compatible(fdt, node, "xen,domain") ) + { + if ( (ret = process_domain_node(bi, fdt, node)) < 0 ) + break; + bi->nr_domains++; + } } /* Until multi-domain construction is added, throw an error */ diff --git a/xen/include/xen/domain-builder.h b/xen/include/xen/domain-builder.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/domain-builder.h +++ b/xen/include/xen/domain-builder.h @@ -XXX,XX +XXX,XX @@ struct boot_info; void builder_init(struct boot_info *bi); -int fdt_read_multiboot_module(const void *fdt, int node, - int address_cells, int size_cells, - struct boot_info *bi) #endif /* __XEN_DOMAIN_BUILDER_H__ */ -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Add support to read the command line from the hyperlauunch device tree. The device tree command line is located in the "bootargs" property of the "multiboot,kernel" node. A boot loader command line, e.g. a grub module string field, takes precendence ove the device tree one since it is easier to modify. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Removed __init from header declarations. * Removed ifdef guards, as DCE ensures the missing definitions don't matter. * Removed ifdef guards from new helpers in domain-builder/fdt.c * Rely on DCE instead. * Restored checks for cmdline_pa being zero. * swapped offset and poffset varnames in libfdt-xen.h helper. * swapped name and pname varnames in libfdt-xen.h helper. * Turned foo == 0 into !foo in libfdt-xen.h helper. --- xen/arch/x86/include/asm/bootinfo.h | 6 ++++-- xen/arch/x86/setup.c | 10 +++++++-- xen/common/domain-builder/core.c | 32 +++++++++++++++++++++++++++++ xen/common/domain-builder/fdt.c | 6 ++++++ xen/common/domain-builder/fdt.h | 24 ++++++++++++++++++++++ xen/include/xen/domain-builder.h | 4 ++++ xen/include/xen/libfdt/libfdt-xen.h | 23 +++++++++++++++++++++ 7 files changed, 101 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -XXX,XX +XXX,XX @@ struct boot_module { /* * Module State Flags: - * relocated: indicates module has been relocated in memory. - * released: indicates module's pages have been freed. + * relocated: indicates module has been relocated in memory. + * released: indicates module's pages have been freed. + * fdt_cmdline: indicates module's cmdline is in the FDT. */ bool relocated:1; bool released:1; + bool fdt_cmdline:1; /* * A boot module may need decompressing by Xen. Headroom is an estimate of diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static size_t __init domain_cmdline_size(const struct boot_info *bi, { size_t s = bi->kextra ? strlen(bi->kextra) : 0; - s += bd->kernel->cmdline_pa ? strlen(__va(bd->kernel->cmdline_pa)) : 0; + if ( bd->kernel->fdt_cmdline ) + s += builder_get_cmdline_size(bi, bd->kernel->cmdline_pa); + else if ( bd->kernel->cmdline_pa ) + s += strlen(__va(bd->kernel->cmdline_pa)); if ( s == 0 ) return s; @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) if ( !(cmdline = xzalloc_array(char, cmdline_size)) ) panic("Error allocating cmdline buffer for %pd\n", d); - if ( bd->kernel->cmdline_pa ) + if ( bd->kernel->fdt_cmdline ) + builder_get_cmdline( + bi, bd->kernel->cmdline_pa, cmdline, cmdline_size); + else if ( bd->kernel->cmdline_pa ) strlcpy(cmdline, cmdline_cook(__va(bd->kernel->cmdline_pa), bi->loader), cmdline_size); diff --git a/xen/common/domain-builder/core.c b/xen/common/domain-builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/core.c +++ b/xen/common/domain-builder/core.c @@ -XXX,XX +XXX,XX @@ #include <xen/lib.h> #include <asm/bootinfo.h> +#include <asm/setup.h> #include "fdt.h" +size_t __init builder_get_cmdline_size(struct boot_info *bi, int offset) +{ + const void *fdt; + int size; + + if ( !IS_ENABLED(CONFIG_DOMAIN_BUILDER) ) + return 0; + + fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + size = fdt_cmdline_prop_size(fdt, offset); + bootstrap_unmap(); + + return max(0, size); +} + +int __init builder_get_cmdline( + struct boot_info *bi, int offset, char *cmdline, size_t size) +{ + const void *fdt; + int ret; + + if ( !IS_ENABLED(CONFIG_DOMAIN_BUILDER) ) + return 0; + + fdt = bootstrap_map_bm(&bi->mods[HYPERLAUNCH_MODULE_IDX]); + ret = fdt_cmdline_prop_copy(fdt, offset, cmdline, size); + bootstrap_unmap(); + + return ret; +} + void __init builder_init(struct boot_info *bi) { bi->hyperlaunch_enabled = false; diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( printk(XENLOG_INFO " kernel: multiboot-index=%d\n", idx); bi->mods[idx].type = BOOTMOD_KERNEL; bd->kernel = &bi->mods[idx]; + + /* If bootloader didn't set cmdline, see if FDT provides one. */ + if ( bd->kernel->cmdline_pa && + !((char *)__va(bd->kernel->cmdline_pa))[0] ) + bd->kernel->fdt_cmdline = fdt_get_prop_offset( + fdt, node, "bootargs", &bd->kernel->cmdline_pa); } } diff --git a/xen/common/domain-builder/fdt.h b/xen/common/domain-builder/fdt.h index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.h +++ b/xen/common/domain-builder/fdt.h @@ -XXX,XX +XXX,XX @@ struct boot_info; /* hyperlaunch fdt is required to be module 0 */ #define HYPERLAUNCH_MODULE_IDX 0 +static inline int __init fdt_cmdline_prop_size(const void *fdt, int offset) +{ + int ret; + + fdt_get_property_by_offset(fdt, offset, &ret); + + return ret; +} + +static inline int __init fdt_cmdline_prop_copy( + const void *fdt, int offset, char *cmdline, size_t size) +{ + int ret; + const struct fdt_property *prop = + fdt_get_property_by_offset(fdt, offset, &ret); + + if ( ret < 0 ) + return ret; + + ASSERT(size > ret); + + return strlcpy(cmdline, prop->data, ret); +} + int has_hyperlaunch_fdt(const struct boot_info *bi); int walk_hyperlaunch_fdt(struct boot_info *bi); diff --git a/xen/include/xen/domain-builder.h b/xen/include/xen/domain-builder.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/domain-builder.h +++ b/xen/include/xen/domain-builder.h @@ -XXX,XX +XXX,XX @@ struct boot_info; +size_t builder_get_cmdline_size(const struct boot_info *bi, int offset); +int builder_get_cmdline(const struct boot_info *bi, int offset, + char *cmdline, size_t size); + void builder_init(struct boot_info *bi); #endif /* __XEN_DOMAIN_BUILDER_H__ */ diff --git a/xen/include/xen/libfdt/libfdt-xen.h b/xen/include/xen/libfdt/libfdt-xen.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/libfdt/libfdt-xen.h +++ b/xen/include/xen/libfdt/libfdt-xen.h @@ -XXX,XX +XXX,XX @@ static inline int __init fdt_prop_as_u32( return 0; } +static inline bool __init fdt_get_prop_offset( + const void *fdt, int node, const char *pname, unsigned long *poffset) +{ + int ret, offset; + const char *name; + + fdt_for_each_property_offset(offset, fdt, node) + { + fdt_getprop_by_offset(fdt, offset, &name, &ret); + + if ( ret < 0 ) + continue; + + if ( !strcmp(name, pname) ) + { + *poffset = offset; + return true; + } + } + + return false; +} + static inline int fdt_get_mem_rsv_paddr(const void *fdt, int n, paddr_t *address, paddr_t *size) -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Look for a subnode of type `multiboot,ramdisk` within a domain node and parse via the fdt_read_multiboot_module() helper. After a successful helper call, the module index is returned and the module is guaranteed to be in the module list. Fix unused typo in adjacent comment. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * s/XENLOG_ERR/XENLOG_WARNING/ on duplicate ramdisk. * Removed stray ")" in printk * s/else if/if/ (because of continue) * Removed trailing continue --- xen/arch/x86/setup.c | 4 ++-- xen/common/domain-builder/fdt.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ void asmlinkage __init noreturn __start_xen(void) * At this point all capabilities that consume boot modules should have * claimed their boot modules. Find the first unclaimed boot module and * claim it as the initrd ramdisk. Do a second search to see if there are - * any remaining unclaimed boot modules, and report them as unusued initrd + * any remaining unclaimed boot modules, and report them as unused initrd * candidates. */ initrdidx = first_boot_module_index(bi, BOOTMOD_UNKNOWN); - if ( initrdidx < MAX_NR_BOOTMODS ) + if ( !bi->hyperlaunch_enabled && initrdidx < MAX_NR_BOOTMODS ) { bi->mods[initrdidx].type = BOOTMOD_RAMDISK; bi->domains[0].module = &bi->mods[initrdidx]; diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( bd->kernel->fdt_cmdline = fdt_get_prop_offset( fdt, node, "bootargs", &bd->kernel->cmdline_pa); } + else if ( !fdt_node_check_compatible(fdt, node, "multiboot,ramdisk") ) + { + int idx; + + if ( bd->module ) + { + printk(XENLOG_WARNING + "Duplicate module for domain %s\n", name); + continue; + } + + idx = fdt_read_multiboot_module(fdt, node, address_cells, + size_cells, bi); + if ( idx < 0 ) + { + printk(XENLOG_ERR + " failed processing module for domain %s\n", + name); + return -EINVAL; + } + + printk(XENLOG_INFO " module: multiboot-index=%d\n", idx); + bi->mods[idx].type = BOOTMOD_RAMDISK; + bd->module = &bi->mods[idx]; + } } if ( !bd->kernel ) -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Introduce the ability to specify the desired domain id for the domain definition. The domain id will be populated in the domid property of the domain node in the device tree configuration. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Add missing newline * Adjusted printks * Checked domid node against list of outstanding domids. --- xen/arch/x86/setup.c | 5 ++-- xen/common/domain-builder/fdt.c | 51 ++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) if ( iommu_enabled ) dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu; - /* Create initial domain. Not d0 for pvshim. */ - bd->domid = get_initial_domain_id(); + if ( bd->domid == DOMID_INVALID ) + /* Create initial domain. Not d0 for pvshim. */ + bd->domid = get_initial_domain_id(); d = domain_create(bd->domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged); if ( IS_ERR(d) ) panic("Error creating d%u: %ld\n", bd->domid, PTR_ERR(d)); diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ /* * Copyright (C) 2024, Apertus Solutions, LLC */ +#include <xen/domain.h> #include <xen/err.h> #include <xen/init.h> #include <xen/lib.h> @@ -XXX,XX +XXX,XX @@ static int __init fdt_read_multiboot_module(const void *fdt, int node, static int __init process_domain_node( struct boot_info *bi, const void *fdt, int dom_node) { - int node; + int node, property; struct boot_domain *bd = &bi->domains[bi->nr_domains]; const char *name = fdt_get_name(fdt, dom_node, NULL) ?: "unknown"; int address_cells = fdt_address_cells(fdt, dom_node); int size_cells = fdt_size_cells(fdt, dom_node); + fdt_for_each_property_offset(property, fdt, dom_node) + { + const struct fdt_property *prop; + const char *prop_name; + int name_len, rc; + + prop = fdt_get_property_by_offset(fdt, property, NULL); + if ( !prop ) + continue; /* silently skip */ + + prop_name = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff), &name_len); + + if ( !strncmp(prop_name, "domid", name_len) ) + { + uint32_t val = DOMID_INVALID; + + if ( (rc = fdt_prop_as_u32(prop, &val)) ) + { + printk(XENLOG_ERR + " failed processing domain id for domain %s\n", name); + return rc; + } + if ( val >= DOMID_FIRST_RESERVED ) + { + printk(XENLOG_ERR " invalid domain id for domain %s\n", name); + return -EINVAL; + } + + for ( unsigned int i = 0; i < bi->nr_domains; i++ ) + { + if ( bi->domains[i].domid == val ) + { + printk(XENLOG_ERR " duplicate id for domain %s\n", name); + return -EINVAL; + } + } + + bd->domid = val; + printk(XENLOG_INFO " domid: %d\n", bd->domid); + } + } + fdt_for_each_subnode(node, fdt, dom_node) { if ( !fdt_node_check_compatible(fdt, node, "multiboot,kernel") ) @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( return -ENODATA; } + if ( bd->domid == DOMID_INVALID ) + bd->domid = get_initial_domain_id(); + else if ( bd->domid != get_initial_domain_id() ) + printk(XENLOG_WARNING + "Warning: Unsuported boot with missing initial domid\n"); + return 0; } -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Enable selecting the mode in which the domain will be built and ran. This includes: - whether it will be either a 32/64 bit domain - if it will be run as a PV or HVM domain - and if it will require a device model (not applicable for dom0) In the device tree, this will be represented as a bit map that will be carried through into struct boot_domain. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * printk adjustments * reject nodes with conflicting mode settings --- xen/arch/x86/include/asm/boot-domain.h | 5 +++++ xen/arch/x86/setup.c | 3 ++- xen/common/domain-builder/fdt.c | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/include/asm/boot-domain.h b/xen/arch/x86/include/asm/boot-domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/boot-domain.h +++ b/xen/arch/x86/include/asm/boot-domain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { domid_t domid; + /* On | Off */ +#define BUILD_MODE_PARAVIRT (1 << 0) /* PV | PVH/HVM */ +#define BUILD_MODE_ENABLE_DM (1 << 1) /* HVM | PVH */ + uint32_t mode; + struct boot_module *kernel; struct boot_module *module; const char *cmdline; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) struct boot_domain *bd = &bi->domains[0]; struct domain *d; - if ( opt_dom0_pvh ) + if ( opt_dom0_pvh || + (bi->hyperlaunch_enabled && !(bd->mode & BUILD_MODE_PARAVIRT)) ) { dom0_cfg.flags |= (XEN_DOMCTL_CDF_hvm | ((hvm_hap_supported() && !opt_dom0_shadow) ? diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( bd->domid = val; printk(XENLOG_INFO " domid: %d\n", bd->domid); } + else if ( !strncmp(prop_name, "mode", name_len) ) + { + if ( (rc = fdt_prop_as_u32(prop, &bd->mode)) ) + { + printk(XENLOG_ERR + " failed processing mode for domain %s\n", name); + return rc; + } + + if ( (bd->mode & BUILD_MODE_PARAVIRT) && + (bd->mode & BUILD_MODE_ENABLE_DM) ) + { + printk(XENLOG_ERR " mode: invalid (pv+hvm)\n"); + return -EINVAL; + } + + printk(XENLOG_INFO " mode: %s\n", + (bd->mode & BUILD_MODE_PARAVIRT) ? "pv" : + (bd->mode & BUILD_MODE_ENABLE_DM) ? "hvm" : + "pvh"); + } } fdt_for_each_subnode(node, fdt, dom_node) -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Add three properties, memory, mem-min, and mem-max, to the domain node device tree parsing to define the memory allocation for a domain. All three fields are expressed in kb and written as a u64 in the device tree entries. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- Can't use KB() rather tha SZ_1K, as that's strictly for literals. v4: * Don't override fdt_prop_as_u64() rc on error. * Add separate printk statements for each memory prop error. * Fix bug setting up dom0_size, dom0_min_size and dom0_max_size * Was overriding dom0_size on all 3 paths. * Pre-initialise max_pages of all boot_domains to be LONG_MAX, just as dom0_max_size. * Eventually dom0_max_size drops out in the bigger series, so we need that logic to be correct. --- xen/arch/x86/dom0_build.c | 8 ++++++ xen/arch/x86/include/asm/boot-domain.h | 4 +++ xen/arch/x86/setup.c | 5 +++- xen/common/domain-builder/fdt.c | 36 ++++++++++++++++++++++++++ xen/include/xen/libfdt/libfdt-xen.h | 10 +++++++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -XXX,XX +XXX,XX @@ int __init construct_dom0(const struct boot_domain *bd) process_pending_softirqs(); + /* If param dom0_size was not set and HL config provided memory size */ + if ( !get_memsize(&dom0_size, ULONG_MAX) && bd->mem_pages ) + dom0_size.nr_pages = bd->mem_pages; + if ( !get_memsize(&dom0_min_size, ULONG_MAX) && bd->min_pages ) + dom0_min_size.nr_pages = bd->min_pages; + if ( !get_memsize(&dom0_max_size, ULONG_MAX) && bd->max_pages ) + dom0_max_size.nr_pages = bd->max_pages; + if ( is_hvm_domain(d) ) rc = dom0_construct_pvh(bd); else if ( is_pv_domain(d) ) diff --git a/xen/arch/x86/include/asm/boot-domain.h b/xen/arch/x86/include/asm/boot-domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/boot-domain.h +++ b/xen/arch/x86/include/asm/boot-domain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { #define BUILD_MODE_ENABLE_DM (1 << 1) /* HVM | PVH */ uint32_t mode; + unsigned long mem_pages; + unsigned long min_pages; + unsigned long max_pages; + struct boot_module *kernel; struct boot_module *module; const char *cmdline; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static const char *cmdline_cook(const char *p, const char *loader_name); struct boot_info __initdata xen_boot_info = { .loader = "unknown", .cmdline = "", - .domains = { [0 ... MAX_NR_BOOTDOMS - 1] = { .domid = DOMID_INVALID } }, + .domains = { [0 ... MAX_NR_BOOTDOMS - 1] = { + .domid = DOMID_INVALID, + .max_pages = ULONG_MAX, + }}, }; static struct boot_info *__init multiboot_fill_boot_info( diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ #include <xen/init.h> #include <xen/lib.h> #include <xen/libfdt/libfdt.h> +#include <xen/sizes.h> #include <asm/bootinfo.h> #include <asm/page.h> @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( (bd->mode & BUILD_MODE_ENABLE_DM) ? "hvm" : "pvh"); } + else if ( strncmp(prop_name, "memory", name_len) == 0 ) + { + uint64_t kb; + if ( (rc = fdt_prop_as_u64(prop, &kb)) ) + { + printk(XENLOG_ERR " bad \"memory\" prop on domain %s\n", name); + return rc; + } + bd->mem_pages = PFN_DOWN(kb * SZ_1K); + printk(XENLOG_ERR " memory: %lu KiB\n", kb); + } + else if ( !strncmp(prop_name, "mem-min", name_len) ) + { + uint64_t kb; + if ( (rc = fdt_prop_as_u64(prop, &kb)) ) + { + printk(XENLOG_ERR + " bad \"mem-min\" prop on domain %s\n", name); + return rc; + } + bd->min_pages = PFN_DOWN(kb * SZ_1K); + printk(XENLOG_INFO " min memory: %lu kb\n", kb); + } + else if ( !strncmp(prop_name, "mem-max", name_len) ) + { + uint64_t kb; + if ( (rc = fdt_prop_as_u64(prop, &kb)) ) + { + printk(XENLOG_ERR + " bad \"mem-max\" prop on domain %s\n", name); + return rc; + } + bd->max_pages = PFN_DOWN(kb * SZ_1K); + printk(XENLOG_INFO " max memory: %lu KiB\n", kb); + } } fdt_for_each_subnode(node, fdt, dom_node) diff --git a/xen/include/xen/libfdt/libfdt-xen.h b/xen/include/xen/libfdt/libfdt-xen.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/libfdt/libfdt-xen.h +++ b/xen/include/xen/libfdt/libfdt-xen.h @@ -XXX,XX +XXX,XX @@ static inline int __init fdt_prop_as_u32( return 0; } +static inline int __init fdt_prop_as_u64( + const struct fdt_property *prop, uint64_t *val) +{ + if ( !prop || fdt32_to_cpu(prop->len) < sizeof(uint64_t) ) + return -EINVAL; + + *val = fdt64_to_cpu(*(const fdt64_t *)prop->data); + return 0; +} + static inline bool __init fdt_get_prop_offset( const void *fdt, int node, const char *pname, unsigned long *poffset) { -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Introduce the `cpus` property, named as such for dom0less compatibility, that represents the maximum number of vcpus to allocate for a domain. In the device tree, it will be encoded as a u32 value. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * s/UINT_MAX/UINT32_MAX/ (cosmetic, but...) * s/vpcpus/vcpus/ in commit message. * Reworded printk() --- xen/arch/x86/dom0_build.c | 3 +++ xen/arch/x86/include/asm/boot-domain.h | 2 ++ xen/common/domain-builder/fdt.c | 11 +++++++++++ 3 files changed, 16 insertions(+) diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -XXX,XX +XXX,XX @@ int __init construct_dom0(const struct boot_domain *bd) if ( !get_memsize(&dom0_max_size, ULONG_MAX) && bd->max_pages ) dom0_max_size.nr_pages = bd->max_pages; + if ( opt_dom0_max_vcpus_max == UINT_MAX && bd->max_vcpus ) + opt_dom0_max_vcpus_max = bd->max_vcpus; + if ( is_hvm_domain(d) ) rc = dom0_construct_pvh(bd); else if ( is_pv_domain(d) ) diff --git a/xen/arch/x86/include/asm/boot-domain.h b/xen/arch/x86/include/asm/boot-domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/boot-domain.h +++ b/xen/arch/x86/include/asm/boot-domain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { unsigned long min_pages; unsigned long max_pages; + unsigned int max_vcpus; + struct boot_module *kernel; struct boot_module *module; const char *cmdline; diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( bd->max_pages = PFN_DOWN(kb * SZ_1K); printk(XENLOG_INFO " max memory: %lu KiB\n", kb); } + else if ( !strncmp(prop_name, "cpus", name_len) ) + { + uint32_t val = UINT32_MAX; + if ( (rc = fdt_prop_as_u32(prop, &val)) ) + { + printk(XENLOG_ERR " bad \"cpus\" prop on domain %s\n", name); + return rc; + } + bd->max_vcpus = val; + printk(XENLOG_INFO " cpus: %d\n", bd->max_vcpus); + } } fdt_for_each_subnode(node, fdt, dom_node) -- 2.43.0
From: "Daniel P. Smith" <dpsmith@apertussolutions.com> Introduce the ability to assign capabilities to a domain via its definition in device tree. The first capability enabled to select is the control domain capability. The capability property is a bitfield in both the device tree and `struct boot_domain`. Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Signed-off-by: Alejandro Vallejo <agarciav@amd.com> --- v4: * Dropped Jason's R-by. * Refactored caps printinng logic * It just wasn't xenlog-compatible as it was. * Moved pv_shim check to builder_init, so the capability is just not given. * And inlined the create_flags variable now that's tractable. * Validated input capabilities after coming out of the DT. --- xen/arch/x86/include/asm/boot-domain.h | 5 +++++ xen/arch/x86/setup.c | 3 ++- xen/common/domain-builder/core.c | 2 ++ xen/common/domain-builder/fdt.c | 20 ++++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/include/asm/boot-domain.h b/xen/arch/x86/include/asm/boot-domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/boot-domain.h +++ b/xen/arch/x86/include/asm/boot-domain.h @@ -XXX,XX +XXX,XX @@ struct boot_domain { domid_t domid; +#define BUILD_CAPS_NONE (0U) +#define BUILD_CAPS_CONTROL (1U << 0) +#define BUILD_CAPS__ALL BUILD_CAPS_CONTROL + uint32_t capabilities; + /* On | Off */ #define BUILD_MODE_PARAVIRT (1 << 0) /* PV | PVH/HVM */ #define BUILD_MODE_ENABLE_DM (1 << 1) /* HVM | PVH */ diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -XXX,XX +XXX,XX @@ static struct domain *__init create_dom0(struct boot_info *bi) if ( bd->domid == DOMID_INVALID ) /* Create initial domain. Not d0 for pvshim. */ bd->domid = get_initial_domain_id(); - d = domain_create(bd->domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged); + d = domain_create(bd->domid, &dom0_cfg, + (bd->capabilities & BUILD_CAPS_CONTROL) ? CDF_privileged : 0); if ( IS_ERR(d) ) panic("Error creating d%u: %ld\n", bd->domid, PTR_ERR(d)); diff --git a/xen/common/domain-builder/core.c b/xen/common/domain-builder/core.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/core.c +++ b/xen/common/domain-builder/core.c @@ -XXX,XX +XXX,XX @@ #include <xen/lib.h> #include <asm/bootinfo.h> +#include <asm/pv/shim.h> #include <asm/setup.h> #include "fdt.h" @@ -XXX,XX +XXX,XX @@ void __init builder_init(struct boot_info *bi) bi->mods[i].type = BOOTMOD_KERNEL; bi->domains[0].kernel = &bi->mods[i]; + bi->domains[0].capabilities |= pv_shim ? 0 : BUILD_CAPS_CONTROL; bi->nr_domains = 1; } } diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -XXX,XX +XXX,XX @@ static int __init process_domain_node( bd->max_vcpus = val; printk(XENLOG_INFO " cpus: %d\n", bd->max_vcpus); } + else if ( !strncmp(prop_name, "capabilities", name_len) ) + { + if ( (rc = fdt_prop_as_u32(prop, &bd->capabilities)) ) + { + printk(XENLOG_ERR + " bad \"capabilities\" on domain %s\n", name); + return rc; + } + + if ( bd->capabilities & ~BUILD_CAPS__ALL ) + { + printk(XENLOG_WARNING " unknown capabilities: %#x\n", + bd->capabilities & ~BUILD_CAPS__ALL); + + bd->capabilities &= BUILD_CAPS__ALL; + } + + printk(XENLOG_INFO " caps: %s\n", + bd->capabilities & BUILD_CAPS_CONTROL ? "c" : ""); + } } fdt_for_each_subnode(node, fdt, dom_node) -- 2.43.0