Commit 2f51c820 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Ingo Molnar:
 "This fixes 3 FPU handling related bugs, an EFI boot crash and a
  runtime warning.

  The EFI fix arrived late but I didn't want to delay it to after v4.5
  because the effects are pretty bad for the systems that are affected
  by it"

[ Actually, I don't think the EFI fix really matters yet, because we
  haven't switched to the separate EFI page tables in mainline yet ]

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/efi: Fix boot crash by always mapping boot service regions into new EFI page tables
  x86/fpu: Fix eager-FPU handling on legacy FPU machines
  x86/delay: Avoid preemptible context checks in delay_mwaitx()
  x86/fpu: Revert ("x86/fpu: Disable AVX when eagerfpu is off")
  x86/fpu: Fix 'no387' regression
parents fda604a4 452308de
...@@ -20,16 +20,15 @@ ...@@ -20,16 +20,15 @@
/* Supported features which support lazy state saving */ /* Supported features which support lazy state saving */
#define XFEATURE_MASK_LAZY (XFEATURE_MASK_FP | \ #define XFEATURE_MASK_LAZY (XFEATURE_MASK_FP | \
XFEATURE_MASK_SSE) XFEATURE_MASK_SSE | \
/* Supported features which require eager state saving */
#define XFEATURE_MASK_EAGER (XFEATURE_MASK_BNDREGS | \
XFEATURE_MASK_BNDCSR | \
XFEATURE_MASK_YMM | \ XFEATURE_MASK_YMM | \
XFEATURE_MASK_OPMASK | \ XFEATURE_MASK_OPMASK | \
XFEATURE_MASK_ZMM_Hi256 | \ XFEATURE_MASK_ZMM_Hi256 | \
XFEATURE_MASK_Hi16_ZMM) XFEATURE_MASK_Hi16_ZMM)
/* Supported features which require eager state saving */
#define XFEATURE_MASK_EAGER (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)
/* All currently supported features */ /* All currently supported features */
#define XCNTXT_MASK (XFEATURE_MASK_LAZY | XFEATURE_MASK_EAGER) #define XCNTXT_MASK (XFEATURE_MASK_LAZY | XFEATURE_MASK_EAGER)
......
...@@ -409,8 +409,10 @@ static inline void copy_init_fpstate_to_fpregs(void) ...@@ -409,8 +409,10 @@ static inline void copy_init_fpstate_to_fpregs(void)
{ {
if (use_xsave()) if (use_xsave())
copy_kernel_to_xregs(&init_fpstate.xsave, -1); copy_kernel_to_xregs(&init_fpstate.xsave, -1);
else else if (static_cpu_has(X86_FEATURE_FXSR))
copy_kernel_to_fxregs(&init_fpstate.fxsave); copy_kernel_to_fxregs(&init_fpstate.fxsave);
else
copy_kernel_to_fregs(&init_fpstate.fsave);
} }
/* /*
......
...@@ -78,6 +78,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c) ...@@ -78,6 +78,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
cr0 &= ~(X86_CR0_TS | X86_CR0_EM); cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
write_cr0(cr0); write_cr0(cr0);
if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
asm volatile("fninit ; fnstsw %0 ; fnstcw %1" asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
: "+m" (fsw), "+m" (fcw)); : "+m" (fsw), "+m" (fcw));
...@@ -85,6 +86,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c) ...@@ -85,6 +86,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
set_cpu_cap(c, X86_FEATURE_FPU); set_cpu_cap(c, X86_FEATURE_FPU);
else else
clear_cpu_cap(c, X86_FEATURE_FPU); clear_cpu_cap(c, X86_FEATURE_FPU);
}
#ifndef CONFIG_MATH_EMULATION #ifndef CONFIG_MATH_EMULATION
if (!cpu_has_fpu) { if (!cpu_has_fpu) {
...@@ -132,7 +134,7 @@ static void __init fpu__init_system_generic(void) ...@@ -132,7 +134,7 @@ static void __init fpu__init_system_generic(void)
* Set up the legacy init FPU context. (xstate init might overwrite this * Set up the legacy init FPU context. (xstate init might overwrite this
* with a more modern format, if the CPU supports it.) * with a more modern format, if the CPU supports it.)
*/ */
fpstate_init_fxstate(&init_fpstate.fxsave); fpstate_init(&init_fpstate);
fpu__init_system_mxcsr(); fpu__init_system_mxcsr();
} }
...@@ -300,12 +302,6 @@ u64 __init fpu__get_supported_xfeatures_mask(void) ...@@ -300,12 +302,6 @@ u64 __init fpu__get_supported_xfeatures_mask(void)
static void __init fpu__clear_eager_fpu_features(void) static void __init fpu__clear_eager_fpu_features(void)
{ {
setup_clear_cpu_cap(X86_FEATURE_MPX); setup_clear_cpu_cap(X86_FEATURE_MPX);
setup_clear_cpu_cap(X86_FEATURE_AVX);
setup_clear_cpu_cap(X86_FEATURE_AVX2);
setup_clear_cpu_cap(X86_FEATURE_AVX512F);
setup_clear_cpu_cap(X86_FEATURE_AVX512PF);
setup_clear_cpu_cap(X86_FEATURE_AVX512ER);
setup_clear_cpu_cap(X86_FEATURE_AVX512CD);
} }
/* /*
......
...@@ -102,7 +102,7 @@ static void delay_mwaitx(unsigned long __loops) ...@@ -102,7 +102,7 @@ static void delay_mwaitx(unsigned long __loops)
* Use cpu_tss as a cacheline-aligned, seldomly * Use cpu_tss as a cacheline-aligned, seldomly
* accessed per-cpu variable as the monitor target. * accessed per-cpu variable as the monitor target.
*/ */
__monitorx(this_cpu_ptr(&cpu_tss), 0, 0); __monitorx(raw_cpu_ptr(&cpu_tss), 0, 0);
/* /*
* AMD, like Intel, supports the EAX hint and EAX=0xf * AMD, like Intel, supports the EAX hint and EAX=0xf
......
...@@ -130,6 +130,27 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size) ...@@ -130,6 +130,27 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
} }
EXPORT_SYMBOL_GPL(efi_query_variable_store); EXPORT_SYMBOL_GPL(efi_query_variable_store);
/*
* Helper function for efi_reserve_boot_services() to figure out if we
* can free regions in efi_free_boot_services().
*
* Use this function to ensure we do not free regions owned by somebody
* else. We must only reserve (and then free) regions:
*
* - Not within any part of the kernel
* - Not the BIOS reserved area (E820_RESERVED, E820_NVS, etc)
*/
static bool can_free_region(u64 start, u64 size)
{
if (start + size > __pa_symbol(_text) && start <= __pa_symbol(_end))
return false;
if (!e820_all_mapped(start, start+size, E820_RAM))
return false;
return true;
}
/* /*
* The UEFI specification makes it clear that the operating system is free to do * 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 * whatever it wants with boot services code after ExitBootServices() has been
...@@ -147,26 +168,50 @@ void __init efi_reserve_boot_services(void) ...@@ -147,26 +168,50 @@ void __init efi_reserve_boot_services(void)
efi_memory_desc_t *md = p; efi_memory_desc_t *md = p;
u64 start = md->phys_addr; u64 start = md->phys_addr;
u64 size = md->num_pages << EFI_PAGE_SHIFT; u64 size = md->num_pages << EFI_PAGE_SHIFT;
bool already_reserved;
if (md->type != EFI_BOOT_SERVICES_CODE && if (md->type != EFI_BOOT_SERVICES_CODE &&
md->type != EFI_BOOT_SERVICES_DATA) md->type != EFI_BOOT_SERVICES_DATA)
continue; continue;
/* Only reserve where possible:
* - Not within any already allocated areas already_reserved = memblock_is_region_reserved(start, size);
* - Not over any memory area (really needed, if above?)
* - Not within any part of the kernel /*
* - Not the bios reserved area * Because the following memblock_reserve() is paired
* with free_bootmem_late() for this region in
* efi_free_boot_services(), we must be extremely
* careful not to reserve, and subsequently free,
* critical regions of memory (like the kernel image) or
* those regions that somebody else has already
* reserved.
*
* A good example of a critical region that must not be
* freed is page zero (first 4Kb of memory), which may
* contain boot services code/data but is marked
* E820_RESERVED by trim_bios_range().
*/ */
if ((start + size > __pa_symbol(_text) if (!already_reserved) {
&& 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); memblock_reserve(start, size);
/*
* If we are the first to reserve the region, no
* one else cares about it. We own it and can
* free it later.
*/
if (can_free_region(start, size))
continue;
}
/*
* We don't own the region. We must not free it.
*
* Setting this bit for a boot services region really
* doesn't make sense as far as the firmware is
* concerned, but it does provide us with a way to tag
* those regions that must not be paired with
* free_bootmem_late().
*/
md->attribute |= EFI_MEMORY_RUNTIME;
} }
} }
...@@ -183,8 +228,8 @@ void __init efi_free_boot_services(void) ...@@ -183,8 +228,8 @@ void __init efi_free_boot_services(void)
md->type != EFI_BOOT_SERVICES_DATA) md->type != EFI_BOOT_SERVICES_DATA)
continue; continue;
/* Could not reserve boot area */ /* Do not free, someone else owns it: */
if (!size) if (md->attribute & EFI_MEMORY_RUNTIME)
continue; continue;
free_bootmem_late(start, size); free_bootmem_late(start, size);
......
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