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 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Tang Liang
2012-Feb-09 03:32 UTC
[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 <liang.tang@oracle.com> --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Tang Liang
2012-Feb-09 03:32 UTC
[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 <liang.tang@oracle.com> Suggested-by:: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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 <liang.tang@oracle.com> --- 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 <drummond@valinux.com> + * Copyright (C) 1999-2002 Hewlett-Packard Co. + * David Mosberger-Tang <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2005-2008 Intel Co. + * Fenghua Yu <fenghua.yu@intel.com> + * Bibo Mao <bibo.mao@intel.com> + * Chandramouli Narayanan <mouli@linux.intel.com> + * Huang Ying <ying.huang@intel.com> + * Copyright (C) 2011-2012 Oracle Co. + * Liang Tang <liang.tang@oracle.com> + * + * 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: <goutham.rao@intel.com> + * 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 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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 <liang.tang@oracle.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> --- 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
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 <liang.tang@oracle.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> --- 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
Konrad Rzeszutek Wilk
2012-Feb-09 16:01 UTC
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 <liang.tang@oracle.com> > --- > 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 <konrad.wilk@oracle.com> 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 <konrad.wilk@oracle.com> --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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 | mjg59@srcf.ucam.org -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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. >-- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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 | mjg59@srcf.ucam.org -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Jan Beulich
2012-Feb-10 15:49 UTC
Re: [Xen-devel] [PATCH 3/5] EFI: add efi driver for Xen efi
>>> On 09.02.12 at 04:33, Tang Liang <liang.tang@oracle.com> 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 <liang.tang@oracle.com> > > --- 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.oCalling 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 <drummond@valinux.com> > + * Copyright (C) 1999-2002 Hewlett-Packard Co. > + * David Mosberger-Tang <davidm@hpl.hp.com> > + * Stephane Eranian <eranian@hpl.hp.com> > + * Copyright (C) 2005-2008 Intel Co. > + * Fenghua Yu <fenghua.yu@intel.com> > + * Bibo Mao <bibo.mao@intel.com> > + * Chandramouli Narayanan <mouli@linux.intel.com> > + * Huang Ying <ying.huang@intel.com> > + * Copyright (C) 2011-2012 Oracle Co. > + * Liang Tang <liang.tang@oracle.com> > + *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: <goutham.rao@intel.com> > + * 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-- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Jan Beulich
2012-Feb-10 16:58 UTC
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 <liang.tang@oracle.com> 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) > {-- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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
Tang Liang
2012-Feb-23 09:12 UTC
[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 <liang.tang@oracle.com> --- 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
Tang Liang
2012-Feb-23 09:13 UTC
[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 <liang.tang@oracle.com> Suggested-by:: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> --- 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
From: Jan Beulich <JBeulich@suse.com> 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 <JBeulich@suse.com> Signed-off-by: Tang Liang <liang.tang@oracle.com> --- 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 <drummond@valinux.com> + * Copyright (C) 1999-2002 Hewlett-Packard Co. + * David Mosberger-Tang <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2005-2008 Intel Co. + * Fenghua Yu <fenghua.yu@intel.com> + * Bibo Mao <bibo.mao@intel.com> + * Chandramouli Narayanan <mouli@linux.intel.com> + * Huang Ying <ying.huang@intel.com> + * Copyright (C) 2011 Novell Co. + * Jan Beulic <JBeulich@suse.com> + * Copyright (C) 2011-2012 Oracle Co. + * Liang Tang <liang.tang@oracle.com> + * + * + * 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: <goutham.rao@intel.com> + * 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
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 <liang.tang@oracle.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> --- 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
Tang Liang
2012-Feb-23 09:14 UTC
[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 <liang.tang@oracle.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> --- 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