Commit b0dc553c authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Borislav Petkov

x86/fpu: Make the EFI FPU calling convention explicit

EFI uses kernel_fpu_begin() to conform to the UEFI calling convention.
This specifically requires initializing FCW (FPU Control Word), whereas
no sane 64-bit kernel code should use legacy 387 operations that
reference FCW.

This should allow to safely change the default semantics of
kernel_fpu_begin() to stop initializing FCW on 64-bit kernels.

 [ bp: Massage commit message a little. ]
Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/25d392fff64680e0f4bb8cf0b1003314dc29eafe.1611205691.git.luto@kernel.org
parent 6ee1d745
...@@ -68,17 +68,33 @@ extern unsigned long efi_fw_vendor, efi_config_table; ...@@ -68,17 +68,33 @@ extern unsigned long efi_fw_vendor, efi_config_table;
#f " called with too many arguments (" #p ">" #n ")"); \ #f " called with too many arguments (" #p ">" #n ")"); \
}) })
static inline void efi_fpu_begin(void)
{
/*
* The UEFI calling convention (UEFI spec 2.3.2 and 2.3.4) requires
* that FCW and MXCSR (64-bit) must be initialized prior to calling
* UEFI code. (Oddly the spec does not require that the FPU stack
* be empty.)
*/
kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR);
}
static inline void efi_fpu_end(void)
{
kernel_fpu_end();
}
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#define arch_efi_call_virt_setup() \ #define arch_efi_call_virt_setup() \
({ \ ({ \
kernel_fpu_begin(); \ efi_fpu_begin(); \
firmware_restrict_branch_speculation_start(); \ firmware_restrict_branch_speculation_start(); \
}) })
#define arch_efi_call_virt_teardown() \ #define arch_efi_call_virt_teardown() \
({ \ ({ \
firmware_restrict_branch_speculation_end(); \ firmware_restrict_branch_speculation_end(); \
kernel_fpu_end(); \ efi_fpu_end(); \
}) })
#define arch_efi_call_virt(p, f, args...) p->f(args) #define arch_efi_call_virt(p, f, args...) p->f(args)
...@@ -107,7 +123,7 @@ struct efi_scratch { ...@@ -107,7 +123,7 @@ struct efi_scratch {
#define arch_efi_call_virt_setup() \ #define arch_efi_call_virt_setup() \
({ \ ({ \
efi_sync_low_kernel_mappings(); \ efi_sync_low_kernel_mappings(); \
kernel_fpu_begin(); \ efi_fpu_begin(); \
firmware_restrict_branch_speculation_start(); \ firmware_restrict_branch_speculation_start(); \
efi_switch_mm(&efi_mm); \ efi_switch_mm(&efi_mm); \
}) })
...@@ -119,7 +135,7 @@ struct efi_scratch { ...@@ -119,7 +135,7 @@ struct efi_scratch {
({ \ ({ \
efi_switch_mm(efi_scratch.prev_mm); \ efi_switch_mm(efi_scratch.prev_mm); \
firmware_restrict_branch_speculation_end(); \ firmware_restrict_branch_speculation_end(); \
kernel_fpu_end(); \ efi_fpu_end(); \
}) })
#ifdef CONFIG_KASAN #ifdef CONFIG_KASAN
......
...@@ -850,7 +850,7 @@ efi_set_virtual_address_map(unsigned long memory_map_size, ...@@ -850,7 +850,7 @@ efi_set_virtual_address_map(unsigned long memory_map_size,
virtual_map); virtual_map);
efi_switch_mm(&efi_mm); efi_switch_mm(&efi_mm);
kernel_fpu_begin(); efi_fpu_begin();
/* Disable interrupts around EFI calls: */ /* Disable interrupts around EFI calls: */
local_irq_save(flags); local_irq_save(flags);
...@@ -859,7 +859,7 @@ efi_set_virtual_address_map(unsigned long memory_map_size, ...@@ -859,7 +859,7 @@ efi_set_virtual_address_map(unsigned long memory_map_size,
descriptor_version, virtual_map); descriptor_version, virtual_map);
local_irq_restore(flags); local_irq_restore(flags);
kernel_fpu_end(); efi_fpu_end();
/* grab the virtually remapped EFI runtime services table pointer */ /* grab the virtually remapped EFI runtime services table pointer */
efi.runtime = READ_ONCE(systab->runtime); efi.runtime = READ_ONCE(systab->runtime);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment