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

[Xen-devel] [REBASE] xen: patches (against Linux kernel) for supporting efi



Please find attached and below a rebased version of the patches to the
Linux kernel needed to get a Linux-based dom0 to come up under
xen.efi, which were last posted by Tang on Feb 23, 2012.  The provided
patch was made against Linux 3.9.3, but should either apply against or
be easily backported to older kernel versions (for example, only 2
hunks fail against 3.7.10).  I tried to take into account Jan's
comments offered for the Feb 8, 2012 ver 1 of the patches.

Using the provided patch, I am able to successfully do a native EFI
boot using xen.efi on a 2012 MacBook Air, with refind kicking off the
boot.  I have noticed no difference from a non-Xen boot; KDE and wifi
work normally, for example.  A non-Xen boot of the patched 3.9.3
kernel works fine as well.  The below xen.cfg was used:

video=gfx-1366x768x32
options=debug console=vga loglvl=all guest_loglvl=all e820-verbose=1
iommu=debug,verbose console_timestamps=true font=8x16
kernel=393test.efi ro root=/dev/sda3 debug ignore_loglevel
earlyprintk=xen i8042.noaux

In order of importance, three items are outstanding:
1) The attached code only works on 64-bit systems, due to setting the
EFI_64BIT in xen_efi_probe().  It looks like a new hypercall is needed
or an existing hypercall needs to be added to check whether the EFI
BIOS is 32- or 64-bit (see comment in code).
2) efivars is not tested
3) XEN_FW_EFI_PCI_ROM hypercall was added in the interim, but is unused in dom0

I apologize for the attached patch not being split up into 5 pieces as
previously presented, and for not observing the formalities for patch
presentation (which is why I also include an attachment).  I hope that
someone with a little more experience and time can address the above
items (particularly #1) and get it incorporated into the kernel this
time around.

Signed-off-by: Eric Shelton <eshelton@xxxxxxxxx>


On February 23, 2012, Tang Liang wrote:
> Hi
>
> The following patches introduce and implement efi support in dom0.
> The efi memory is owned by Xen and efi run-time service can not be called
> directly in dom0, so a new efi driver is needed by Xen efi.
> These patches are based on v3.3.0-rc2+.
>
> Descriptions for these patches:
>
> The efi public functions are changed to function pointers in efi_init_funcs
> struct. They act as efi generic functions as default.
> As a benefit from this change, we can register xen efi init func.
>
> In order to add xen efi video support, it is required to add xen-efi's
> new video type(XEN_VGATYPE_EFI_LFB) case handler in the function xen_init_vga
> and set the video type to VIDEO_TYPE_EFI to enable efi video mode.
>
> I have tested this patch on Dell Opti 790.
>
> Xen efi boot support is added by Jan Beulich, more detail information can be
> gotten from the url:
> http://wiki.xen.org/xenwiki/XenParavirtOps, search "efi" in the page.
>
> The example of config file for efi boot:
> kernel=vmlinuz-3.3.0-rc2+ root=xx ro console=tty0
> ramdisk=initramfs-3.3.0-rc2+.img
> video=gfx-x.0
>
> The detailed test which i have done:
> First, Check efifb driver work well or not and check the kernel messesge ro
> see the follow info:
> [    0.576705] efifb: probing for efifb
> [    0.577357] efifb: framebuffer at 0xd0000000, mapped to 
> 0xffffc90005800000, using 3752k, total 65472k
> [    0.577360] efifb: mode is 800x600x32, linelength=3200, pages=1
> [    0.577362] efifb: scrolling: redraw
> [    0.577364] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>
> Second, Check efi systab and variable is work well or not.
> cat the information in /sys/firmware/efi to check the efi systab and variable
> is right or not.
>
> Third, Run Linux firmware testing tools which is downloaded from this Url.
> http://linuxfirmwarekit.org/download.php
>
> Jan Beulich (1):
>       EFI: add efi driver for Xen efi
>
> Tang Liang (4):
>       EFI: Provide registration for efi_init.. etc efi public      function
>       EFI: seperate get efi table info code to single function
>       Xen efi: Add xen efi enabled detect
>       Xen vga: add the xen efi video mode support
>
> arch/x86/platform/efi/Makefile   |    2 +-
> arch/x86/platform/efi/efi-xen.c  |  460 ++++++++++++++++++++++++++++++++++++++
> arch/x86/platform/efi/efi.c      |   63 +++++-
> arch/x86/xen/enlighten.c         |    3 +
> arch/x86/xen/vga.c               |    7 +
> include/linux/efi.h              |   14 +-
> include/xen/interface/platform.h |  122 ++++++++++
> include/xen/interface/xen.h      |    1 +
> 8 files changed, 665 insertions(+), 7 deletions(-)
>
> Thanks
> Liang.

=========== PATCH BELOW ===========

diff -urN a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
--- a/arch/x86/platform/efi/efi.c 2013-05-22 20:37:13.432000000 -0400
+++ b/arch/x86/platform/efi/efi.c 2013-05-23 02:23:03.384000000 -0400
@@ -95,6 +95,29 @@
 }
 EXPORT_SYMBOL(efi_enabled);

+static void efi_init_generic(void);
+static void efi_late_init_generic(void);
+
+static void efi_enter_virtual_mode_generic(void);
+static u32 efi_mem_type_generic(unsigned long phys_addr);
+static u64 efi_mem_attributes_generic(unsigned long phys_addr);
+static void efi_reserve_boot_services_generic(void);
+static void efi_free_boot_services_generic(void);
+static int efi_memblock_x86_reserve_range_generic(void);
+
+static const struct efi_init_funcs __initconst efi_generic_funcs = {
+ .init       = efi_init_generic,
+ .late_init       = efi_late_init_generic,
+ .reserve_boot_services = efi_reserve_boot_services_generic,
+ .free_boot_services    = efi_free_boot_services_generic,
+ .enter_virtual_mode    = efi_enter_virtual_mode_generic,
+ .mem_type       = efi_mem_type_generic,
+ .mem_attributes       = efi_mem_attributes_generic,
+ .x86_reserve_range     = efi_memblock_x86_reserve_range_generic
+};
+
+const struct efi_init_funcs *efi_override_funcs =  &efi_generic_funcs;
+
 static bool __initdata disable_runtime = false;
 static int __init setup_noefi(char *arg)
 {
@@ -443,7 +466,7 @@
  sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 }

-int __init efi_memblock_x86_reserve_range(void)
+int __init efi_memblock_x86_reserve_range_generic(void)
 {
  unsigned long pmap;

@@ -475,6 +498,8 @@
  void *p;
  int i;

+ if (memmap.map == NULL) return;
+
  for (p = memmap.map, i = 0;
      p < memmap.map_end;
      p += memmap.desc_size, i++) {
@@ -488,7 +513,7 @@
 }
 #endif  /*  EFI_DEBUG  */

-void __init efi_reserve_boot_services(void)
+static void efi_reserve_boot_services_generic(void)
 {
  void *p;

@@ -529,7 +554,7 @@
  }
 }

-void __init efi_free_boot_services(void)
+void __init efi_free_boot_services_generic(void)
 {
  void *p;

@@ -644,7 +669,7 @@
  return 0;
 }

-static int __init efi_config_init(u64 tables, int nr_tables)
+int __init efi_config_init(u64 tables, int nr_tables, struct efi *efi_t)
 {
  void *config_tables, *tablep;
  int i, sz;
@@ -665,7 +690,7 @@

  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;

@@ -679,7 +704,7 @@
  pr_cont("\n");
  pr_err("Table located above 4GB, disabling EFI.\n");
  early_iounmap(config_tables,
-      efi.systab->nr_tables * sz);
+      nr_tables * sz);
  return -EINVAL;
  }
 #endif
@@ -688,33 +713,33 @@
  table = ((efi_config_table_32_t *)tablep)->table;
  }
  if (!efi_guidcmp(guid, MPS_TABLE_GUID)) {
- efi.mps = table;
+ efi_t->mps = table;
  pr_cont(" MPS=0x%lx ", table);
  } else if (!efi_guidcmp(guid, ACPI_20_TABLE_GUID)) {
- efi.acpi20 = table;
+ efi_t->acpi20 = table;
  pr_cont(" ACPI 2.0=0x%lx ", table);
  } else if (!efi_guidcmp(guid, ACPI_TABLE_GUID)) {
- efi.acpi = table;
+ efi_t->acpi = table;
  pr_cont(" ACPI=0x%lx ", table);
  } else if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID)) {
- efi.smbios = table;
+ efi_t->smbios = table;
  pr_cont(" SMBIOS=0x%lx ", table);
 #ifdef CONFIG_X86_UV
  } else if (!efi_guidcmp(guid, UV_SYSTEM_TABLE_GUID)) {
- efi.uv_systab = table;
+ efi_t->uv_systab = table;
  pr_cont(" UVsystab=0x%lx ", table);
 #endif
  } else if (!efi_guidcmp(guid, HCDP_TABLE_GUID)) {
- efi.hcdp = table;
+ efi_t->hcdp = table;
  pr_cont(" HCDP=0x%lx ", table);
  } else if (!efi_guidcmp(guid, UGA_IO_PROTOCOL_GUID)) {
- efi.uga = table;
+ efi_t->uga = table;
  pr_cont(" UGA=0x%lx ", table);
  }
  tablep += sz;
  }
  pr_cont("\n");
- early_iounmap(config_tables, efi.systab->nr_tables * sz);
+ early_iounmap(config_tables, nr_tables * sz);
  return 0;
 }

@@ -770,7 +795,7 @@
  return 0;
 }

-void __init efi_init(void)
+static void efi_init_generic(void)
 {
  efi_char16_t *c16;
  char vendor[100] = "unknown";
@@ -830,7 +855,7 @@
  efi.systab->hdr.revision >> 16,
  efi.systab->hdr.revision & 0xffff, vendor);

- if (efi_config_init(efi.systab->tables, efi.systab->nr_tables))
+ if (efi_config_init(efi.systab->tables, efi.systab->nr_tables, &efi))
  return;

  set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
@@ -865,9 +890,11 @@
 #endif
 }

-void __init efi_late_init(void)
+void __init efi_late_init_generic(void)
 {
+#ifdef CONFIG_ACPI_BGRT
  efi_bgrt_init();
+#endif
 }

 void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
@@ -947,7 +974,7 @@
  * This enables the runtime services to be called without having to
  * thunk back into physical mode for every invocation.
  */
-void __init efi_enter_virtual_mode(void)
+static void efi_enter_virtual_mode_generic(void)
 {
  efi_memory_desc_t *md, *prev_md = NULL;
  efi_status_t status;
@@ -1080,7 +1107,7 @@
 /*
  * Convenience functions to obtain memory types and attributes
  */
-u32 efi_mem_type(unsigned long phys_addr)
+static u32 efi_mem_type_generic(unsigned long phys_addr)
 {
  efi_memory_desc_t *md;
  void *p;
@@ -1098,7 +1125,7 @@
  return 0;
 }

-u64 efi_mem_attributes(unsigned long phys_addr)
+static u64 efi_mem_attributes_generic(unsigned long phys_addr)
 {
  efi_memory_desc_t *md;
  void *p;
@@ -1113,6 +1140,68 @@
  return 0;
 }

+void efi_init_function_register(const struct efi_init_funcs *funcs)
+{
+ efi_override_funcs = funcs;
+}
+
+void __init efi_init(void)
+{
+ if (efi_override_funcs->init)
+ {
+ efi_override_funcs->init();
+ }
+ else
+ {
+ memmap.map = NULL;  /* Xen case */
+ }
+}
+
+void __init efi_late_init(void)
+{
+ if (efi_override_funcs->late_init)
+ efi_override_funcs->late_init();
+}
+
+void __init efi_reserve_boot_services(void)
+{
+ if (efi_override_funcs->reserve_boot_services)
+ efi_override_funcs->reserve_boot_services();
+}
+
+void __init efi_free_boot_services(void)
+{
+ if (efi_override_funcs->free_boot_services)
+ efi_override_funcs->free_boot_services();
+}
+
+void __init efi_enter_virtual_mode(void)
+{
+ if (efi_override_funcs->enter_virtual_mode)
+ efi_override_funcs->enter_virtual_mode();
+}
+
+int __init efi_memblock_x86_reserve_range(void)
+{
+ if (efi_override_funcs->x86_reserve_range)
+ return efi_override_funcs->x86_reserve_range();
+ return 0;
+}
+
+u32 efi_mem_type(unsigned long phys_addr)
+{
+ if (efi_override_funcs->mem_type)
+ return efi_override_funcs->mem_type(phys_addr);
+ return EFI_INVALID_TYPE;
+}
+
+u64 efi_mem_attributes(unsigned long phys_addr)
+{
+ if (efi_override_funcs->mem_attributes)
+ return efi_override_funcs->mem_attributes(phys_addr);
+ return EFI_INVALID_ATTRIBUTE;
+}
+
 /*
  * Some firmware has serious problems when using more than 50% of the EFI
  * variable store, i.e. it triggers bugs that can brick machines. Ensure that
diff -urN a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
--- a/arch/x86/platform/efi/Makefile 2013-05-22 20:39:05.260000000 -0400
+++ b/arch/x86/platform/efi/Makefile 2013-05-23 02:04:00.048000000 -0400
@@ -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 -urN a/arch/x86/platform/efi/xen.c b/arch/x86/platform/efi/xen.c
--- a/arch/x86/platform/efi/xen.c 1969-12-31 19:00:00.000000000 -0500
+++ b/arch/x86/platform/efi/xen.c 2013-05-23 02:28:22.340000000 -0400
@@ -0,0 +1,428 @@
+/*
+ * 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>
+ */
+
+#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 <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 void register_xen_efi_function(void);
+
+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 const struct efi __initconst efi_xen = {
+ .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,
+ .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,
+ .get_next_high_mono_count = xen_efi_get_next_high_mono_count,
+ .query_variable_info      = xen_efi_query_variable_info,
+ .update_capsule           = xen_efi_update_capsule,
+ .query_capsule_caps       = xen_efi_query_capsule_caps,
+};
+
+void 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) {
+ /*efi_enabled = 1;*/
+ set_bit(EFI_BOOT, &x86_efi_facility);
+ /* this should be set based on whether the EFI loader
+ * signature contains "EL64" (see arch/x86/kernel/setup.c).
+ * Looks like a new hypercall will be needed for this */
+ set_bit(EFI_64BIT, &x86_efi_facility);
+
+ register_xen_efi_function();
+ }
+}
+
+
+static 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;
+
+ efi = efi_xen;
+ op.cmd = XENPF_firmware_info;
+ op.u.firmware_info.type = XEN_FW_EFI_INFO;
+
+ /*
+ * Show what we know for posterity
+ */
+ 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, &efi))
+ 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
+ */
+static 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;
+}
+
+static 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;
+}
+
+static const struct __initconst efi_init_funcs xen_efi_funcs = {
+ .init        = efi_init_xen,
+ .late_init = NULL,
+ .reserve_boot_services  = NULL,
+ .free_boot_services     = NULL,
+ .enter_virtual_mode     = NULL,
+ .mem_type        = efi_mem_type_xen,
+ .mem_attributes        = efi_mem_attributes_xen,
+ .x86_reserve_range = NULL
+};
+
+static void register_xen_efi_function(void)
+{
+ efi_init_function_register(&xen_efi_funcs);
+}
diff -urN a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
--- a/arch/x86/xen/enlighten.c 2013-05-22 20:36:48.608000000 -0400
+++ b/arch/x86/xen/enlighten.c 2013-05-22 20:44:15.784000000 -0400
@@ -31,6 +31,7 @@
 #include <linux/pci.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
+#include <linux/efi.h>

 #include <xen/xen.h>
 #include <xen/events.h>
@@ -1532,6 +1533,8 @@

  xen_setup_runstate_info(0);

+ if (xen_initial_domain())
+ xen_efi_probe();
  /* Start the world */
 #ifdef CONFIG_X86_32
  i386_start_kernel();
diff -urN a/include/linux/efi.h b/include/linux/efi.h
--- a/include/linux/efi.h 2013-05-22 20:36:14.820000000 -0400
+++ b/include/linux/efi.h 2013-05-23 02:22:12.544000000 -0400
@@ -84,7 +84,10 @@
 #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 */
@@ -554,6 +557,17 @@
  efi_set_virtual_address_map_t *set_virtual_address_map;
 } efi;

+struct efi_init_funcs {
+ void (*init)(void);
+ void (*late_init)(void);
+ void (*reserve_boot_services)(void);
+ void (*free_boot_services)(void);
+ void (*enter_virtual_mode)(void);
+ u32 (*mem_type)(unsigned long phys_addr);
+ u64 (*mem_attributes)(unsigned long phys_addr);
+ int (*x86_reserve_range)(void);
+};
+
 static inline int
 efi_guidcmp (efi_guid_t left, efi_guid_t right)
 {
@@ -591,13 +605,16 @@
 extern u32 efi_mem_type (unsigned long phys_addr);
 extern u64 efi_mem_attributes (unsigned long phys_addr);
 extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
-extern int __init efi_uart_console_only (void);
+extern int efi_uart_console_only (void);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
  struct resource *data_resource, struct resource *bss_resource);
 extern unsigned long efi_get_time(void);
 extern int efi_set_rtc_mmss(unsigned long nowtime);
 extern void efi_reserve_boot_services(void);
 extern struct efi_memory_map memmap;
+extern void efi_init_function_register(const struct efi_init_funcs *funcs);
+extern int efi_config_init(u64 tables, int nr_tables, struct efi *efi_t);
+extern void xen_efi_probe(void);

 /**
  * efi_range_is_wc - check the WC bit on an address range
@@ -621,7 +638,7 @@
 }

 #ifdef CONFIG_EFI_PCDP
-extern int __init efi_setup_pcdp_console(char *);
+extern int efi_setup_pcdp_console(char *);
 #endif

 /*
diff -urN a/include/xen/interface/platform.h b/include/xen/interface/platform.h
--- a/include/xen/interface/platform.h 2013-05-22 20:35:50.280000000 -0400
+++ b/include/xen/interface/platform.h 2013-05-22 20:43:17.068000000 -0400
@@ -108,10 +108,111 @@
 };
 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 @@
  /* 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 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;
diff -urN a/init/main.c b/init/main.c
--- a/init/main.c 2013-05-22 20:35:17.768000000 -0400
+++ b/init/main.c 2013-05-22 20:43:51.468000000 -0400
@@ -634,10 +634,12 @@
  acpi_early_init(); /* before LAPIC and SMP init */
  sfi_init_late();

+#ifdef CONFIG_X86
  if (efi_enabled(EFI_RUNTIME_SERVICES)) {
  efi_late_init();
  efi_free_boot_services();
  }
+#endif

  ftrace_init();

Attachment: xen-efi-rebase-3.9.3.patch
Description: Binary data

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