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:
		
						commit
						76f09aa464
					
				| @ -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; | ||||
| 	} | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -56,13 +56,6 @@ | ||||
| 
 | ||||
| #define EFI_DEBUG | ||||
| 
 | ||||
| #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 }; | ||||
| 
 | ||||
| struct efi_memory_map memmap; | ||||
| 
 | ||||
| static struct efi efi_phys __initdata; | ||||
| @ -95,139 +88,6 @@ static int __init setup_add_efi_memmap(char *arg) | ||||
| } | ||||
| early_param("add_efi_memmap", setup_add_efi_memmap); | ||||
| 
 | ||||
| static bool efi_no_storage_paranoia; | ||||
| 
 | ||||
| static int __init setup_storage_paranoia(char *arg) | ||||
| { | ||||
| 	efi_no_storage_paranoia = true; | ||||
| 	return 0; | ||||
| } | ||||
| early_param("efi_no_storage_paranoia", setup_storage_paranoia); | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| static efi_status_t __init phys_efi_set_virtual_address_map( | ||||
| 	unsigned long memory_map_size, | ||||
| 	unsigned long descriptor_size, | ||||
| @ -244,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; | ||||
| @ -350,6 +174,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) { | ||||
| @ -392,69 +219,15 @@ static void __init print_efi_memmap(void) | ||||
| #endif  /*  EFI_DEBUG  */ | ||||
| } | ||||
| 
 | ||||
| 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_unmap_memmap(void) | ||||
| { | ||||
| 	clear_bit(EFI_MEMMAP, &efi.flags); | ||||
| 	if (memmap.map) { | ||||
| 		early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); | ||||
| 		early_memunmap(memmap.map, memmap.nr_map * memmap.desc_size); | ||||
| 		memmap.map = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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(); | ||||
| } | ||||
| 
 | ||||
| static int __init efi_systab_init(void *phys) | ||||
| { | ||||
| 	if (efi_enabled(EFI_64BIT)) { | ||||
| @ -467,12 +240,12 @@ static int __init efi_systab_init(void *phys) | ||||
| 			if (!data) | ||||
| 				return -ENOMEM; | ||||
| 		} | ||||
| 		systab64 = early_ioremap((unsigned long)phys, | ||||
| 		systab64 = early_memremap((unsigned long)phys, | ||||
| 					 sizeof(*systab64)); | ||||
| 		if (systab64 == NULL) { | ||||
| 			pr_err("Couldn't map the system table!\n"); | ||||
| 			if (data) | ||||
| 				early_iounmap(data, sizeof(*data)); | ||||
| 				early_memunmap(data, sizeof(*data)); | ||||
| 			return -ENOMEM; | ||||
| 		} | ||||
| 
 | ||||
| @ -504,9 +277,9 @@ static int __init efi_systab_init(void *phys) | ||||
| 					   systab64->tables; | ||||
| 		tmp |= data ? data->tables : systab64->tables; | ||||
| 
 | ||||
| 		early_iounmap(systab64, sizeof(*systab64)); | ||||
| 		early_memunmap(systab64, sizeof(*systab64)); | ||||
| 		if (data) | ||||
| 			early_iounmap(data, sizeof(*data)); | ||||
| 			early_memunmap(data, sizeof(*data)); | ||||
| #ifdef CONFIG_X86_32 | ||||
| 		if (tmp >> 32) { | ||||
| 			pr_err("EFI data located above 4GB, disabling EFI.\n"); | ||||
| @ -516,7 +289,7 @@ static int __init efi_systab_init(void *phys) | ||||
| 	} else { | ||||
| 		efi_system_table_32_t *systab32; | ||||
| 
 | ||||
| 		systab32 = early_ioremap((unsigned long)phys, | ||||
| 		systab32 = early_memremap((unsigned long)phys, | ||||
| 					 sizeof(*systab32)); | ||||
| 		if (systab32 == NULL) { | ||||
| 			pr_err("Couldn't map the system table!\n"); | ||||
| @ -537,7 +310,7 @@ static int __init efi_systab_init(void *phys) | ||||
| 		efi_systab.nr_tables = systab32->nr_tables; | ||||
| 		efi_systab.tables = systab32->tables; | ||||
| 
 | ||||
| 		early_iounmap(systab32, sizeof(*systab32)); | ||||
| 		early_memunmap(systab32, sizeof(*systab32)); | ||||
| 	} | ||||
| 
 | ||||
| 	efi.systab = &efi_systab; | ||||
| @ -563,7 +336,7 @@ static int __init efi_runtime_init32(void) | ||||
| { | ||||
| 	efi_runtime_services_32_t *runtime; | ||||
| 
 | ||||
| 	runtime = early_ioremap((unsigned long)efi.systab->runtime, | ||||
| 	runtime = early_memremap((unsigned long)efi.systab->runtime, | ||||
| 			sizeof(efi_runtime_services_32_t)); | ||||
| 	if (!runtime) { | ||||
| 		pr_err("Could not map the runtime service table!\n"); | ||||
| @ -578,7 +351,7 @@ static int __init efi_runtime_init32(void) | ||||
| 	efi_phys.set_virtual_address_map = | ||||
| 			(efi_set_virtual_address_map_t *) | ||||
| 			(unsigned long)runtime->set_virtual_address_map; | ||||
| 	early_iounmap(runtime, sizeof(efi_runtime_services_32_t)); | ||||
| 	early_memunmap(runtime, sizeof(efi_runtime_services_32_t)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -587,7 +360,7 @@ static int __init efi_runtime_init64(void) | ||||
| { | ||||
| 	efi_runtime_services_64_t *runtime; | ||||
| 
 | ||||
| 	runtime = early_ioremap((unsigned long)efi.systab->runtime, | ||||
| 	runtime = early_memremap((unsigned long)efi.systab->runtime, | ||||
| 			sizeof(efi_runtime_services_64_t)); | ||||
| 	if (!runtime) { | ||||
| 		pr_err("Could not map the runtime service table!\n"); | ||||
| @ -602,7 +375,7 @@ static int __init efi_runtime_init64(void) | ||||
| 	efi_phys.set_virtual_address_map = | ||||
| 			(efi_set_virtual_address_map_t *) | ||||
| 			(unsigned long)runtime->set_virtual_address_map; | ||||
| 	early_iounmap(runtime, sizeof(efi_runtime_services_64_t)); | ||||
| 	early_memunmap(runtime, sizeof(efi_runtime_services_64_t)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -616,14 +389,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); | ||||
| 
 | ||||
| @ -632,8 +415,11 @@ 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_ioremap((unsigned long)memmap.phys_map, | ||||
| 	memmap.map = early_memremap((unsigned long)memmap.phys_map, | ||||
| 				   memmap.nr_map * memmap.desc_size); | ||||
| 	if (memmap.map == NULL) { | ||||
| 		pr_err("Could not map the memory map!\n"); | ||||
| @ -649,62 +435,6 @@ static int __init efi_memmap_init(void) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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. | ||||
|  */ | ||||
| static 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_iounmap(tablep, nr_tables * sz); | ||||
| 
 | ||||
| out_memremap: | ||||
| 	early_iounmap(data, sizeof(*data)); | ||||
| out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void __init efi_init(void) | ||||
| { | ||||
| 	efi_char16_t *c16; | ||||
| @ -728,8 +458,6 @@ void __init efi_init(void) | ||||
| 	if (efi_systab_init(efi_phys.systab)) | ||||
| 		return; | ||||
| 
 | ||||
| 	set_bit(EFI_SYSTEM_TABLES, &efi.flags); | ||||
| 
 | ||||
| 	efi.config_table = (unsigned long)efi.systab->tables; | ||||
| 	efi.fw_vendor	 = (unsigned long)efi.systab->fw_vendor; | ||||
| 	efi.runtime	 = (unsigned long)efi.systab->runtime; | ||||
| @ -737,14 +465,14 @@ void __init efi_init(void) | ||||
| 	/*
 | ||||
| 	 * Show what we know for posterity | ||||
| 	 */ | ||||
| 	c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2); | ||||
| 	c16 = tmp = early_memremap(efi.systab->fw_vendor, 2); | ||||
| 	if (c16) { | ||||
| 		for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i) | ||||
| 			vendor[i] = *c16++; | ||||
| 		vendor[i] = '\0'; | ||||
| 	} else | ||||
| 		pr_err("Could not map the firmware vendor!\n"); | ||||
| 	early_iounmap(tmp, 2); | ||||
| 	early_memunmap(tmp, 2); | ||||
| 
 | ||||
| 	pr_info("EFI v%u.%.02u by %s\n", | ||||
| 		efi.systab->hdr.revision >> 16, | ||||
| @ -770,8 +498,6 @@ void __init efi_init(void) | ||||
| 	if (efi_memmap_init()) | ||||
| 		return; | ||||
| 
 | ||||
| 	set_bit(EFI_MEMMAP, &efi.flags); | ||||
| 
 | ||||
| 	print_efi_memmap(); | ||||
| } | ||||
| 
 | ||||
| @ -847,22 +573,6 @@ void __init old_map_region(efi_memory_desc_t *md) | ||||
| 		       (unsigned long long)md->phys_addr); | ||||
| } | ||||
| 
 | ||||
| static void 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; | ||||
| } | ||||
| 
 | ||||
| /* Merge contiguous regions of the same type and attribute */ | ||||
| static void __init efi_merge_regions(void) | ||||
| { | ||||
| @ -1049,7 +759,7 @@ static void __init kexec_enter_virtual_mode(void) | ||||
| 	 */ | ||||
| 	efi.runtime_version = efi_systab.hdr.revision; | ||||
| 
 | ||||
| 	native_runtime_setup(); | ||||
| 	efi_native_runtime_setup(); | ||||
| 
 | ||||
| 	efi.set_virtual_address_map = NULL; | ||||
| 
 | ||||
| @ -1057,11 +767,7 @@ static void __init kexec_enter_virtual_mode(void) | ||||
| 		runtime_code_page_mkexec(); | ||||
| 
 | ||||
| 	/* clean DUMMY object */ | ||||
| 	efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||||
| 			 EFI_VARIABLE_NON_VOLATILE | | ||||
| 			 EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||||
| 			 EFI_VARIABLE_RUNTIME_ACCESS, | ||||
| 			 0, NULL); | ||||
| 	efi_delete_dummy_variable(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| @ -1142,7 +848,7 @@ static void __init __efi_enter_virtual_mode(void) | ||||
| 	efi.runtime_version = efi_systab.hdr.revision; | ||||
| 
 | ||||
| 	if (efi_is_native()) | ||||
| 		native_runtime_setup(); | ||||
| 		efi_native_runtime_setup(); | ||||
| 	else | ||||
| 		efi_thunk_runtime_setup(); | ||||
| 
 | ||||
| @ -1179,15 +885,14 @@ static void __init __efi_enter_virtual_mode(void) | ||||
| 	free_pages((unsigned long)new_memmap, pg_shift); | ||||
| 
 | ||||
| 	/* clean DUMMY object */ | ||||
| 	efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||||
| 			 EFI_VARIABLE_NON_VOLATILE | | ||||
| 			 EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||||
| 			 EFI_VARIABLE_RUNTIME_ACCESS, | ||||
| 			 0, NULL); | ||||
| 	efi_delete_dummy_variable(); | ||||
| } | ||||
| 
 | ||||
| void __init efi_enter_virtual_mode(void) | ||||
| { | ||||
| 	if (efi_enabled(EFI_PARAVIRT)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (efi_setup) | ||||
| 		kexec_enter_virtual_mode(); | ||||
| 	else | ||||
| @ -1220,6 +925,9 @@ u64 efi_mem_attributes(unsigned long phys_addr) | ||||
| 	efi_memory_desc_t *md; | ||||
| 	void *p; | ||||
| 
 | ||||
| 	if (!efi_enabled(EFI_MEMMAP)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | ||||
| 		md = p; | ||||
| 		if ((md->phys_addr <= phys_addr) && | ||||
| @ -1230,86 +938,6 @@ u64 efi_mem_attributes(unsigned long phys_addr) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||||
| 					 EFI_VARIABLE_NON_VOLATILE | | ||||
| 					 EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||||
| 					 EFI_VARIABLE_RUNTIME_ACCESS, | ||||
| 					 0, dummy); | ||||
| 		} | ||||
| 
 | ||||
| 		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); | ||||
| 
 | ||||
| static int __init parse_efi_cmdline(char *str) | ||||
| { | ||||
| 	if (*str == '=') | ||||
| @ -1321,22 +949,3 @@ static int __init parse_efi_cmdline(char *str) | ||||
| 	return 0; | ||||
| } | ||||
| early_param("efi", parse_efi_cmdline); | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
|  | ||||
							
								
								
									
										290
									
								
								arch/x86/platform/efi/quirks.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								arch/x86/platform/efi/quirks.c
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
|  | ||||
							
								
								
									
										43
									
								
								arch/x86/xen/efi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								arch/x86/xen/efi.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| /*
 | ||||
|  * Copyright (c) 2014 Oracle Co., Daniel Kiper | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/efi.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/string.h> | ||||
| 
 | ||||
| #include <xen/xen-ops.h> | ||||
| 
 | ||||
| #include <asm/setup.h> | ||||
| 
 | ||||
| void __init xen_efi_init(void) | ||||
| { | ||||
| 	efi_system_table_t *efi_systab_xen; | ||||
| 
 | ||||
| 	efi_systab_xen = xen_efi_probe(); | ||||
| 
 | ||||
| 	if (efi_systab_xen == NULL) | ||||
| 		return; | ||||
| 
 | ||||
| 	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); | ||||
| } | ||||
| @ -1718,6 +1718,8 @@ asmlinkage __visible void __init xen_start_kernel(void) | ||||
| 
 | ||||
| 	xen_setup_runstate_info(0); | ||||
| 
 | ||||
| 	xen_efi_init(); | ||||
| 
 | ||||
| 	/* Start the world */ | ||||
| #ifdef CONFIG_X86_32 | ||||
| 	i386_start_kernel(); | ||||
|  | ||||
| @ -105,6 +105,14 @@ static inline void __init xen_init_apic(void) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_XEN_EFI | ||||
| extern void xen_efi_init(void); | ||||
| #else | ||||
| static inline void __init xen_efi_init(void) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* Declare an asm function, along with symbols needed to make it
 | ||||
|    inlineable */ | ||||
| #define DECL_ASM(ret, name, ...)		\ | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										368
									
								
								drivers/xen/efi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								drivers/xen/efi.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,368 @@ | ||||
| /*
 | ||||
|  * EFI support for Xen. | ||||
|  * | ||||
|  * Copyright (C) 1999 VA Linux Systems | ||||
|  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> | ||||
|  * Copyright (C) 1999-2002 Hewlett-Packard Co. | ||||
|  *	David Mosberger-Tang <davidm@hpl.hp.com> | ||||
|  *	Stephane Eranian <eranian@hpl.hp.com> | ||||
|  * Copyright (C) 2005-2008 Intel Co. | ||||
|  *	Fenghua Yu <fenghua.yu@intel.com> | ||||
|  *	Bibo Mao <bibo.mao@intel.com> | ||||
|  *	Chandramouli Narayanan <mouli@linux.intel.com> | ||||
|  *	Huang Ying <ying.huang@intel.com> | ||||
|  * Copyright (C) 2011 Novell Co. | ||||
|  *	Jan Beulich <JBeulich@suse.com> | ||||
|  * Copyright (C) 2011-2012 Oracle Co. | ||||
|  *	Liang Tang <liang.tang@oracle.com> | ||||
|  * Copyright (c) 2014 Oracle Co., Daniel Kiper | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/bug.h> | ||||
| #include <linux/efi.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/string.h> | ||||
| 
 | ||||
| #include <xen/interface/xen.h> | ||||
| #include <xen/interface/platform.h> | ||||
| #include <xen/xen.h> | ||||
| 
 | ||||
| #include <asm/xen/hypercall.h> | ||||
| 
 | ||||
| #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; | ||||
| } | ||||
| @ -20,6 +20,7 @@ | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/pfn.h> | ||||
| #include <linux/pstore.h> | ||||
| #include <linux/reboot.h> | ||||
| 
 | ||||
| #include <asm/page.h> | ||||
| 
 | ||||
| @ -521,6 +522,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 | ||||
|  */ | ||||
| @ -870,11 +873,13 @@ 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; | ||||
| 
 | ||||
| extern int efi_reboot_quirk_mode; | ||||
| extern bool efi_poweroff_required(void); | ||||
| 
 | ||||
| /* Iterate through an efi_memory_map */ | ||||
| #define for_each_efi_memory_desc(m, md)					   \ | ||||
| 	for ((md) = (m)->map;						   \ | ||||
| @ -916,7 +921,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 | ||||
| /*
 | ||||
| @ -926,11 +932,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 | ||||
| 
 | ||||
| /*
 | ||||
| @ -1031,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; | ||||
| @ -1161,4 +1166,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 */ | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| 
 | ||||
| #include <linux/percpu.h> | ||||
| #include <linux/notifier.h> | ||||
| #include <linux/efi.h> | ||||
| #include <asm/xen/interface.h> | ||||
| 
 | ||||
| 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 inline efi_system_table_t __init *xen_efi_probe(void) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* INCLUDE_XEN_OPS_H */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user