linux/drivers/firmware/efi/fdtparams.c
Ard Biesheuvel e457ed516a 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>
2020-02-23 21:59:42 +01:00

127 lines
2.9 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "efi: " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/efi.h>
#include <linux/libfdt.h>
#include <linux/of_fdt.h>
#include <asm/unaligned.h>
enum {
SYSTAB,
MMBASE,
MMSIZE,
DCSIZE,
DCVERS,
PARAMCOUNT
};
static __initconst const char name[][22] = {
[SYSTAB] = "System Table ",
[MMBASE] = "MemMap Address ",
[MMSIZE] = "MemMap Size ",
[DCSIZE] = "MemMap Desc. Size ",
[DCVERS] = "MemMap Desc. Version ",
};
static __initconst const struct {
const char path[17];
const char params[PARAMCOUNT][26];
} dt_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",
}
}
};
static int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
const char *rname, void *var, int size)
{
const void *prop;
int len;
u64 val;
prop = fdt_getprop(fdt, node, pname, &len);
if (!prop)
return 1;
val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
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", rname, size * 2, val);
return 0;
}
u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
{
const void *fdt = initial_boot_params;
unsigned long systab;
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) },
};
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++) {
node = fdt_path_offset(fdt, dt_params[i].path);
if (node < 0)
continue;
if (efi_enabled(EFI_DBG))
pr_info("Getting UEFI parameters from %s in DT:\n",
dt_params[i].path);
for (j = 0; j < ARRAY_SIZE(target); j++) {
const char *pname = dt_params[i].params[j];
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:
pr_info("UEFI not found.\n");
return 0;
}