mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
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:
@@ -347,12 +347,18 @@ config CMDLINE_FORCE
|
||||
This is useful if you cannot or don't want to change the
|
||||
command-line options your boot loader passes to the kernel.
|
||||
|
||||
config EFI_STUB
|
||||
bool
|
||||
|
||||
config EFI
|
||||
bool "UEFI runtime support"
|
||||
depends on OF && !CPU_BIG_ENDIAN
|
||||
select LIBFDT
|
||||
select UCS2_STRING
|
||||
select EFI_PARAMS_FROM_FDT
|
||||
select EFI_RUNTIME_WRAPPERS
|
||||
select EFI_STUB
|
||||
select EFI_ARMSTUB
|
||||
default y
|
||||
help
|
||||
This option provides support for runtime services provided
|
||||
|
||||
@@ -52,6 +52,7 @@ core-$(CONFIG_XEN) += arch/arm64/xen/
|
||||
core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
|
||||
libs-y := arch/arm64/lib/ $(libs-y)
|
||||
libs-y += $(LIBGCC)
|
||||
libs-$(CONFIG_EFI_STUB) += drivers/firmware/efi/libstub/
|
||||
|
||||
# Default target when executing plain make
|
||||
KBUILD_IMAGE := Image.gz
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _ASM_EFI_H
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/neon.h>
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
extern void efi_init(void);
|
||||
@@ -11,4 +12,36 @@ extern void efi_idmap_init(void);
|
||||
#define efi_idmap_init()
|
||||
#endif
|
||||
|
||||
#define efi_call_virt(f, ...) \
|
||||
({ \
|
||||
efi_##f##_t *__f = efi.systab->runtime->f; \
|
||||
efi_status_t __s; \
|
||||
\
|
||||
kernel_neon_begin(); \
|
||||
__s = __f(__VA_ARGS__); \
|
||||
kernel_neon_end(); \
|
||||
__s; \
|
||||
})
|
||||
|
||||
#define __efi_call_virt(f, ...) \
|
||||
({ \
|
||||
efi_##f##_t *__f = efi.systab->runtime->f; \
|
||||
\
|
||||
kernel_neon_begin(); \
|
||||
__f(__VA_ARGS__); \
|
||||
kernel_neon_end(); \
|
||||
})
|
||||
|
||||
/* arch specific definitions used by the stub code */
|
||||
|
||||
/*
|
||||
* AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
|
||||
* start of kernel and may not cross a 2MiB boundary. We set alignment to
|
||||
* 2MiB so we know it won't cross a 2MiB boundary.
|
||||
*/
|
||||
#define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */
|
||||
#define MAX_FDT_OFFSET SZ_512M
|
||||
|
||||
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
|
||||
|
||||
#endif /* _ASM_EFI_H */
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) \
|
||||
-I$(src)/../../../scripts/dtc/libfdt
|
||||
CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
|
||||
CFLAGS_REMOVE_ftrace.o = -pg
|
||||
CFLAGS_REMOVE_insn.o = -pg
|
||||
|
||||
@@ -10,46 +10,16 @@
|
||||
*
|
||||
*/
|
||||
#include <linux/efi.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
/*
|
||||
* AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
|
||||
* start of kernel and may not cross a 2MiB boundary. We set alignment to
|
||||
* 2MiB so we know it won't cross a 2MiB boundary.
|
||||
*/
|
||||
#define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */
|
||||
#define MAX_FDT_OFFSET SZ_512M
|
||||
|
||||
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
|
||||
|
||||
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;
|
||||
@@ -69,7 +39,7 @@ static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
|
||||
if (*image_addr != (dram_base + TEXT_OFFSET)) {
|
||||
pr_efi_err(sys_table, "Failed to alloc kernel memory\n");
|
||||
efi_free(sys_table, kernel_memsize, *image_addr);
|
||||
return EFI_ERROR;
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
*image_size = kernel_memsize;
|
||||
}
|
||||
|
||||
+25
-17
@@ -414,13 +414,24 @@ static int __init arm64_enter_virtual_mode(void)
|
||||
for_each_efi_memory_desc(&memmap, md) {
|
||||
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
||||
continue;
|
||||
if (remap_region(md, &virt_md))
|
||||
++count;
|
||||
if (!remap_region(md, &virt_md))
|
||||
goto err_unmap;
|
||||
++count;
|
||||
}
|
||||
|
||||
efi.systab = (__force void *)efi_lookup_mapped_addr(efi_system_table);
|
||||
if (efi.systab)
|
||||
set_bit(EFI_SYSTEM_TABLES, &efi.flags);
|
||||
if (!efi.systab) {
|
||||
/*
|
||||
* If we have no virtual mapping for the System Table at this
|
||||
* point, the memory map doesn't cover the physical offset where
|
||||
* it resides. This means the System Table will be inaccessible
|
||||
* to Runtime Services themselves once the virtual mapping is
|
||||
* installed.
|
||||
*/
|
||||
pr_err("Failed to remap EFI System Table -- buggy firmware?\n");
|
||||
goto err_unmap;
|
||||
}
|
||||
set_bit(EFI_SYSTEM_TABLES, &efi.flags);
|
||||
|
||||
local_irq_save(flags);
|
||||
cpu_switch_mm(idmap_pg_dir, &init_mm);
|
||||
@@ -449,21 +460,18 @@ static int __init arm64_enter_virtual_mode(void)
|
||||
|
||||
/* Set up runtime services function pointers */
|
||||
runtime = efi.systab->runtime;
|
||||
efi.get_time = runtime->get_time;
|
||||
efi.set_time = runtime->set_time;
|
||||
efi.get_wakeup_time = runtime->get_wakeup_time;
|
||||
efi.set_wakeup_time = runtime->set_wakeup_time;
|
||||
efi.get_variable = runtime->get_variable;
|
||||
efi.get_next_variable = runtime->get_next_variable;
|
||||
efi.set_variable = runtime->set_variable;
|
||||
efi.query_variable_info = runtime->query_variable_info;
|
||||
efi.update_capsule = runtime->update_capsule;
|
||||
efi.query_capsule_caps = runtime->query_capsule_caps;
|
||||
efi.get_next_high_mono_count = runtime->get_next_high_mono_count;
|
||||
efi.reset_system = runtime->reset_system;
|
||||
|
||||
efi_native_runtime_setup();
|
||||
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
/* unmap all mappings that succeeded: there are 'count' of those */
|
||||
for (virt_md = virtmap; count--; virt_md += memmap.desc_size) {
|
||||
md = virt_md;
|
||||
iounmap((__force void __iomem *)md->virt_addr);
|
||||
}
|
||||
kfree(virtmap);
|
||||
return -1;
|
||||
}
|
||||
early_initcall(arm64_enter_virtual_mode);
|
||||
|
||||
@@ -426,6 +426,7 @@ extern void iounmap (volatile void __iomem *addr);
|
||||
extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size);
|
||||
#define early_memremap(phys_addr, size) early_ioremap(phys_addr, size)
|
||||
extern void early_iounmap (volatile void __iomem *addr, unsigned long size);
|
||||
#define early_memunmap(addr, size) early_iounmap(addr, size)
|
||||
static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned long size)
|
||||
{
|
||||
return ioremap(phys_addr, size);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1522,6 +1522,7 @@ config EFI
|
||||
bool "EFI runtime service support"
|
||||
depends on ACPI
|
||||
select UCS2_STRING
|
||||
select EFI_RUNTIME_WRAPPERS
|
||||
---help---
|
||||
This enables the kernel to use EFI runtime services that are
|
||||
available (such as the EFI variable services).
|
||||
|
||||
@@ -33,7 +33,8 @@ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
|
||||
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
|
||||
|
||||
ifeq ($(CONFIG_EFI_STUB), y)
|
||||
VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
|
||||
VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \
|
||||
$(objtree)/drivers/firmware/efi/libstub/lib.a
|
||||
endif
|
||||
|
||||
$(obj)/vmlinux: $(VMLINUX_OBJS) FORCE
|
||||
|
||||
@@ -19,10 +19,7 @@
|
||||
|
||||
static efi_system_table_t *sys_table;
|
||||
|
||||
static struct efi_config *efi_early;
|
||||
|
||||
#define efi_call_early(f, ...) \
|
||||
efi_early->call(efi_early->f, __VA_ARGS__);
|
||||
struct efi_config *efi_early;
|
||||
|
||||
#define BOOT_SERVICES(bits) \
|
||||
static void setup_boot_services##bits(struct efi_config *c) \
|
||||
@@ -48,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,
|
||||
@@ -156,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)
|
||||
{
|
||||
@@ -166,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;
|
||||
@@ -184,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;
|
||||
@@ -249,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)
|
||||
@@ -258,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;
|
||||
@@ -284,8 +280,6 @@ static void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
|
||||
}
|
||||
}
|
||||
|
||||
#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
|
||||
|
||||
static void find_bits(unsigned long mask, u8 *pos, u8 *size)
|
||||
{
|
||||
u8 first, len;
|
||||
@@ -1038,6 +1032,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
||||
int i;
|
||||
unsigned long ramdisk_addr;
|
||||
unsigned long ramdisk_size;
|
||||
unsigned long initrd_addr_max;
|
||||
|
||||
efi_early = c;
|
||||
sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
|
||||
@@ -1100,14 +1095,21 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
||||
|
||||
memset(sdt, 0, sizeof(*sdt));
|
||||
|
||||
if (hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G)
|
||||
initrd_addr_max = -1UL;
|
||||
else
|
||||
initrd_addr_max = hdr->initrd_addr_max;
|
||||
|
||||
status = handle_cmdline_files(sys_table, image,
|
||||
(char *)(unsigned long)hdr->cmd_line_ptr,
|
||||
"initrd=", hdr->initrd_addr_max,
|
||||
"initrd=", initrd_addr_max,
|
||||
&ramdisk_addr, &ramdisk_size);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail2;
|
||||
hdr->ramdisk_image = ramdisk_addr;
|
||||
hdr->ramdisk_size = ramdisk_size;
|
||||
hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
|
||||
hdr->ramdisk_size = ramdisk_size & 0xffffffff;
|
||||
boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
|
||||
boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32;
|
||||
|
||||
return boot_params;
|
||||
fail2:
|
||||
@@ -1374,7 +1376,10 @@ struct boot_params *efi_main(struct efi_config *c,
|
||||
|
||||
setup_graphics(boot_params);
|
||||
|
||||
setup_efi_pci(boot_params);
|
||||
status = setup_efi_pci(boot_params);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk(sys_table, "setup_efi_pci() failed!\n");
|
||||
}
|
||||
|
||||
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
||||
sizeof(*gdt), (void **)&gdt);
|
||||
@@ -1401,16 +1406,20 @@ struct boot_params *efi_main(struct efi_config *c,
|
||||
hdr->init_size, hdr->init_size,
|
||||
hdr->pref_address,
|
||||
hdr->kernel_alignment);
|
||||
if (status != EFI_SUCCESS)
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk(sys_table, "efi_relocate_kernel() failed!\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdr->pref_address = hdr->code32_start;
|
||||
hdr->code32_start = bzimage_addr;
|
||||
}
|
||||
|
||||
status = exit_boot(boot_params, handle, is64);
|
||||
if (status != EFI_SUCCESS)
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk(sys_table, "exit_boot() failed!\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memset((char *)gdt->address, 0x0, gdt->size);
|
||||
desc = (struct desc_struct *)gdt->address;
|
||||
@@ -1470,5 +1479,6 @@ struct boot_params *efi_main(struct efi_config *c,
|
||||
|
||||
return boot_params;
|
||||
fail:
|
||||
efi_printk(sys_table, "efi_main() failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -103,20 +103,4 @@ struct efi_uga_draw_protocol {
|
||||
void *blt;
|
||||
};
|
||||
|
||||
struct efi_config {
|
||||
u64 image_handle;
|
||||
u64 table;
|
||||
u64 allocate_pool;
|
||||
u64 allocate_pages;
|
||||
u64 get_memory_map;
|
||||
u64 free_pool;
|
||||
u64 free_pages;
|
||||
u64 locate_handle;
|
||||
u64 handle_protocol;
|
||||
u64 exit_boot_services;
|
||||
u64 text_output;
|
||||
efi_status_t (*call)(unsigned long, ...);
|
||||
bool is64;
|
||||
} __packed;
|
||||
|
||||
#endif /* BOOT_COMPRESSED_EBOOT_H */
|
||||
|
||||
@@ -154,7 +154,7 @@ extra_header_fields:
|
||||
#else
|
||||
.quad 0 # ImageBase
|
||||
#endif
|
||||
.long 0x20 # SectionAlignment
|
||||
.long CONFIG_PHYSICAL_ALIGN # SectionAlignment
|
||||
.long 0x20 # FileAlignment
|
||||
.word 0 # MajorOperatingSystemVersion
|
||||
.word 0 # MinorOperatingSystemVersion
|
||||
|
||||
@@ -104,6 +104,8 @@ extern void __init runtime_code_page_mkexec(void);
|
||||
extern void __init efi_runtime_mkexec(void);
|
||||
extern void __init efi_dump_pagetable(void);
|
||||
extern void __init efi_apply_memmap_quirks(void);
|
||||
extern int __init efi_reuse_config(u64 tables, int nr_tables);
|
||||
extern void efi_delete_dummy_variable(void);
|
||||
|
||||
struct efi_setup_data {
|
||||
u64 fw_vendor;
|
||||
@@ -156,6 +158,33 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
#endif /* CONFIG_EFI_MIXED */
|
||||
|
||||
|
||||
/* arch specific definitions used by the stub code */
|
||||
|
||||
struct efi_config {
|
||||
u64 image_handle;
|
||||
u64 table;
|
||||
u64 allocate_pool;
|
||||
u64 allocate_pages;
|
||||
u64 get_memory_map;
|
||||
u64 free_pool;
|
||||
u64 free_pages;
|
||||
u64 locate_handle;
|
||||
u64 handle_protocol;
|
||||
u64 exit_boot_services;
|
||||
u64 text_output;
|
||||
efi_status_t (*call)(unsigned long, ...);
|
||||
bool is64;
|
||||
} __packed;
|
||||
|
||||
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.
|
||||
@@ -168,6 +197,10 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
|
||||
#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 */
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <asm/realmode.h>
|
||||
#include <asm/x86_init.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
/*
|
||||
* 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);
|
||||
@@ -528,11 +542,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;
|
||||
|
||||
|
||||
@@ -924,10 +924,10 @@ void __init setup_arch(char **cmdline_p)
|
||||
#endif
|
||||
#ifdef CONFIG_EFI
|
||||
if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
|
||||
"EL32", 4)) {
|
||||
EFI32_LOADER_SIGNATURE, 4)) {
|
||||
set_bit(EFI_BOOT, &efi.flags);
|
||||
} else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
|
||||
"EL64", 4)) {
|
||||
EFI64_LOADER_SIGNATURE, 4)) {
|
||||
set_bit(EFI_BOOT, &efi.flags);
|
||||
set_bit(EFI_64BIT, &efi.flags);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
|
||||
obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o
|
||||
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
|
||||
obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
|
||||
obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
|
||||
|
||||
+46
-437
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,290 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/uv/uv.h>
|
||||
|
||||
#define EFI_MIN_RESERVE 5120
|
||||
|
||||
#define EFI_DUMMY_GUID \
|
||||
EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
|
||||
|
||||
static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
|
||||
|
||||
static bool efi_no_storage_paranoia;
|
||||
|
||||
/*
|
||||
* Some firmware implementations refuse to boot if there's insufficient
|
||||
* space in the variable store. The implementation of garbage collection
|
||||
* in some FW versions causes stale (deleted) variables to take up space
|
||||
* longer than intended and space is only freed once the store becomes
|
||||
* almost completely full.
|
||||
*
|
||||
* Enabling this option disables the space checks in
|
||||
* efi_query_variable_store() and forces garbage collection.
|
||||
*
|
||||
* Only enable this option if deleting EFI variables does not free up
|
||||
* space in your variable store, e.g. if despite deleting variables
|
||||
* you're unable to create new ones.
|
||||
*/
|
||||
static int __init setup_storage_paranoia(char *arg)
|
||||
{
|
||||
efi_no_storage_paranoia = true;
|
||||
return 0;
|
||||
}
|
||||
early_param("efi_no_storage_paranoia", setup_storage_paranoia);
|
||||
|
||||
/*
|
||||
* Deleting the dummy variable which kicks off garbage collection
|
||||
*/
|
||||
void efi_delete_dummy_variable(void)
|
||||
{
|
||||
efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
|
||||
EFI_VARIABLE_NON_VOLATILE |
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some firmware implementations refuse to boot if there's insufficient space
|
||||
* in the variable store. Ensure that we never use more than a safe limit.
|
||||
*
|
||||
* Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
|
||||
* store.
|
||||
*/
|
||||
efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
|
||||
{
|
||||
efi_status_t status;
|
||||
u64 storage_size, remaining_size, max_size;
|
||||
|
||||
if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
|
||||
return 0;
|
||||
|
||||
status = efi.query_variable_info(attributes, &storage_size,
|
||||
&remaining_size, &max_size);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
/*
|
||||
* We account for that by refusing the write if permitting it would
|
||||
* reduce the available space to under 5KB. This figure was provided by
|
||||
* Samsung, so should be safe.
|
||||
*/
|
||||
if ((remaining_size - size < EFI_MIN_RESERVE) &&
|
||||
!efi_no_storage_paranoia) {
|
||||
|
||||
/*
|
||||
* Triggering garbage collection may require that the firmware
|
||||
* generate a real EFI_OUT_OF_RESOURCES error. We can force
|
||||
* that by attempting to use more space than is available.
|
||||
*/
|
||||
unsigned long dummy_size = remaining_size + 1024;
|
||||
void *dummy = kzalloc(dummy_size, GFP_ATOMIC);
|
||||
|
||||
if (!dummy)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
|
||||
EFI_VARIABLE_NON_VOLATILE |
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
dummy_size, dummy);
|
||||
|
||||
if (status == EFI_SUCCESS) {
|
||||
/*
|
||||
* This should have failed, so if it didn't make sure
|
||||
* that we delete it...
|
||||
*/
|
||||
efi_delete_dummy_variable();
|
||||
}
|
||||
|
||||
kfree(dummy);
|
||||
|
||||
/*
|
||||
* The runtime code may now have triggered a garbage collection
|
||||
* run, so check the variable info again
|
||||
*/
|
||||
status = efi.query_variable_info(attributes, &storage_size,
|
||||
&remaining_size, &max_size);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
/*
|
||||
* There still isn't enough room, so return an error
|
||||
*/
|
||||
if (remaining_size - size < EFI_MIN_RESERVE)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(efi_query_variable_store);
|
||||
|
||||
/*
|
||||
* The UEFI specification makes it clear that the operating system is free to do
|
||||
* whatever it wants with boot services code after ExitBootServices() has been
|
||||
* called. Ignoring this recommendation a significant bunch of EFI implementations
|
||||
* continue calling into boot services code (SetVirtualAddressMap). In order to
|
||||
* work around such buggy implementations we reserve boot services region during
|
||||
* EFI init and make sure it stays executable. Then, after SetVirtualAddressMap(), it
|
||||
* is discarded.
|
||||
*/
|
||||
void __init efi_reserve_boot_services(void)
|
||||
{
|
||||
void *p;
|
||||
|
||||
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
||||
efi_memory_desc_t *md = p;
|
||||
u64 start = md->phys_addr;
|
||||
u64 size = md->num_pages << EFI_PAGE_SHIFT;
|
||||
|
||||
if (md->type != EFI_BOOT_SERVICES_CODE &&
|
||||
md->type != EFI_BOOT_SERVICES_DATA)
|
||||
continue;
|
||||
/* Only reserve where possible:
|
||||
* - Not within any already allocated areas
|
||||
* - Not over any memory area (really needed, if above?)
|
||||
* - Not within any part of the kernel
|
||||
* - Not the bios reserved area
|
||||
*/
|
||||
if ((start + size > __pa_symbol(_text)
|
||||
&& start <= __pa_symbol(_end)) ||
|
||||
!e820_all_mapped(start, start+size, E820_RAM) ||
|
||||
memblock_is_region_reserved(start, size)) {
|
||||
/* Could not reserve, skip it */
|
||||
md->num_pages = 0;
|
||||
memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n",
|
||||
start, start+size-1);
|
||||
} else
|
||||
memblock_reserve(start, size);
|
||||
}
|
||||
}
|
||||
|
||||
void __init efi_free_boot_services(void)
|
||||
{
|
||||
void *p;
|
||||
|
||||
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
||||
efi_memory_desc_t *md = p;
|
||||
unsigned long long start = md->phys_addr;
|
||||
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
|
||||
|
||||
if (md->type != EFI_BOOT_SERVICES_CODE &&
|
||||
md->type != EFI_BOOT_SERVICES_DATA)
|
||||
continue;
|
||||
|
||||
/* Could not reserve boot area */
|
||||
if (!size)
|
||||
continue;
|
||||
|
||||
free_bootmem_late(start, size);
|
||||
}
|
||||
|
||||
efi_unmap_memmap();
|
||||
}
|
||||
|
||||
/*
|
||||
* A number of config table entries get remapped to virtual addresses
|
||||
* after entering EFI virtual mode. However, the kexec kernel requires
|
||||
* their physical addresses therefore we pass them via setup_data and
|
||||
* correct those entries to their respective physical addresses here.
|
||||
*
|
||||
* Currently only handles smbios which is necessary for some firmware
|
||||
* implementation.
|
||||
*/
|
||||
int __init efi_reuse_config(u64 tables, int nr_tables)
|
||||
{
|
||||
int i, sz, ret = 0;
|
||||
void *p, *tablep;
|
||||
struct efi_setup_data *data;
|
||||
|
||||
if (!efi_setup)
|
||||
return 0;
|
||||
|
||||
if (!efi_enabled(EFI_64BIT))
|
||||
return 0;
|
||||
|
||||
data = early_memremap(efi_setup, sizeof(*data));
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!data->smbios)
|
||||
goto out_memremap;
|
||||
|
||||
sz = sizeof(efi_config_table_64_t);
|
||||
|
||||
p = tablep = early_memremap(tables, nr_tables * sz);
|
||||
if (!p) {
|
||||
pr_err("Could not map Configuration table!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_memremap;
|
||||
}
|
||||
|
||||
for (i = 0; i < efi.systab->nr_tables; i++) {
|
||||
efi_guid_t guid;
|
||||
|
||||
guid = ((efi_config_table_64_t *)p)->guid;
|
||||
|
||||
if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID))
|
||||
((efi_config_table_64_t *)p)->table = data->smbios;
|
||||
p += sz;
|
||||
}
|
||||
early_memunmap(tablep, nr_tables * sz);
|
||||
|
||||
out_memremap:
|
||||
early_memunmap(data, sizeof(*data));
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __init efi_apply_memmap_quirks(void)
|
||||
{
|
||||
/*
|
||||
* Once setup is done earlier, unmap the EFI memory map on mismatched
|
||||
* firmware/kernel architectures since there is no support for runtime
|
||||
* services.
|
||||
*/
|
||||
if (!efi_runtime_supported()) {
|
||||
pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
|
||||
efi_unmap_memmap();
|
||||
}
|
||||
|
||||
/*
|
||||
* UV doesn't support the new EFI pagetable mapping yet.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -22,3 +22,4 @@ obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
|
||||
obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
|
||||
obj-$(CONFIG_XEN_DOM0) += apic.o vga.o
|
||||
obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o
|
||||
obj-$(CONFIG_XEN_EFI) += efi.o
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user