On Sat, Jul 8, 2023 at 12:15 PM Stefano Stabellini <sstabell...@kernel.org>
wrote:

> On Sat, 1 Jul 2023, Christopher Clark wrote:
> > Adjust the PV and PVH dom0 construction entry points to take boot module
> > structures as parameters, and add further fields to the boot module
> > structures to plumb the data needed to support this use. Populate these
> > from the multiboot module data.
> >
> > This change removes multiboot from the PV and PVH dom0 construction
> logic.
> >
> > Introduce and use new inline accessor functions for navigating the boot
> > module structures.
> >
> > The per-boot-module arrays are expanded from singletons to accommodate
> > all modules, up to a static maximum of 64 modules including Xen that can
> > be accepted from a bootloader to match the previous value from the
> > module map check.
> >
> > The field that identifies the type of a boot module (kernel, ramdisk,
> > etc) is introduced to the common boot module structure and declared as a
> > non-enum integer type to allow the field to be of a known-size and so
> > structure can be packed in a subsequent patch in the series, and it will
> > then be reconciled with the equivalent Arm boot field type.
> >
> > The command line provided by multiboot for each boot module is added
> > directly to the boot_module structure, which is appropriate for this
> > logic just replacing multiboot.
> >
> > The maximum number of boot modules that a bootloader can provide in
> > addition to the Xen hypervisor is preserved from prior logic with the
> > module_map at 63.
> >
> > Signed-off-by: Christopher Clark <christopher.w.cl...@gmail.com>
> > Signed-off-by: Daniel P. Smith <dpsm...@apertussolutions.com>
> >
> > ---
> > Changes since v1: patch is a subset of v1 series patches 2 and 3.
> > - The module_map is kept for now since still in use.
> > - Move the static inline functions into a separate dedicated header.
> > - <mm-frame.h> and <compiler.h> replace prior inclusion of <mm.h>
> >   for simpler dependencies.
> >
> >  xen/arch/x86/dom0_build.c             |  10 +-
> >  xen/arch/x86/hvm/dom0_build.c         |  43 +++---
> >  xen/arch/x86/include/asm/boot.h       |  36 +++++
> >  xen/arch/x86/include/asm/bootinfo.h   |  24 +++
> >  xen/arch/x86/include/asm/dom0_build.h |  13 +-
> >  xen/arch/x86/include/asm/setup.h      |   4 +-
> >  xen/arch/x86/pv/dom0_build.c          |  32 ++--
> >  xen/arch/x86/setup.c                  | 206 +++++++++++++++-----------
> >  xen/include/xen/bootinfo.h            |  27 ++++
> >  9 files changed, 254 insertions(+), 141 deletions(-)
> >
> > diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c
> > index 9f5300a3ef..42310202a2 100644
> > --- a/xen/arch/x86/dom0_build.c
> > +++ b/xen/arch/x86/dom0_build.c
> > @@ -4,6 +4,7 @@
> >   * Copyright (c) 2002-2005, K A Fraser
> >   */
> >
> > +#include <xen/bootinfo.h>
> >  #include <xen/init.h>
> >  #include <xen/iocap.h>
> >  #include <xen/libelf.h>
> > @@ -562,9 +563,8 @@ int __init dom0_setup_permissions(struct domain *d)
> >      return rc;
> >  }
> >
> > -int __init construct_dom0(struct domain *d, const module_t *image,
> > -                          unsigned long image_headroom, module_t
> *initrd,
> > -                          char *cmdline)
> > +int __init construct_dom0(struct domain *d, const struct boot_module
> *image,
> > +    struct boot_module *initrd, char *cmdline)
> >  {
> >      int rc;
> >
> > @@ -576,9 +576,9 @@ int __init construct_dom0(struct domain *d, const
> module_t *image,
> >      process_pending_softirqs();
> >
> >      if ( is_hvm_domain(d) )
> > -        rc = dom0_construct_pvh(d, image, image_headroom, initrd,
> cmdline);
> > +        rc = dom0_construct_pvh(d, image, initrd, cmdline);
> >      else if ( is_pv_domain(d) )
> > -        rc = dom0_construct_pv(d, image, image_headroom, initrd,
> cmdline);
> > +        rc = dom0_construct_pv(d, image, initrd, cmdline);
> >      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 56fe89632b..c094863bb8 100644
> > --- a/xen/arch/x86/hvm/dom0_build.c
> > +++ b/xen/arch/x86/hvm/dom0_build.c
> > @@ -8,9 +8,9 @@
> >   */
> >
> >  #include <xen/acpi.h>
> > +#include <xen/bootinfo.h>
> >  #include <xen/init.h>
> >  #include <xen/libelf.h>
> > -#include <xen/multiboot.h>
> >  #include <xen/pci.h>
> >  #include <xen/softirq.h>
> >
> > @@ -530,14 +530,13 @@ static paddr_t __init find_memory(
> >      return INVALID_PADDR;
> >  }
> >
> > -static int __init pvh_load_kernel(struct domain *d, const module_t
> *image,
> > -                                  unsigned long image_headroom,
> > -                                  module_t *initrd, void *image_base,
> > -                                  char *cmdline, paddr_t *entry,
> > -                                  paddr_t *start_info_addr)
> > +static int __init pvh_load_kernel(
> > +    struct domain *d, const struct boot_module *image,
> > +    struct boot_module *initrd, void *image_base, char *cmdline,
> paddr_t *entry,
> > +    paddr_t *start_info_addr)
> >  {
> > -    void *image_start = image_base + image_headroom;
> > -    unsigned long image_len = image->mod_end;
> > +    void *image_start = image_base + image->arch->headroom;
> > +    unsigned long image_len = image->size;
> >      struct elf_binary elf;
> >      struct elf_dom_parms parms;
> >      paddr_t last_addr;
> > @@ -546,7 +545,7 @@ static int __init pvh_load_kernel(struct domain *d,
> const module_t *image,
> >      struct vcpu *v = d->vcpu[0];
> >      int rc;
> >
> > -    if ( (rc = bzimage_parse(image_base, &image_start, image_headroom,
> > +    if ( (rc = bzimage_parse(image_base, &image_start,
> image->arch->headroom,
> >                               &image_len)) != 0 )
> >      {
> >          printk("Error trying to detect bz compressed kernel\n");
> > @@ -594,7 +593,7 @@ static int __init pvh_load_kernel(struct domain *d,
> const module_t *image,
> >       * simplify it.
> >       */
> >      last_addr = find_memory(d, &elf, sizeof(start_info) +
> > -                            (initrd ? ROUNDUP(initrd->mod_end,
> PAGE_SIZE) +
> > +                            (initrd ? ROUNDUP(initrd->size, PAGE_SIZE) +
> >                                        sizeof(mod)
> >                                      : 0) +
> >                              (cmdline ? ROUNDUP(strlen(cmdline) + 1,
> > @@ -608,8 +607,8 @@ static int __init pvh_load_kernel(struct domain *d,
> const module_t *image,
> >
> >      if ( initrd != NULL )
> >      {
> > -        rc = hvm_copy_to_guest_phys(last_addr,
> mfn_to_virt(initrd->mod_start),
> > -                                    initrd->mod_end, v);
> > +        rc = hvm_copy_to_guest_phys(last_addr,
> maddr_to_virt(initrd->start),
> > +                                    initrd->size, v);
> >          if ( rc )
> >          {
> >              printk("Unable to copy initrd to guest\n");
> > @@ -617,11 +616,11 @@ static int __init pvh_load_kernel(struct domain
> *d, const module_t *image,
> >          }
> >
> >          mod.paddr = last_addr;
> > -        mod.size = initrd->mod_end;
> > -        last_addr += ROUNDUP(initrd->mod_end, elf_64bit(&elf) ? 8 : 4);
> > -        if ( initrd->string )
> > +        mod.size = initrd->size;
> > +        last_addr += ROUNDUP(initrd->size, elf_64bit(&elf) ? 8 : 4);
> > +        if ( initrd->string.len )
> >          {
> > -            char *str = __va(initrd->string);
> > +            char *str = initrd->string.bytes;
> >              size_t len = strlen(str) + 1;
> >
> >              rc = hvm_copy_to_guest_phys(last_addr, str, len, v);
> > @@ -1176,10 +1175,9 @@ static void __hwdom_init pvh_setup_mmcfg(struct
> domain *d)
> >      }
> >  }
> >
> > -int __init dom0_construct_pvh(struct domain *d, const module_t *image,
> > -                              unsigned long image_headroom,
> > -                              module_t *initrd,
> > -                              char *cmdline)
> > +int __init dom0_construct_pvh(
> > +    struct domain *d, const struct boot_module *image,
> > +    struct boot_module *initrd, char *cmdline)
> >  {
> >      paddr_t entry, start_info;
> >      int rc;
> > @@ -1209,9 +1207,8 @@ int __init dom0_construct_pvh(struct domain *d,
> const module_t *image,
> >          return rc;
> >      }
> >
> > -    rc = pvh_load_kernel(d, image, image_headroom, initrd,
> > -                         bootstrap_map_multiboot(image),
> > -                         cmdline, &entry, &start_info);
> > +    rc = pvh_load_kernel(d, image, initrd, bootstrap_map(image),
> cmdline,
> > +                         &entry, &start_info);
> >      if ( rc )
> >      {
> >          printk("Failed to load Dom0 kernel\n");
> > diff --git a/xen/arch/x86/include/asm/boot.h
> b/xen/arch/x86/include/asm/boot.h
> > index 10b17f12b2..bcf4f2e2e3 100644
> > --- a/xen/arch/x86/include/asm/boot.h
> > +++ b/xen/arch/x86/include/asm/boot.h
> > @@ -19,6 +19,42 @@ static inline void *bootstrap_map_multiboot(const
> module_t *mod)
> >      return bootstrap_map(&bm);
> >  }
> >
> > +static inline unsigned long bootmodule_index(
> > +    const struct boot_info *info, bootmod_type_t bootmod_type,
> > +    unsigned long start)
> > +{
> > +    for ( ; start < info->nr_mods; start++ )
> > +        if ( info->mods[start].bootmod_type == bootmod_type )
> > +            return start;
> > +
> > +    return info->nr_mods + 1;
> > +}
> > +
> > +static inline struct boot_module *bootmodule_next(
> > +    const struct boot_info *info, bootmod_type_t bootmod_type)
> > +{
> > +    unsigned long i;
> > +
> > +    for ( i = 0; i < info->nr_mods; i++ )
> > +        if ( info->mods[i].bootmod_type == bootmod_type )
> > +            return &info->mods[i];
> > +
> > +    return NULL;
> > +}
> > +
> > +static inline void bootmodule_update_start(struct boot_module *bm,
> > +    paddr_t new_start)
> > +{
> > +    bm->start = new_start;
> > +    bm->mfn = maddr_to_mfn(new_start);
> > +}
> > +
> > +static inline void bootmodule_update_mfn(struct boot_module *bm, mfn_t
> new_mfn)
> > +{
> > +    bm->mfn = new_mfn;
> > +    bm->start = mfn_to_maddr(new_mfn);
> > +}
> > +
> >  #endif
> >
> >  /*
> > diff --git a/xen/arch/x86/include/asm/bootinfo.h
> b/xen/arch/x86/include/asm/bootinfo.h
> > index a25054f372..30c27980e0 100644
> > --- a/xen/arch/x86/include/asm/bootinfo.h
> > +++ b/xen/arch/x86/include/asm/bootinfo.h
> > @@ -2,9 +2,33 @@
> >  #define __ARCH_X86_BOOTINFO_H__
> >
> >  struct arch_bootmodule {
> > +#define BOOTMOD_FLAG_X86_RELOCATED     1U << 0
> > +    uint32_t flags;
> >      unsigned headroom;
> >  };
> >
> > +struct arch_boot_info {
> > +    uint32_t flags;
> > +#define BOOTINFO_FLAG_X86_CMDLINE      1U << 2
>
> Is this to indicate the presence of the Xen cmdline?
>

Yes; it replaces the previous use of the MBI_CMDLINE flag and is set
whenever MBI_CMDLINE is set when passed from multiboot. This indicates that
a command line has been passed via multiboot.

A comment in the conversion function confirms the intended use of the flag
field:
    /* The BOOTINFO_FLAG_X86_* flags are a 1-1 map to MBI_* */


>
>
> > +#define BOOTINFO_FLAG_X86_MODULES      1U << 3
> > +#define BOOTINFO_FLAG_X86_MEMMAP       1U << 6
> > +#define BOOTINFO_FLAG_X86_LOADERNAME   1U << 9
> > +
> > +    char *boot_loader_name;
> > +
> > +    uint32_t mmap_length;
> > +    paddr_t mmap_addr;
> > +};
> > +
> > +struct __packed mb_memmap {
> > +    uint32_t size;
> > +    uint32_t base_addr_low;
> > +    uint32_t base_addr_high;
> > +    uint32_t length_low;
> > +    uint32_t length_high;
> > +    uint32_t type;
> > +};
> > +
> >  #endif
> >
> >  /*
> > diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
> > index 3b623a4149..f9b04daebd 100644
> > --- a/xen/arch/x86/setup.c
> > +++ b/xen/arch/x86/setup.c
> > @@ -37,6 +37,7 @@
> >  #include <asm/processor.h>
> >  #include <asm/mpspec.h>
> >  #include <asm/apic.h>
> > +#include <asm/boot.h>
> >  #include <asm/msi.h>
> >  #include <asm/desc.h>
> >  #include <asm/paging.h>
> > @@ -59,6 +60,9 @@
> >  #include <asm/prot-key.h>
> >  #include <asm/pv/domain.h>
> >
> > +/* Max number of boot modules a bootloader can provide in addition to
> Xen */
> > +#define MAX_NR_BOOTMODS 63
>
> Call it MAX_MODULES ?
> Like I wrote in the past, you already did the hard work of aligning the
> interfaces, we might as well also use the same names.
>

On the general naming: BOOTMODS is more descriptive in that it indicates an
association between the module and the context it is from: ie. boot, and is
a module handed to the hypervisor by a bootloader (as opposed to say, a
late-loaded module). The term BOOTMOD is also already used within the Arm
source, see: BOOTMOD_MAX_CMDLINE.

On using the same name: following the feedback in the previous round of
reviews this value doesn't include a count of the hypervisor itself; so it
isn't the same thing and so I wouldn't use the same name for it.


>
> [...]
>
> > @@ -1357,12 +1382,14 @@ void __init noreturn __start_xen(unsigned long
> mbi_p)
> >           * respective reserve_e820_ram() invocation below. No need to
> >           * query efi_boot_mem_unused() here, though.
> >           */
> > -        mod[boot_info->nr_mods].mod_start = virt_to_mfn(_stext);
> > -        mod[boot_info->nr_mods].mod_end = __2M_rwdata_end - _stext;
> > +        bootmodule_update_start(&boot_info->mods[boot_info->nr_mods],
> > +                                virt_to_maddr(_stext));
> > +        boot_info->mods[boot_info->nr_mods].size = __2M_rwdata_end -
> _stext;
> >      }
>
> The original code had the end address as "__2M_rwdata_end - _stext"
> while now we have the size as "__2M_rwdata_end - _stext" which is not
> the same?
>

(this was answered by Jan in a previous reply)

>
>
>
> >      boot_info->mods[0].arch->headroom =
> > -        bzimage_headroom(bootstrap_map_multiboot(mod), mod->mod_end);
> > +        bzimage_headroom(bootstrap_map(&boot_info->mods[0]),
> > +                         boot_info->mods[0].size);
> >
> >      bootstrap_map(NULL);
> >
>
> [...]
>
>
> > diff --git a/xen/include/xen/bootinfo.h b/xen/include/xen/bootinfo.h
> > index eb93cc3439..2f4284a91f 100644
> > --- a/xen/include/xen/bootinfo.h
> > +++ b/xen/include/xen/bootinfo.h
> > @@ -2,23 +2,50 @@
> >  #define __XEN_BOOTINFO_H__
> >
> >  #include <xen/types.h>
> > +#include <xen/compiler.h>
> > +#include <xen/mm-frame.h>
> >
> >  #ifdef CONFIG_X86
> >  #include <asm/bootinfo.h>
> >  #else
> >      struct arch_bootmodule { };
> > +    struct arch_boot_info { };
> >  #endif
> >
> > +/* Boot module binary type / purpose */
> > +#define BOOTMOD_UNKNOWN     0
> > +#define BOOTMOD_XEN         1
> > +#define BOOTMOD_FDT         2
> > +#define BOOTMOD_KERNEL      3
> > +#define BOOTMOD_RAMDISK     4
> > +#define BOOTMOD_XSM         5
> > +#define BOOTMOD_UCODE       6
> > +#define BOOTMOD_GUEST_DTB   7
> > +typedef unsigned int bootmod_type_t;
> > +
> > +#define BOOTMOD_STRING_MAX_LEN 1024
>
> BOOTMOD_MAX_CMDLINE ?
>

The string associated with a boot module may not be a command line; it
depends on the type of the module, hence BOOTMOD_MAX_STRING was what it was
called in v1 of the hyperlaunch series, and I revised it to this since I
think it's clearer.
ie. There's a purpose to the rename.


>
>
> > +struct boot_string {
>
> struct bootcmdline ?
>

It is similar to bootcmdline in that it stores the contents of the string
provided by the bootloader to associate with a boot module, but the struct
contents differ and the way that it is accessed is different too.

I think it replaces bootcmdline once the new structures are fully in use on
Arm.


>
>
> > +    char bytes[BOOTMOD_STRING_MAX_LEN];
>
> cmdline?
>

It may not be command line, depending on the module type, hence the
interest in using a different term for it.


>
> If the string is \0 terminated we don't need len?
>

This is for generalized strings associated with boot modules supplied by
the bootloader, not just command lines, so additional consideration may be
wanted. This is a defensive mechanism, attackers don't follow
specifications and sometimes people cause bugs.


>
>
> > +    size_t len;
> > +};
> > +
> >  struct boot_module {
> > +    bootmod_type_t bootmod_type;
>
> Why not use a good old enum?
>

The early x86 boot logic that runs in 32-bit mode populates the structures
which are then accessed in the main hypervisor initialization logic in
64-bit mode, and we would like to have a single common definition for the
structures in a header that is useable in both places, so that requires
preparing for fixed-size types in packed structures; an enum isn't
guaranteed to compile to
the same size in those two cases, so doesn't pack. To make transition for
the Arm code easier I can make these definitions closer to the old enum
though.


>
>
> >      paddr_t start;
> > +    mfn_t mfn;
>
> I think mfn should be in arch_bootmodule
>

I think that's ok if it's not needed in non-x86 logic.


>
>
> >      size_t size;
> >
> >      struct arch_bootmodule *arch;
> > +    struct boot_string string;
> >  };
> >
> >  struct boot_info {
> > +    char *cmdline;
>
> Is this for Xen cmdline?


Yes


> While all the other cmdline are in the various
> struct boot_string? Is there any benefit in using the BOOTMOD_XEN for it?
> BOOTMOD_XEN is not used so far, so if you don't end up using it,
> probably not, otherwise it could be considered.
>

ok - I agree that we haven't dropped any use of BOOTMOD_XEN so far but will
keep it in mind.

thanks,

Christopher


>
>
>
>
> >      unsigned int nr_mods;
> >      struct boot_module *mods;
> > +
> > +    struct arch_boot_info *arch;
> >  };
> >
> >  #endif
> > --
> > 2.25.1
> >
> >
>

Reply via email to