Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI changes from Ingo Molnar: "Main changes in this cycle are: - arm64 efi stub fixes, preservation of FP/SIMD registers across firmware calls, and conversion of the EFI stub code into a static library - Ard Biesheuvel - Xen EFI support - Daniel Kiper - Support for autoloading the efivars driver - Lee, Chun-Yi - Use the PE/COFF headers in the x86 EFI boot stub to request that the stub be loaded with CONFIG_PHYSICAL_ALIGN alignment - Michael Brown - Consolidate all the x86 EFI quirks into one file - Saurabh Tangri - Additional error logging in x86 EFI boot stub - Ulf Winkelvos - Support loading initrd above 4G in EFI boot stub - Yinghai Lu - EFI reboot patches for ACPI hardware reduced platforms" * 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (31 commits) efi/arm64: Handle missing virtual mapping for UEFI System Table arch/x86/xen: Silence compiler warnings xen: Silence compiler warnings x86/efi: Request desired alignment via the PE/COFF headers x86/efi: Add better error logging to EFI boot stub efi: Autoload efivars efi: Update stale locking comment for struct efivars arch/x86: Remove efi_set_rtc_mmss() arch/x86: Replace plain strings with constants xen: Put EFI machinery in place xen: Define EFI related stuff arch/x86: Remove redundant set_bit(EFI_MEMMAP) call arch/x86: Remove redundant set_bit(EFI_SYSTEM_TABLES) call efi: Introduce EFI_PARAVIRT flag arch/x86: Do not access EFI memory map if it is not available efi: Use early_mem*() instead of early_io*() arch/ia64: Define early_memunmap() x86/reboot: Add EFI reboot quirk for ACPI Hardware Reduced flag efi/reboot: Allow powering off machines using EFI efi/reboot: Add generic wrapper around EfiResetSystem() ...
This commit is contained in:
@@ -54,6 +54,12 @@ config EFI_PARAMS_FROM_FDT
|
||||
the EFI runtime support gets system table address, memory
|
||||
map address, and other parameters from the device tree.
|
||||
|
||||
config EFI_RUNTIME_WRAPPERS
|
||||
bool
|
||||
|
||||
config EFI_ARMSTUB
|
||||
bool
|
||||
|
||||
endmenu
|
||||
|
||||
config UEFI_CPER
|
||||
|
@@ -1,8 +1,10 @@
|
||||
#
|
||||
# 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
|
||||
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
|
||||
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
|
||||
obj-$(CONFIG_EFI_STUB) += libstub/
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct efi __read_mostly efi = {
|
||||
.mps = EFI_INVALID_TABLE_ADDR,
|
||||
@@ -104,16 +105,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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return mode;
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
static struct attribute_group efi_subsys_attr_group = {
|
||||
@@ -298,7 +302,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
|
||||
if (table64 >> 32) {
|
||||
pr_cont("\n");
|
||||
pr_err("Table located above 4GB, disabling EFI.\n");
|
||||
early_iounmap(config_tables,
|
||||
early_memunmap(config_tables,
|
||||
efi.systab->nr_tables * sz);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -314,13 +318,27 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
|
||||
tablep += sz;
|
||||
}
|
||||
pr_cont("\n");
|
||||
early_iounmap(config_tables, efi.systab->nr_tables * sz);
|
||||
early_memunmap(config_tables, efi.systab->nr_tables * sz);
|
||||
|
||||
set_bit(EFI_CONFIG_TABLES, &efi.flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_VARS_MODULE
|
||||
static int __init efi_load_efivars(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
||||
if (!efi_enabled(EFI_RUNTIME_SERVICES))
|
||||
return 0;
|
||||
|
||||
pdev = platform_device_register_simple("efivars", 0, NULL, 0);
|
||||
return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
|
||||
}
|
||||
device_initcall(efi_load_efivars);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFI_PARAMS_FROM_FDT
|
||||
|
||||
#define UEFI_PARAM(name, prop, field) \
|
||||
|
@@ -78,6 +78,7 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
|
||||
MODULE_DESCRIPTION("sysfs interface to EFI Variables");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(EFIVARS_VERSION);
|
||||
MODULE_ALIAS("platform:efivars");
|
||||
|
||||
LIST_HEAD(efivar_sysfs_list);
|
||||
EXPORT_SYMBOL_GPL(efivar_sysfs_list);
|
||||
|
26
drivers/firmware/efi/libstub/Makefile
Normal file
26
drivers/firmware/efi/libstub/Makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# The stub may be linked into the kernel proper or into a separate boot binary,
|
||||
# but in either case, it executes before the kernel does (with MMU disabled) so
|
||||
# things like ftrace and stack-protector are likely to cause trouble if left
|
||||
# enabled, even if doing so doesn't break the build.
|
||||
#
|
||||
cflags-$(CONFIG_X86_32) := -march=i386
|
||||
cflags-$(CONFIG_X86_64) := -mcmodel=small
|
||||
cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
|
||||
-fPIC -fno-strict-aliasing -mno-red-zone \
|
||||
-mno-mmx -mno-sse -DDISABLE_BRANCH_PROFILING
|
||||
|
||||
cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS))
|
||||
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \
|
||||
-fno-builtin -fpic -mno-single-pic-base
|
||||
|
||||
KBUILD_CFLAGS := $(cflags-y) \
|
||||
$(call cc-option,-ffreestanding) \
|
||||
$(call cc-option,-fno-stack-protector)
|
||||
|
||||
GCOV_PROFILE := n
|
||||
|
||||
lib-y := efi-stub-helper.o
|
||||
lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o
|
||||
|
||||
CFLAGS_fdt.o += -I$(srctree)/scripts/dtc/libfdt/
|
@@ -12,6 +12,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
#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
|
@@ -9,18 +9,20 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
#define EFI_READ_CHUNK_SIZE (1024 * 1024)
|
||||
|
||||
/* error code which can't be mistaken for valid address */
|
||||
#define EFI_ERROR (~0UL)
|
||||
|
||||
|
||||
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;
|
42
drivers/firmware/efi/libstub/efistub.h
Normal file
42
drivers/firmware/efi/libstub/efistub.h
Normal file
@@ -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
|
@@ -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 <linux/efi.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
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;
|
56
drivers/firmware/efi/reboot.c
Normal file
56
drivers/firmware/efi/reboot.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation; author Matt Fleming
|
||||
* Copyright (c) 2014 Red Hat, Inc., Mark Salter <msalter@redhat.com>
|
||||
*/
|
||||
#include <linux/efi.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
int efi_reboot_quirk_mode = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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);
|
161
drivers/firmware/efi/runtime-wrappers.c
Normal file
161
drivers/firmware/efi/runtime-wrappers.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* runtime-wrappers.c - Runtime Services function call wrappers
|
||||
*
|
||||
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* Split off from arch/x86/platform/efi/efi.c
|
||||
*
|
||||
* Copyright (C) 1999 VA Linux Systems
|
||||
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
|
||||
* Copyright (C) 1999-2002 Hewlett-Packard Co.
|
||||
* Copyright (C) 2005-2008 Intel Co.
|
||||
* Copyright (C) 2013 SuSE Labs
|
||||
*
|
||||
* This file is released under the GPLv2.
|
||||
*/
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/spinlock.h> /* spinlock_t */
|
||||
#include <asm/efi.h>
|
||||
|
||||
/*
|
||||
* As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"),
|
||||
* the EFI specification requires that callers of the time related runtime
|
||||
* functions serialize with other CMOS accesses in the kernel, as the EFI time
|
||||
* functions may choose to also use the legacy CMOS RTC.
|
||||
*/
|
||||
__weak DEFINE_SPINLOCK(rtc_lock);
|
||||
|
||||
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt(get_time, tm, tc);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_set_time(efi_time_t *tm)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt(set_time, tm);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
|
||||
efi_bool_t *pending,
|
||||
efi_time_t *tm)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt(set_wakeup_time, enabled, tm);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_variable(efi_char16_t *name,
|
||||
efi_guid_t *vendor,
|
||||
u32 *attr,
|
||||
unsigned long *data_size,
|
||||
void *data)
|
||||
{
|
||||
return efi_call_virt(get_variable, name, vendor, attr, data_size, data);
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
|
||||
efi_char16_t *name,
|
||||
efi_guid_t *vendor)
|
||||
{
|
||||
return efi_call_virt(get_next_variable, name_size, name, vendor);
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_set_variable(efi_char16_t *name,
|
||||
efi_guid_t *vendor,
|
||||
u32 attr,
|
||||
unsigned long data_size,
|
||||
void *data)
|
||||
{
|
||||
return efi_call_virt(set_variable, name, vendor, attr, data_size, data);
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_query_variable_info(u32 attr,
|
||||
u64 *storage_space,
|
||||
u64 *remaining_space,
|
||||
u64 *max_variable_size)
|
||||
{
|
||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
return efi_call_virt(query_variable_info, attr, storage_space,
|
||||
remaining_space, max_variable_size);
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
|
||||
{
|
||||
return efi_call_virt(get_next_high_mono_count, count);
|
||||
}
|
||||
|
||||
static void virt_efi_reset_system(int reset_type,
|
||||
efi_status_t status,
|
||||
unsigned long data_size,
|
||||
efi_char16_t *data)
|
||||
{
|
||||
__efi_call_virt(reset_system, reset_type, status, data_size, data);
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
|
||||
unsigned long count,
|
||||
unsigned long sg_list)
|
||||
{
|
||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
return efi_call_virt(update_capsule, capsules, count, sg_list);
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
|
||||
unsigned long count,
|
||||
u64 *max_size,
|
||||
int *reset_type)
|
||||
{
|
||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
return efi_call_virt(query_capsule_caps, capsules, count, max_size,
|
||||
reset_type);
|
||||
}
|
||||
|
||||
void efi_native_runtime_setup(void)
|
||||
{
|
||||
efi.get_time = virt_efi_get_time;
|
||||
efi.set_time = virt_efi_set_time;
|
||||
efi.get_wakeup_time = virt_efi_get_wakeup_time;
|
||||
efi.set_wakeup_time = virt_efi_set_wakeup_time;
|
||||
efi.get_variable = virt_efi_get_variable;
|
||||
efi.get_next_variable = virt_efi_get_next_variable;
|
||||
efi.set_variable = virt_efi_set_variable;
|
||||
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
|
||||
efi.reset_system = virt_efi_reset_system;
|
||||
efi.query_variable_info = virt_efi_query_variable_info;
|
||||
efi.update_capsule = virt_efi_update_capsule;
|
||||
efi.query_capsule_caps = virt_efi_query_capsule_caps;
|
||||
}
|
Reference in New Issue
Block a user