Commit 0cac5c30 authored by Shannon Zhao's avatar Shannon Zhao Committed by David Vrabel

Xen: EFI: Parse DT parameters for Xen specific UEFI

The EFI DT parameters for bare metal are located under /chosen node,
while for Xen Dom0 they are located under /hyperviosr/uefi node. These
parameters under /chosen and /hyperviosr/uefi are not expected to appear
at the same time.

Parse these EFI parameters and initialize EFI like the way for bare
metal except the runtime services because the runtime services for Xen
Dom0 are available through hypercalls and they are always enabled. So it
sets the EFI_RUNTIME_SERVICES flag if it finds /hyperviosr/uefi node and
bails out in arm_enable_runtime_services() when EFI_RUNTIME_SERVICES
flag is set already.
Signed-off-by: default avatarShannon Zhao <shannon.zhao@linaro.org>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Signed-off-by: default avatarMatt Fleming <matt@codeblueprint.co.uk>
parent 9c609868
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
#include <asm/paravirt.h> #include <asm/paravirt.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
#include <asm/xen/xen-ops.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <asm/efi.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -261,6 +263,19 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, ...@@ -261,6 +263,19 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname,
!strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix)))
hyper_node.version = s + strlen(hyper_node.prefix); hyper_node.version = s + strlen(hyper_node.prefix);
/*
* Check if Xen supports EFI by checking whether there is the
* "/hypervisor/uefi" node in DT. If so, runtime services are available
* through proxy functions (e.g. in case of Xen dom0 EFI implementation
* they call special hypercall which executes relevant EFI functions)
* and that is why they are always enabled.
*/
if (IS_ENABLED(CONFIG_XEN_EFI)) {
if ((of_get_flat_dt_subnode_by_name(node, "uefi") > 0) &&
!efi_runtime_disabled())
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
}
return 0; return 0;
} }
...@@ -352,6 +367,13 @@ static int __init xen_guest_init(void) ...@@ -352,6 +367,13 @@ static int __init xen_guest_init(void)
return -ENODEV; return -ENODEV;
} }
/*
* The fdt parsing codes have set EFI_RUNTIME_SERVICES if Xen EFI
* parameters are found. Force enable runtime services.
*/
if (efi_enabled(EFI_RUNTIME_SERVICES))
xen_efi_runtime_setup();
shared_info_page = (struct shared_info *)get_zeroed_page(GFP_KERNEL); shared_info_page = (struct shared_info *)get_zeroed_page(GFP_KERNEL);
if (!shared_info_page) { if (!shared_info_page) {
......
...@@ -107,6 +107,11 @@ static int __init arm_enable_runtime_services(void) ...@@ -107,6 +107,11 @@ static int __init arm_enable_runtime_services(void)
return 0; return 0;
} }
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
pr_info("EFI runtime services access via paravirt.\n");
return 0;
}
pr_info("Remapping and enabling EFI services.\n"); pr_info("Remapping and enabling EFI services.\n");
mapsize = efi.memmap.map_end - efi.memmap.map; mapsize = efi.memmap.map_end - efi.memmap.map;
......
...@@ -472,12 +472,14 @@ device_initcall(efi_load_efivars); ...@@ -472,12 +472,14 @@ device_initcall(efi_load_efivars);
FIELD_SIZEOF(struct efi_fdt_params, field) \ FIELD_SIZEOF(struct efi_fdt_params, field) \
} }
static __initdata struct { struct params {
const char name[32]; const char name[32];
const char propname[32]; const char propname[32];
int offset; int offset;
int size; int size;
} dt_params[] = { };
static __initdata struct params fdt_params[] = {
UEFI_PARAM("System Table", "linux,uefi-system-table", system_table), UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap), UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size), UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
...@@ -485,44 +487,91 @@ static __initdata struct { ...@@ -485,44 +487,91 @@ static __initdata struct {
UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver) 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 { struct param_info {
int found; int found;
void *params; void *params;
const char *missing;
}; };
static int __init fdt_find_uefi_params(unsigned long node, const char *uname, static int __init __find_uefi_params(unsigned long node,
int depth, void *data) struct param_info *info,
struct params *params)
{ {
struct param_info *info = data;
const void *prop; const void *prop;
void *dest; void *dest;
u64 val; u64 val;
int i, len; int i, len;
if (depth != 1 || strcmp(uname, "chosen") != 0) for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) {
return 0; prop = of_get_flat_dt_prop(node, params[i].propname, &len);
if (!prop) {
for (i = 0; i < ARRAY_SIZE(dt_params); i++) { info->missing = params[i].name;
prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
if (!prop)
return 0; return 0;
dest = info->params + dt_params[i].offset; }
dest = info->params + params[i].offset;
info->found++; info->found++;
val = of_read_number(prop, len / sizeof(u32)); val = of_read_number(prop, len / sizeof(u32));
if (dt_params[i].size == sizeof(u32)) if (params[i].size == sizeof(u32))
*(u32 *)dest = val; *(u32 *)dest = val;
else else
*(u64 *)dest = val; *(u64 *)dest = val;
if (efi_enabled(EFI_DBG)) if (efi_enabled(EFI_DBG))
pr_info(" %s: 0x%0*llx\n", dt_params[i].name, pr_info(" %s: 0x%0*llx\n", params[i].name,
dt_params[i].size * 2, val); params[i].size * 2, val);
} }
return 1; 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) {
node = of_get_flat_dt_subnode_by_name(node, subnode);
if (node < 0)
return 0;
}
return __find_uefi_params(node, info, dt_params[i].params);
}
return 0;
}
int __init efi_get_fdt_params(struct efi_fdt_params *params) int __init efi_get_fdt_params(struct efi_fdt_params *params)
{ {
struct param_info info; struct param_info info;
...@@ -538,7 +587,7 @@ int __init efi_get_fdt_params(struct efi_fdt_params *params) ...@@ -538,7 +587,7 @@ int __init efi_get_fdt_params(struct efi_fdt_params *params)
pr_info("UEFI not found.\n"); pr_info("UEFI not found.\n");
else if (!ret) else if (!ret)
pr_err("Can't find '%s' in device tree!\n", pr_err("Can't find '%s' in device tree!\n",
dt_params[info.found].name); info.missing);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment