From: Ard Biesheuvel <ardb@kernel.org>
To: Leif Lindholm <leif@nuviainc.com>
Cc: linux-efi <linux-efi@vger.kernel.org>,
linux-arm-kernel <linux-arm-kernel@lists.infradead.org>,
Atish Patra <atish.patra@wdc.com>
Subject: Re: [PATCH 3/3] efi/arm: rewrite FDT param discovery routines
Date: Thu, 20 Feb 2020 20:20:22 +0100 [thread overview]
Message-ID: <CAKv+Gu-VCFT8G8knvCkBtUZ1uVnMzyA8G1dWJc4aeKNBJ8GqUg@mail.gmail.com> (raw)
In-Reply-To: <20200220183001.GE23627@bivouac.eciton.net>
On Thu, 20 Feb 2020 at 19:30, Leif Lindholm <leif@nuviainc.com> wrote:
>
> On Wed, Feb 19, 2020 at 16:24:40 +0100, Ard Biesheuvel wrote:
> > The efi_get_fdt_params() routine uses the early OF device tree
> > traversal helpers, that iterate over each node in the DT and invoke
> > a caller provided callback that can inspect the node's contents and
> > look for the required data. This requires a special param struct to
> > be passed around, with pointers into param enumeration structs that
> > contain (and duplicate) property names and offsets into yet another
> > struct that carries the collected data.
> >
> > Since we know the data we look for is either under /hypervisor/uefi
> > or under /chosen, it is much simpler to use the libfdt routines
> > directly, and try to grab a reference to either node directly, and
> > read each property in sequence.
> >
> > Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> > ---
> > drivers/firmware/efi/fdtparams.c | 203 ++++++++------------
> > 1 file changed, 85 insertions(+), 118 deletions(-)
> >
> > diff --git a/drivers/firmware/efi/fdtparams.c b/drivers/firmware/efi/fdtparams.c
> > index 7a384b307c56..23af4062e913 100644
> > --- a/drivers/firmware/efi/fdtparams.c
> > +++ b/drivers/firmware/efi/fdtparams.c
> > @@ -5,154 +5,121 @@
> > #include <linux/module.h>
> > #include <linux/init.h>
> > #include <linux/efi.h>
> > -#include <linux/of.h>
> > +#include <linux/libfdt.h>
> > #include <linux/of_fdt.h>
> >
> > -#include <asm/early_ioremap.h>
> > +#include <asm/unaligned.h>
> >
> > -#define UEFI_PARAM(name, prop, field) \
> > - { \
> > - { name }, \
> > - { prop }, \
> > - offsetof(struct efi_fdt_params, field), \
> > - sizeof_field(struct efi_fdt_params, field) \
> > - }
> > -
> > -struct efi_fdt_params {
> > - u64 system_table;
> > - u64 mmap;
> > - u32 mmap_size;
> > - u32 desc_size;
> > - u32 desc_ver;
> > -};
> > -
> > -struct params {
> > - const char name[32];
> > - const char propname[32];
> > - int offset;
> > - int size;
> > +enum {
> > + SYSTAB,
> > + MMBASE,
> > + MMSIZE,
> > + DCSIZE,
> > + DCVERS,
> > };
> >
> > -static __initdata struct params fdt_params[] = {
> > - UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
> > - UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
> > - UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
> > - UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
> > - UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
> > +static __initconst const char name[][22] = {
>
> I was going to complain about that 22, and I still think it looks a
> bit iffy, but I can't find a compiler that doesn't throw a warning if
> the value changes, so I guess I'm being over sensitive.
>
Yeah, 32 is just as arbitrary, and wastes more space :-)
> > + [SYSTAB] = "System Table ",
> > + [MMBASE] = "MemMap Address ",
> > + [MMSIZE] = "MemMap Size ",
> > + [DCSIZE] = "MemMap Desc. Size ",
> > + [DCVERS] = "MemMap Desc. Version ",
> > };
> >
> > -static __initdata struct params xen_fdt_params[] = {
> > - UEFI_PARAM("System Table", "xen,uefi-system-table", system_table),
> > - UEFI_PARAM("MemMap Address", "xen,uefi-mmap-start", mmap),
> > - UEFI_PARAM("MemMap Size", "xen,uefi-mmap-size", mmap_size),
> > - UEFI_PARAM("MemMap Desc. Size", "xen,uefi-mmap-desc-size", desc_size),
> > - UEFI_PARAM("MemMap Desc. Version", "xen,uefi-mmap-desc-ver", desc_ver)
> > -};
> > -
> > -#define EFI_FDT_PARAMS_SIZE ARRAY_SIZE(fdt_params)
> > -
> > -static __initdata struct {
> > - const char *uname;
> > - const char *subnode;
> > - struct params *params;
> > +static __initconst const struct {
> > + const char path[17];
> > + const char params[5][26];
>
> And I guess the same is true here, but the 5 *could* theoretically be
> replaced by a compile-time calculation of DCVERS - SYSTAB + 1. That
> may not be less error prone however. Finishing the enum on a
> somethingMAX entry might make it slightly better?
>
Yeah that make sense - I'll change that.
> But the error checking isn't really what I'm after, but getting rid of
> the opaqueness. Could we have comments about which specific string
> lengths we're matching against here for us bears of very little brain?
>
Sure.
> > } dt_params[] = {
> > - { "hypervisor", "uefi", xen_fdt_params },
> > - { "chosen", NULL, fdt_params },
> > -};
> > -
> > -struct param_info {
> > - int found;
> > - void *params;
> > - const char *missing;
> > +#ifdef CONFIG_XEN
> > + {
> > + "/hypervisor/uefi",
> > + {
> > + [SYSTAB] = "xen,uefi-system-table",
> > + [MMBASE] = "xen,uefi-mmap-start",
> > + [MMSIZE] = "xen,uefi-mmap-size",
> > + [DCSIZE] = "xen,uefi-mmap-desc-size",
> > + [DCVERS] = "xen,uefi-mmap-desc-ver",
> > + }
> > + },
> > +#endif
> > + {
> > + "/chosen",
> > + {
> > + [SYSTAB] = "linux,uefi-system-table",
> > + [MMBASE] = "linux,uefi-mmap-start",
> > + [MMSIZE] = "linux,uefi-mmap-size",
> > + [DCSIZE] = "linux,uefi-mmap-desc-size",
> > + [DCVERS] = "linux,uefi-mmap-desc-ver",
> > + }
> > + }
> > };
> >
> > -static int __init __find_uefi_params(unsigned long node,
> > - struct param_info *info,
> > - struct params *params)
> > +static int __init efi_get_fdt_prop(const void *fdt, int node, int dtp, int pp,
> > + void *var, int size)
> > {
> > const void *prop;
> > - void *dest;
> > + int len;
> > u64 val;
> > - int i, len;
> >
> > - for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) {
> > - prop = of_get_flat_dt_prop(node, params[i].propname, &len);
> > - if (!prop) {
> > - info->missing = params[i].name;
> > - return 0;
> > - }
> > -
> > - dest = info->params + params[i].offset;
> > - info->found++;
> > + prop = fdt_getprop(fdt, node, dt_params[dtp].params[pp], &len);
> > + if (!prop) {
> > + pr_err("Can't find property '%s' in device tree!\n",
> > + dt_params[dtp].params[pp]);
> > + return 1;
> > + }
> >
> > - val = of_read_number(prop, len / sizeof(u32));
> > + val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
> >
> > - if (params[i].size == sizeof(u32))
> > - *(u32 *)dest = val;
> > - else
> > - *(u64 *)dest = val;
> > + if (size == 8)
> > + *(u64 *)var = val;
> > + else
> > + *(u32 *)var = (val <= U32_MAX) ? val : U32_MAX; // saturate
> >
> > - if (efi_enabled(EFI_DBG))
> > - pr_info(" %s: 0x%0*llx\n", params[i].name,
> > - params[i].size * 2, val);
> > - }
> > + if (efi_enabled(EFI_DBG))
> > + pr_info(" %s: 0x%0*llx\n", name[pp], size * 2, val);
> >
> > - return 1;
> > + return 0;
> > }
> >
> > -static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
> > - int depth, void *data)
> > +u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
> > {
> > - struct param_info *info = data;
> > + const void *fdt = initial_boot_params;
> > + unsigned long systab;
> > + struct {
> > + void *var;
> > + int size;
> > + } target[] = {
> > + [SYSTAB] = { &systab, sizeof(systab) },
> > + [MMBASE] = { &mm->phys_map, sizeof(mm->phys_map) },
> > + [MMSIZE] = { &mm->size, sizeof(mm->size) },
> > + [DCSIZE] = { &mm->desc_size, sizeof(mm->desc_size) },
> > + [DCVERS] = { &mm->desc_version, sizeof(mm->desc_version) },
> > + };
> > int i;
> >
> > + BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
> > + BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
> > +
> > for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
> > - const char *subnode = dt_params[i].subnode;
> > + int node;
> > + int j;
> >
> > - if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) {
> > - info->missing = dt_params[i].params[0].name;
> > + node = fdt_path_offset(fdt, dt_params[i].path);
> > + if (node < 0)
> > continue;
> > - }
> >
> > - if (subnode) {
> > - int err = of_get_flat_dt_subnode_by_name(node, subnode);
> > + if (efi_enabled(EFI_DBG))
> > + pr_info("Getting UEFI parameters from %s in DT:\n",
> > + dt_params[i].path);
> >
> > - if (err < 0)
> > + for (j = 0; j < ARRAY_SIZE(target); j++) {
> > + if (efi_get_fdt_prop(fdt, node, i, j, target[j].var,
> > + target[j].size)) {
> > return 0;
> > -
> > - node = err;
> > + }
> > }
> > -
> > - return __find_uefi_params(node, info, dt_params[i].params);
> > + return systab;
> > }
> > -
> > + pr_info("UEFI not found.\n");
> > return 0;
> > }
> > -
> > -u64 __init efi_get_fdt_params(struct efi_memory_map_data *memmap)
> > -{
> > - struct efi_fdt_params params;
> > - struct param_info info;
> > - int ret;
> > -
> > - pr_info("Getting EFI parameters from FDT:\n");
> > -
> > - info.found = 0;
> > - info.params = ¶ms;
> > -
> > - ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
> > - if (!info.found) {
> > - pr_info("UEFI not found.\n");
> > - return 0;
> > - } else if (!ret) {
> > - pr_err("Can't find '%s' in device tree!\n", info.missing);
> > - return 0;
> > - }
> > -
> > - memmap->desc_version = params.desc_ver;
> > - memmap->desc_size = params.desc_size;
> > - memmap->size = params.mmap_size;
> > - memmap->phys_map = params.mmap;
> > -
> > - return params.system_table;
> > -}
> > --
> > 2.17.1
> >
prev parent reply other threads:[~2020-02-20 19:20 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-19 15:24 [PATCH 0/3] efi/arm: refactor DT EFI param parsing Ard Biesheuvel
2020-02-19 15:24 ` [PATCH 1/3] efi/arm: move FDT param discovery code out of efi.c Ard Biesheuvel
2020-02-19 15:24 ` [PATCH 2/3] efi/arm: move FDT specific definitions into fdtparams.c Ard Biesheuvel
2020-02-19 15:24 ` [PATCH 3/3] efi/arm: rewrite FDT param discovery routines Ard Biesheuvel
2020-02-20 18:30 ` Leif Lindholm
2020-02-20 19:20 ` Ard Biesheuvel [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAKv+Gu-VCFT8G8knvCkBtUZ1uVnMzyA8G1dWJc4aeKNBJ8GqUg@mail.gmail.com \
--to=ardb@kernel.org \
--cc=atish.patra@wdc.com \
--cc=leif@nuviainc.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-efi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).