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

[Xen-devel] Is: Linux-EFI code to call Xen's EFI hypercalls [RFC PATCH comments] Was:Re: Xen 4.4 development update



On Thu, Aug 15, 2013 at 01:32:12AM -0400, Eric Shelton wrote:
> 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.

First of, thank you for taking a stab at it and redoing it.

Some general comments:
 - the #ifdef CONFIG_XEN is generaly frowend upon. If you need them they should
   be in header files. The exception is the CONFIG_X86 and
   CONFIG_X86_64. Now said that there are other instances of code where
   it is sprinkled with #ifdef CONFIG_ACPI .. #ifdef CONFIG_PCI, and so
   on. It would have been nice if all of that got moved to a header file
   but in reality that could make it just more confusing. Enough about
   that - what I want to say is that doing #idef CONFIG_XEN is something
   we have been trying the utmost to not put in generic code. The
   reasoning is that instead of using the API (so for example if we have
   an generic layer and then there are platform related drivers - we
   want to implement the stuff in the platform drivers - not add
   side-channels for a specific platform).
 - Is there any way to move the bulk of the hypercalls in the
   efi_runtime services. Meaning alter the efi_runtime services
   to do hypercalls instead of EFI calls? That way I would think most
   of the EFI general logic would be untouched? This is going back to
   the first comment - you would want to leave as much generic code
   untouched as possible. And implement the bulk of the code in the
   platform specific code.
 - When approaching Matthew I would suggest you label it as RFC - to get
   an idea of how he would like it done - as I don't think he will
   take the patch as is. He might suggest the thing I just mentioned
   above. Or perhaps make most of the 'efi_*' calls go through some form
   of function table that by default is set to baremetal_efi_calls
   (see x86_init.c)
 - There are some code paths that just do:
        if (xen)
                return;
   But it is not clear why that is so (missing comments). This is needed
   b/c if somebody wants to redo the code in the future they would need to
   know where to place that 'if (xen) do something different'
 - You want to credit Jan Beulich in the commit description saying
   that the patch was derieved from the work that he did for SuSE Linux.
   Liang Tang took some of that - but he forgot to mention that in the
   initial post.
 - It is unclear to me why the machine_ops assigment has been changed?

Thank you again for taking a stab at it! I know that getting push back
on patches is not a thing that anybody likes - but the end goal is make
it be fantastic and sometimes that takes a couple of rounds (or about a
dozen as my first patches for Linux took that many revisions)

> 
> =============
> 
> 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®.