185034e72d
Some firmware still needs a 1:1 (virt->phys) mapping even after we've called SetVirtualAddressMap(). So install the mapping alongside our existing kernel mapping whenever we make EFI calls in virtual mode. This bug was discovered on ASUS machines where the firmware implementation of GetTime() accesses the RTC device via physical addresses, even though that's bogus per the UEFI spec since we've informed the firmware via SetVirtualAddressMap() that the boottime memory map is no longer valid. This bug seems to be present in a lot of consumer devices, so there's not a lot we can do about this spec violation apart from workaround it. Cc: JérômeCarretero <cJ-ko@zougloub.eu> Cc: Vasco Dias <rafa.vasco@gmail.com> Acked-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
130 lines
4.6 KiB
C
130 lines
4.6 KiB
C
#ifndef _ASM_X86_EFI_H
|
|
#define _ASM_X86_EFI_H
|
|
|
|
#ifdef CONFIG_X86_32
|
|
|
|
#define EFI_LOADER_SIGNATURE "EL32"
|
|
|
|
extern unsigned long asmlinkage efi_call_phys(void *, ...);
|
|
|
|
#define efi_call_phys0(f) efi_call_phys(f)
|
|
#define efi_call_phys1(f, a1) efi_call_phys(f, a1)
|
|
#define efi_call_phys2(f, a1, a2) efi_call_phys(f, a1, a2)
|
|
#define efi_call_phys3(f, a1, a2, a3) efi_call_phys(f, a1, a2, a3)
|
|
#define efi_call_phys4(f, a1, a2, a3, a4) \
|
|
efi_call_phys(f, a1, a2, a3, a4)
|
|
#define efi_call_phys5(f, a1, a2, a3, a4, a5) \
|
|
efi_call_phys(f, a1, a2, a3, a4, a5)
|
|
#define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \
|
|
efi_call_phys(f, a1, a2, a3, a4, a5, a6)
|
|
/*
|
|
* Wrap all the virtual calls in a way that forces the parameters on the stack.
|
|
*/
|
|
|
|
#define efi_call_virt(f, args...) \
|
|
((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args)
|
|
|
|
#define efi_call_virt0(f) efi_call_virt(f)
|
|
#define efi_call_virt1(f, a1) efi_call_virt(f, a1)
|
|
#define efi_call_virt2(f, a1, a2) efi_call_virt(f, a1, a2)
|
|
#define efi_call_virt3(f, a1, a2, a3) efi_call_virt(f, a1, a2, a3)
|
|
#define efi_call_virt4(f, a1, a2, a3, a4) \
|
|
efi_call_virt(f, a1, a2, a3, a4)
|
|
#define efi_call_virt5(f, a1, a2, a3, a4, a5) \
|
|
efi_call_virt(f, a1, a2, a3, a4, a5)
|
|
#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \
|
|
efi_call_virt(f, a1, a2, a3, a4, a5, a6)
|
|
|
|
#define efi_ioremap(addr, size, type) ioremap_cache(addr, size)
|
|
|
|
#else /* !CONFIG_X86_32 */
|
|
|
|
#define EFI_LOADER_SIGNATURE "EL64"
|
|
|
|
extern u64 efi_call0(void *fp);
|
|
extern u64 efi_call1(void *fp, u64 arg1);
|
|
extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
|
|
extern u64 efi_call3(void *fp, u64 arg1, u64 arg2, u64 arg3);
|
|
extern u64 efi_call4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4);
|
|
extern u64 efi_call5(void *fp, u64 arg1, u64 arg2, u64 arg3,
|
|
u64 arg4, u64 arg5);
|
|
extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,
|
|
u64 arg4, u64 arg5, u64 arg6);
|
|
|
|
#define efi_call_phys0(f) \
|
|
efi_call0((void *)(f))
|
|
#define efi_call_phys1(f, a1) \
|
|
efi_call1((void *)(f), (u64)(a1))
|
|
#define efi_call_phys2(f, a1, a2) \
|
|
efi_call2((void *)(f), (u64)(a1), (u64)(a2))
|
|
#define efi_call_phys3(f, a1, a2, a3) \
|
|
efi_call3((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3))
|
|
#define efi_call_phys4(f, a1, a2, a3, a4) \
|
|
efi_call4((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3), \
|
|
(u64)(a4))
|
|
#define efi_call_phys5(f, a1, a2, a3, a4, a5) \
|
|
efi_call5((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3), \
|
|
(u64)(a4), (u64)(a5))
|
|
#define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \
|
|
efi_call6((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3), \
|
|
(u64)(a4), (u64)(a5), (u64)(a6))
|
|
|
|
extern unsigned long efi_call_virt_prelog(void);
|
|
extern void efi_call_virt_epilog(unsigned long);
|
|
|
|
#define efi_callx(x, func, ...) \
|
|
({ \
|
|
efi_status_t __status; \
|
|
unsigned long __pgd; \
|
|
\
|
|
__pgd = efi_call_virt_prelog(); \
|
|
__status = efi_call##x(func, __VA_ARGS__); \
|
|
efi_call_virt_epilog(__pgd); \
|
|
__status; \
|
|
})
|
|
|
|
#define efi_call_virt0(f) \
|
|
efi_callx(0, (void *)(efi.systab->runtime->f))
|
|
#define efi_call_virt1(f, a1) \
|
|
efi_callx(1, (void *)(efi.systab->runtime->f), (u64)(a1))
|
|
#define efi_call_virt2(f, a1, a2) \
|
|
efi_callx(2, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2))
|
|
#define efi_call_virt3(f, a1, a2, a3) \
|
|
efi_callx(3, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
|
|
(u64)(a3))
|
|
#define efi_call_virt4(f, a1, a2, a3, a4) \
|
|
efi_callx(4, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
|
|
(u64)(a3), (u64)(a4))
|
|
#define efi_call_virt5(f, a1, a2, a3, a4, a5) \
|
|
efi_callx(5, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
|
|
(u64)(a3), (u64)(a4), (u64)(a5))
|
|
#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \
|
|
efi_callx(6, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
|
|
(u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
|
|
|
|
extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
|
|
u32 type);
|
|
|
|
#endif /* CONFIG_X86_32 */
|
|
|
|
extern int add_efi_memmap;
|
|
extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
|
|
extern int efi_memblock_x86_reserve_range(void);
|
|
extern void efi_call_phys_prelog(void);
|
|
extern void efi_call_phys_epilog(void);
|
|
|
|
#ifndef CONFIG_EFI
|
|
/*
|
|
* IF EFI is not configured, have the EFI calls return -ENOSYS.
|
|
*/
|
|
#define efi_call0(_f) (-ENOSYS)
|
|
#define efi_call1(_f, _a1) (-ENOSYS)
|
|
#define efi_call2(_f, _a1, _a2) (-ENOSYS)
|
|
#define efi_call3(_f, _a1, _a2, _a3) (-ENOSYS)
|
|
#define efi_call4(_f, _a1, _a2, _a3, _a4) (-ENOSYS)
|
|
#define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS)
|
|
#define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS)
|
|
#endif /* CONFIG_EFI */
|
|
|
|
#endif /* _ASM_X86_EFI_H */
|