Hey,
This patch series adds EFI support for Xen dom0 guests.
It is based on Jan Beulich and Tang Liang work. I was
trying to take into account all previous comments,
however, if I missed something sorry for that.
Daniel
arch/x86/kernel/setup.c | 4 +-
arch/x86/platform/efi/efi.c | 106 ++++++++++--------------
arch/x86/xen/enlighten.c | 24 ++++++
drivers/firmware/efi/efi.c | 25 +++---
drivers/xen/Kconfig | 4 +
drivers/xen/Makefile | 3 +
drivers/xen/efi.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/efi.h | 4 +-
include/xen/interface/platform.h | 123 ++++++++++++++++++++++++++++
9 files changed, 583 insertions(+), 77 deletions(-)
Daniel Kiper (9):
efi: Use early_mem*() instead of early_io*()
arch/x86: Do not access EFI memory map if it is not available
efi: Introduce EFI_PARAVIRT flag
arch/x86: Remove redundant set_bit(EFI_SYSTEM_TABLES) call
arch/x86: Remove redundant set_bit(EFI_MEMMAP) call
xen: Define EFI related stuff
xen: Put EFI machinery in place
arch/x86: Replace plain strings with constants
arch/x86: Remove efi_set_rtc_mmss()
Define constants and structures which are needed to properly
execute EFI related hypercall in Xen dom0.
This patch is based on Jan Beulich and Tang Liang work.
Signed-off-by: Jan Beulich <[email protected]>
Signed-off-by: Tang Liang <[email protected]>
Signed-off-by: Daniel Kiper <[email protected]>
---
v6 - suggestions/fixes:
- fix indentation
(suggested by David Vrabel).
v5 - suggestions/fixes:
- improve commit message
(suggested by David Vrabel).
v4 - suggestions/fixes:
- change some types from generic to Xen specific ones
(suggested by Stefano Stabellini),
- do some formating changes
(suggested by Jan Beulich).
---
include/xen/interface/platform.h | 123 ++++++++++++++++++++++++++++++++++++++
1 file changed, 123 insertions(+)
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index f1331e3..5cc49ea 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -108,11 +108,113 @@ struct xenpf_platform_quirk {
};
DEFINE_GUEST_HANDLE_STRUCT(xenpf_platform_quirk_t);
+#define XENPF_efi_runtime_call 49
+#define XEN_EFI_get_time 1
+#define XEN_EFI_set_time 2
+#define XEN_EFI_get_wakeup_time 3
+#define XEN_EFI_set_wakeup_time 4
+#define XEN_EFI_get_next_high_monotonic_count 5
+#define XEN_EFI_get_variable 6
+#define XEN_EFI_set_variable 7
+#define XEN_EFI_get_next_variable_name 8
+#define XEN_EFI_query_variable_info 9
+#define XEN_EFI_query_capsule_capabilities 10
+#define XEN_EFI_update_capsule 11
+
+struct xenpf_efi_runtime_call {
+ uint32_t function;
+ /*
+ * This field is generally used for per sub-function flags (defined
+ * below), except for the XEN_EFI_get_next_high_monotonic_count case,
+ * where it holds the single returned value.
+ */
+ uint32_t misc;
+ xen_ulong_t status;
+ union {
+#define XEN_EFI_GET_TIME_SET_CLEARS_NS 0x00000001
+ struct {
+ struct xenpf_efi_time {
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t min;
+ uint8_t sec;
+ uint32_t ns;
+ int16_t tz;
+ uint8_t daylight;
+ } time;
+ uint32_t resolution;
+ uint32_t accuracy;
+ } get_time;
+
+ struct xenpf_efi_time set_time;
+
+#define XEN_EFI_GET_WAKEUP_TIME_ENABLED 0x00000001
+#define XEN_EFI_GET_WAKEUP_TIME_PENDING 0x00000002
+ struct xenpf_efi_time get_wakeup_time;
+
+#define XEN_EFI_SET_WAKEUP_TIME_ENABLE 0x00000001
+#define XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY 0x00000002
+ struct xenpf_efi_time set_wakeup_time;
+
+#define XEN_EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define XEN_EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define XEN_EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+ struct {
+ GUEST_HANDLE(void) name; /* UCS-2/UTF-16 string */
+ xen_ulong_t size;
+ GUEST_HANDLE(void) data;
+ struct xenpf_efi_guid {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+ } vendor_guid;
+ } get_variable, set_variable;
+
+ struct {
+ xen_ulong_t size;
+ GUEST_HANDLE(void) name; /* UCS-2/UTF-16 string */
+ struct xenpf_efi_guid vendor_guid;
+ } get_next_variable_name;
+
+ struct {
+ uint32_t attr;
+ uint64_t max_store_size;
+ uint64_t remain_store_size;
+ uint64_t max_size;
+ } query_variable_info;
+
+ struct {
+ GUEST_HANDLE(void) capsule_header_array;
+ xen_ulong_t capsule_count;
+ uint64_t max_capsule_size;
+ uint32_t reset_type;
+ } query_capsule_capabilities;
+
+ struct {
+ GUEST_HANDLE(void) capsule_header_array;
+ xen_ulong_t capsule_count;
+ uint64_t sg_list; /* machine address */
+ } update_capsule;
+ } u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_efi_runtime_call);
+
+#define XEN_FW_EFI_VERSION 0
+#define XEN_FW_EFI_CONFIG_TABLE 1
+#define XEN_FW_EFI_VENDOR 2
+#define XEN_FW_EFI_MEM_INFO 3
+#define XEN_FW_EFI_RT_VERSION 4
+
#define XENPF_firmware_info 50
#define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */
#define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */
#define XEN_FW_VBEDDC_INFO 3 /* from int 10 AX=4f15 */
+#define XEN_FW_EFI_INFO 4 /* from EFI */
#define XEN_FW_KBD_SHIFT_FLAGS 5 /* Int16, Fn02: Get keyboard shift flags. */
+
struct xenpf_firmware_info {
/* IN variables. */
uint32_t type;
@@ -144,6 +246,26 @@ struct xenpf_firmware_info {
GUEST_HANDLE(uchar) edid;
} vbeddc_info; /* XEN_FW_VBEDDC_INFO */
+ union xenpf_efi_info {
+ uint32_t version;
+ struct {
+ uint64_t addr; /* EFI_CONFIGURATION_TABLE */
+ uint32_t nent;
+ } cfg;
+ struct {
+ uint32_t revision;
+ uint32_t bufsz; /* input, in bytes */
+ GUEST_HANDLE(void) name;
+ /* UCS-2/UTF-16 string */
+ } vendor;
+ struct {
+ uint64_t addr;
+ uint64_t size;
+ uint64_t attr;
+ uint32_t type;
+ } mem;
+ } efi_info; /* XEN_FW_EFI_INFO */
+
uint8_t kbd_shift_flags; /* XEN_FW_KBD_SHIFT_FLAGS */
} u;
};
@@ -362,6 +484,7 @@ struct xen_platform_op {
struct xenpf_read_memtype read_memtype;
struct xenpf_microcode_update microcode;
struct xenpf_platform_quirk platform_quirk;
+ struct xenpf_efi_runtime_call efi_runtime_call;
struct xenpf_firmware_info firmware_info;
struct xenpf_enter_acpi_sleep enter_acpi_sleep;
struct xenpf_change_freq change_freq;
--
1.7.10.4
Introduce EFI_PARAVIRT flag. If it is set then kernel runs
on EFI platform but it has not direct control on EFI stuff
like EFI runtime, tables, structures, etc. If not this means
that Linux Kernel has direct access to EFI infrastructure
and everything runs as usual.
This functionality is used in Xen dom0 because hypervisor
has full control on EFI stuff and all calls from dom0 to
EFI must be requested via special hypercall which in turn
executes relevant EFI code in behalf of dom0.
Signed-off-by: Daniel Kiper <[email protected]>
---
v6 - suggestions/fixes:
- rename EFI_NO_DIRECT to EFI_PARAVIRT
(suggested by David Vrabel),
- improve code comments
(suggested by Matt Fleming).
v5 - suggestions/fixes:
- rename EFI_DIRECT to EFI_NO_DIRECT
(suggested by David Vrabel),
- limit EFI_NO_DIRECT usage
(suggested by Jan Beulich and Matt Fleming),
- improve commit message
(suggested by David Vrabel).
---
arch/x86/platform/efi/efi.c | 31 +++++++++++++++++++++++++------
drivers/firmware/efi/efi.c | 21 ++++++++++++---------
include/linux/efi.h | 3 ++-
3 files changed, 39 insertions(+), 16 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index d2d3c41..b9c23d7 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -350,6 +350,9 @@ int __init efi_memblock_x86_reserve_range(void)
struct efi_info *e = &boot_params.efi_info;
unsigned long pmap;
+ if (efi_enabled(EFI_PARAVIRT))
+ return 0;
+
#ifdef CONFIG_X86_32
/* Can't handle data above 4GB at this time */
if (e->efi_memmap_hi) {
@@ -616,14 +619,24 @@ static int __init efi_runtime_init(void)
* the runtime services table so that we can grab the physical
* address of several of the EFI runtime functions, needed to
* set the firmware into virtual mode.
+ *
+ * When EFI_PARAVIRT is in force then we could not map runtime
+ * service memory region because we do not have direct access to it.
+ * However, 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 (efi_enabled(EFI_64BIT))
- rv = efi_runtime_init64();
- else
- rv = efi_runtime_init32();
- if (rv)
- return rv;
+ if (!efi_enabled(EFI_PARAVIRT)) {
+ if (efi_enabled(EFI_64BIT))
+ rv = efi_runtime_init64();
+ else
+ rv = efi_runtime_init32();
+
+ if (rv)
+ return rv;
+ }
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
@@ -632,6 +645,9 @@ static int __init efi_runtime_init(void)
static int __init efi_memmap_init(void)
{
+ if (efi_enabled(EFI_PARAVIRT))
+ return 0;
+
/* Map the EFI memory map */
memmap.map = early_memremap((unsigned long)memmap.phys_map,
memmap.nr_map * memmap.desc_size);
@@ -1188,6 +1204,9 @@ static void __init __efi_enter_virtual_mode(void)
void __init efi_enter_virtual_mode(void)
{
+ if (efi_enabled(EFI_PARAVIRT))
+ return;
+
if (efi_setup)
kexec_enter_virtual_mode();
else
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 023937a..ac88ec0 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -104,16 +104,19 @@ static struct attribute *efi_subsys_attrs[] = {
static umode_t efi_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
- umode_t mode = attr->mode;
-
- if (attr == &efi_attr_fw_vendor.attr)
- return (efi.fw_vendor == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
- else if (attr == &efi_attr_runtime.attr)
- return (efi.runtime == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
- else if (attr == &efi_attr_config_table.attr)
- return (efi.config_table == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
+ if (attr == &efi_attr_fw_vendor.attr) {
+ if (efi_enabled(EFI_PARAVIRT) ||
+ efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
+ return 0;
+ } else if (attr == &efi_attr_runtime.attr) {
+ if (efi.runtime == EFI_INVALID_TABLE_ADDR)
+ return 0;
+ } else if (attr == &efi_attr_config_table.attr) {
+ if (efi.config_table == EFI_INVALID_TABLE_ADDR)
+ return 0;
+ }
- return mode;
+ return attr->mode;
}
static struct attribute_group efi_subsys_attr_group = {
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 41bbf8b..713a4f1 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -916,7 +916,8 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */
#define EFI_MEMMAP 4 /* Can we use EFI memory map? */
#define EFI_64BIT 5 /* Is the firmware 64-bit? */
-#define EFI_ARCH_1 6 /* First arch-specific bit */
+#define EFI_PARAVIRT 6 /* Access is via a paravirt interface */
+#define EFI_ARCH_1 7 /* First arch-specific bit */
#ifdef CONFIG_EFI
/*
--
1.7.10.4
We've got constants, so let's use them instead of hard-coded values.
Signed-off-by: Daniel Kiper <[email protected]>
---
v6 - suggestions/fixes:
- improve commit message
(suggested by Matt Fleming).
---
arch/x86/kernel/setup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 78a0e62..41ead8d 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -924,10 +924,10 @@ void __init setup_arch(char **cmdline_p)
#endif
#ifdef CONFIG_EFI
if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
- "EL32", 4)) {
+ EFI32_LOADER_SIGNATURE, 4)) {
set_bit(EFI_BOOT, &efi.flags);
} else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
- "EL64", 4)) {
+ EFI64_LOADER_SIGNATURE, 4)) {
set_bit(EFI_BOOT, &efi.flags);
set_bit(EFI_64BIT, &efi.flags);
}
--
1.7.10.4
This patch enables EFI usage under Xen dom0. Standard EFI Linux
Kernel infrastructure cannot be used because it requires direct
access to EFI data and code. However, in dom0 case it is not possible
because above mentioned EFI stuff is fully owned and controlled
by Xen hypervisor. In this case all calls from dom0 to EFI must
be requested via special hypercall which in turn executes relevant
EFI code in behalf of dom0.
When dom0 kernel boots it checks for EFI availability on a machine.
If it is detected then artificial EFI system table is filled.
Native EFI callas are replaced by functions which mimics them
by calling relevant hypercall. Later pointer to EFI system table
is passed to standard EFI machinery and it continues EFI subsystem
initialization taking into account that there is no direct access
to EFI boot services, runtime, tables, structures, etc. After that
system runs as usual.
This patch is based on Jan Beulich and Tang Liang work.
Signed-off-by: Jan Beulich <[email protected]>
Signed-off-by: Tang Liang <[email protected]>
Signed-off-by: Daniel Kiper <[email protected]>
---
v6 - suggestions/fixes:
- remove unneeded BUG() call
(suggested by Stefano Stabellini).
v5 - suggestions/fixes:
- improve macro usage readability
(suggested by Andrew Cooper and David Vrabel),
- conditions cleanup
(suggested by David Vrabel),
- use -fshort-wchar option
(suggested by Jan Beulich),
- Kconfig rule cleanup
(suggested by Jan Beulich),
- forward port fixes from SUSE kernel
(suggested by Jan Beulich),
- improve commit message
(suggested by David Vrabel).
v4 - suggestions/fixes:
- "just populate an efi_system_table_t object"
(suggested by Matt Fleming).
---
arch/x86/xen/enlighten.c | 24 +++
drivers/xen/Kconfig | 4 +
drivers/xen/Makefile | 3 +
drivers/xen/efi.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 398 insertions(+)
create mode 100644 drivers/xen/efi.c
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index ffb101e..04611ea 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -32,6 +32,7 @@
#include <linux/gfp.h>
#include <linux/memblock.h>
#include <linux/edd.h>
+#include <linux/efi.h>
#include <xen/xen.h>
#include <xen/events.h>
@@ -150,6 +151,15 @@ struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info;
*/
static int have_vcpu_info_placement = 1;
+#ifdef CONFIG_XEN_EFI
+extern efi_system_table_t __init *xen_efi_probe(void);
+#else
+static efi_system_table_t __init *xen_efi_probe(void)
+{
+ return NULL;
+}
+#endif
+
struct tls_descs {
struct desc_struct desc[3];
};
@@ -1520,6 +1530,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
{
struct physdev_set_iopl set_iopl;
int rc;
+ efi_system_table_t *efi_systab_xen;
if (!xen_start_info)
return;
@@ -1718,6 +1729,19 @@ asmlinkage __visible void __init xen_start_kernel(void)
xen_setup_runstate_info(0);
+ efi_systab_xen = xen_efi_probe();
+
+ if (efi_systab_xen) {
+ strncpy((char *)&boot_params.efi_info.efi_loader_signature, "Xen",
+ sizeof(boot_params.efi_info.efi_loader_signature));
+ boot_params.efi_info.efi_systab = (__u32)__pa(efi_systab_xen);
+ boot_params.efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32);
+
+ set_bit(EFI_BOOT, &efi.flags);
+ set_bit(EFI_PARAVIRT, &efi.flags);
+ set_bit(EFI_64BIT, &efi.flags);
+ }
+
/* Start the world */
#ifdef CONFIG_X86_32
i386_start_kernel();
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 38fb36e..8bc0183 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -240,4 +240,8 @@ config XEN_MCE_LOG
config XEN_HAVE_PVMMU
bool
+config XEN_EFI
+ def_bool y
+ depends on X86_64 && EFI
+
endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 45e00af..84044b5 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -9,6 +9,8 @@ obj-y += xenbus/
nostackp := $(call cc-option, -fno-stack-protector)
CFLAGS_features.o := $(nostackp)
+CFLAGS_efi.o += -fshort-wchar
+
dom0-$(CONFIG_PCI) += pci.o
dom0-$(CONFIG_USB_SUPPORT) += dbgp.o
dom0-$(CONFIG_ACPI) += acpi.o $(xen-pad-y)
@@ -33,6 +35,7 @@ obj-$(CONFIG_XEN_STUB) += xen-stub.o
obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o
obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o
obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
+obj-$(CONFIG_XEN_EFI) += efi.o
xen-evtchn-y := evtchn.o
xen-gntdev-y := gntdev.o
xen-gntalloc-y := gntalloc.o
diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
new file mode 100644
index 0000000..d8d55a5
--- /dev/null
+++ b/drivers/xen/efi.c
@@ -0,0 +1,367 @@
+/*
+ * EFI support for Xen.
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <[email protected]>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ * David Mosberger-Tang <[email protected]>
+ * Stephane Eranian <[email protected]>
+ * Copyright (C) 2005-2008 Intel Co.
+ * Fenghua Yu <[email protected]>
+ * Bibo Mao <[email protected]>
+ * Chandramouli Narayanan <[email protected]>
+ * Huang Ying <[email protected]>
+ * Copyright (C) 2011 Novell Co.
+ * Jan Beulich <[email protected]>
+ * Copyright (C) 2011-2012 Oracle Co.
+ * Liang Tang <[email protected]>
+ * Copyright (c) 2014 Oracle Co., Daniel Kiper
+ */
+
+#include <linux/bug.h>
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/platform.h>
+
+#include <asm/xen/hypercall.h>
+
+#define INIT_EFI_OP(name) \
+ {.cmd = XENPF_efi_runtime_call, \
+ .u.efi_runtime_call.function = XEN_EFI_##name, \
+ .u.efi_runtime_call.misc = 0}
+
+#define efi_data(op) (op.u.efi_runtime_call)
+
+static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+ struct xen_platform_op op = INIT_EFI_OP(get_time);
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ if (tm) {
+ BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_time.time));
+ memcpy(tm, &efi_data(op).u.get_time.time, sizeof(*tm));
+ }
+
+ if (tc) {
+ tc->resolution = efi_data(op).u.get_time.resolution;
+ tc->accuracy = efi_data(op).u.get_time.accuracy;
+ tc->sets_to_zero = !!(efi_data(op).misc &
+ XEN_EFI_GET_TIME_SET_CLEARS_NS);
+ }
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_set_time(efi_time_t *tm)
+{
+ struct xen_platform_op op = INIT_EFI_OP(set_time);
+
+ BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time));
+ memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm));
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
+ efi_bool_t *pending,
+ efi_time_t *tm)
+{
+ struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time);
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ if (tm) {
+ BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_wakeup_time));
+ memcpy(tm, &efi_data(op).u.get_wakeup_time, sizeof(*tm));
+ }
+
+ if (enabled)
+ *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
+
+ if (pending)
+ *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+ struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time);
+
+ BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time));
+ if (enabled)
+ efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
+ if (tm)
+ memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm));
+ else
+ efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_get_variable(efi_char16_t *name,
+ efi_guid_t *vendor,
+ u32 *attr,
+ unsigned long *data_size,
+ void *data)
+{
+ struct xen_platform_op op = INIT_EFI_OP(get_variable);
+
+ set_xen_guest_handle(efi_data(op).u.get_variable.name, name);
+ BUILD_BUG_ON(sizeof(*vendor) !=
+ sizeof(efi_data(op).u.get_variable.vendor_guid));
+ memcpy(&efi_data(op).u.get_variable.vendor_guid, vendor, sizeof(*vendor));
+ efi_data(op).u.get_variable.size = *data_size;
+ set_xen_guest_handle(efi_data(op).u.get_variable.data, data);
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ *data_size = efi_data(op).u.get_variable.size;
+ if (attr)
+ *attr = efi_data(op).misc;
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
+ efi_char16_t *name,
+ efi_guid_t *vendor)
+{
+ struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name);
+
+ efi_data(op).u.get_next_variable_name.size = *name_size;
+ set_xen_guest_handle(efi_data(op).u.get_next_variable_name.name, name);
+ BUILD_BUG_ON(sizeof(*vendor) !=
+ sizeof(efi_data(op).u.get_next_variable_name.vendor_guid));
+ memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor,
+ sizeof(*vendor));
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ *name_size = efi_data(op).u.get_next_variable_name.size;
+ memcpy(vendor, &efi_data(op).u.get_next_variable_name.vendor_guid,
+ sizeof(*vendor));
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_set_variable(efi_char16_t *name,
+ efi_guid_t *vendor,
+ u32 attr,
+ unsigned long data_size,
+ void *data)
+{
+ struct xen_platform_op op = INIT_EFI_OP(set_variable);
+
+ set_xen_guest_handle(efi_data(op).u.set_variable.name, name);
+ efi_data(op).misc = attr;
+ BUILD_BUG_ON(sizeof(*vendor) !=
+ sizeof(efi_data(op).u.set_variable.vendor_guid));
+ memcpy(&efi_data(op).u.set_variable.vendor_guid, vendor, sizeof(*vendor));
+ efi_data(op).u.set_variable.size = data_size;
+ set_xen_guest_handle(efi_data(op).u.set_variable.data, data);
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_query_variable_info(u32 attr,
+ u64 *storage_space,
+ u64 *remaining_space,
+ u64 *max_variable_size)
+{
+ struct xen_platform_op op = INIT_EFI_OP(query_variable_info);
+
+ if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+ return EFI_UNSUPPORTED;
+
+ efi_data(op).u.query_variable_info.attr = attr;
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ *storage_space = efi_data(op).u.query_variable_info.max_store_size;
+ *remaining_space = efi_data(op).u.query_variable_info.remain_store_size;
+ *max_variable_size = efi_data(op).u.query_variable_info.max_size;
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
+{
+ struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count);
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ *count = efi_data(op).misc;
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
+ unsigned long count,
+ unsigned long sg_list)
+{
+ struct xen_platform_op op = INIT_EFI_OP(update_capsule);
+
+ if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+ return EFI_UNSUPPORTED;
+
+ set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array,
+ capsules);
+ efi_data(op).u.update_capsule.capsule_count = count;
+ efi_data(op).u.update_capsule.sg_list = sg_list;
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ return efi_data(op).status;
+}
+
+static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
+ unsigned long count,
+ u64 *max_size,
+ int *reset_type)
+{
+ struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities);
+
+ if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+ return EFI_UNSUPPORTED;
+
+ set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array,
+ capsules);
+ efi_data(op).u.query_capsule_capabilities.capsule_count = count;
+
+ if (HYPERVISOR_dom0_op(&op) < 0)
+ return EFI_UNSUPPORTED;
+
+ *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size;
+ *reset_type = efi_data(op).u.query_capsule_capabilities.reset_type;
+
+ return efi_data(op).status;
+}
+
+static efi_char16_t vendor[100] __initdata;
+
+static efi_system_table_t efi_systab_xen __initdata = {
+ .hdr = {
+ .signature = EFI_SYSTEM_TABLE_SIGNATURE,
+ .revision = 0, /* Initialized later. */
+ .headersize = 0, /* Ignored by Linux Kernel. */
+ .crc32 = 0, /* Ignored by Linux Kernel. */
+ .reserved = 0
+ },
+ .fw_vendor = EFI_INVALID_TABLE_ADDR, /* Initialized later. */
+ .fw_revision = 0, /* Initialized later. */
+ .con_in_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
+ .con_in = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
+ .con_out_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
+ .con_out = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
+ .stderr_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
+ .stderr = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
+ .runtime = (efi_runtime_services_t *)EFI_INVALID_TABLE_ADDR,
+ /* Not used under Xen. */
+ .boottime = (efi_boot_services_t *)EFI_INVALID_TABLE_ADDR,
+ /* Not used under Xen. */
+ .nr_tables = 0, /* Initialized later. */
+ .tables = EFI_INVALID_TABLE_ADDR /* Initialized later. */
+};
+
+static const struct efi efi_xen __initconst = {
+ .systab = NULL, /* Initialized later. */
+ .runtime_version = 0, /* Initialized later. */
+ .mps = EFI_INVALID_TABLE_ADDR,
+ .acpi = EFI_INVALID_TABLE_ADDR,
+ .acpi20 = EFI_INVALID_TABLE_ADDR,
+ .smbios = EFI_INVALID_TABLE_ADDR,
+ .sal_systab = EFI_INVALID_TABLE_ADDR,
+ .boot_info = EFI_INVALID_TABLE_ADDR,
+ .hcdp = EFI_INVALID_TABLE_ADDR,
+ .uga = EFI_INVALID_TABLE_ADDR,
+ .uv_systab = EFI_INVALID_TABLE_ADDR,
+ .fw_vendor = EFI_INVALID_TABLE_ADDR,
+ .runtime = EFI_INVALID_TABLE_ADDR,
+ .config_table = EFI_INVALID_TABLE_ADDR,
+ .get_time = xen_efi_get_time,
+ .set_time = xen_efi_set_time,
+ .get_wakeup_time = xen_efi_get_wakeup_time,
+ .set_wakeup_time = xen_efi_set_wakeup_time,
+ .get_variable = xen_efi_get_variable,
+ .get_next_variable = xen_efi_get_next_variable,
+ .set_variable = xen_efi_set_variable,
+ .query_variable_info = xen_efi_query_variable_info,
+ .update_capsule = xen_efi_update_capsule,
+ .query_capsule_caps = xen_efi_query_capsule_caps,
+ .get_next_high_mono_count = xen_efi_get_next_high_mono_count,
+ .reset_system = NULL, /* Functionality provided by Xen. */
+ .set_virtual_address_map = NULL, /* Not used under Xen. */
+ .memmap = NULL, /* Not used under Xen. */
+ .flags = 0 /* Initialized later. */
+};
+
+efi_system_table_t __init *xen_efi_probe(void)
+{
+ struct xen_platform_op op = {
+ .cmd = XENPF_firmware_info,
+ .u.firmware_info = {
+ .type = XEN_FW_EFI_INFO,
+ .index = XEN_FW_EFI_CONFIG_TABLE
+ }
+ };
+ union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+
+ if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op) < 0)
+ return NULL;
+
+ /* Here we know that Xen runs on EFI platform. */
+
+ efi = efi_xen;
+
+ efi_systab_xen.tables = info->cfg.addr;
+ efi_systab_xen.nr_tables = info->cfg.nent;
+
+ op.cmd = XENPF_firmware_info;
+ op.u.firmware_info.type = XEN_FW_EFI_INFO;
+ op.u.firmware_info.index = XEN_FW_EFI_VENDOR;
+ info->vendor.bufsz = sizeof(vendor);
+ set_xen_guest_handle(info->vendor.name, vendor);
+
+ if (HYPERVISOR_dom0_op(&op) == 0) {
+ efi_systab_xen.fw_vendor = __pa_symbol(vendor);
+ efi_systab_xen.fw_revision = info->vendor.revision;
+ } else
+ efi_systab_xen.fw_vendor = __pa_symbol(L"UNKNOWN");
+
+ op.cmd = XENPF_firmware_info;
+ op.u.firmware_info.type = XEN_FW_EFI_INFO;
+ op.u.firmware_info.index = XEN_FW_EFI_VERSION;
+
+ if (HYPERVISOR_dom0_op(&op) == 0)
+ efi_systab_xen.hdr.revision = info->version;
+
+ op.cmd = XENPF_firmware_info;
+ op.u.firmware_info.type = XEN_FW_EFI_INFO;
+ op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
+
+ if (HYPERVISOR_dom0_op(&op) == 0)
+ efi.runtime_version = info->version;
+
+ return &efi_systab_xen;
+}
--
1.7.10.4
efi_set_rtc_mmss() is never used to set RTC due to bugs found
on many EFI platforms. It is set directly by mach_set_rtc_mmss().
Hence, remove unused efi_set_rtc_mmss() function.
Signed-off-by: Daniel Kiper <[email protected]>
---
v6 - suggestions/fixes:
- remove efi_set_rtc_mmss() instead of commenting out it
(suggested by Stefano Stabellini, Juergen Gross,
H. Peter Anvin and Matt Fleming).
---
arch/x86/platform/efi/efi.c | 36 ------------------------------------
include/linux/efi.h | 1 -
2 files changed, 37 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index da15df9..d569eea 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -244,42 +244,6 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
return status;
}
-int efi_set_rtc_mmss(const struct timespec *now)
-{
- unsigned long nowtime = now->tv_sec;
- efi_status_t status;
- efi_time_t eft;
- efi_time_cap_t cap;
- struct rtc_time tm;
-
- status = efi.get_time(&eft, &cap);
- if (status != EFI_SUCCESS) {
- pr_err("Oops: efitime: can't read time!\n");
- return -1;
- }
-
- rtc_time_to_tm(nowtime, &tm);
- if (!rtc_valid_tm(&tm)) {
- eft.year = tm.tm_year + 1900;
- eft.month = tm.tm_mon + 1;
- eft.day = tm.tm_mday;
- eft.minute = tm.tm_min;
- eft.second = tm.tm_sec;
- eft.nanosecond = 0;
- } else {
- pr_err("%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
- __func__, nowtime);
- return -1;
- }
-
- status = efi.set_time(&eft);
- if (status != EFI_SUCCESS) {
- pr_err("Oops: efitime: can't write time!\n");
- return -1;
- }
- return 0;
-}
-
void efi_get_time(struct timespec *now)
{
efi_status_t status;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 713a4f1..322366b 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -870,7 +870,6 @@ extern int __init efi_uart_console_only (void);
extern void efi_initialize_iomem_resources(struct resource *code_resource,
struct resource *data_resource, struct resource *bss_resource);
extern void efi_get_time(struct timespec *now);
-extern int efi_set_rtc_mmss(const struct timespec *now);
extern void efi_reserve_boot_services(void);
extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
extern struct efi_memory_map memmap;
--
1.7.10.4
Do not access EFI memory map if it is not available. At least
Xen dom0 EFI implementation does not have an access to it.
Signed-off-by: Daniel Kiper <[email protected]>
---
v6 - suggestions/fixes:
- create this separate patch from main EFI_PARAVIRT patch
(suggested by Matt Fleming).
---
arch/x86/platform/efi/efi.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 0ee1f46..d2d3c41 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -1220,6 +1220,9 @@ u64 efi_mem_attributes(unsigned long phys_addr)
efi_memory_desc_t *md;
void *p;
+ if (!efi_enabled(EFI_MEMMAP))
+ return 0;
+
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
if ((md->phys_addr <= phys_addr) &&
--
1.7.10.4
Use early_mem*() instead of early_io*() because all mapped EFI regions
are memory (usually RAM but they could also be ROM, EPROM, EEPROM, flash,
etc.) not I/O regions. Additionally, I/O family calls do not work correctly
under Xen in our case. early_ioremap() skips the PFN to MFN conversion
when building the PTE. Using it for memory will attempt to map the wrong
machine frame. However, all artificial EFI structures created under Xen
live in dom0 memory and should be mapped/unmapped using early_mem*() family
calls which map domain memory.
Signed-off-by: Daniel Kiper <[email protected]>
---
v6 - suggestions/fixes:
- improve commit message
(suggested by Matthew Garrett and Matt Fleming),
- do not change indentation
(suggested by Matt Fleming).
---
arch/x86/platform/efi/efi.c | 32 ++++++++++++++++----------------
drivers/firmware/efi/efi.c | 4 ++--
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 87fc96b..0ee1f46 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -427,7 +427,7 @@ void __init efi_unmap_memmap(void)
{
clear_bit(EFI_MEMMAP, &efi.flags);
if (memmap.map) {
- early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
+ early_memunmap(memmap.map, memmap.nr_map * memmap.desc_size);
memmap.map = NULL;
}
}
@@ -467,12 +467,12 @@ static int __init efi_systab_init(void *phys)
if (!data)
return -ENOMEM;
}
- systab64 = early_ioremap((unsigned long)phys,
+ systab64 = early_memremap((unsigned long)phys,
sizeof(*systab64));
if (systab64 == NULL) {
pr_err("Couldn't map the system table!\n");
if (data)
- early_iounmap(data, sizeof(*data));
+ early_memunmap(data, sizeof(*data));
return -ENOMEM;
}
@@ -504,9 +504,9 @@ static int __init efi_systab_init(void *phys)
systab64->tables;
tmp |= data ? data->tables : systab64->tables;
- early_iounmap(systab64, sizeof(*systab64));
+ early_memunmap(systab64, sizeof(*systab64));
if (data)
- early_iounmap(data, sizeof(*data));
+ early_memunmap(data, sizeof(*data));
#ifdef CONFIG_X86_32
if (tmp >> 32) {
pr_err("EFI data located above 4GB, disabling EFI.\n");
@@ -516,7 +516,7 @@ static int __init efi_systab_init(void *phys)
} else {
efi_system_table_32_t *systab32;
- systab32 = early_ioremap((unsigned long)phys,
+ systab32 = early_memremap((unsigned long)phys,
sizeof(*systab32));
if (systab32 == NULL) {
pr_err("Couldn't map the system table!\n");
@@ -537,7 +537,7 @@ static int __init efi_systab_init(void *phys)
efi_systab.nr_tables = systab32->nr_tables;
efi_systab.tables = systab32->tables;
- early_iounmap(systab32, sizeof(*systab32));
+ early_memunmap(systab32, sizeof(*systab32));
}
efi.systab = &efi_systab;
@@ -563,7 +563,7 @@ static int __init efi_runtime_init32(void)
{
efi_runtime_services_32_t *runtime;
- runtime = early_ioremap((unsigned long)efi.systab->runtime,
+ runtime = early_memremap((unsigned long)efi.systab->runtime,
sizeof(efi_runtime_services_32_t));
if (!runtime) {
pr_err("Could not map the runtime service table!\n");
@@ -578,7 +578,7 @@ static int __init efi_runtime_init32(void)
efi_phys.set_virtual_address_map =
(efi_set_virtual_address_map_t *)
(unsigned long)runtime->set_virtual_address_map;
- early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
+ early_memunmap(runtime, sizeof(efi_runtime_services_32_t));
return 0;
}
@@ -587,7 +587,7 @@ static int __init efi_runtime_init64(void)
{
efi_runtime_services_64_t *runtime;
- runtime = early_ioremap((unsigned long)efi.systab->runtime,
+ runtime = early_memremap((unsigned long)efi.systab->runtime,
sizeof(efi_runtime_services_64_t));
if (!runtime) {
pr_err("Could not map the runtime service table!\n");
@@ -602,7 +602,7 @@ static int __init efi_runtime_init64(void)
efi_phys.set_virtual_address_map =
(efi_set_virtual_address_map_t *)
(unsigned long)runtime->set_virtual_address_map;
- early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
+ early_memunmap(runtime, sizeof(efi_runtime_services_64_t));
return 0;
}
@@ -633,7 +633,7 @@ static int __init efi_runtime_init(void)
static int __init efi_memmap_init(void)
{
/* Map the EFI memory map */
- memmap.map = early_ioremap((unsigned long)memmap.phys_map,
+ memmap.map = early_memremap((unsigned long)memmap.phys_map,
memmap.nr_map * memmap.desc_size);
if (memmap.map == NULL) {
pr_err("Could not map the memory map!\n");
@@ -697,10 +697,10 @@ static int __init efi_reuse_config(u64 tables, int nr_tables)
((efi_config_table_64_t *)p)->table = data->smbios;
p += sz;
}
- early_iounmap(tablep, nr_tables * sz);
+ early_memunmap(tablep, nr_tables * sz);
out_memremap:
- early_iounmap(data, sizeof(*data));
+ early_memunmap(data, sizeof(*data));
out:
return ret;
}
@@ -737,14 +737,14 @@ void __init efi_init(void)
/*
* Show what we know for posterity
*/
- c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2);
+ c16 = tmp = early_memremap(efi.systab->fw_vendor, 2);
if (c16) {
for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
vendor[i] = *c16++;
vendor[i] = '\0';
} else
pr_err("Could not map the firmware vendor!\n");
- early_iounmap(tmp, 2);
+ early_memunmap(tmp, 2);
pr_info("EFI v%u.%.02u by %s\n",
efi.systab->hdr.revision >> 16,
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index cd36deb..023937a 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -298,7 +298,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
if (table64 >> 32) {
pr_cont("\n");
pr_err("Table located above 4GB, disabling EFI.\n");
- early_iounmap(config_tables,
+ early_memunmap(config_tables,
efi.systab->nr_tables * sz);
return -EINVAL;
}
@@ -314,7 +314,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
tablep += sz;
}
pr_cont("\n");
- early_iounmap(config_tables, efi.systab->nr_tables * sz);
+ early_memunmap(config_tables, efi.systab->nr_tables * sz);
set_bit(EFI_CONFIG_TABLES, &efi.flags);
--
1.7.10.4
Remove redundant set_bit(EFI_MEMMAP, &efi.flags) call.
It is executed earlier in efi_memmap_init().
Signed-off-by: Daniel Kiper <[email protected]>
---
arch/x86/platform/efi/efi.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index ae3d398..da15df9 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -784,8 +784,6 @@ void __init efi_init(void)
if (efi_memmap_init())
return;
- set_bit(EFI_MEMMAP, &efi.flags);
-
print_efi_memmap();
}
--
1.7.10.4
Remove redundant set_bit(EFI_SYSTEM_TABLES, &efi.flags) call.
It is executed earlier in efi_systab_init().
Signed-off-by: Daniel Kiper <[email protected]>
---
arch/x86/platform/efi/efi.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index b9c23d7..ae3d398 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -744,8 +744,6 @@ void __init efi_init(void)
if (efi_systab_init(efi_phys.systab))
return;
- set_bit(EFI_SYSTEM_TABLES, &efi.flags);
-
efi.config_table = (unsigned long)efi.systab->tables;
efi.fw_vendor = (unsigned long)efi.systab->fw_vendor;
efi.runtime = (unsigned long)efi.systab->runtime;
--
1.7.10.4
On Fri, 20 Jun 2014, Daniel Kiper wrote:
> This patch enables EFI usage under Xen dom0. Standard EFI Linux
> Kernel infrastructure cannot be used because it requires direct
> access to EFI data and code. However, in dom0 case it is not possible
> because above mentioned EFI stuff is fully owned and controlled
> by Xen hypervisor. In this case all calls from dom0 to EFI must
> be requested via special hypercall which in turn executes relevant
> EFI code in behalf of dom0.
>
> When dom0 kernel boots it checks for EFI availability on a machine.
> If it is detected then artificial EFI system table is filled.
> Native EFI callas are replaced by functions which mimics them
> by calling relevant hypercall. Later pointer to EFI system table
> is passed to standard EFI machinery and it continues EFI subsystem
> initialization taking into account that there is no direct access
> to EFI boot services, runtime, tables, structures, etc. After that
> system runs as usual.
>
> This patch is based on Jan Beulich and Tang Liang work.
>
> Signed-off-by: Jan Beulich <[email protected]>
> Signed-off-by: Tang Liang <[email protected]>
> Signed-off-by: Daniel Kiper <[email protected]>
> ---
> v6 - suggestions/fixes:
> - remove unneeded BUG() call
> (suggested by Stefano Stabellini).
>
> v5 - suggestions/fixes:
> - improve macro usage readability
> (suggested by Andrew Cooper and David Vrabel),
> - conditions cleanup
> (suggested by David Vrabel),
> - use -fshort-wchar option
> (suggested by Jan Beulich),
> - Kconfig rule cleanup
> (suggested by Jan Beulich),
> - forward port fixes from SUSE kernel
> (suggested by Jan Beulich),
> - improve commit message
> (suggested by David Vrabel).
>
> v4 - suggestions/fixes:
> - "just populate an efi_system_table_t object"
> (suggested by Matt Fleming).
> ---
> arch/x86/xen/enlighten.c | 24 +++
> drivers/xen/Kconfig | 4 +
> drivers/xen/Makefile | 3 +
> drivers/xen/efi.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 398 insertions(+)
> create mode 100644 drivers/xen/efi.c
>
> diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
> index ffb101e..04611ea 100644
> --- a/arch/x86/xen/enlighten.c
> +++ b/arch/x86/xen/enlighten.c
> @@ -32,6 +32,7 @@
> #include <linux/gfp.h>
> #include <linux/memblock.h>
> #include <linux/edd.h>
> +#include <linux/efi.h>
>
> #include <xen/xen.h>
> #include <xen/events.h>
> @@ -150,6 +151,15 @@ struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info;
> */
> static int have_vcpu_info_placement = 1;
>
> +#ifdef CONFIG_XEN_EFI
> +extern efi_system_table_t __init *xen_efi_probe(void);
> +#else
> +static efi_system_table_t __init *xen_efi_probe(void)
> +{
> + return NULL;
> +}
> +#endif
I should have spotted this before, but it would be better to move this
chunk to an header file under include/xen.
> struct tls_descs {
> struct desc_struct desc[3];
> };
> @@ -1520,6 +1530,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
> {
> struct physdev_set_iopl set_iopl;
> int rc;
> + efi_system_table_t *efi_systab_xen;
>
> if (!xen_start_info)
> return;
> @@ -1718,6 +1729,19 @@ asmlinkage __visible void __init xen_start_kernel(void)
>
> xen_setup_runstate_info(0);
>
> + efi_systab_xen = xen_efi_probe();
> +
> + if (efi_systab_xen) {
> + strncpy((char *)&boot_params.efi_info.efi_loader_signature, "Xen",
> + sizeof(boot_params.efi_info.efi_loader_signature));
> + boot_params.efi_info.efi_systab = (__u32)__pa(efi_systab_xen);
> + boot_params.efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32);
> +
> + set_bit(EFI_BOOT, &efi.flags);
> + set_bit(EFI_PARAVIRT, &efi.flags);
> + set_bit(EFI_64BIT, &efi.flags);
> + }
> +
> /* Start the world */
> #ifdef CONFIG_X86_32
> i386_start_kernel();
> diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
> index 38fb36e..8bc0183 100644
> --- a/drivers/xen/Kconfig
> +++ b/drivers/xen/Kconfig
> @@ -240,4 +240,8 @@ config XEN_MCE_LOG
> config XEN_HAVE_PVMMU
> bool
>
> +config XEN_EFI
> + def_bool y
> + depends on X86_64 && EFI
> +
> endmenu
> diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
> index 45e00af..84044b5 100644
> --- a/drivers/xen/Makefile
> +++ b/drivers/xen/Makefile
> @@ -9,6 +9,8 @@ obj-y += xenbus/
> nostackp := $(call cc-option, -fno-stack-protector)
> CFLAGS_features.o := $(nostackp)
>
> +CFLAGS_efi.o += -fshort-wchar
> +
> dom0-$(CONFIG_PCI) += pci.o
> dom0-$(CONFIG_USB_SUPPORT) += dbgp.o
> dom0-$(CONFIG_ACPI) += acpi.o $(xen-pad-y)
> @@ -33,6 +35,7 @@ obj-$(CONFIG_XEN_STUB) += xen-stub.o
> obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o
> obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o
> obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
> +obj-$(CONFIG_XEN_EFI) += efi.o
> xen-evtchn-y := evtchn.o
> xen-gntdev-y := gntdev.o
> xen-gntalloc-y := gntalloc.o
> diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
> new file mode 100644
> index 0000000..d8d55a5
> --- /dev/null
> +++ b/drivers/xen/efi.c
> @@ -0,0 +1,367 @@
> +/*
> + * EFI support for Xen.
> + *
> + * Copyright (C) 1999 VA Linux Systems
> + * Copyright (C) 1999 Walt Drummond <[email protected]>
> + * Copyright (C) 1999-2002 Hewlett-Packard Co.
> + * David Mosberger-Tang <[email protected]>
> + * Stephane Eranian <[email protected]>
> + * Copyright (C) 2005-2008 Intel Co.
> + * Fenghua Yu <[email protected]>
> + * Bibo Mao <[email protected]>
> + * Chandramouli Narayanan <[email protected]>
> + * Huang Ying <[email protected]>
> + * Copyright (C) 2011 Novell Co.
> + * Jan Beulich <[email protected]>
> + * Copyright (C) 2011-2012 Oracle Co.
> + * Liang Tang <[email protected]>
> + * Copyright (c) 2014 Oracle Co., Daniel Kiper
> + */
> +
> +#include <linux/bug.h>
> +#include <linux/efi.h>
> +#include <linux/init.h>
> +#include <linux/string.h>
> +
> +#include <xen/interface/xen.h>
> +#include <xen/interface/platform.h>
> +
> +#include <asm/xen/hypercall.h>
> +
> +#define INIT_EFI_OP(name) \
> + {.cmd = XENPF_efi_runtime_call, \
> + .u.efi_runtime_call.function = XEN_EFI_##name, \
> + .u.efi_runtime_call.misc = 0}
> +
> +#define efi_data(op) (op.u.efi_runtime_call)
> +
> +static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(get_time);
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + if (tm) {
> + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_time.time));
> + memcpy(tm, &efi_data(op).u.get_time.time, sizeof(*tm));
> + }
> +
> + if (tc) {
> + tc->resolution = efi_data(op).u.get_time.resolution;
> + tc->accuracy = efi_data(op).u.get_time.accuracy;
> + tc->sets_to_zero = !!(efi_data(op).misc &
> + XEN_EFI_GET_TIME_SET_CLEARS_NS);
> + }
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_set_time(efi_time_t *tm)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(set_time);
> +
> + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time));
> + memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm));
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
> + efi_bool_t *pending,
> + efi_time_t *tm)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time);
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + if (tm) {
> + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_wakeup_time));
> + memcpy(tm, &efi_data(op).u.get_wakeup_time, sizeof(*tm));
> + }
> +
> + if (enabled)
> + *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
> +
> + if (pending)
> + *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time);
> +
> + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time));
> + if (enabled)
> + efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
> + if (tm)
> + memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm));
> + else
> + efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_get_variable(efi_char16_t *name,
> + efi_guid_t *vendor,
> + u32 *attr,
> + unsigned long *data_size,
> + void *data)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(get_variable);
> +
> + set_xen_guest_handle(efi_data(op).u.get_variable.name, name);
> + BUILD_BUG_ON(sizeof(*vendor) !=
> + sizeof(efi_data(op).u.get_variable.vendor_guid));
> + memcpy(&efi_data(op).u.get_variable.vendor_guid, vendor, sizeof(*vendor));
> + efi_data(op).u.get_variable.size = *data_size;
> + set_xen_guest_handle(efi_data(op).u.get_variable.data, data);
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + *data_size = efi_data(op).u.get_variable.size;
> + if (attr)
> + *attr = efi_data(op).misc;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
> + efi_char16_t *name,
> + efi_guid_t *vendor)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name);
> +
> + efi_data(op).u.get_next_variable_name.size = *name_size;
> + set_xen_guest_handle(efi_data(op).u.get_next_variable_name.name, name);
> + BUILD_BUG_ON(sizeof(*vendor) !=
> + sizeof(efi_data(op).u.get_next_variable_name.vendor_guid));
> + memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor,
> + sizeof(*vendor));
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + *name_size = efi_data(op).u.get_next_variable_name.size;
> + memcpy(vendor, &efi_data(op).u.get_next_variable_name.vendor_guid,
> + sizeof(*vendor));
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_set_variable(efi_char16_t *name,
> + efi_guid_t *vendor,
> + u32 attr,
> + unsigned long data_size,
> + void *data)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(set_variable);
> +
> + set_xen_guest_handle(efi_data(op).u.set_variable.name, name);
> + efi_data(op).misc = attr;
> + BUILD_BUG_ON(sizeof(*vendor) !=
> + sizeof(efi_data(op).u.set_variable.vendor_guid));
> + memcpy(&efi_data(op).u.set_variable.vendor_guid, vendor, sizeof(*vendor));
> + efi_data(op).u.set_variable.size = data_size;
> + set_xen_guest_handle(efi_data(op).u.set_variable.data, data);
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_query_variable_info(u32 attr,
> + u64 *storage_space,
> + u64 *remaining_space,
> + u64 *max_variable_size)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(query_variable_info);
> +
> + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
> + return EFI_UNSUPPORTED;
> +
> + efi_data(op).u.query_variable_info.attr = attr;
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + *storage_space = efi_data(op).u.query_variable_info.max_store_size;
> + *remaining_space = efi_data(op).u.query_variable_info.remain_store_size;
> + *max_variable_size = efi_data(op).u.query_variable_info.max_size;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count);
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + *count = efi_data(op).misc;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
> + unsigned long count,
> + unsigned long sg_list)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(update_capsule);
> +
> + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
> + return EFI_UNSUPPORTED;
> +
> + set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array,
> + capsules);
> + efi_data(op).u.update_capsule.capsule_count = count;
> + efi_data(op).u.update_capsule.sg_list = sg_list;
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
> + unsigned long count,
> + u64 *max_size,
> + int *reset_type)
> +{
> + struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities);
> +
> + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
> + return EFI_UNSUPPORTED;
> +
> + set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array,
> + capsules);
> + efi_data(op).u.query_capsule_capabilities.capsule_count = count;
> +
> + if (HYPERVISOR_dom0_op(&op) < 0)
> + return EFI_UNSUPPORTED;
> +
> + *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size;
> + *reset_type = efi_data(op).u.query_capsule_capabilities.reset_type;
> +
> + return efi_data(op).status;
> +}
> +
> +static efi_char16_t vendor[100] __initdata;
> +
> +static efi_system_table_t efi_systab_xen __initdata = {
> + .hdr = {
> + .signature = EFI_SYSTEM_TABLE_SIGNATURE,
> + .revision = 0, /* Initialized later. */
> + .headersize = 0, /* Ignored by Linux Kernel. */
> + .crc32 = 0, /* Ignored by Linux Kernel. */
> + .reserved = 0
> + },
> + .fw_vendor = EFI_INVALID_TABLE_ADDR, /* Initialized later. */
> + .fw_revision = 0, /* Initialized later. */
> + .con_in_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
> + .con_in = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
> + .con_out_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
> + .con_out = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
> + .stderr_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
> + .stderr = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
> + .runtime = (efi_runtime_services_t *)EFI_INVALID_TABLE_ADDR,
> + /* Not used under Xen. */
> + .boottime = (efi_boot_services_t *)EFI_INVALID_TABLE_ADDR,
> + /* Not used under Xen. */
> + .nr_tables = 0, /* Initialized later. */
> + .tables = EFI_INVALID_TABLE_ADDR /* Initialized later. */
> +};
> +
> +static const struct efi efi_xen __initconst = {
> + .systab = NULL, /* Initialized later. */
> + .runtime_version = 0, /* Initialized later. */
> + .mps = EFI_INVALID_TABLE_ADDR,
> + .acpi = EFI_INVALID_TABLE_ADDR,
> + .acpi20 = EFI_INVALID_TABLE_ADDR,
> + .smbios = EFI_INVALID_TABLE_ADDR,
> + .sal_systab = EFI_INVALID_TABLE_ADDR,
> + .boot_info = EFI_INVALID_TABLE_ADDR,
> + .hcdp = EFI_INVALID_TABLE_ADDR,
> + .uga = EFI_INVALID_TABLE_ADDR,
> + .uv_systab = EFI_INVALID_TABLE_ADDR,
> + .fw_vendor = EFI_INVALID_TABLE_ADDR,
> + .runtime = EFI_INVALID_TABLE_ADDR,
> + .config_table = EFI_INVALID_TABLE_ADDR,
> + .get_time = xen_efi_get_time,
> + .set_time = xen_efi_set_time,
> + .get_wakeup_time = xen_efi_get_wakeup_time,
> + .set_wakeup_time = xen_efi_set_wakeup_time,
> + .get_variable = xen_efi_get_variable,
> + .get_next_variable = xen_efi_get_next_variable,
> + .set_variable = xen_efi_set_variable,
> + .query_variable_info = xen_efi_query_variable_info,
> + .update_capsule = xen_efi_update_capsule,
> + .query_capsule_caps = xen_efi_query_capsule_caps,
> + .get_next_high_mono_count = xen_efi_get_next_high_mono_count,
> + .reset_system = NULL, /* Functionality provided by Xen. */
> + .set_virtual_address_map = NULL, /* Not used under Xen. */
> + .memmap = NULL, /* Not used under Xen. */
> + .flags = 0 /* Initialized later. */
> +};
> +
> +efi_system_table_t __init *xen_efi_probe(void)
> +{
> + struct xen_platform_op op = {
> + .cmd = XENPF_firmware_info,
> + .u.firmware_info = {
> + .type = XEN_FW_EFI_INFO,
> + .index = XEN_FW_EFI_CONFIG_TABLE
> + }
> + };
> + union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
> +
> + if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op) < 0)
> + return NULL;
> +
> + /* Here we know that Xen runs on EFI platform. */
> +
> + efi = efi_xen;
> +
> + efi_systab_xen.tables = info->cfg.addr;
> + efi_systab_xen.nr_tables = info->cfg.nent;
> +
> + op.cmd = XENPF_firmware_info;
> + op.u.firmware_info.type = XEN_FW_EFI_INFO;
> + op.u.firmware_info.index = XEN_FW_EFI_VENDOR;
> + info->vendor.bufsz = sizeof(vendor);
> + set_xen_guest_handle(info->vendor.name, vendor);
> +
> + if (HYPERVISOR_dom0_op(&op) == 0) {
> + efi_systab_xen.fw_vendor = __pa_symbol(vendor);
> + efi_systab_xen.fw_revision = info->vendor.revision;
> + } else
> + efi_systab_xen.fw_vendor = __pa_symbol(L"UNKNOWN");
> +
> + op.cmd = XENPF_firmware_info;
> + op.u.firmware_info.type = XEN_FW_EFI_INFO;
> + op.u.firmware_info.index = XEN_FW_EFI_VERSION;
> +
> + if (HYPERVISOR_dom0_op(&op) == 0)
> + efi_systab_xen.hdr.revision = info->version;
> +
> + op.cmd = XENPF_firmware_info;
> + op.u.firmware_info.type = XEN_FW_EFI_INFO;
> + op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
> +
> + if (HYPERVISOR_dom0_op(&op) == 0)
> + efi.runtime_version = info->version;
> +
> + return &efi_systab_xen;
> +}
> --
> 1.7.10.4
>
>>> On 20.06.14 at 23:29, <[email protected]> wrote:
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -298,7 +298,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
> if (table64 >> 32) {
> pr_cont("\n");
> pr_err("Table located above 4GB, disabling EFI.\n");
> - early_iounmap(config_tables,
> + early_memunmap(config_tables,
> efi.systab->nr_tables * sz);
> return -EINVAL;
> }
> @@ -314,7 +314,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
> tablep += sz;
> }
> pr_cont("\n");
> - early_iounmap(config_tables, efi.systab->nr_tables * sz);
> + early_memunmap(config_tables, efi.systab->nr_tables * sz);
>
> set_bit(EFI_CONFIG_TABLES, &efi.flags);
>
If these two changes are really deemed necessary (there's the
implied assumption currently in place that early_iounmap() can
undo early_memremap() mappings), then ia64 will need a
definition added for early_memunmap() or its build will break.
Jan
On 20/06/14 22:29, Daniel Kiper wrote:
> Define constants and structures which are needed to properly
> execute EFI related hypercall in Xen dom0.
Reviewed-by: David Vrabel <[email protected]>
Thanks.
David
On 20/06/14 22:29, Daniel Kiper wrote:
> Do not access EFI memory map if it is not available. At least
> Xen dom0 EFI implementation does not have an access to it.
Could it make one based on the XENMEM_memory_map or
XENMEM_machine_memory_map hypercall?
David
On 20/06/14 22:29, Daniel Kiper wrote:
> This patch enables EFI usage under Xen dom0. Standard EFI Linux
> Kernel infrastructure cannot be used because it requires direct
> access to EFI data and code. However, in dom0 case it is not possible
> because above mentioned EFI stuff is fully owned and controlled
> by Xen hypervisor. In this case all calls from dom0 to EFI must
> be requested via special hypercall which in turn executes relevant
> EFI code in behalf of dom0.
>
> When dom0 kernel boots it checks for EFI availability on a machine.
> If it is detected then artificial EFI system table is filled.
> Native EFI callas are replaced by functions which mimics them
> by calling relevant hypercall. Later pointer to EFI system table
> is passed to standard EFI machinery and it continues EFI subsystem
> initialization taking into account that there is no direct access
> to EFI boot services, runtime, tables, structures, etc. After that
> system runs as usual.
Reviewed-by: David Vrabel <[email protected]>
(With or without the change suggested by Stefano).
Thanks.
David
>>> On 23.06.14 at 11:53, <[email protected]> wrote:
> On 20/06/14 22:29, Daniel Kiper wrote:
>> Do not access EFI memory map if it is not available. At least
>> Xen dom0 EFI implementation does not have an access to it.
>
> Could it make one based on the XENMEM_memory_map or
> XENMEM_machine_memory_map hypercall?
No, the correct operation to implement this and efi_mem_type()
similar function is XEN_FW_EFI_INFO, index XEN_FW_EFI_MEM_INFO.
Jan
I am CC'ing IA-64 guys.
On Mon, Jun 23, 2014 at 08:19:00AM +0100, Jan Beulich wrote:
> >>> On 20.06.14 at 23:29, <[email protected]> wrote:
> > --- a/drivers/firmware/efi/efi.c
> > +++ b/drivers/firmware/efi/efi.c
> > @@ -298,7 +298,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
> > if (table64 >> 32) {
> > pr_cont("\n");
> > pr_err("Table located above 4GB, disabling EFI.\n");
> > - early_iounmap(config_tables,
> > + early_memunmap(config_tables,
> > efi.systab->nr_tables * sz);
> > return -EINVAL;
> > }
> > @@ -314,7 +314,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
> > tablep += sz;
> > }
> > pr_cont("\n");
> > - early_iounmap(config_tables, efi.systab->nr_tables * sz);
> > + early_memunmap(config_tables, efi.systab->nr_tables * sz);
> >
> > set_bit(EFI_CONFIG_TABLES, &efi.flags);
> >
>
> If these two changes are really deemed necessary (there's the
> implied assumption currently in place that early_iounmap() can
> undo early_memremap() mappings), then ia64 will need a
> definition added for early_memunmap() or its build will break.
I know that early_memunmap() == early_iounmap() in general. However,
I think that it is less confusing if use relevant functions in pairs
(i.e. early_memremap() with early_memunmap(), ...) than mix them up.
We have following choices here:
- leave early_iounmap() as is in drivers/firmware/efi/efi.c
(arch/x86/platform/efi/efi.c:early_iounmap() -> early_memunmap()
changes should be left as is),
- include asm/early_ioremap.h in arch/ia64/include/asm/io.h
(as I can see the same think is done for x86 and arm64).
I prefer second solution but I do not insist.
Daniel
On Mon, Jun 23, 2014 at 10:57:31AM +0100, David Vrabel wrote:
> On 20/06/14 22:29, Daniel Kiper wrote:
> > This patch enables EFI usage under Xen dom0. Standard EFI Linux
> > Kernel infrastructure cannot be used because it requires direct
> > access to EFI data and code. However, in dom0 case it is not possible
> > because above mentioned EFI stuff is fully owned and controlled
> > by Xen hypervisor. In this case all calls from dom0 to EFI must
> > be requested via special hypercall which in turn executes relevant
> > EFI code in behalf of dom0.
> >
> > When dom0 kernel boots it checks for EFI availability on a machine.
> > If it is detected then artificial EFI system table is filled.
> > Native EFI callas are replaced by functions which mimics them
> > by calling relevant hypercall. Later pointer to EFI system table
> > is passed to standard EFI machinery and it continues EFI subsystem
> > initialization taking into account that there is no direct access
> > to EFI boot services, runtime, tables, structures, etc. After that
> > system runs as usual.
>
> Reviewed-by: David Vrabel <[email protected]>
Thanks for this and second one.
> (With or without the change suggested by Stefano).
I am going to take into account Stefano's idea.
Daniel
On Mon, Jun 23, 2014 at 12:00:01PM +0100, Jan Beulich wrote:
> >>> On 23.06.14 at 11:53, <[email protected]> wrote:
> > On 20/06/14 22:29, Daniel Kiper wrote:
> >> Do not access EFI memory map if it is not available. At least
> >> Xen dom0 EFI implementation does not have an access to it.
> >
> > Could it make one based on the XENMEM_memory_map or
> > XENMEM_machine_memory_map hypercall?
>
> No, the correct operation to implement this and efi_mem_type()
> similar function is XEN_FW_EFI_INFO, index XEN_FW_EFI_MEM_INFO.
efi_mem_attributes() is used only on IA-64 arch. So, that is why
I completely removed relevant Xen code.
Daniel
> I am CC'ing IA-64 guys.
The *_unmap() functions are no-op on ia64 - because we have mappings for everything all the time
- the *_map() functions just need to compute the proper address to use to get the right attributes
(so we don't mix and match cacheable and uncachable access to the same address). But there is
nothing to tear down afterwards.
I do tend to agree with Daniel that is seems odd to setup the mapping with one class of function
and then tear it down with another.
-Tony