[PATCH v3] smbios: arm64: Ensure table is written at a good address

Ilias Apalodimas ilias.apalodimas at linaro.org
Tue Nov 21 21:50:12 CET 2023


Hi Simon,

On Tue, 21 Nov 2023 at 04:58, Simon Glass <sjg at chromium.org> wrote:
>
> U-Boot typically sets up its malloc() pool near the top of memory. On
> ARM64 systems this can result in an SMBIOS table above 4GB which is
> not supported by SMBIOSv2.
>
> Work around this problem by automatically choosing an address below 4GB
> (but as high as possible), if needed.
>
> Tell efi_loader about the address in the same way as we do for ACPI
> tables.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
> Please see previous discussion here:
>
>   https://patchwork.ozlabs.org/project/uboot/patch/
>   20231025123117.v2.1.I054cad60e00f8cfde39256c7c7d9c960987fb9be at changeid/
>
> Changes in v3:
> - Add RISC-V to the condition, too
> - Update the commit message
>
> Changes in v2:
> - Update to search for a suitable area automatically, if enabled
>
>  lib/Kconfig                 | 13 ++++++++
>  lib/efi_loader/efi_smbios.c | 63 ++++++++++++++++++++++++++++++++++++-
>  2 files changed, 75 insertions(+), 1 deletion(-)
>
> diff --git a/lib/Kconfig b/lib/Kconfig
> index 19649517a39b..c70faeeebed5 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -998,6 +998,19 @@ config GENERATE_SMBIOS_TABLE
>           See also SMBIOS_SYSINFO which allows SMBIOS values to be provided in
>           the devicetree.
>
> +config SMBIOS_TABLE_FIXED
> +       bool "Place the SMBIOS table at a special address"
> +       depends on GENERATE_SMBIOS_TABLE && SMBIOS && EFI_LOADER
> +       depends on ARM64 || RISCV
> +       default y
> +       help
> +         Use this option to place the SMBIOS table at a special address.
> +
> +         U-Boot typically sets up its malloc() pool near the top of memory. On
> +         ARM64 systems this can result in an SMBIOS table above 4GB which is
> +         not supported by SMBIOSv2. This option works around this problem by
> +         chosing an address just below 4GB, if needed.
> +
>  endmenu
>
>  config LIB_RATIONAL
> diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c
> index 48446f654d9b..566f206af5b6 100644
> --- a/lib/efi_loader/efi_smbios.c
> +++ b/lib/efi_loader/efi_smbios.c
> @@ -47,6 +47,60 @@ efi_status_t efi_smbios_register(void)
>                                                map_sysmem(addr, 0));
>  }
>
> +/**
> + * find_addr_below() - Find a usable region below the given max_addr
> + *
> + * Check if *addrp is suitable to define a memory region which finishes below
> + * @max_addr + @req_size. If so, do nothing and return 0
> + *
> + * As a backup, if CONFIG_SMBIOS_TABLE_FIXED is enabled, search for a
> + * 4KB-aligned DRAM region which is large enough. Make sure it is below U-Boot's
> + * stack space, assumed to be 64KB.
> + *
> + * @max_addr: Maximum address that can be used (region must finish before here)
> + * @req:size: Required size of region
> + * @addrp: On entry: Current proposed address; on exit, holds the new address,
> + *     on success
> + * Return 0 if OK (existing region was OK, or a new one was found), -ENOSPC if
> + * nothing suitable was found
> + */
> +static int find_addr_below(ulong max_addr, ulong req_size, ulong *addrp)
> +{
> +       struct bd_info *bd = gd->bd;
> +       ulong max_base;
> +       int i;
> +
> +       max_base = max_addr - req_size;
> +       if (*addrp <= max_base)
> +               return 0;
> +
> +       if (!IS_ENABLED(CONFIG_SMBIOS_TABLE_FIXED))
> +               return -ENOSPC;
> +
> +       /* Make sure that the base is at least 64KB below the stack */
> +       max_base = min(max_base,
> +                      ALIGN(gd->start_addr_sp - SZ_64K - req_size, SZ_4K));
> +
> +       for (i = CONFIG_NR_DRAM_BANKS - 1; i >= 0; i--) {
> +               ulong start = bd->bi_dram[i].start;
> +               ulong size = bd->bi_dram[i].size;
> +               ulong addr;
> +
> +               /* chose an address at most req_size bytes before the end */
> +               addr = min(max_base, start - req_size + size);
> +
> +               /* check this is in the range */
> +               if (addr >= start && addr + req_size < start + size) {
> +                       *addrp = addr;
> +                       log_warning("Forcing SMBIOS table to address %lx\n",
> +                                   addr);
> +                       return 0;
> +               }
> +       }
> +
> +       return -ENOSPC;
> +}

This function doesn't really belong here. We should move it to the mem
subsystem.
AFAICT this is a hotfix for 2024.01. So I prefer picking this [0]
instead, since the smbios table generation is still controlled by EFI

[0] https://lore.kernel.org/u-boot/20231120222558.32014-1-heinrich.schuchardt@canonical.com/

Thanks
/Ilias
> +
>  static int install_smbios_table(void)
>  {
>         ulong addr;
> @@ -61,7 +115,14 @@ static int install_smbios_table(void)
>                 return log_msg_ret("mem", -ENOMEM);
>
>         addr = map_to_sysmem(buf);
> -       if (!write_smbios_table(addr)) {
> +
> +       /*
> +        * Deal with a fixed address if needed. For simplicity we assume that
> +        * the SMBIOS-table size is <64KB. If a suitable address cannot be
> +        * found, then write_smbios_table() returns an error.
> +        */
> +       if (find_addr_below(SZ_4G - 1, SZ_64K, &addr) ||
> +           !write_smbios_table(addr)) {
>                 log_err("Failed to write SMBIOS table\n");
>                 return log_msg_ret("smbios", -EINVAL);
>         }
> --
> 2.43.0.rc1.413.gea7ed67945-goog
>


More information about the U-Boot mailing list