2012-02-23 09:14:39

by Tang Liang

[permalink] [raw]
Subject: [PATCH 0/5] xen: patches for supporting efi

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.
--
1.7.7.5


2012-02-23 09:14:45

by Tang Liang

[permalink] [raw]
Subject: [PATCH 5/5V2] Xen vga: add the xen efi video mode support

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.

Signed-off-by: Tang Liang <[email protected]>
Acked-by: Konrad Rzeszutek Wilk <[email protected]>
---
arch/x86/xen/vga.c | 7 +++++++
include/xen/interface/xen.h | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/x86/xen/vga.c b/arch/x86/xen/vga.c
index 1cd7f4d..6722e37 100644
--- a/arch/x86/xen/vga.c
+++ b/arch/x86/xen/vga.c
@@ -35,6 +35,7 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
info->u.text_mode_3.font_height;
break;

+ case XEN_VGATYPE_EFI_LFB:
case XEN_VGATYPE_VESA_LFB:
if (size < offsetof(struct dom0_vga_console_info,
u.vesa_lfb.gbl_caps))
@@ -54,6 +55,12 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
screen_info->blue_pos = info->u.vesa_lfb.blue_pos;
screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size;
screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos;
+
+ if (info->video_type == XEN_VGATYPE_EFI_LFB) {
+ screen_info->orig_video_isVGA = VIDEO_TYPE_EFI;
+ break;
+ }
+
if (size >= offsetof(struct dom0_vga_console_info,
u.vesa_lfb.gbl_caps)
+ sizeof(info->u.vesa_lfb.gbl_caps))
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index a890804..c84ba71 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -454,6 +454,7 @@ struct dom0_vga_console_info {
uint8_t video_type;
#define XEN_VGATYPE_TEXT_MODE_3 0x03
#define XEN_VGATYPE_VESA_LFB 0x23
+#define XEN_VGATYPE_EFI_LFB 0x70

union {
struct {
--
1.7.7.5

2012-02-23 09:14:42

by Tang Liang

[permalink] [raw]
Subject: [PATCH 1/5V2] EFI: Provide registration for efi_init.. etc efi public function

The efi public functions are changed to function pointer 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.

[v2: Fixed compile issues spotted by Konrad,
change variables defined suggested by Jan]

Signed-off-by: Tang Liang <[email protected]>
---
arch/x86/platform/efi/efi.c | 66 +++++++++++++++++++++++++++++++++++++++---
include/linux/efi.h | 11 +++++++
2 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 4cf9bd0..dd690e6 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -50,6 +50,24 @@
#define PFX "EFI: "

int efi_enabled;
+
+static void efi_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 const struct efi_init_funcs efi_generic_funcs = {
+ .efi_init = efi_init_generic,
+ .efi_reserve_boot_services = efi_reserve_boot_services_generic,
+ .efi_enter_virtual_mode = efi_enter_virtual_mode_generic,
+ .efi_mem_type = efi_mem_type_generic,
+ .efi_mem_attributes = efi_mem_attributes_generic
+};
+
+const struct efi_init_funcs *efi_override_funcs = &efi_generic_funcs;
+
EXPORT_SYMBOL(efi_enabled);

struct efi __read_mostly efi = {
@@ -376,7 +394,7 @@ static void __init print_efi_memmap(void)
}
#endif /* EFI_DEBUG */

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

@@ -429,7 +447,7 @@ static void __init efi_free_boot_services(void)
}
}

-void __init efi_init(void)
+static void efi_init_generic(void)
{
efi_config_table_t *config_tables;
efi_runtime_services_t *runtime;
@@ -618,7 +636,7 @@ static void __init runtime_code_page_mkexec(void)
* 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;
@@ -752,7 +770,7 @@ void __init efi_enter_virtual_mode(void)
/*
* 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;
@@ -767,7 +785,7 @@ u32 efi_mem_type(unsigned long phys_addr)
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;
@@ -781,3 +799,41 @@ u64 efi_mem_attributes(unsigned long phys_addr)
}
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->efi_init)
+ efi_override_funcs->efi_init();
+}
+
+void __init efi_reserve_boot_services(void)
+{
+ if (efi_override_funcs->efi_reserve_boot_services)
+ efi_override_funcs->efi_reserve_boot_services();
+}
+
+void __init efi_enter_virtual_mode(void)
+{
+ if (efi_override_funcs->efi_enter_virtual_mode)
+ efi_override_funcs->efi_enter_virtual_mode();
+}
+
+
+u32 efi_mem_type(unsigned long phys_addr)
+{
+ if (efi_override_funcs->efi_mem_type)
+ return efi_override_funcs->efi_mem_type(phys_addr);
+ return EFI_INVALID_TYPE;
+}
+
+u64 efi_mem_attributes(unsigned long phys_addr)
+{
+ if (efi_override_funcs->efi_mem_attributes)
+ return efi_override_funcs->efi_mem_attributes(phys_addr);
+ return EFI_INVALID_ATTRIBUTE;
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 37c3007..469ac66 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -79,8 +79,10 @@ typedef struct {
#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12
#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 */
@@ -434,6 +436,14 @@ extern struct efi {
efi_set_virtual_address_map_t *set_virtual_address_map;
} efi;

+struct efi_init_funcs {
+ void (*efi_init)(void);
+ void (*efi_reserve_boot_services)(void);
+ void (*efi_enter_virtual_mode)(void);
+ u32 (*efi_mem_type)(unsigned long phys_addr);
+ u64 (*efi_mem_attributes)(unsigned long phys_addr);
+};
+
static inline int
efi_guidcmp (efi_guid_t left, efi_guid_t right)
{
@@ -464,6 +474,7 @@ 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);

/**
* efi_range_is_wc - check the WC bit on an address range
--
1.7.7.5

2012-02-23 09:15:17

by Tang Liang

[permalink] [raw]
Subject: [PATCH 3/5V2] EFI: add efi driver for Xen efi

From: Jan Beulich <[email protected]>

The efi memory is owned by Xen and efi run-time service can not be called
directly,so a new efi driver is needed by Xen efi.
We call efi run-time service through the Xen in Xen efi driver.

[v2: Modifications done to abstract calls]

Signed-off-by: Jan Beulich <[email protected]>
Signed-off-by: Tang Liang <[email protected]>
---
arch/x86/platform/efi/Makefile | 3 +
arch/x86/platform/efi/efi-xen.c | 432 ++++++++++++++++++++++++++++++++++++++
include/linux/efi.h | 1 +
include/xen/interface/platform.h | 122 +++++++++++
4 files changed, 558 insertions(+), 0 deletions(-)
create mode 100644 arch/x86/platform/efi/efi-xen.c

diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index 73b8be0..9577899 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1 +1,4 @@
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
+ifdef CONFIG_XEN
+obj-$(CONFIG_EFI) += efi-xen.o
+endif
diff --git a/arch/x86/platform/efi/efi-xen.c b/arch/x86/platform/efi/efi-xen.c
new file mode 100644
index 0000000..c133d60
--- /dev/null
+++ b/arch/x86/platform/efi/efi-xen.c
@@ -0,0 +1,432 @@
+/*
+ * Common EFI (Extensible Firmware Interface) support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <[email protected]>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ * David Mosberger-Tang <[email protected]>
+ * Stephane Eranian <[email protected]>
+ * Copyright (C) 2005-2008 Intel Co.
+ * Fenghua Yu <[email protected]>
+ * Bibo Mao <[email protected]>
+ * Chandramouli Narayanan <[email protected]>
+ * Huang Ying <[email protected]>
+ * Copyright (C) 2011 Novell Co.
+ * Jan Beulic <[email protected]>
+ * Copyright (C) 2011-2012 Oracle Co.
+ * Liang Tang <[email protected]>
+ *
+ *
+ * Copied from efi_32.c to eliminate the duplicated code between EFI
+ * 32/64 support code. --ying 2007-10-26
+ *
+ * All EFI Runtime Services are not implemented yet as EFI only
+ * supports physical mode addressing on SoftSDV. This is to be fixed
+ * in a future version. --drummond 1999-07-20
+ *
+ * Implemented EFI runtime services and virtual mode calls. --davidm
+ *
+ * Goutham Rao: <[email protected]>
+ * Skip non-WB memory and ignore empty memory ranges.
+ */
+
+#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 struct efi __read_mostly 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;
+
+ register_xen_efi_function();
+ }
+}
+
+
+static void __init efi_init_xen(void)
+{
+ efi_config_table_t *config_tables;
+ 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 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");
+
+ /*
+ * 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();
+ config_tables = early_ioremap(
+ info->cfg.addr,
+ info->cfg.nent * sizeof(efi_config_table_t));
+ if (config_tables == NULL)
+ panic("Could not map EFI Configuration Table!\n");
+
+ get_efi_table_info(config_tables, info->cfg.nent, &efi);
+
+ early_iounmap(config_tables,
+ info->cfg.nent * sizeof(efi_config_table_t));
+
+ 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 efi_init_funcs xen_efi_funcs = {
+ .efi_init = efi_init_xen,
+ .efi_reserve_boot_services = NULL,
+ .efi_enter_virtual_mode = NULL,
+ .efi_mem_type = efi_mem_type_xen,
+ .efi_mem_attributes = efi_mem_attributes_xen
+};
+
+static void register_xen_efi_function(void)
+{
+ efi_init_function_register(&xen_efi_funcs);
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 4276c96..7b46590 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -477,6 +477,7 @@ extern struct efi_memory_map memmap;
extern void efi_init_function_register(const struct efi_init_funcs *funcs);
extern void get_efi_table_info(efi_config_table_t *config_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
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index c168468..77eb0fa 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -108,10 +108,112 @@ 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 XEN_FW_EFI_VERSION 0
+#define XEN_FW_EFI_CONFIG_TABLE 1
+#define XEN_FW_EFI_VENDOR 2
+#define XEN_FW_EFI_MEM_INFO 3
+#define XEN_FW_EFI_RT_VERSION 4
+
#define XENPF_firmware_info 50
#define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */
#define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */
#define XEN_FW_VBEDDC_INFO 3 /* from int 10 AX=4f15 */
+#define XEN_FW_EFI_INFO 4 /* from EFI */
+
struct xenpf_firmware_info {
/* IN variables. */
uint32_t type;
@@ -142,6 +244,25 @@ 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;
+ } efi_info; /* XEN_FW_EFI_INFO */
} u;
};
DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t);
@@ -307,6 +428,7 @@ struct xen_platform_op {
struct xenpf_read_memtype read_memtype;
struct xenpf_microcode_update microcode;
struct xenpf_platform_quirk platform_quirk;
+ struct xenpf_efi_runtime_call efi_runtime_call;
struct xenpf_firmware_info firmware_info;
struct xenpf_enter_acpi_sleep enter_acpi_sleep;
struct xenpf_change_freq change_freq;
--
1.7.7.5

2012-02-23 09:15:14

by Tang Liang

[permalink] [raw]
Subject: [PATCH 2/5V2] EFI: seperate get efi table info code to single function

Seperate get efi table info code to generic function,
xen efi driver will call it too.

Signed-off-by: Tang Liang <[email protected]>
Suggested-by:: Konrad Rzeszutek Wilk <[email protected]>
---
arch/x86/platform/efi/efi.c | 77 ++++++++++++++++++++++++-------------------
include/linux/efi.h | 2 +
2 files changed, 45 insertions(+), 34 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index dd690e6..dcb7842 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -447,6 +447,47 @@ static void __init efi_free_boot_services(void)
}
}

+void get_efi_table_info(efi_config_table_t *config_tables, int nr_tables,
+ struct efi *efi_t)
+{
+ int i;
+
+ printk(KERN_INFO);
+ for (i = 0; i < nr_tables; i++) {
+ if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
+ efi_t->mps = config_tables[i].table;
+ printk(" MPS=0x%lx ", config_tables[i].table);
+ } else if (!efi_guidcmp(config_tables[i].guid,
+ ACPI_20_TABLE_GUID)) {
+ efi_t->acpi20 = config_tables[i].table;
+ printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
+ } else if (!efi_guidcmp(config_tables[i].guid,
+ ACPI_TABLE_GUID)) {
+ efi_t->acpi = config_tables[i].table;
+ printk(" ACPI=0x%lx ", config_tables[i].table);
+ } else if (!efi_guidcmp(config_tables[i].guid,
+ SMBIOS_TABLE_GUID)) {
+ efi_t->smbios = config_tables[i].table;
+ printk(" SMBIOS=0x%lx ", config_tables[i].table);
+#ifdef CONFIG_X86_UV
+ } else if (!efi_guidcmp(config_tables[i].guid,
+ UV_SYSTEM_TABLE_GUID)) {
+ efi_t->uv_systab = config_tables[i].table;
+ printk(" UVsystab=0x%lx ", config_tables[i].table);
+#endif
+ } else if (!efi_guidcmp(config_tables[i].guid,
+ HCDP_TABLE_GUID)) {
+ efi_t->hcdp = config_tables[i].table;
+ printk(" HCDP=0x%lx ", config_tables[i].table);
+ } else if (!efi_guidcmp(config_tables[i].guid,
+ UGA_IO_PROTOCOL_GUID)) {
+ efi_t->uga = config_tables[i].table;
+ printk(" UGA=0x%lx ", config_tables[i].table);
+ }
+ }
+ printk("\n");
+}
+
static void efi_init_generic(void)
{
efi_config_table_t *config_tables;
@@ -508,40 +549,8 @@ static void efi_init_generic(void)
if (config_tables == NULL)
printk(KERN_ERR "Could not map EFI Configuration Table!\n");

- printk(KERN_INFO);
- for (i = 0; i < efi.systab->nr_tables; i++) {
- if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
- efi.mps = config_tables[i].table;
- printk(" MPS=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- ACPI_20_TABLE_GUID)) {
- efi.acpi20 = config_tables[i].table;
- printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- ACPI_TABLE_GUID)) {
- efi.acpi = config_tables[i].table;
- printk(" ACPI=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- SMBIOS_TABLE_GUID)) {
- efi.smbios = config_tables[i].table;
- printk(" SMBIOS=0x%lx ", config_tables[i].table);
-#ifdef CONFIG_X86_UV
- } else if (!efi_guidcmp(config_tables[i].guid,
- UV_SYSTEM_TABLE_GUID)) {
- efi.uv_systab = config_tables[i].table;
- printk(" UVsystab=0x%lx ", config_tables[i].table);
-#endif
- } else if (!efi_guidcmp(config_tables[i].guid,
- HCDP_TABLE_GUID)) {
- efi.hcdp = config_tables[i].table;
- printk(" HCDP=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- UGA_IO_PROTOCOL_GUID)) {
- efi.uga = config_tables[i].table;
- printk(" UGA=0x%lx ", config_tables[i].table);
- }
- }
- printk("\n");
+ get_efi_table_info(config_tables, efi.systab->nr_tables, &efi);
+
early_iounmap(config_tables,
efi.systab->nr_tables * sizeof(efi_config_table_t));

diff --git a/include/linux/efi.h b/include/linux/efi.h
index 469ac66..4276c96 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -475,6 +475,8 @@ 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 void get_efi_table_info(efi_config_table_t *config_tables, int nr_tables,
+ struct efi *efi_t);

/**
* efi_range_is_wc - check the WC bit on an address range
--
1.7.7.5

2012-02-23 09:15:48

by Tang Liang

[permalink] [raw]
Subject: [PATCH 4/5V2] Xen efi: Add xen efi enabled detect

We need to use hypercall to detect the xen efi enabled or not.
If xen efi enable is set,replace the efi public function to xen efi public
function and set efi_enabled to 1 in the function efi_probe;

Signed-off-by: Tang Liang <[email protected]>
Acked-by: Konrad Rzeszutek Wilk <[email protected]>
---
arch/x86/xen/enlighten.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 12eb07b..92982c1 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -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/interface/xen.h>
@@ -1282,6 +1283,8 @@ asmlinkage void __init xen_start_kernel(void)

xen_setup_runstate_info(0);

+ if (xen_initial_domain())
+ xen_efi_probe();
/* Start the world */
#ifdef CONFIG_X86_32
i386_start_kernel();
--
1.7.7.5