Skip to content

Commit

Permalink
efi/arm: Move FDT param discovery code out of efi.c
Browse files Browse the repository at this point in the history
On ARM systems, we discover the UEFI system table address and memory
map address from the /chosen node in the device tree, or in the Xen
case, from a similar node under /hypervisor.

Before making some functional changes to that code, move it into its
own file that only gets built if CONFIG_EFI_PARAMS_FROM_FDT=y.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
  • Loading branch information
Ard Biesheuvel committed Feb 23, 2020
1 parent 97aa276 commit ac5abc7
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 135 deletions.
1 change: 1 addition & 0 deletions drivers/firmware/efi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ KASAN_SANITIZE_runtime-wrappers.o := n
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o tpm.o
obj-$(CONFIG_EFI) += capsule.o memmap.o
obj-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdtparams.o
obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_ESRT) += esrt.o
obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
Expand Down
135 changes: 0 additions & 135 deletions drivers/firmware/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <linux/device.h>
#include <linux/efi.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/io.h>
#include <linux/kexec.h>
#include <linux/platform_device.h>
Expand Down Expand Up @@ -646,140 +645,6 @@ static int __init efi_load_efivars(void)
device_initcall(efi_load_efivars);
#endif

#ifdef CONFIG_EFI_PARAMS_FROM_FDT

#define UEFI_PARAM(name, prop, field) \
{ \
{ name }, \
{ prop }, \
offsetof(struct efi_fdt_params, field), \
sizeof_field(struct efi_fdt_params, field) \
}

struct params {
const char name[32];
const char propname[32];
int offset;
int size;
};

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 __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[] = {
{ "hypervisor", "uefi", xen_fdt_params },
{ "chosen", NULL, fdt_params },
};

struct param_info {
int found;
void *params;
const char *missing;
};

static int __init __find_uefi_params(unsigned long node,
struct param_info *info,
struct params *params)
{
const void *prop;
void *dest;
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++;

val = of_read_number(prop, len / sizeof(u32));

if (params[i].size == sizeof(u32))
*(u32 *)dest = 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;
}

int __init efi_get_fdt_params(struct efi_fdt_params *params)
{
struct param_info info;
int ret;

pr_info("Getting EFI parameters from FDT:\n");

info.found = 0;
info.params = params;

ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
if (!info.found)
pr_info("UEFI not found.\n");
else if (!ret)
pr_err("Can't find '%s' in device tree!\n",
info.missing);

return ret;
}
#endif /* CONFIG_EFI_PARAMS_FROM_FDT */

static __initdata char memory_type_name[][20] = {
"Reserved",
"Loader Code",
Expand Down
142 changes: 142 additions & 0 deletions drivers/firmware/efi/fdtparams.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// 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/of.h>
#include <linux/of_fdt.h>

#include <asm/early_ioremap.h>

#define UEFI_PARAM(name, prop, field) \
{ \
{ name }, \
{ prop }, \
offsetof(struct efi_fdt_params, field), \
sizeof_field(struct efi_fdt_params, field) \
}

struct params {
const char name[32];
const char propname[32];
int offset;
int size;
};

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 __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[] = {
{ "hypervisor", "uefi", xen_fdt_params },
{ "chosen", NULL, fdt_params },
};

struct param_info {
int found;
void *params;
const char *missing;
};

static int __init __find_uefi_params(unsigned long node,
struct param_info *info,
struct params *params)
{
const void *prop;
void *dest;
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++;

val = of_read_number(prop, len / sizeof(u32));

if (params[i].size == sizeof(u32))
*(u32 *)dest = 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;
}

int __init efi_get_fdt_params(struct efi_fdt_params *params)
{
struct param_info info;
int ret;

pr_info("Getting EFI parameters from FDT:\n");

info.found = 0;
info.params = params;

ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
if (!info.found)
pr_info("UEFI not found.\n");
else if (!ret)
pr_err("Can't find '%s' in device tree!\n",
info.missing);

return ret;
}

0 comments on commit ac5abc7

Please sign in to comment.