[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v4 05/13] x86/hyperlaunch: Add helpers to locate multiboot modules


  • To: <dmkhn@xxxxxxxxx>
  • From: Alejandro Vallejo <agarciav@xxxxxxx>
  • Date: Wed, 23 Apr 2025 13:12:03 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=proton.me smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=FSe4xzZ/l7UZnQ28PKXHhXP1kzT/+jUf+MATFOebIQ4=; b=Kuo/7zp99n1JF9aWV8+7+UQ4OP4CiA2mAdy5MUbKAL92otS4GgYVj2/yzOXGO33nPMI05p9Hr/E+X0KlxwcCJkCHGz7LQwKVM5jPPZjwdMMhua7giDTlTwFA6JJAOXbQcvtGe1ehXRAJB7yP/L4nAdV1un3yWCxm5iL7oF3VXqpTSNxYsjusHheMGYy7akCGoITn+WXJeUtiXDscbxta0NPL7E8ux06hz95EZr1WJ35r2rfUGFDy9yZIVSMTRLu1romj0FlZLfuFLaiBMMxNSPpLS/CWSPvqALIxIQ9Om2aeZ73LCrv0fY6KdcNo9eeU1vcPLnoBRuGN6r5c57iiQQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=FdippMtPwaszWZ9uvTt0ceU2j4w7vd/ipVfqiSRQSOI/j28CpDBtmaP8NnF3a48zg1S3cbehclgV0LovV+c/+D45hOVOU7ZgDLnYPKr98VTl7hBFdbvEqEhT964Y2oP66W3KNy+npp+G2qZ3sh1Dsr8+3zC/bKiVD2FTuz6UVQgwnP2NRYpaOixeH5EulZUAdL0xBbN/O7V/b3o0JasobzBiBJkECuLr3j+JQcl7KJnCHZdzuQm37V4A0RlIQ4aPpEWs+ktplQG5vphq74G7ZGMlfTcYc+Y3KDTjorClR8j+UaW5XZxqLD1hyhErQzsxFVe8bqOc6QK4r6jvJ2HhLQ==
  • Cc: <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, "Julien Grall" <julien@xxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, "Bertrand Marquis" <bertrand.marquis@xxxxxxx>, Jason Andryuk <jason.andryuk@xxxxxxx>
  • Delivery-date: Wed, 23 Apr 2025 12:12:33 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On Fri Apr 18, 2025 at 11:30 PM BST, dmkhn wrote:
> On Thu, Apr 17, 2025 at 01:48:27PM +0100, Alejandro Vallejo wrote:
>> 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@xxxxxxx>
>> Signed-off-by: Alejandro Vallejo <agarciav@xxxxxxx>
>> ---
>> 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 b5ff8220da..d73536fed6 100644
>> --- a/xen/common/domain-builder/fdt.c
>> +++ b/xen/common/domain-builder/fdt.c
>> @@ -13,6 +13,168 @@
>> 
>>  #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,
>
> I would do s/read_fdt_prop_as_reg/fdt_prop_as_reg/ similar to 
> fdt_prop_as_u32()
> below.

Yes, that sounds better.

>
>> +                                       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 955aead497..8c98a256eb 100644
>> --- a/xen/common/domain-builder/fdt.h
>> +++ b/xen/common/domain-builder/fdt.h
>> @@ -2,6 +2,8 @@
>>  #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 ac2b84775d..ace6b6875b 100644
>> --- a/xen/include/xen/domain-builder.h
>> +++ b/xen/include/xen/domain-builder.h
>> @@ -5,5 +5,8 @@
>>  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 a5340bc9f4..deafb25d98 100644
>> --- a/xen/include/xen/libfdt/libfdt-xen.h
>> +++ b/xen/include/xen/libfdt/libfdt-xen.h
>> @@ -12,6 +12,17 @@
>>  #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;
>> +}
>
> My understanding is domain builder establishes its own shims around libfdt so
> libfdt is kept unmodified and it is easier to pick up libfdt updates.
>
> So, IMO, this function should reside in xen/common/domain-builder/fdt.c
>
> Thoughts?

Ugh. Too much code motion is not good for your head. I did mean to move
them all (I mentioned it in an earlier response to Jan, I think). Will
do for good this time.

Cheers,
Alejandro



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.