efi/arm: Rewrite FDT param discovery routines

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, and
just try to grab a reference to either node directly, and read each
property in sequence.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2020-02-19 15:29:06 +01:00
parent 3b2e4b4c63
commit e457ed516a

View File

@ -5,154 +5,122 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/of.h> #include <linux/libfdt.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <asm/early_ioremap.h> #include <asm/unaligned.h>
#define UEFI_PARAM(name, prop, field) \ enum {
{ \ SYSTAB,
{ name }, \ MMBASE,
{ prop }, \ MMSIZE,
offsetof(struct efi_fdt_params, field), \ DCSIZE,
sizeof_field(struct efi_fdt_params, field) \ DCVERS,
}
struct efi_fdt_params { PARAMCOUNT
u64 system_table;
u64 mmap;
u32 mmap_size;
u32 desc_size;
u32 desc_ver;
}; };
struct params { static __initconst const char name[][22] = {
const char name[32]; [SYSTAB] = "System Table ",
const char propname[32]; [MMBASE] = "MemMap Address ",
int offset; [MMSIZE] = "MemMap Size ",
int size; [DCSIZE] = "MemMap Desc. Size ",
[DCVERS] = "MemMap Desc. Version ",
}; };
static __initdata struct params fdt_params[] = { static __initconst const struct {
UEFI_PARAM("System Table", "linux,uefi-system-table", system_table), const char path[17];
UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap), const char params[PARAMCOUNT][26];
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 __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;
} dt_params[] = { } dt_params[] = {
{ "hypervisor", "uefi", xen_fdt_params }, {
{ "chosen", NULL, fdt_params }, #ifdef CONFIG_XEN // <-------17------>
.path = "/hypervisor/uefi",
.params = {
[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
.path = "/chosen",
.params = { // <-----------26----------->
[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",
}
}
}; };
struct param_info { static int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
int found; const char *rname, void *var, int size)
void *params;
const char *missing;
};
static int __init __find_uefi_params(unsigned long node,
struct param_info *info,
struct params *params)
{ {
const void *prop; const void *prop;
void *dest; int len;
u64 val; u64 val;
int i, len;
for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) { prop = fdt_getprop(fdt, node, pname, &len);
prop = of_get_flat_dt_prop(node, params[i].propname, &len); if (!prop)
if (!prop) { return 1;
info->missing = params[i].name;
return 0;
}
dest = info->params + params[i].offset; val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
info->found++;
val = of_read_number(prop, len / sizeof(u32)); if (size == 8)
*(u64 *)var = val;
else
*(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate
if (params[i].size == sizeof(u32)) if (efi_enabled(EFI_DBG))
*(u32 *)dest = val; pr_info(" %s: 0x%0*llx\n", rname, size * 2, val);
else
*(u64 *)dest = val;
if (efi_enabled(EFI_DBG))
pr_info(" %s: 0x%0*llx\n", params[i].name,
params[i].size * 2, val);
}
return 1;
}
static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
int depth, void *data)
{
struct param_info *info = data;
int i;
for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
const char *subnode = dt_params[i].subnode;
if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) {
info->missing = dt_params[i].params[0].name;
continue;
}
if (subnode) {
int err = of_get_flat_dt_subnode_by_name(node, subnode);
if (err < 0)
return 0;
node = err;
}
return __find_uefi_params(node, info, dt_params[i].params);
}
return 0; return 0;
} }
u64 __init efi_get_fdt_params(struct efi_memory_map_data *memmap) u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
{ {
struct efi_fdt_params params; const void *fdt = initial_boot_params;
struct param_info info; unsigned long systab;
int ret; int i, j, node;
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) },
};
pr_info("Getting EFI parameters from FDT:\n"); BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
info.found = 0; for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
info.params = &params; node = fdt_path_offset(fdt, dt_params[i].path);
if (node < 0)
continue;
ret = of_scan_flat_dt(fdt_find_uefi_params, &info); if (efi_enabled(EFI_DBG))
if (!info.found) { pr_info("Getting UEFI parameters from %s in DT:\n",
pr_info("UEFI not found.\n"); dt_params[i].path);
return 0;
} else if (!ret) { for (j = 0; j < ARRAY_SIZE(target); j++) {
pr_err("Can't find '%s' in device tree!\n", info.missing); const char *pname = dt_params[i].params[j];
return 0;
if (!efi_get_fdt_prop(fdt, node, pname, name[j],
target[j].var, target[j].size))
continue;
if (!j)
goto notfound;
pr_err("Can't find property '%s' in DT!\n", pname);
return 0;
}
return systab;
} }
notfound:
memmap->desc_version = params.desc_ver; pr_info("UEFI not found.\n");
memmap->desc_size = params.desc_size; return 0;
memmap->size = params.mmap_size;
memmap->phys_map = params.mmap;
return params.system_table;
} }