2012-02-09 03:30:32

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

Tang Liang (4):
EFI: Provide registration for efi_init.. etc efi public function
EFI: add efi driver for Xen efi
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-09 03:32:14

by Tang Liang

[permalink] [raw]
Subject: [PATCH 1/5] 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.

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

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 4cf9bd0..d567e29 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -50,6 +50,23 @@
#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);
+
+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
+};
+
+struct efi_init_funcs *efi_override_funcs = &efi_generic_funcs;
+
EXPORT_SYMBOL(efi_enabled);

struct efi __read_mostly efi = {
@@ -376,7 +393,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 +446,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 +635,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 +769,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 +784,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 +798,41 @@ u64 efi_mem_attributes(unsigned long phys_addr)
}
return 0;
}
+
+void efi_init_function_register(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..62e0a1f 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -79,8 +79,9 @@ 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 +435,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 +473,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(struct efi_init_funcs *funcs);

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

2012-02-09 03:32:43

by Tang Liang

[permalink] [raw]
Subject: [PATCH 2/5] 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 d567e29..d7b19ee 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -446,6 +446,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;
@@ -507,40 +548,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 62e0a1f..633371c 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -474,6 +474,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(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-09 03:33:04

by Tang Liang

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

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.

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..f4f6235
--- /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-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
+
+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 __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) {
+ 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 void efi_enter_virtual_mode_xen(void) { };
+static void efi_reserve_boot_services_xen(void) { };
+
+struct efi_init_funcs xen_efi_funcs = {
+ .__efi_init = efi_init_xen,
+ .__efi_reserve_boot_services = efi_reserve_boot_services_xen,
+ .__efi_enter_virtual_mode = efi_enter_virtual_mode_xen,
+ .__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 633371c..3b26d50 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -476,6 +476,7 @@ extern struct efi_memory_map memmap;
extern void efi_init_function_register(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 __init 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-09 03:33:16

by Tang Liang

[permalink] [raw]
Subject: [PATCH 4/5] 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

2012-02-09 03:33:31

by Tang Liang

[permalink] [raw]
Subject: [PATCH 5/5] 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-09 16:04:33

by Konrad Rzeszutek Wilk

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

On Thu, Feb 09, 2012 at 11:32:08AM +0800, Tang Liang wrote:
> 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.
>
> Signed-off-by: Tang Liang <[email protected]>
> ---
> arch/x86/platform/efi/efi.c | 65 +++++++++++++++++++++++++++++++++++++++---
> include/linux/efi.h | 12 +++++++-
> 2 files changed, 71 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
> index 4cf9bd0..d567e29 100644
> --- a/arch/x86/platform/efi/efi.c
> +++ b/arch/x86/platform/efi/efi.c
> @@ -50,6 +50,23 @@
> #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);
> +
> +struct efi_init_funcs efi_generic_funcs = {
> + .__efi_init = efi_init_generic,
> + .__efi_reserve_boot_services = efi_reserve_boot_services_generic,

Hmm, did you compile test this? I get:

/home/konrad/ssd/linux/arch/x86/platform/efi/efi.c:62: error: ‘efi_reserve_boot_services_generic’ undeclared here (not in a function)

The patch below fixes it:


>From 6ecdc001b99f06f73fe55ea24663c9a3921c285e Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <[email protected]>
Date: Thu, 9 Feb 2012 10:59:17 -0500
Subject: [PATCH] efi: Fix compiler error introduced by moving of the code
decleration.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The compiler error is :

arch/x86/platform/efi/efi.c:62: error: ‘efi_reserve_boot_services_generic’ undeclared here (not in a function

And declearing it before the use fixes the issue.

Signed-off-by: Konrad Rzeszutek Wilk <[email protected]>
---
arch/x86/platform/efi/efi.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index d7b19ee..c21b325 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -56,6 +56,7 @@ 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);

struct efi_init_funcs efi_generic_funcs = {
.__efi_init = efi_init_generic,
--
1.7.7.5

2012-02-09 19:47:29

by Matthew Garrett

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

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.

--
Matthew Garrett | [email protected]

2012-02-10 07:24:28

by Tang Liang

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

Hi,Matthew
the xen efi call need to use hypercall. that is different from the
generic efi code. do you any idea about that. thanks!


On 2012-2-10 3:47, Matthew Garrett wrote:
> 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.
>

2012-02-10 13:45:32

by Matthew Garrett

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

On Fri, Feb 10, 2012 at 03:24:18PM +0800, liang tang wrote:
> Hi,Matthew
> the xen efi call need to use hypercall. that is different from the
> generic efi code. do you any idea about that. thanks!

Right, but 32-bit EFI needs to make different calls to 64-bit EFI
anyway. It would be good if the abstraction could be done at this level
instead of duplicating the code.

--
Matthew Garrett | [email protected]

2012-02-10 15:50:04

by Jan Beulich

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

>>> On 09.02.12 at 04:33, Tang Liang <[email protected]> wrote:

As noted in a private mail already, this lack a From:, as large parts of
this are quite obviously derived from what we have in our SLE and
openSUSE trees. Feel free to also stick my Signed-off-by in further
down.

> 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.
>
> Signed-off-by: Tang Liang <[email protected]>
>
> --- 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

Calling this just xen.c would seem more natural to me. The *-xen.c
naming convention really is necessary only in the legacy (and forward
ported) trees.

> +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..f4f6235
> --- /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-2012 Oracle Co.
> + * Liang Tang <[email protected]>
> + *

I think everything between here ...

> + * 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.

... and here is meaningless in this file.

> + */
>...
> +struct efi __read_mostly efi_xen = {

With this just being copied in an __init function below, this can be
both static and __initdata (or even const __initconst).

> + .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,
> +};
>...
> +static void efi_enter_virtual_mode_xen(void) { };
> +static void efi_reserve_boot_services_xen(void) { };

With the generic wrapper checking for NULL pointers I don't see why you
need empty placeholders here.

> +
> +struct efi_init_funcs xen_efi_funcs = {

static const.

> + .__efi_init = efi_init_xen,
> + .__efi_reserve_boot_services = efi_reserve_boot_services_xen,
> + .__efi_enter_virtual_mode = efi_enter_virtual_mode_xen,
> + .__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);
> +}
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -476,6 +476,7 @@ extern struct efi_memory_map memmap;
> extern void efi_init_function_register(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 __init xen_efi_probe(void);

No __init in declarations.

Jan

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

2012-02-10 16:58:33

by Jan Beulich

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

>>> On 09.02.12 at 04:32, Tang Liang <[email protected]> wrote:
> --- a/arch/x86/platform/efi/efi.c
> +++ b/arch/x86/platform/efi/efi.c
> @@ -50,6 +50,23 @@
> #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);
> +
> +struct efi_init_funcs efi_generic_funcs = {

static const.

> + .__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
> +};
> +
> +struct efi_init_funcs *efi_override_funcs = &efi_generic_funcs;

const struct ...

> +
> EXPORT_SYMBOL(efi_enabled);
>
> struct efi __read_mostly efi = {
> @@ -781,3 +798,41 @@ u64 efi_mem_attributes(unsigned long phys_addr)
> }
> return 0;
> }
> +
> +void efi_init_function_register(struct efi_init_funcs *funcs)

... (const struct ...

> +{
> + 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;
> +}
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -79,8 +79,9 @@ typedef struct {
> #define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12
> #define EFI_PAL_CODE 13
> #define EFI_MAX_MEMORY_TYPE 14
> -

I would suggest to retain the newline.

> +#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 +435,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);

What is the reason for having the __ (or even the whole __efi_) at
their beginning?

Jan

> +};
> +
> static inline int
> efi_guidcmp (efi_guid_t left, efi_guid_t right)
> {