From 022ee6c558fc933679e151f00f84332974147fa2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 26 Jun 2014 12:09:05 +0200 Subject: efi/x86: Move UEFI Runtime Services wrappers to generic code In order for other archs (such as arm64) to be able to reuse the virtual mode function call wrappers, move them to drivers/firmware/efi/runtime-wrappers.c. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming --- include/linux/efi.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/efi.h b/include/linux/efi.h index 41bbf8ba4ba8..0ceb816bdfc2 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -521,6 +521,8 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules, int *reset_type); typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size); +void efi_native_runtime_setup(void); + /* * EFI Configuration Table and GUID definitions */ -- cgit v1.2.3 From bd669475d14e3279a7f96ed917a82df5da6ad52d Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 2 Jul 2014 14:54:42 +0200 Subject: efi: efistub: Refactor stub components In order to move from the #include "../../../xxxxx.c" anti-pattern used by both the x86 and arm64 versions of the stub to a static library linked into either the kernel proper (arm64) or a separate boot executable (x86), there is some prepatory work required. This patch does the following: - move forward declarations of functions shared between the arch specific and the generic parts of the stub to include/linux/efi.h - move forward declarations of functions shared between various .c files of the generic stub code to a new local header file called "efistub.h" - add #includes to all .c files which were formerly relying on the #includor to include the correct header files - remove all static modifiers from functions which will need to be externally visible once we move to a static library Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming --- arch/arm64/kernel/efi-stub.c | 29 ++++--------- arch/x86/boot/compressed/eboot.c | 13 +++--- drivers/firmware/efi/arm-stub.c | 32 +++++++++------ drivers/firmware/efi/efi-stub-helper.c | 74 +++++++++++++++++----------------- drivers/firmware/efi/efistub.h | 42 +++++++++++++++++++ drivers/firmware/efi/fdt.c | 20 +++++---- include/linux/efi.h | 42 +++++++++++++++++++ 7 files changed, 164 insertions(+), 88 deletions(-) create mode 100644 drivers/firmware/efi/efistub.h (limited to 'include') diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c index 23cbde4324b1..e4999021b07d 100644 --- a/arch/arm64/kernel/efi-stub.c +++ b/arch/arm64/kernel/efi-stub.c @@ -11,36 +11,21 @@ */ #include #include -#include #include -static void efi_char16_printk(efi_system_table_t *sys_table_arg, - efi_char16_t *str); - -static efi_status_t efi_open_volume(efi_system_table_t *sys_table, - void *__image, void **__fh); -static efi_status_t efi_file_close(void *handle); - -static efi_status_t -efi_file_read(void *handle, unsigned long *size, void *addr); - -static efi_status_t -efi_file_size(efi_system_table_t *sys_table, void *__fh, - efi_char16_t *filename_16, void **handle, u64 *file_sz); - /* Include shared EFI stub code */ #include "../../../drivers/firmware/efi/efi-stub-helper.c" #include "../../../drivers/firmware/efi/fdt.c" #include "../../../drivers/firmware/efi/arm-stub.c" -static efi_status_t handle_kernel_image(efi_system_table_t *sys_table, - unsigned long *image_addr, - unsigned long *image_size, - unsigned long *reserve_addr, - unsigned long *reserve_size, - unsigned long dram_base, - efi_loaded_image_t *image) +efi_status_t handle_kernel_image(efi_system_table_t *sys_table, + unsigned long *image_addr, + unsigned long *image_size, + unsigned long *reserve_addr, + unsigned long *reserve_size, + unsigned long dram_base, + efi_loaded_image_t *image) { efi_status_t status; unsigned long kernel_size, kernel_memsize = 0; diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index c066bc4e3051..916bbdd7dd28 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -45,8 +45,7 @@ static void setup_boot_services##bits(struct efi_config *c) \ BOOT_SERVICES(32); BOOT_SERVICES(64); -static void efi_printk(efi_system_table_t *, char *); -static void efi_char16_printk(efi_system_table_t *, efi_char16_t *); +void efi_char16_printk(efi_system_table_t *, efi_char16_t *); static efi_status_t __file_size32(void *__fh, efi_char16_t *filename_16, @@ -153,7 +152,7 @@ grow: return status; } -static efi_status_t +efi_status_t efi_file_size(efi_system_table_t *sys_table, void *__fh, efi_char16_t *filename_16, void **handle, u64 *file_sz) { @@ -163,7 +162,7 @@ efi_file_size(efi_system_table_t *sys_table, void *__fh, return __file_size32(__fh, filename_16, handle, file_sz); } -static inline efi_status_t +efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr) { unsigned long func; @@ -181,7 +180,7 @@ efi_file_read(void *handle, unsigned long *size, void *addr) } } -static inline efi_status_t efi_file_close(void *handle) +efi_status_t efi_file_close(void *handle) { if (efi_early->is64) { efi_file_handle_64_t *fh = handle; @@ -246,7 +245,7 @@ static inline efi_status_t __open_volume64(void *__image, void **__fh) return status; } -static inline efi_status_t +efi_status_t efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh) { if (efi_early->is64) @@ -255,7 +254,7 @@ efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh) return __open_volume32(__image, __fh); } -static void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) +void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) { unsigned long output_string; size_t offset; diff --git a/drivers/firmware/efi/arm-stub.c b/drivers/firmware/efi/arm-stub.c index 41114ce03b01..480339b6b110 100644 --- a/drivers/firmware/efi/arm-stub.c +++ b/drivers/firmware/efi/arm-stub.c @@ -12,6 +12,11 @@ * */ +#include +#include + +#include "efistub.h" + static int __init efi_secureboot_enabled(efi_system_table_t *sys_table_arg) { static efi_guid_t const var_guid __initconst = EFI_GLOBAL_VARIABLE_GUID; @@ -36,8 +41,8 @@ static int __init efi_secureboot_enabled(efi_system_table_t *sys_table_arg) } } -static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, - void *__image, void **__fh) +efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, + void *__image, void **__fh) { efi_file_io_interface_t *io; efi_loaded_image_t *image = __image; @@ -60,14 +65,15 @@ static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, *__fh = fh; return status; } -static efi_status_t efi_file_close(void *handle) + +efi_status_t efi_file_close(void *handle) { efi_file_handle_t *fh = handle; return fh->close(handle); } -static efi_status_t +efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr) { efi_file_handle_t *fh = handle; @@ -76,7 +82,7 @@ efi_file_read(void *handle, unsigned long *size, void *addr) } -static efi_status_t +efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, efi_char16_t *filename_16, void **handle, u64 *file_sz) { @@ -129,7 +135,7 @@ grow: -static void efi_char16_printk(efi_system_table_t *sys_table_arg, +void efi_char16_printk(efi_system_table_t *sys_table_arg, efi_char16_t *str) { struct efi_simple_text_output_protocol *out; @@ -145,13 +151,13 @@ static void efi_char16_printk(efi_system_table_t *sys_table_arg, * must be reserved. On failure it is required to free all * all allocations it has made. */ -static efi_status_t handle_kernel_image(efi_system_table_t *sys_table, - unsigned long *image_addr, - unsigned long *image_size, - unsigned long *reserve_addr, - unsigned long *reserve_size, - unsigned long dram_base, - efi_loaded_image_t *image); +efi_status_t handle_kernel_image(efi_system_table_t *sys_table, + unsigned long *image_addr, + unsigned long *image_size, + unsigned long *reserve_addr, + unsigned long *reserve_size, + unsigned long dram_base, + efi_loaded_image_t *image); /* * EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint * that is described in the PE/COFF header. Most of the code is the same diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index eb6d4be9e722..32d5cca30f49 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -9,18 +9,20 @@ * under the terms of the GNU General Public License version 2. * */ -#define EFI_READ_CHUNK_SIZE (1024 * 1024) -/* error code which can't be mistaken for valid address */ -#define EFI_ERROR (~0UL) +#include +#include + +#include "efistub.h" +#define EFI_READ_CHUNK_SIZE (1024 * 1024) struct file_info { efi_file_handle_t *handle; u64 size; }; -static void efi_printk(efi_system_table_t *sys_table_arg, char *str) +void efi_printk(efi_system_table_t *sys_table_arg, char *str) { char *s8; @@ -37,16 +39,12 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str) } } -#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg) -#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg) - - -static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, - efi_memory_desc_t **map, - unsigned long *map_size, - unsigned long *desc_size, - u32 *desc_ver, - unsigned long *key_ptr) +efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, + efi_memory_desc_t **map, + unsigned long *map_size, + unsigned long *desc_size, + u32 *desc_ver, + unsigned long *key_ptr) { efi_memory_desc_t *m = NULL; efi_status_t status; @@ -88,7 +86,7 @@ fail: } -static unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg) +unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg) { efi_status_t status; unsigned long map_size; @@ -116,9 +114,9 @@ static unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg) /* * Allocate at the highest possible address that is not above 'max'. */ -static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, unsigned long align, - unsigned long *addr, unsigned long max) +efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr, unsigned long max) { unsigned long map_size, desc_size; efi_memory_desc_t *map; @@ -202,9 +200,9 @@ fail: /* * Allocate at the lowest possible address. */ -static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, unsigned long align, - unsigned long *addr) +efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr) { unsigned long map_size, desc_size; efi_memory_desc_t *map; @@ -271,8 +269,8 @@ fail: return status; } -static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, - unsigned long addr) +void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, + unsigned long addr) { unsigned long nr_pages; @@ -290,12 +288,12 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, * We only support loading a file from the same filesystem as * the kernel image. */ -static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, - efi_loaded_image_t *image, - char *cmd_line, char *option_string, - unsigned long max_addr, - unsigned long *load_addr, - unsigned long *load_size) +efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + char *cmd_line, char *option_string, + unsigned long max_addr, + unsigned long *load_addr, + unsigned long *load_size) { struct file_info *files; unsigned long file_addr; @@ -477,12 +475,12 @@ fail: * address is not available the lowest available address will * be used. */ -static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, - unsigned long *image_addr, - unsigned long image_size, - unsigned long alloc_size, - unsigned long preferred_addr, - unsigned long alignment) +efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, + unsigned long *image_addr, + unsigned long image_size, + unsigned long alloc_size, + unsigned long preferred_addr, + unsigned long alignment) { unsigned long cur_image_addr; unsigned long new_addr = 0; @@ -589,9 +587,9 @@ static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n) * Size of memory allocated return in *cmd_line_len. * Returns NULL on error. */ -static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, - efi_loaded_image_t *image, - int *cmd_line_len) +char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + int *cmd_line_len) { const u16 *s2; u8 *s1 = NULL; diff --git a/drivers/firmware/efi/efistub.h b/drivers/firmware/efi/efistub.h new file mode 100644 index 000000000000..304ab295ca1a --- /dev/null +++ b/drivers/firmware/efi/efistub.h @@ -0,0 +1,42 @@ + +#ifndef _DRIVERS_FIRMWARE_EFI_EFISTUB_H +#define _DRIVERS_FIRMWARE_EFI_EFISTUB_H + +/* error code which can't be mistaken for valid address */ +#define EFI_ERROR (~0UL) + +void efi_char16_printk(efi_system_table_t *, efi_char16_t *); + +efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, + void **__fh); + +efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, + efi_char16_t *filename_16, void **handle, + u64 *file_sz); + +efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr); + +efi_status_t efi_file_close(void *handle); + +unsigned long get_dram_base(efi_system_table_t *sys_table_arg); + +efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, + unsigned long orig_fdt_size, + void *fdt, int new_fdt_size, char *cmdline_ptr, + u64 initrd_addr, u64 initrd_size, + efi_memory_desc_t *memory_map, + unsigned long map_size, unsigned long desc_size, + u32 desc_ver); + +efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, + void *handle, + unsigned long *new_fdt_addr, + unsigned long max_addr, + u64 initrd_addr, u64 initrd_size, + char *cmdline_ptr, + unsigned long fdt_addr, + unsigned long fdt_size); + +void *get_fdt(efi_system_table_t *sys_table); + +#endif diff --git a/drivers/firmware/efi/fdt.c b/drivers/firmware/efi/fdt.c index 3aec36d7aae9..86d2934840e2 100644 --- a/drivers/firmware/efi/fdt.c +++ b/drivers/firmware/efi/fdt.c @@ -10,13 +10,17 @@ * */ -static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, - unsigned long orig_fdt_size, - void *fdt, int new_fdt_size, char *cmdline_ptr, - u64 initrd_addr, u64 initrd_size, - efi_memory_desc_t *memory_map, - unsigned long map_size, unsigned long desc_size, - u32 desc_ver) +#include +#include +#include + +efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, + unsigned long orig_fdt_size, + void *fdt, int new_fdt_size, char *cmdline_ptr, + u64 initrd_addr, u64 initrd_size, + efi_memory_desc_t *memory_map, + unsigned long map_size, unsigned long desc_size, + u32 desc_ver) { int node, prev; int status; @@ -255,7 +259,7 @@ fail: return EFI_LOAD_ERROR; } -static void *get_fdt(efi_system_table_t *sys_table) +void *get_fdt(efi_system_table_t *sys_table) { efi_guid_t fdt_guid = DEVICE_TREE_GUID; efi_config_table_t *tables; diff --git a/include/linux/efi.h b/include/linux/efi.h index 0ceb816bdfc2..3a64f2f85821 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1163,4 +1163,46 @@ static inline void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {} #endif +/* prototypes shared between arch specific and generic stub code */ + +#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg) +#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg) + +void efi_printk(efi_system_table_t *sys_table_arg, char *str); + +void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, + unsigned long addr); + +char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, int *cmd_line_len); + +efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, + efi_memory_desc_t **map, + unsigned long *map_size, + unsigned long *desc_size, + u32 *desc_ver, + unsigned long *key_ptr); + +efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr); + +efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr, unsigned long max); + +efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, + unsigned long *image_addr, + unsigned long image_size, + unsigned long alloc_size, + unsigned long preferred_addr, + unsigned long alignment); + +efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + char *cmd_line, char *option_string, + unsigned long max_addr, + unsigned long *load_addr, + unsigned long *load_size); + #endif /* _LINUX_EFI_H */ -- cgit v1.2.3 From 8562c99cdd30217dea3609e268572f8764f401a5 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 13 Jun 2014 12:22:22 +0100 Subject: efi/reboot: Add generic wrapper around EfiResetSystem() Implement efi_reboot(), which is really just a wrapper around the EfiResetSystem() EFI runtime service, but it does at least allow us to funnel all callers through a single location. It also simplifies the callsites since users no longer need to check to see whether EFI_RUNTIME_SERVICES are enabled. Cc: Tony Luck Tested-by: Mark Salter Signed-off-by: Matt Fleming --- arch/ia64/kernel/process.c | 2 +- arch/x86/kernel/reboot.c | 6 +----- drivers/firmware/efi/Makefile | 2 +- drivers/firmware/efi/reboot.c | 26 ++++++++++++++++++++++++++ include/linux/efi.h | 4 ++++ 5 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 drivers/firmware/efi/reboot.c (limited to 'include') diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 55d4ba47a907..deed6fa96bb0 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -662,7 +662,7 @@ void machine_restart (char *restart_cmd) { (void) notify_die(DIE_MACHINE_RESTART, restart_cmd, NULL, 0, 0, 0); - (*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL); + efi_reboot(REBOOT_WARM, NULL); } void diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 52b1157c53eb..09e709fd1830 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -528,11 +528,7 @@ static void native_machine_emergency_restart(void) break; case BOOT_EFI: - if (efi_enabled(EFI_RUNTIME_SERVICES)) - efi.reset_system(reboot_mode == REBOOT_WARM ? - EFI_RESET_WARM : - EFI_RESET_COLD, - EFI_SUCCESS, 0, NULL); + efi_reboot(reboot_mode, NULL); reboot_type = BOOT_BIOS; break; diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index a204d1474cec..d8be608a9f3b 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -1,7 +1,7 @@ # # Makefile for linux kernel # -obj-$(CONFIG_EFI) += efi.o vars.o +obj-$(CONFIG_EFI) += efi.o vars.o reboot.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o obj-$(CONFIG_UEFI_CPER) += cper.o diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c new file mode 100644 index 000000000000..81bf925f70f5 --- /dev/null +++ b/drivers/firmware/efi/reboot.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014 Intel Corporation; author Matt Fleming + * Copyright (c) 2014 Red Hat, Inc., Mark Salter + */ +#include +#include + +void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) +{ + int efi_mode; + + if (!efi_enabled(EFI_RUNTIME_SERVICES)) + return; + + switch (reboot_mode) { + case REBOOT_WARM: + case REBOOT_SOFT: + efi_mode = EFI_RESET_WARM; + break; + default: + efi_mode = EFI_RESET_COLD; + break; + } + + efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL); +} diff --git a/include/linux/efi.h b/include/linux/efi.h index 3a64f2f85821..e6980ba528ec 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -928,11 +929,14 @@ static inline bool efi_enabled(int feature) { return test_bit(feature, &efi.flags) != 0; } +extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused); #else static inline bool efi_enabled(int feature) { return false; } +static inline void +efi_reboot(enum reboot_mode reboot_mode, const char *__unused) {} #endif /* -- cgit v1.2.3 From 0c5ed61adbdbf2ca5de934642d5be1e971c498c1 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 13 Jun 2014 12:35:21 +0100 Subject: efi/reboot: Allow powering off machines using EFI Not only can EfiResetSystem() be used to reboot, it can also be used to power down machines. By and large, this functionality doesn't work very well across the range of EFI machines in the wild, so it should definitely only be used as a last resort. In an ideal world, this wouldn't be needed at all. Unfortunately, we're starting to see machines where EFI is the *only* reliable way to power down, and nothing else, not PCI, not ACPI, works. efi_poweroff_required() should be implemented on a per-architecture basis, since exactly when we should be using EFI runtime services is a platform-specific decision. There's no analogue for reboot because each architecture handles reboot very differently - the x86 code in particular is pretty complex. Patches to enable this for specific classes of hardware will be submitted separately. Tested-by: Mark Salter Signed-off-by: Matt Fleming --- drivers/firmware/efi/reboot.c | 22 ++++++++++++++++++++++ include/linux/efi.h | 2 ++ 2 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c index 81bf925f70f5..e9eeeb3c6345 100644 --- a/drivers/firmware/efi/reboot.c +++ b/drivers/firmware/efi/reboot.c @@ -24,3 +24,25 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL); } + +bool __weak efi_poweroff_required(void) +{ + return false; +} + +static void efi_power_off(void) +{ + efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); +} + +static int __init efi_shutdown_init(void) +{ + if (!efi_enabled(EFI_RUNTIME_SERVICES)) + return -ENODEV; + + if (efi_poweroff_required()) + pm_power_off = efi_power_off; + + return 0; +} +late_initcall(efi_shutdown_init); diff --git a/include/linux/efi.h b/include/linux/efi.h index e6980ba528ec..9917f58ee83e 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -878,6 +878,8 @@ extern void efi_reserve_boot_services(void); extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose); extern struct efi_memory_map memmap; +extern bool efi_poweroff_required(void); + /* Iterate through an efi_memory_map */ #define for_each_efi_memory_desc(m, md) \ for ((md) = (m)->map; \ -- cgit v1.2.3 From 44be28e9dd9880dca3e2cbf7a844f2114e67f2cb Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 13 Jun 2014 12:39:55 +0100 Subject: x86/reboot: Add EFI reboot quirk for ACPI Hardware Reduced flag It appears that the BayTrail-T class of hardware requires EFI in order to powerdown and reboot and no other reliable method exists. This quirk is generally applicable to all hardware that has the ACPI Hardware Reduced bit set, since usually ACPI would be the preferred method. Cc: Len Brown Cc: Mark Salter Cc: "Rafael J. Wysocki" Signed-off-by: Matt Fleming --- arch/x86/include/asm/efi.h | 6 ++++++ arch/x86/kernel/reboot.c | 18 ++++++++++++++++-- arch/x86/platform/efi/quirks.c | 23 +++++++++++++++++++++++ drivers/firmware/efi/reboot.c | 8 ++++++++ include/linux/efi.h | 1 + 5 files changed, 54 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 9043f365ebf5..044a2fd3c5fe 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -183,6 +183,8 @@ extern struct efi_config *efi_early; #define efi_call_early(f, ...) \ efi_early->call(efi_early->f, __VA_ARGS__); +extern bool efi_reboot_required(void); + #else /* * IF EFI is not configured, have the EFI calls return -ENOSYS. @@ -195,6 +197,10 @@ extern struct efi_config *efi_early; #define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS) #define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS) static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} +static inline bool efi_reboot_required(void) +{ + return false; +} #endif /* CONFIG_EFI */ #endif /* _ASM_X86_EFI_H */ diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 09e709fd1830..17962e667a91 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -28,6 +28,7 @@ #include #include #include +#include /* * Power off function, if any @@ -401,12 +402,25 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { static int __init reboot_init(void) { + int rv; + /* * Only do the DMI check if reboot_type hasn't been overridden * on the command line */ - if (reboot_default) - dmi_check_system(reboot_dmi_table); + if (!reboot_default) + return 0; + + /* + * The DMI quirks table takes precedence. If no quirks entry + * matches and the ACPI Hardware Reduced bit is set, force EFI + * reboot. + */ + rv = dmi_check_system(reboot_dmi_table); + + if (!rv && efi_reboot_required()) + reboot_type = BOOT_EFI; + return 0; } core_initcall(reboot_init); diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index b4cb9182f155..1c7380da65ff 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -265,3 +266,25 @@ void __init efi_apply_memmap_quirks(void) if (is_uv_system()) set_bit(EFI_OLD_MEMMAP, &efi.flags); } + +/* + * For most modern platforms the preferred method of powering off is via + * ACPI. However, there are some that are known to require the use of + * EFI runtime services and for which ACPI does not work at all. + * + * Using EFI is a last resort, to be used only if no other option + * exists. + */ +bool efi_reboot_required(void) +{ + if (!acpi_gbl_reduced_hardware) + return false; + + efi_reboot_quirk_mode = EFI_RESET_WARM; + return true; +} + +bool efi_poweroff_required(void) +{ + return !!acpi_gbl_reduced_hardware; +} diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c index e9eeeb3c6345..9c59d1c795d1 100644 --- a/drivers/firmware/efi/reboot.c +++ b/drivers/firmware/efi/reboot.c @@ -5,6 +5,8 @@ #include #include +int efi_reboot_quirk_mode = -1; + void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) { int efi_mode; @@ -22,6 +24,12 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) break; } + /* + * If a quirk forced an EFI reset mode, always use that. + */ + if (efi_reboot_quirk_mode != -1) + efi_mode = efi_reboot_quirk_mode; + efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL); } diff --git a/include/linux/efi.h b/include/linux/efi.h index 9917f58ee83e..bac0f93dc473 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -878,6 +878,7 @@ extern void efi_reserve_boot_services(void); extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose); extern struct efi_memory_map memmap; +extern int efi_reboot_quirk_mode; extern bool efi_poweroff_required(void); /* Iterate through an efi_memory_map */ -- cgit v1.2.3 From 9f27bc543bdf92e179927037e2ab8ed0261579a9 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 30 Jun 2014 19:52:58 +0200 Subject: efi: Introduce EFI_PARAVIRT flag Introduce EFI_PARAVIRT flag. If it is set then kernel runs on EFI platform but it has not direct control on EFI stuff like EFI runtime, tables, structures, etc. If not this means that Linux Kernel has direct access to EFI infrastructure and everything runs as usual. This functionality is used in Xen dom0 because hypervisor has full control on EFI stuff and all calls from dom0 to EFI must be requested via special hypercall which in turn executes relevant EFI code in behalf of dom0. Signed-off-by: Daniel Kiper Signed-off-by: Matt Fleming --- arch/x86/platform/efi/efi.c | 31 +++++++++++++++++++++++++------ drivers/firmware/efi/efi.c | 21 ++++++++++++--------- include/linux/efi.h | 3 ++- 3 files changed, 39 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 7d627a02ed82..d9026538cfdb 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -210,6 +210,9 @@ int __init efi_memblock_x86_reserve_range(void) struct efi_info *e = &boot_params.efi_info; unsigned long pmap; + if (efi_enabled(EFI_PARAVIRT)) + return 0; + #ifdef CONFIG_X86_32 /* Can't handle data above 4GB at this time */ if (e->efi_memmap_hi) { @@ -422,14 +425,24 @@ static int __init efi_runtime_init(void) * the runtime services table so that we can grab the physical * address of several of the EFI runtime functions, needed to * set the firmware into virtual mode. + * + * When EFI_PARAVIRT is in force then we could not map runtime + * service memory region because we do not have direct access to it. + * However, runtime services are available through proxy functions + * (e.g. in case of Xen dom0 EFI implementation they call special + * hypercall which executes relevant EFI functions) and that is why + * they are always enabled. */ - if (efi_enabled(EFI_64BIT)) - rv = efi_runtime_init64(); - else - rv = efi_runtime_init32(); - if (rv) - return rv; + if (!efi_enabled(EFI_PARAVIRT)) { + if (efi_enabled(EFI_64BIT)) + rv = efi_runtime_init64(); + else + rv = efi_runtime_init32(); + + if (rv) + return rv; + } set_bit(EFI_RUNTIME_SERVICES, &efi.flags); @@ -438,6 +451,9 @@ static int __init efi_runtime_init(void) static int __init efi_memmap_init(void) { + if (efi_enabled(EFI_PARAVIRT)) + return 0; + /* Map the EFI memory map */ memmap.map = early_memremap((unsigned long)memmap.phys_map, memmap.nr_map * memmap.desc_size); @@ -914,6 +930,9 @@ static void __init __efi_enter_virtual_mode(void) void __init efi_enter_virtual_mode(void) { + if (efi_enabled(EFI_PARAVIRT)) + return; + if (efi_setup) kexec_enter_virtual_mode(); else diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 023937a63a48..ac88ec05eb70 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -104,16 +104,19 @@ static struct attribute *efi_subsys_attrs[] = { static umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { - umode_t mode = attr->mode; - - if (attr == &efi_attr_fw_vendor.attr) - return (efi.fw_vendor == EFI_INVALID_TABLE_ADDR) ? 0 : mode; - else if (attr == &efi_attr_runtime.attr) - return (efi.runtime == EFI_INVALID_TABLE_ADDR) ? 0 : mode; - else if (attr == &efi_attr_config_table.attr) - return (efi.config_table == EFI_INVALID_TABLE_ADDR) ? 0 : mode; + if (attr == &efi_attr_fw_vendor.attr) { + if (efi_enabled(EFI_PARAVIRT) || + efi.fw_vendor == EFI_INVALID_TABLE_ADDR) + return 0; + } else if (attr == &efi_attr_runtime.attr) { + if (efi.runtime == EFI_INVALID_TABLE_ADDR) + return 0; + } else if (attr == &efi_attr_config_table.attr) { + if (efi.config_table == EFI_INVALID_TABLE_ADDR) + return 0; + } - return mode; + return attr->mode; } static struct attribute_group efi_subsys_attr_group = { diff --git a/include/linux/efi.h b/include/linux/efi.h index bac0f93dc473..c7a29a26e900 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -922,7 +922,8 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */ #define EFI_MEMMAP 4 /* Can we use EFI memory map? */ #define EFI_64BIT 5 /* Is the firmware 64-bit? */ -#define EFI_ARCH_1 6 /* First arch-specific bit */ +#define EFI_PARAVIRT 6 /* Access is via a paravirt interface */ +#define EFI_ARCH_1 7 /* First arch-specific bit */ #ifdef CONFIG_EFI /* -- cgit v1.2.3 From bf1e3ae468aca7ce34110a59ed5d1b877890014b Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 30 Jun 2014 19:53:01 +0200 Subject: xen: Define EFI related stuff Define constants and structures which are needed to properly execute EFI related hypercall in Xen dom0. This patch is based on Jan Beulich and Tang Liang work. Signed-off-by: Jan Beulich Signed-off-by: Tang Liang Signed-off-by: Daniel Kiper Reviewed-by: David Vrabel Acked-by: Stefano Stabellini Signed-off-by: Matt Fleming --- include/xen/interface/platform.h | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) (limited to 'include') diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h index f1331e3e7271..5cc49ea8d840 100644 --- a/include/xen/interface/platform.h +++ b/include/xen/interface/platform.h @@ -108,11 +108,113 @@ 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; + xen_ulong_t 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 */ + xen_ulong_t 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 { + xen_ulong_t 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; + xen_ulong_t capsule_count; + uint64_t max_capsule_size; + uint32_t reset_type; + } query_capsule_capabilities; + + struct { + GUEST_HANDLE(void) capsule_header_array; + xen_ulong_t 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 */ #define XEN_FW_KBD_SHIFT_FLAGS 5 /* Int16, Fn02: Get keyboard shift flags. */ + struct xenpf_firmware_info { /* IN variables. */ uint32_t type; @@ -144,6 +246,26 @@ struct xenpf_firmware_info { 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 */ + uint8_t kbd_shift_flags; /* XEN_FW_KBD_SHIFT_FLAGS */ } u; }; @@ -362,6 +484,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; -- cgit v1.2.3 From be81c8a1da24288b0231be50130a64f5cdffdcd4 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 30 Jun 2014 19:53:02 +0200 Subject: xen: Put EFI machinery in place This patch enables EFI usage under Xen dom0. Standard EFI Linux Kernel infrastructure cannot be used because it requires direct access to EFI data and code. However, in dom0 case it is not possible because above mentioned EFI stuff is fully owned and controlled by Xen hypervisor. In this case all calls from dom0 to EFI must be requested via special hypercall which in turn executes relevant EFI code in behalf of dom0. When dom0 kernel boots it checks for EFI availability on a machine. If it is detected then artificial EFI system table is filled. Native EFI callas are replaced by functions which mimics them by calling relevant hypercall. Later pointer to EFI system table is passed to standard EFI machinery and it continues EFI subsystem initialization taking into account that there is no direct access to EFI boot services, runtime, tables, structures, etc. After that system runs as usual. This patch is based on Jan Beulich and Tang Liang work. Signed-off-by: Jan Beulich Signed-off-by: Tang Liang Signed-off-by: Daniel Kiper Reviewed-by: David Vrabel Acked-by: Stefano Stabellini --- arch/x86/xen/enlighten.c | 15 ++ drivers/xen/Kconfig | 4 + drivers/xen/Makefile | 3 + drivers/xen/efi.c | 368 +++++++++++++++++++++++++++++++++++++++++++++++ include/xen/xen-ops.h | 11 ++ 5 files changed, 401 insertions(+) create mode 100644 drivers/xen/efi.c (limited to 'include') diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index f17b29210ac4..bc89647f0325 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -1520,6 +1521,7 @@ asmlinkage __visible void __init xen_start_kernel(void) { struct physdev_set_iopl set_iopl; int rc; + efi_system_table_t *efi_systab_xen; if (!xen_start_info) return; @@ -1715,6 +1717,19 @@ asmlinkage __visible void __init xen_start_kernel(void) xen_setup_runstate_info(0); + efi_systab_xen = xen_efi_probe(); + + if (efi_systab_xen) { + strncpy((char *)&boot_params.efi_info.efi_loader_signature, "Xen", + sizeof(boot_params.efi_info.efi_loader_signature)); + boot_params.efi_info.efi_systab = (__u32)__pa(efi_systab_xen); + boot_params.efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32); + + set_bit(EFI_BOOT, &efi.flags); + set_bit(EFI_PARAVIRT, &efi.flags); + set_bit(EFI_64BIT, &efi.flags); + } + /* Start the world */ #ifdef CONFIG_X86_32 i386_start_kernel(); diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 38fb36e1c592..8bc01838daf9 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -240,4 +240,8 @@ config XEN_MCE_LOG config XEN_HAVE_PVMMU bool +config XEN_EFI + def_bool y + depends on X86_64 && EFI + endmenu diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 45e00afa7f2d..84044b554e33 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -9,6 +9,8 @@ obj-y += xenbus/ nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_features.o := $(nostackp) +CFLAGS_efi.o += -fshort-wchar + dom0-$(CONFIG_PCI) += pci.o dom0-$(CONFIG_USB_SUPPORT) += dbgp.o dom0-$(CONFIG_ACPI) += acpi.o $(xen-pad-y) @@ -33,6 +35,7 @@ obj-$(CONFIG_XEN_STUB) += xen-stub.o obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o +obj-$(CONFIG_XEN_EFI) += efi.o xen-evtchn-y := evtchn.o xen-gntdev-y := gntdev.o xen-gntalloc-y := gntalloc.o diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c new file mode 100644 index 000000000000..31f618a49661 --- /dev/null +++ b/drivers/xen/efi.c @@ -0,0 +1,368 @@ +/* + * EFI support for Xen. + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999-2002 Hewlett-Packard Co. + * David Mosberger-Tang + * Stephane Eranian + * Copyright (C) 2005-2008 Intel Co. + * Fenghua Yu + * Bibo Mao + * Chandramouli Narayanan + * Huang Ying + * Copyright (C) 2011 Novell Co. + * Jan Beulich + * Copyright (C) 2011-2012 Oracle Co. + * Liang Tang + * Copyright (c) 2014 Oracle Co., Daniel Kiper + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define INIT_EFI_OP(name) \ + {.cmd = XENPF_efi_runtime_call, \ + .u.efi_runtime_call.function = XEN_EFI_##name, \ + .u.efi_runtime_call.misc = 0} + +#define efi_data(op) (op.u.efi_runtime_call) + +static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) +{ + struct xen_platform_op op = INIT_EFI_OP(get_time); + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + if (tm) { + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_time.time)); + memcpy(tm, &efi_data(op).u.get_time.time, sizeof(*tm)); + } + + if (tc) { + tc->resolution = efi_data(op).u.get_time.resolution; + tc->accuracy = efi_data(op).u.get_time.accuracy; + tc->sets_to_zero = !!(efi_data(op).misc & + XEN_EFI_GET_TIME_SET_CLEARS_NS); + } + + return efi_data(op).status; +} + +static efi_status_t xen_efi_set_time(efi_time_t *tm) +{ + struct xen_platform_op op = INIT_EFI_OP(set_time); + + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time)); + memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm)); + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + return efi_data(op).status; +} + +static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled, + efi_bool_t *pending, + efi_time_t *tm) +{ + struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time); + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + if (tm) { + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_wakeup_time)); + memcpy(tm, &efi_data(op).u.get_wakeup_time, sizeof(*tm)); + } + + if (enabled) + *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED); + + if (pending) + *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING); + + return efi_data(op).status; +} + +static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) +{ + struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time); + + BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time)); + if (enabled) + efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE; + if (tm) + memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm)); + else + efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY; + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + return efi_data(op).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) +{ + struct xen_platform_op op = INIT_EFI_OP(get_variable); + + set_xen_guest_handle(efi_data(op).u.get_variable.name, name); + BUILD_BUG_ON(sizeof(*vendor) != + sizeof(efi_data(op).u.get_variable.vendor_guid)); + memcpy(&efi_data(op).u.get_variable.vendor_guid, vendor, sizeof(*vendor)); + efi_data(op).u.get_variable.size = *data_size; + set_xen_guest_handle(efi_data(op).u.get_variable.data, data); + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + *data_size = efi_data(op).u.get_variable.size; + if (attr) + *attr = efi_data(op).misc; + + return efi_data(op).status; +} + +static efi_status_t xen_efi_get_next_variable(unsigned long *name_size, + efi_char16_t *name, + efi_guid_t *vendor) +{ + struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name); + + efi_data(op).u.get_next_variable_name.size = *name_size; + set_xen_guest_handle(efi_data(op).u.get_next_variable_name.name, name); + BUILD_BUG_ON(sizeof(*vendor) != + sizeof(efi_data(op).u.get_next_variable_name.vendor_guid)); + memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor, + sizeof(*vendor)); + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + *name_size = efi_data(op).u.get_next_variable_name.size; + memcpy(vendor, &efi_data(op).u.get_next_variable_name.vendor_guid, + sizeof(*vendor)); + + return efi_data(op).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) +{ + struct xen_platform_op op = INIT_EFI_OP(set_variable); + + set_xen_guest_handle(efi_data(op).u.set_variable.name, name); + efi_data(op).misc = attr; + BUILD_BUG_ON(sizeof(*vendor) != + sizeof(efi_data(op).u.set_variable.vendor_guid)); + memcpy(&efi_data(op).u.set_variable.vendor_guid, vendor, sizeof(*vendor)); + efi_data(op).u.set_variable.size = data_size; + set_xen_guest_handle(efi_data(op).u.set_variable.data, data); + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + return efi_data(op).status; +} + +static efi_status_t xen_efi_query_variable_info(u32 attr, + u64 *storage_space, + u64 *remaining_space, + u64 *max_variable_size) +{ + struct xen_platform_op op = INIT_EFI_OP(query_variable_info); + + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) + return EFI_UNSUPPORTED; + + efi_data(op).u.query_variable_info.attr = attr; + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + *storage_space = efi_data(op).u.query_variable_info.max_store_size; + *remaining_space = efi_data(op).u.query_variable_info.remain_store_size; + *max_variable_size = efi_data(op).u.query_variable_info.max_size; + + return efi_data(op).status; +} + +static efi_status_t xen_efi_get_next_high_mono_count(u32 *count) +{ + struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count); + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + *count = efi_data(op).misc; + + return efi_data(op).status; +} + +static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules, + unsigned long count, + unsigned long sg_list) +{ + struct xen_platform_op op = INIT_EFI_OP(update_capsule); + + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) + return EFI_UNSUPPORTED; + + set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array, + capsules); + efi_data(op).u.update_capsule.capsule_count = count; + efi_data(op).u.update_capsule.sg_list = sg_list; + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + return efi_data(op).status; +} + +static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules, + unsigned long count, + u64 *max_size, + int *reset_type) +{ + struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities); + + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) + return EFI_UNSUPPORTED; + + set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array, + capsules); + efi_data(op).u.query_capsule_capabilities.capsule_count = count; + + if (HYPERVISOR_dom0_op(&op) < 0) + return EFI_UNSUPPORTED; + + *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size; + *reset_type = efi_data(op).u.query_capsule_capabilities.reset_type; + + return efi_data(op).status; +} + +static efi_char16_t vendor[100] __initdata; + +static efi_system_table_t efi_systab_xen __initdata = { + .hdr = { + .signature = EFI_SYSTEM_TABLE_SIGNATURE, + .revision = 0, /* Initialized later. */ + .headersize = 0, /* Ignored by Linux Kernel. */ + .crc32 = 0, /* Ignored by Linux Kernel. */ + .reserved = 0 + }, + .fw_vendor = EFI_INVALID_TABLE_ADDR, /* Initialized later. */ + .fw_revision = 0, /* Initialized later. */ + .con_in_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */ + .con_in = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */ + .con_out_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */ + .con_out = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */ + .stderr_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */ + .stderr = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */ + .runtime = (efi_runtime_services_t *)EFI_INVALID_TABLE_ADDR, + /* Not used under Xen. */ + .boottime = (efi_boot_services_t *)EFI_INVALID_TABLE_ADDR, + /* Not used under Xen. */ + .nr_tables = 0, /* Initialized later. */ + .tables = EFI_INVALID_TABLE_ADDR /* Initialized later. */ +}; + +static const struct efi efi_xen __initconst = { + .systab = NULL, /* Initialized later. */ + .runtime_version = 0, /* Initialized later. */ + .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, + .fw_vendor = EFI_INVALID_TABLE_ADDR, + .runtime = EFI_INVALID_TABLE_ADDR, + .config_table = 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, + .query_variable_info = xen_efi_query_variable_info, + .update_capsule = xen_efi_update_capsule, + .query_capsule_caps = xen_efi_query_capsule_caps, + .get_next_high_mono_count = xen_efi_get_next_high_mono_count, + .reset_system = NULL, /* Functionality provided by Xen. */ + .set_virtual_address_map = NULL, /* Not used under Xen. */ + .memmap = NULL, /* Not used under Xen. */ + .flags = 0 /* Initialized later. */ +}; + +efi_system_table_t __init *xen_efi_probe(void) +{ + struct xen_platform_op op = { + .cmd = XENPF_firmware_info, + .u.firmware_info = { + .type = XEN_FW_EFI_INFO, + .index = XEN_FW_EFI_CONFIG_TABLE + } + }; + union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info; + + if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op) < 0) + return NULL; + + /* Here we know that Xen runs on EFI platform. */ + + efi = efi_xen; + + efi_systab_xen.tables = info->cfg.addr; + efi_systab_xen.nr_tables = info->cfg.nent; + + op.cmd = XENPF_firmware_info; + op.u.firmware_info.type = XEN_FW_EFI_INFO; + op.u.firmware_info.index = XEN_FW_EFI_VENDOR; + info->vendor.bufsz = sizeof(vendor); + set_xen_guest_handle(info->vendor.name, vendor); + + if (HYPERVISOR_dom0_op(&op) == 0) { + efi_systab_xen.fw_vendor = __pa_symbol(vendor); + efi_systab_xen.fw_revision = info->vendor.revision; + } else + efi_systab_xen.fw_vendor = __pa_symbol(L"UNKNOWN"); + + op.cmd = XENPF_firmware_info; + op.u.firmware_info.type = XEN_FW_EFI_INFO; + op.u.firmware_info.index = XEN_FW_EFI_VERSION; + + if (HYPERVISOR_dom0_op(&op) == 0) + efi_systab_xen.hdr.revision = info->version; + + op.cmd = XENPF_firmware_info; + op.u.firmware_info.type = XEN_FW_EFI_INFO; + op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION; + + if (HYPERVISOR_dom0_op(&op) == 0) + efi.runtime_version = info->version; + + return &efi_systab_xen; +} diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 0b3149ed7eaa..771bbba27ccb 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -3,6 +3,7 @@ #include #include +#include #include DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); @@ -35,4 +36,14 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int numpgs, struct page **pages); bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); + +#ifdef CONFIG_XEN_EFI +extern efi_system_table_t *xen_efi_probe(void); +#else +static efi_system_table_t __init *xen_efi_probe(void) +{ + return NULL; +} +#endif + #endif /* INCLUDE_XEN_OPS_H */ -- cgit v1.2.3 From f383d00a0d1f94a7d60c753ec8e3e402889f9622 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 30 Jun 2014 19:53:04 +0200 Subject: arch/x86: Remove efi_set_rtc_mmss() efi_set_rtc_mmss() is never used to set RTC due to bugs found on many EFI platforms. It is set directly by mach_set_rtc_mmss(). Hence, remove unused efi_set_rtc_mmss() function. Signed-off-by: Daniel Kiper Signed-off-by: Matt Fleming --- arch/x86/platform/efi/efi.c | 36 ------------------------------------ include/linux/efi.h | 1 - 2 files changed, 37 deletions(-) (limited to 'include') diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 85fb16cd6479..850da94fef30 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -104,42 +104,6 @@ static efi_status_t __init phys_efi_set_virtual_address_map( return status; } -int efi_set_rtc_mmss(const struct timespec *now) -{ - unsigned long nowtime = now->tv_sec; - efi_status_t status; - efi_time_t eft; - efi_time_cap_t cap; - struct rtc_time tm; - - status = efi.get_time(&eft, &cap); - if (status != EFI_SUCCESS) { - pr_err("Oops: efitime: can't read time!\n"); - return -1; - } - - rtc_time_to_tm(nowtime, &tm); - if (!rtc_valid_tm(&tm)) { - eft.year = tm.tm_year + 1900; - eft.month = tm.tm_mon + 1; - eft.day = tm.tm_mday; - eft.minute = tm.tm_min; - eft.second = tm.tm_sec; - eft.nanosecond = 0; - } else { - pr_err("%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n", - __func__, nowtime); - return -1; - } - - status = efi.set_time(&eft); - if (status != EFI_SUCCESS) { - pr_err("Oops: efitime: can't write time!\n"); - return -1; - } - return 0; -} - void efi_get_time(struct timespec *now) { efi_status_t status; diff --git a/include/linux/efi.h b/include/linux/efi.h index c7a29a26e900..59c8acfebca7 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -873,7 +873,6 @@ extern int __init efi_uart_console_only (void); extern void efi_initialize_iomem_resources(struct resource *code_resource, struct resource *data_resource, struct resource *bss_resource); extern void efi_get_time(struct timespec *now); -extern int efi_set_rtc_mmss(const struct timespec *now); extern void efi_reserve_boot_services(void); extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose); extern struct efi_memory_map memmap; -- cgit v1.2.3 From 82f990a82244f8dfeb7e776186dc4811eb651ed7 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Tue, 8 Jul 2014 12:28:33 +0100 Subject: efi: Update stale locking comment for struct efivars The comment describing how struct efivars->lock is used hasn't been updated in sync with the code. Fix it. Reported-by: Ard Biesheuvel Cc: Mike Waychison Signed-off-by: Matt Fleming --- include/linux/efi.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/efi.h b/include/linux/efi.h index 59c8acfebca7..efc681fd5895 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1040,12 +1040,8 @@ struct efivar_operations { struct efivars { /* * ->lock protects two things: - * 1) ->list - adds, removals, reads, writes - * 2) ops.[gs]et_variable() calls. - * It must not be held when creating sysfs entries or calling kmalloc. - * ops.get_next_variable() is only called from register_efivars() - * or efivar_update_sysfs_entries(), - * which is protected by the BKL, so that path is safe. + * 1) efivarfs_list and efivars_sysfs_list + * 2) ->ops calls */ spinlock_t lock; struct kset *kset; -- cgit v1.2.3 From 57f7138d760700f56a8aa944376c28ff83c47c26 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Sat, 12 Jul 2014 23:09:47 +0200 Subject: xen: Silence compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add inline keyword to silence the following compiler warnings if xen_efi_probe() is not used: CC arch/x86/xen/setup.o In file included from arch/x86/xen/xen-ops.h:7:0, from arch/x86/xen/setup.c:31: include/xen/xen-ops.h:43:35: warning: ‘xen_efi_probe’ defined but not used [-Wunused-function] Signed-off-by: Daniel Kiper Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: Matt Fleming --- include/xen/xen-ops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 771bbba27ccb..7491ee5d8164 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -40,7 +40,7 @@ bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); #ifdef CONFIG_XEN_EFI extern efi_system_table_t *xen_efi_probe(void); #else -static efi_system_table_t __init *xen_efi_probe(void) +static inline efi_system_table_t __init *xen_efi_probe(void) { return NULL; } -- cgit v1.2.3