[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] Xen 4.4 development update



On 08/09/2013 02:56 PM, Daniel Kiper wrote:
On Thu, Aug 08, 2013 at 04:51:51PM -0400, Eric Shelton wrote:
On Thu, Aug 8, 2013 at 3:55 PM, Konrad Rzeszutek Wilk
<konrad.wilk@xxxxxxxxxx> wrote:
. . .
Rework them. The maintainer would like it done differently - that was my
recollection last year when I chatted with him (Matthew Garret).

Daniel will know more - but he is right now making multiboot2 work with
Xen and then attacking this.

Back then (https://lkml.org/lkml/2012/2/9/299), Matthew said:

Hm. Is there absolutely no way to do this by replacing efi_call_*? It'd
really be nice to avoid yet another set of duplicate functions here -
the ia64/x86 situation is already bad enough. Ideally this would be
sufficiently generic that arm can also plug into it.

It looks like the arm patches are just now nearing commit worthiness,
with V2 just posted a couple of days ago:

https://lkml.org/lkml/2013/8/6/584

It looks like Garrett's goal of merging arm and x86 EFI code is being
realized, and that I will need to refactor my patchset to keep up with
these changes.  Roy Franz seems to be doing the heavy lifting on arm
EFI, with Matt Fleming serving as the maintainer.

I have not dug very deep but it looks that it is only EFI loader
patch series (called stub in Linux Kernel). It is not related to
Xen EFI stuff in Linux Kernel.

That looks correct. The only file in common between the two sets of patches is include/linux/efi.h, and those changes do not affect each other.

Related to this, is the Xen hypervisor booting under EFI for arm
already?  I assume not, if Linux currently lacks the needed
hypercalls.  Does anything arm-specific need to happen in an
EFI-friendly dom0 kernel, given that it is hypercall driven?  Is there
a platform for test?

IIRC there is no EFI support in Xen on ARM. However, you should ask
Stefano and/or Ian Campbell for more details. They are ARM maintainers
for Xen.

As Konrad said I am working on multiboot2 protocol support for Xen.
It is needed to load Xen from e.g. GRUB2 loader on EFI platforms.
I would like to finish this first because there are some interests
in that project. Then I will be working on EFI support for Xen
in Linux Kernel. However, if you like to work on this stuff go
ahead. I do no have any objections. Just drop me line then I would
not duplicate your efforts.

In the interest of getting a more finalized patch out while I still recall some of the details of this, please find below a revised patch. There continues to be an issue with reboot working on my laptop, but I think it is in the hypervisor, as the kernel is making the hypercall requesting the reboot. Unfortunately, I do not have the tools to debug Xen on my laptop, as it lacks a serial port and I do not have a few of the things needed for EHCI port debugging. The kernel reboots just fine when running directly under EFI, although I do not know right now if it is via the EFI runtime or the more traditional reboot mechanisms.

If there are no comments, I will try running this by the Linux EFI maintainer.

=============

From: Eric Shelton <eshelton@xxxxxxxxx>
Date: Thu, 15 Aug 2013 00:31:08 -0400
Subject: [PATCH 1/1] EFI stub: add support for boot under EFI-booted Xen

Allows dom0 kernel to detect when it is running under a Xen hypervisor booted under EFI, and then make hyper calls to Xen to identify and obtain resources such as ACPI tables, E820 information, and the EFI console in order to complete booting.

Applies cleanly against 3.11rc5 and recent arm efi patches.

Signed-off-by: Eric Shelton <eshelton@xxxxxxxxx>
---
 arch/x86/platform/efi/Makefile   |   3 +
 arch/x86/platform/efi/efi.c      |  82 ++++++--
arch/x86/platform/efi/xen.c | 427 +++++++++++++++++++++++++++++++++++++++
 arch/x86/xen/enlighten.c         |  22 +-
 include/linux/efi.h              |   8 +
 include/xen/interface/platform.h | 132 ++++++++++++
 6 files changed, 649 insertions(+), 25 deletions(-)
 create mode 100644 arch/x86/platform/efi/xen.c

diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index 6db1cc4..f485766 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1,2 +1,5 @@
 obj-$(CONFIG_EFI)              += efi.o efi_$(BITS).o efi_stub_$(BITS).o
+#ifdef CONFIG_XEN
+obj-$(CONFIG_EFI)              += xen.o
+#endif
 obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 90f6ed1..ca043bda 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -12,6 +12,7 @@
  *     Bibo Mao <bibo.mao@xxxxxxxxx>
  *     Chandramouli Narayanan <mouli@xxxxxxxxxxxxxxx>
  *     Huang Ying <ying.huang@xxxxxxxxx>
+ * Copyright (C) 2013 Eric Shelton <eshelton@xxxxxxxxx>
  *
  * Copied from efi_32.c to eliminate the duplicated code between EFI
  * 32/64 support code. --ying 2007-10-26
@@ -51,6 +52,12 @@
 #include <asm/x86_init.h>
 #include <asm/rtc.h>

+#ifdef CONFIG_XEN
+extern void efi_init_xen(void);
+extern u32 efi_mem_type_xen(unsigned long phys_addr);
+extern u64 efi_mem_attributes_xen(unsigned long phys_addr);
+#endif
+
 #define EFI_DEBUG      1

 #define EFI_MIN_RESERVE 5120
@@ -381,6 +388,11 @@ int __init efi_memblock_x86_reserve_range(void)
        struct efi_info *e = &boot_params.efi_info;
        unsigned long pmap;

+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN))
+               return 0;
+#endif
+
 #ifdef CONFIG_X86_32
        /* Can't handle data above 4GB at this time */
        if (e->efi_memmap_hi) {
@@ -409,6 +421,8 @@ static void __init print_efi_memmap(void)
        void *p;
        int i;

+       if (memmap.map == NULL) return;
+
        for (p = memmap.map, i = 0;
             p < memmap.map_end;
             p += memmap.desc_size, i++) {
@@ -426,6 +440,11 @@ void __init efi_reserve_boot_services(void)
 {
        void *p;

+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN))
+               return;
+#endif
+
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                efi_memory_desc_t *md = p;
                u64 start = md->phys_addr;
@@ -467,6 +486,11 @@ void __init efi_free_boot_services(void)
 {
        void *p;

+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN))
+               return;
+#endif
+
        if (!efi_is_native())
                return;

@@ -578,20 +602,15 @@ static int __init efi_systab_init(void *phys)
        return 0;
 }

-static int __init efi_config_init(u64 tables, int nr_tables)
+int __init efi_config_init(u64 tables, int nr_tables, int entrySz)
 {
        void *config_tables, *tablep;
-       int i, sz;
-
-       if (efi_enabled(EFI_64BIT))
-               sz = sizeof(efi_config_table_64_t);
-       else
-               sz = sizeof(efi_config_table_32_t);
+       int i;

        /*
         * Let's see what config tables the firmware passed to us.
         */
-       config_tables = early_ioremap(tables, nr_tables * sz);
+       config_tables = early_ioremap(tables, nr_tables * entrySz);
        if (config_tables == NULL) {
                pr_err("Could not map Configuration table!\n");
                return -ENOMEM;
@@ -599,7 +618,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)

        tablep = config_tables;
        pr_info("");
-       for (i = 0; i < efi.systab->nr_tables; i++) {
+       for (i = 0; i < nr_tables; i++) {
                efi_guid_t guid;
                unsigned long table;

@@ -612,8 +631,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)
                        if (table64 >> 32) {
                                pr_cont("\n");
                                pr_err("Table located above 4GB, disabling 
EFI.\n");
-                               early_iounmap(config_tables,
-                                             efi.systab->nr_tables * sz);
+                               early_iounmap(config_tables, nr_tables * 
entrySz);
                                return -EINVAL;
                        }
 #endif
@@ -645,10 +663,10 @@ static int __init efi_config_init(u64 tables, int nr_tables)
                        efi.uga = table;
                        pr_cont(" UGA=0x%lx ", table);
                }
-               tablep += sz;
+               tablep += entrySz;
        }
        pr_cont("\n");
-       early_iounmap(config_tables, efi.systab->nr_tables * sz);
+       early_iounmap(config_tables, nr_tables * entrySz);
        return 0;
 }

@@ -708,9 +726,16 @@ void __init efi_init(void)
 {
        efi_char16_t *c16;
        char vendor[100] = "unknown";
-       int i = 0;
+       int entrySz, i = 0;
        void *tmp;

+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN)) {
+               efi_init_xen();
+               return;
+       }
+#endif
+
 #ifdef CONFIG_X86_32
        if (boot_params.efi_info.efi_systab_hi ||
            boot_params.efi_info.efi_memmap_hi) {
@@ -745,7 +770,12 @@ void __init efi_init(void)
                efi.systab->hdr.revision >> 16,
                efi.systab->hdr.revision & 0xffff, vendor);

-       if (efi_config_init(efi.systab->tables, efi.systab->nr_tables))
+       if (efi_enabled(EFI_64BIT))
+               entrySz = sizeof(efi_config_table_64_t);
+       else
+               entrySz = sizeof(efi_config_table_32_t);
+
+       if (efi_config_init(efi.systab->tables, efi.systab->nr_tables, entrySz))
                return;

        set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
@@ -782,7 +812,14 @@ void __init efi_init(void)

 void __init efi_late_init(void)
 {
+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN))
+               return;
+#endif
+
+#ifdef CONFIG_ACPI_BGRT
        efi_bgrt_init();
+#endif
 }

 void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
@@ -871,6 +908,11 @@ void __init efi_enter_virtual_mode(void)
        void *p, *va, *new_memmap = NULL;
        int count = 0;

+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN))
+               return;
+#endif
+
        efi.systab = NULL;

        /*
@@ -1007,6 +1049,11 @@ u32 efi_mem_type(unsigned long phys_addr)
        efi_memory_desc_t *md;
        void *p;

+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN))
+               return efi_mem_type_xen(phys_addr);
+#endif
+
        if (!efi_enabled(EFI_MEMMAP))
                return 0;

@@ -1025,6 +1072,11 @@ u64 efi_mem_attributes(unsigned long phys_addr)
        efi_memory_desc_t *md;
        void *p;

+#ifdef CONFIG_XEN
+       if (efi_enabled(EFI_XEN))
+               return efi_mem_attributes_xen(phys_addr);
+#endif
+
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
                if ((md->phys_addr <= phys_addr) &&
diff --git a/arch/x86/platform/efi/xen.c b/arch/x86/platform/efi/xen.c
new file mode 100644
index 0000000..ec0943a
--- /dev/null
+++ b/arch/x86/platform/efi/xen.c
@@ -0,0 +1,427 @@
+/*
+ * Xen EFI (Extensible Firmware Interface) support functions
+ * Based on related efforts in SLE and SUSE trees
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@xxxxxxxxxxx>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ *     David Mosberger-Tang <davidm@xxxxxxxxxx>
+ *     Stephane Eranian <eranian@xxxxxxxxxx>
+ * Copyright (C) 2005-2008 Intel Co.
+ *     Fenghua Yu <fenghua.yu@xxxxxxxxx>
+ *     Bibo Mao <bibo.mao@xxxxxxxxx>
+ *     Chandramouli Narayanan <mouli@xxxxxxxxxxxxxxx>
+ *     Huang Ying <ying.huang@xxxxxxxxx>
+ * Copyright (C) 2011 Novell Co.
+ *     Jan Beulic <JBeulich@xxxxxxxx>
+ * Copyright (C) 2011-2012 Oracle Co.
+ *     Liang Tang <liang.tang@xxxxxxxxxx>
+ * Copyright (C) 2013 Eric Shelton <eshelton@xxxxxxxxx>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/efi.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#include <asm/setup.h>
+#include <asm/efi.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/x86_init.h>
+
+#include <xen/interface/platform.h>
+#include <xen/interface/sched.h>
+#include <asm/xen/hypercall.h>
+
+#define PFX            "EFI: "
+
+#define call (op.u.efi_runtime_call)
+#define DECLARE_CALL(what) \
+       struct xen_platform_op op; \
+       op.cmd = XENPF_efi_runtime_call; \
+       call.function = XEN_EFI_##what; \
+       call.misc = 0
+
+static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+       int err;
+       DECLARE_CALL(get_time);
+
+       err = HYPERVISOR_dom0_op(&op);
+       if (err)
+               return EFI_UNSUPPORTED;
+
+       if (tm) {
+               BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.get_time.time));
+               memcpy(tm, &call.u.get_time.time, sizeof(*tm));
+       }
+
+       if (tc) {
+               tc->resolution = call.u.get_time.resolution;
+               tc->accuracy = call.u.get_time.accuracy;
+               tc->sets_to_zero = !!(call.misc &
+                                     XEN_EFI_GET_TIME_SET_CLEARS_NS);
+       }
+
+       return call.status;
+}
+
+static efi_status_t xen_efi_set_time(efi_time_t *tm)
+{
+       DECLARE_CALL(set_time);
+
+       BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.set_time));
+       memcpy(&call.u.set_time, tm, sizeof(*tm));
+
+       return HYPERVISOR_dom0_op(&op) ? EFI_UNSUPPORTED : call.status;
+}
+
+static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
+                                           efi_bool_t *pending,
+                                           efi_time_t *tm)
+{
+       int err;
+       DECLARE_CALL(get_wakeup_time);
+
+       err = HYPERVISOR_dom0_op(&op);
+       if (err)
+               return EFI_UNSUPPORTED;
+
+       if (tm) {
+               BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.get_wakeup_time));
+               memcpy(tm, &call.u.get_wakeup_time, sizeof(*tm));
+       }
+
+       if (enabled)
+               *enabled = !!(call.misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
+
+       if (pending)
+               *pending = !!(call.misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
+
+       return call.status;
+}
+
+static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+       DECLARE_CALL(set_wakeup_time);
+
+       BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.set_wakeup_time));
+       if (enabled)
+               call.misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
+       if (tm)
+               memcpy(&call.u.set_wakeup_time, tm, sizeof(*tm));
+       else
+               call.misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
+
+       return HYPERVISOR_dom0_op(&op) ? EFI_UNSUPPORTED : call.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)
+{
+       int err;
+       DECLARE_CALL(get_variable);
+
+       set_xen_guest_handle(call.u.get_variable.name, name);
+       BUILD_BUG_ON(sizeof(*vendor) !=
+                    sizeof(call.u.get_variable.vendor_guid));
+       memcpy(&call.u.get_variable.vendor_guid, vendor, sizeof(*vendor));
+       call.u.get_variable.size = *data_size;
+       set_xen_guest_handle(call.u.get_variable.data, data);
+       err = HYPERVISOR_dom0_op(&op);
+       if (err)
+               return EFI_UNSUPPORTED;
+
+       *data_size = call.u.get_variable.size;
+       *attr = call.misc; /* misc in struction is U32 variable*/
+
+       return call.status;
+}
+
+static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
+                                             efi_char16_t *name,
+                                             efi_guid_t *vendor)
+{
+       int err;
+       DECLARE_CALL(get_next_variable_name);
+       if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+               return EFI_UNSUPPORTED;
+       call.u.get_next_variable_name.size = *name_size;
+       set_xen_guest_handle(call.u.get_next_variable_name.name, name);
+       BUILD_BUG_ON(sizeof(*vendor) !=
+                    sizeof(call.u.get_next_variable_name.vendor_guid));
+       memcpy(&call.u.get_next_variable_name.vendor_guid, vendor,
+              sizeof(*vendor));
+       err = HYPERVISOR_dom0_op(&op);
+       if (err)
+               return EFI_UNSUPPORTED;
+
+       *name_size = call.u.get_next_variable_name.size;
+       memcpy(vendor, &call.u.get_next_variable_name.vendor_guid,
+              sizeof(*vendor));
+
+       return call.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)
+{
+       DECLARE_CALL(set_variable);
+
+       set_xen_guest_handle(call.u.set_variable.name, name);
+       call.misc = attr;
+       BUILD_BUG_ON(sizeof(*vendor) !=
+                    sizeof(call.u.set_variable.vendor_guid));
+       memcpy(&call.u.set_variable.vendor_guid, vendor, sizeof(*vendor));
+       call.u.set_variable.size = data_size;
+       set_xen_guest_handle(call.u.set_variable.data, data);
+
+       return HYPERVISOR_dom0_op(&op) ? EFI_UNSUPPORTED : call.status;
+}
+
+static efi_status_t xen_efi_query_variable_info(u32 attr,
+                                               u64 *storage_space,
+                                               u64 *remaining_space,
+                                               u64 *max_variable_size)
+{
+       int err;
+       DECLARE_CALL(query_variable_info);
+
+       if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+               return EFI_UNSUPPORTED;
+
+       err = HYPERVISOR_dom0_op(&op);
+       if (err)
+               return EFI_UNSUPPORTED;
+
+       *storage_space = call.u.query_variable_info.max_store_size;
+       *remaining_space = call.u.query_variable_info.remain_store_size;
+       *max_variable_size = call.u.query_variable_info.max_size;
+
+       return call.status;
+}
+
+static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
+{
+       int err;
+       DECLARE_CALL(get_next_high_monotonic_count);
+
+       err = HYPERVISOR_dom0_op(&op);
+       if (err)
+               return EFI_UNSUPPORTED;
+
+       *count = call.misc;
+
+       return call.status;
+}
+
+static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
+                                          unsigned long count,
+                                          unsigned long sg_list)
+{
+       DECLARE_CALL(update_capsule);
+
+       if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+               return EFI_UNSUPPORTED;
+
+       set_xen_guest_handle(call.u.update_capsule.capsule_header_array,
+                            capsules);
+       call.u.update_capsule.capsule_count = count;
+       call.u.update_capsule.sg_list = sg_list;
+
+       return HYPERVISOR_dom0_op(&op) ? EFI_UNSUPPORTED : call.status;
+}
+
+static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
+                                              unsigned long count,
+                                              u64 *max_size,
+                                              int *reset_type)
+{
+       int err;
+       DECLARE_CALL(query_capsule_capabilities);
+
+       if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+               return EFI_UNSUPPORTED;
+
+       set_xen_guest_handle(call.u.query_capsule_capabilities.
+               capsule_header_array, capsules);
+       call.u.query_capsule_capabilities.capsule_count = count;
+
+       err = HYPERVISOR_dom0_op(&op);
+       if (err)
+               return EFI_UNSUPPORTED;
+
+       *max_size = call.u.query_capsule_capabilities.max_capsule_size;
+       *reset_type = call.u.query_capsule_capabilities.reset_type;
+
+       return call.status;
+}
+
+#undef DECLARE_CALL
+#undef call
+
+static void xen_efi_reset_system(int reset_type,
+                                 efi_status_t status,
+                                unsigned long data_size,
+                                efi_char16_t *data)
+{
+       struct sched_shutdown r = { .reason = SHUTDOWN_reboot };
+
+       if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r))
+               BUG();
+}
+
+void __init xen_efi_probe(void)
+{
+       static struct xen_platform_op __initdata op = {
+               .cmd = XENPF_firmware_info,
+               .u.firmware_info = {
+                       .type = XEN_FW_EFI_INFO,
+                       .index = XEN_FW_EFI_CONFIG_TABLE
+               }
+       };
+
+       if (HYPERVISOR_dom0_op(&op) == 0) {
+               /* TODO: check return info */
+               set_bit(EFI_XEN, &x86_efi_facility);
+               set_bit(EFI_BOOT, &x86_efi_facility);
+               /* since hypervisor calls the runtime, 32/64 bit
+                * EFI/kernel mismatch is not an issue.  Set to
+                * match kernel so runtime calls will be made */
+#ifdef CONFIG_64BIT
+               set_bit(EFI_64BIT, &x86_efi_facility);
+#endif
+       }
+}
+
+
+void __init efi_init_xen(void)
+{
+       efi_char16_t c16[100];
+       char vendor[ARRAY_SIZE(c16)] = "unknown";
+       int ret, i;
+       struct xen_platform_op op;
+       union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+
+       /* redirect system to Xen hypercall implementation */
+       efi.systab                   = NULL,
+       efi.mps                      = EFI_INVALID_TABLE_ADDR;
+       efi.acpi                     = EFI_INVALID_TABLE_ADDR;
+       efi.acpi20                   = EFI_INVALID_TABLE_ADDR;
+       efi.smbios                   = EFI_INVALID_TABLE_ADDR;
+       efi.sal_systab               = EFI_INVALID_TABLE_ADDR;
+       efi.boot_info                = EFI_INVALID_TABLE_ADDR;
+       efi.hcdp                     = EFI_INVALID_TABLE_ADDR;
+       efi.uga                      = EFI_INVALID_TABLE_ADDR;
+       efi.uv_systab                = EFI_INVALID_TABLE_ADDR;
+       efi.get_time                 = xen_efi_get_time;
+       efi.set_time                 = xen_efi_set_time;
+       efi.get_wakeup_time          = xen_efi_get_wakeup_time;
+       efi.set_wakeup_time          = xen_efi_set_wakeup_time;
+       efi.get_variable             = xen_efi_get_variable;
+       efi.get_next_variable        = xen_efi_get_next_variable;
+       efi.set_variable             = xen_efi_set_variable;
+       efi.query_variable_info      = xen_efi_query_variable_info;
+       efi.update_capsule           = xen_efi_update_capsule;
+       efi.query_capsule_caps       = xen_efi_query_capsule_caps;
+       efi.get_next_high_mono_count = xen_efi_get_next_high_mono_count;
+       efi.set_virtual_address_map  = NULL;
+       efi.reset_system             = xen_efi_reset_system;
+
+       /*
+        * Show what we know for posterity
+        */
+       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(c16);
+       set_xen_guest_handle(info->vendor.name, c16);
+       ret = HYPERVISOR_dom0_op(&op);
+       if (!ret) {
+               for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
+                       vendor[i] = c16[i];
+               vendor[i] = '\0';
+       } else
+               pr_err("Could not get the firmware vendor!\n");
+
+       op.u.firmware_info.index = XEN_FW_EFI_VERSION;
+       ret = HYPERVISOR_dom0_op(&op);
+       if (!ret)
+               pr_info("EFI-xen v%u.%.02u by %s\n",
+                      info->version >> 16,
+                      info->version & 0xffff, vendor);
+       else
+               pr_err("Could not get EFI revision!\n");
+
+       op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
+       ret = HYPERVISOR_dom0_op(&op);
+       if (!ret)
+               efi.runtime_version = info->version;
+       else
+               pr_warn(PFX "Could not get runtime services revision.\n");
+       set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
+
+       /*
+        * Let's see what config tables the firmware passed to us.
+        */
+       op.u.firmware_info.index = XEN_FW_EFI_CONFIG_TABLE;
+       if (HYPERVISOR_dom0_op(&op))
+               BUG();
+
+       if (efi_config_init(info->cfg.addr, info->cfg.nent,
+                           sizeof(efi_config_table_64_t)))
+               panic("Could not init EFI Configuration Tables!\n");
+       set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
+
+       /* the EFI memory info is digested by the hypervisor and
+        * supplied to dom0 via E820 entries */
+       set_bit(EFI_MEMMAP, &x86_efi_facility);
+
+       set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility); /* not checked */
+
+       /* NOTE: efi.c only does this for CONFIG_X86_32 */
+       x86_platform.get_wallclock = efi_get_time;
+       x86_platform.set_wallclock = efi_set_rtc_mmss;
+}
+
+/*
+ * Convenience functions to obtain memory types and attributes
+ */
+u32 efi_mem_type_xen(unsigned long phys_addr)
+{
+       struct xen_platform_op op;
+       union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+
+       op.cmd = XENPF_firmware_info;
+       op.u.firmware_info.type = XEN_FW_EFI_INFO;
+       op.u.firmware_info.index = XEN_FW_EFI_MEM_INFO;
+       info->mem.addr = phys_addr;
+       info->mem.size = 0;
+       return HYPERVISOR_dom0_op(&op) ? 0 : info->mem.type;
+}
+
+u64 efi_mem_attributes_xen(unsigned long phys_addr)
+{
+       struct xen_platform_op op;
+       union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+
+       op.cmd = XENPF_firmware_info;
+       op.u.firmware_info.type = XEN_FW_EFI_INFO;
+       op.u.firmware_info.index = XEN_FW_EFI_MEM_INFO;
+       info->mem.addr = phys_addr;
+       info->mem.size = 0;
+       return HYPERVISOR_dom0_op(&op) ? 0 : info->mem.attr;
+}
+
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 193097e..51edc64 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>
@@ -1342,15 +1343,6 @@ int xen_panic_handler_init(void)
        return 0;
 }

-static const struct machine_ops xen_machine_ops __initconst = {
-       .restart = xen_restart,
-       .halt = xen_machine_halt,
-       .power_off = xen_machine_power_off,
-       .shutdown = xen_machine_halt,
-       .crash_shutdown = xen_crash_shutdown,
-       .emergency_restart = xen_emergency_restart,
-};
-
 static void __init xen_boot_params_init_edd(void)
 {
 #if IS_ENABLED(CONFIG_EDD)
@@ -1493,7 +1485,12 @@ asmlinkage void __init xen_start_kernel(void)
                pv_mmu_ops.ptep_modify_prot_commit = 
xen_ptep_modify_prot_commit;
        }

-       machine_ops = xen_machine_ops;
+       machine_ops.restart = xen_restart;
+       machine_ops.halt = xen_machine_halt;
+       machine_ops.power_off = xen_machine_power_off;
+       machine_ops.shutdown = xen_machine_halt;
+       machine_ops.crash_shutdown = xen_crash_shutdown;
+       machine_ops.emergency_restart = xen_emergency_restart;

        /*
         * The only reliable way to retain the initial address of the
@@ -1613,6 +1610,11 @@ asmlinkage void __init xen_start_kernel(void)

        xen_setup_runstate_info(0);

+#ifdef CONFIG_EFI
+       if (xen_initial_domain())
+               xen_efi_probe();
+#endif
+
        /* Start the world */
 #ifdef CONFIG_X86_32
        i386_start_kernel();
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 5f8f176..2781dea 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -84,7 +84,10 @@ typedef      struct {
 #define EFI_PAL_CODE                   13
 #define EFI_MAX_MEMORY_TYPE            14

+#define EFI_INVALID_TYPE               0xffffffff
+
 /* Attribute values: */
+#define EFI_INVALID_ATTRIBUTE ((u64)0x0000000000000000ULL) /* invalid attribute */
 #define EFI_MEMORY_UC          ((u64)0x0000000000000001ULL)    /* uncached */
 #define EFI_MEMORY_WC          ((u64)0x0000000000000002ULL)    /* 
write-coalescing */
 #define EFI_MEMORY_WT          ((u64)0x0000000000000004ULL)    /* 
write-through */
@@ -597,6 +600,10 @@ extern void efi_initialize_iomem_resources(struct resource *code_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);
+#ifdef CONFIG_XEN
+extern int __init efi_config_init(u64 tables, int nr_tables, int entrySz);
+extern void xen_efi_probe(void);
+#endif
 extern struct efi_memory_map memmap;

 /**
@@ -634,6 +641,7 @@ 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_XEN                        6       /* Must we access EFI via Xen? 
*/

 #ifdef CONFIG_EFI
 # ifdef CONFIG_X86
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index c57d5f6..d005f0b 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -108,10 +108,111 @@ 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;
+       unsigned long 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 */
+               unsigned long 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 {
+               unsigned long 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;
+               unsigned long capsule_count;
+               uint64_t max_capsule_size;
+               unsigned int reset_type;
+               } query_capsule_capabilities;
+
+       struct {
+               GUEST_HANDLE(void) capsule_header_array;
+               unsigned long capsule_count;
+               uint64_t sg_list; /* machine address */
+               } update_capsule;
+       } u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_efi_runtime_call);
+
 #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_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  XEN_FW_EFI_PCI_ROM        5
#define XEN_FW_KBD_SHIFT_FLAGS 5 /* Int16, Fn02: Get keyboard shift flags. */
 struct xenpf_firmware_info {
        /* IN variables. */
@@ -143,6 +244,36 @@ struct xenpf_firmware_info {
                        /* must refer to 128-byte buffer */
                        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;
+                       struct {
+                               /* IN variables */
+                               uint16_t segment;
+                               uint8_t bus;
+                               uint8_t devfn;
+                               uint16_t vendor;
+                               uint16_t devid;
+                               /* OUT variables */
+                               uint64_t address;
+                               xen_ulong_t size;
+                               } pci_rom;
+               } efi_info; /* XEN_FW_EFI_INFO */

                uint8_t kbd_shift_flags; /* XEN_FW_KBD_SHIFT_FLAGS */
        } u;
@@ -361,6 +492,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.8.3.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.