Commit 8eab6cd0 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 Peter Anvin:
 "This is a collection of minor fixes for x86, plus the IRET information
  leak fix (forbid the use of 16-bit segments in 64-bit mode)"

NOTE! We may have to relax the "forbid the use of 16-bit segments in
64-bit mode" part, since there may be people who still run and depend on
16-bit Windows binaries under Wine.

But I'm taking this in the current unconditional form for now to see who
(if anybody) screams bloody murder.  Maybe nobody cares.  And maybe
we'll have to update it with some kind of runtime enablement (like our
vm.mmap_min_addr tunable that people who run dosemu/qemu/wine already
need to tweak).

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86-64, modify_ldt: Ban 16-bit segments on 64-bit kernels
  efi: Pass correct file handle to efi_file_{read,close}
  x86/efi: Correct EFI boot stub use of code32_start
  x86/efi: Fix boot failure with EFI stub
  x86/platform/hyperv: Handle VMBUS driver being a module
  x86/apic: Reinstate error IRQ Pentium erratum 3AP workaround
  x86, CMCI: Add proper detection of end of CMCI storms
parents ede1d63f b3b42ac2
...@@ -112,7 +112,7 @@ __file_size64(void *__fh, efi_char16_t *filename_16, ...@@ -112,7 +112,7 @@ __file_size64(void *__fh, efi_char16_t *filename_16,
efi_file_info_t *info; efi_file_info_t *info;
efi_status_t status; efi_status_t status;
efi_guid_t info_guid = EFI_FILE_INFO_ID; efi_guid_t info_guid = EFI_FILE_INFO_ID;
u32 info_sz; u64 info_sz;
status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16, status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
EFI_FILE_MODE_READ, (u64)0); EFI_FILE_MODE_READ, (u64)0);
...@@ -167,31 +167,31 @@ efi_file_size(efi_system_table_t *sys_table, void *__fh, ...@@ -167,31 +167,31 @@ efi_file_size(efi_system_table_t *sys_table, void *__fh,
} }
static inline efi_status_t static inline efi_status_t
efi_file_read(void *__fh, void *handle, unsigned long *size, void *addr) efi_file_read(void *handle, unsigned long *size, void *addr)
{ {
unsigned long func; unsigned long func;
if (efi_early->is64) { if (efi_early->is64) {
efi_file_handle_64_t *fh = __fh; efi_file_handle_64_t *fh = handle;
func = (unsigned long)fh->read; func = (unsigned long)fh->read;
return efi_early->call(func, handle, size, addr); return efi_early->call(func, handle, size, addr);
} else { } else {
efi_file_handle_32_t *fh = __fh; efi_file_handle_32_t *fh = handle;
func = (unsigned long)fh->read; func = (unsigned long)fh->read;
return efi_early->call(func, handle, size, addr); return efi_early->call(func, handle, size, addr);
} }
} }
static inline efi_status_t efi_file_close(void *__fh, void *handle) static inline efi_status_t efi_file_close(void *handle)
{ {
if (efi_early->is64) { if (efi_early->is64) {
efi_file_handle_64_t *fh = __fh; efi_file_handle_64_t *fh = handle;
return efi_early->call((unsigned long)fh->close, handle); return efi_early->call((unsigned long)fh->close, handle);
} else { } else {
efi_file_handle_32_t *fh = __fh; efi_file_handle_32_t *fh = handle;
return efi_early->call((unsigned long)fh->close, handle); return efi_early->call((unsigned long)fh->close, handle);
} }
...@@ -1016,6 +1016,9 @@ void setup_graphics(struct boot_params *boot_params) ...@@ -1016,6 +1016,9 @@ void setup_graphics(struct boot_params *boot_params)
* Because the x86 boot code expects to be passed a boot_params we * Because the x86 boot code expects to be passed a boot_params we
* need to create one ourselves (usually the bootloader would create * need to create one ourselves (usually the bootloader would create
* one for us). * one for us).
*
* The caller is responsible for filling out ->code32_start in the
* returned boot_params.
*/ */
struct boot_params *make_boot_params(struct efi_config *c) struct boot_params *make_boot_params(struct efi_config *c)
{ {
...@@ -1081,8 +1084,6 @@ struct boot_params *make_boot_params(struct efi_config *c) ...@@ -1081,8 +1084,6 @@ struct boot_params *make_boot_params(struct efi_config *c)
hdr->vid_mode = 0xffff; hdr->vid_mode = 0xffff;
hdr->boot_flag = 0xAA55; hdr->boot_flag = 0xAA55;
hdr->code32_start = (__u64)(unsigned long)image->image_base;
hdr->type_of_loader = 0x21; hdr->type_of_loader = 0x21;
/* Convert unicode cmdline to ascii */ /* Convert unicode cmdline to ascii */
......
...@@ -59,6 +59,7 @@ ENTRY(efi_pe_entry) ...@@ -59,6 +59,7 @@ ENTRY(efi_pe_entry)
call make_boot_params call make_boot_params
cmpl $0, %eax cmpl $0, %eax
je fail je fail
movl %esi, BP_code32_start(%eax)
popl %ecx popl %ecx
pushl %eax pushl %eax
pushl %ecx pushl %ecx
...@@ -90,12 +91,7 @@ fail: ...@@ -90,12 +91,7 @@ fail:
hlt hlt
jmp fail jmp fail
2: 2:
call 3f movl BP_code32_start(%esi), %eax
3:
popl %eax
subl $3b, %eax
subl BP_pref_address(%esi), %eax
add BP_code32_start(%esi), %eax
leal preferred_addr(%eax), %eax leal preferred_addr(%eax), %eax
jmp *%eax jmp *%eax
......
...@@ -261,6 +261,8 @@ ENTRY(efi_pe_entry) ...@@ -261,6 +261,8 @@ ENTRY(efi_pe_entry)
cmpq $0,%rax cmpq $0,%rax
je fail je fail
mov %rax, %rsi mov %rax, %rsi
leaq startup_32(%rip), %rax
movl %eax, BP_code32_start(%rsi)
jmp 2f /* Skip the relocation */ jmp 2f /* Skip the relocation */
handover_entry: handover_entry:
...@@ -284,12 +286,7 @@ fail: ...@@ -284,12 +286,7 @@ fail:
hlt hlt
jmp fail jmp fail
2: 2:
call 3f movl BP_code32_start(%esi), %eax
3:
popq %rax
subq $3b, %rax
subq BP_pref_address(%rsi), %rax
add BP_code32_start(%esi), %eax
leaq preferred_addr(%rax), %rax leaq preferred_addr(%rax), %rax
jmp *%rax jmp *%rax
......
...@@ -1996,6 +1996,7 @@ static inline void __smp_error_interrupt(struct pt_regs *regs) ...@@ -1996,6 +1996,7 @@ static inline void __smp_error_interrupt(struct pt_regs *regs)
}; };
/* First tickle the hardware, only then report what went on. -- REW */ /* First tickle the hardware, only then report what went on. -- REW */
if (lapic_get_maxlvt() > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
v = apic_read(APIC_ESR); v = apic_read(APIC_ESR);
ack_APIC_irq(); ack_APIC_irq();
......
...@@ -89,6 +89,9 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait); ...@@ -89,6 +89,9 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait);
static DEFINE_PER_CPU(struct mce, mces_seen); static DEFINE_PER_CPU(struct mce, mces_seen);
static int cpu_missing; static int cpu_missing;
/* CMCI storm detection filter */
static DEFINE_PER_CPU(unsigned long, mce_polled_error);
/* /*
* MCA banks polled by the period polling timer for corrected events. * MCA banks polled by the period polling timer for corrected events.
* With Intel CMCI, this only has MCA banks which do not support CMCI (if any). * With Intel CMCI, this only has MCA banks which do not support CMCI (if any).
...@@ -595,6 +598,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) ...@@ -595,6 +598,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
{ {
struct mce m; struct mce m;
int i; int i;
unsigned long *v;
this_cpu_inc(mce_poll_count); this_cpu_inc(mce_poll_count);
...@@ -614,6 +618,8 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) ...@@ -614,6 +618,8 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
if (!(m.status & MCI_STATUS_VAL)) if (!(m.status & MCI_STATUS_VAL))
continue; continue;
v = &get_cpu_var(mce_polled_error);
set_bit(0, v);
/* /*
* Uncorrected or signalled events are handled by the exception * Uncorrected or signalled events are handled by the exception
* handler when it is enabled, so don't process those here. * handler when it is enabled, so don't process those here.
...@@ -1278,10 +1284,18 @@ static unsigned long mce_adjust_timer_default(unsigned long interval) ...@@ -1278,10 +1284,18 @@ static unsigned long mce_adjust_timer_default(unsigned long interval)
static unsigned long (*mce_adjust_timer)(unsigned long interval) = static unsigned long (*mce_adjust_timer)(unsigned long interval) =
mce_adjust_timer_default; mce_adjust_timer_default;
static int cmc_error_seen(void)
{
unsigned long *v = &__get_cpu_var(mce_polled_error);
return test_and_clear_bit(0, v);
}
static void mce_timer_fn(unsigned long data) static void mce_timer_fn(unsigned long data)
{ {
struct timer_list *t = &__get_cpu_var(mce_timer); struct timer_list *t = &__get_cpu_var(mce_timer);
unsigned long iv; unsigned long iv;
int notify;
WARN_ON(smp_processor_id() != data); WARN_ON(smp_processor_id() != data);
...@@ -1296,7 +1310,9 @@ static void mce_timer_fn(unsigned long data) ...@@ -1296,7 +1310,9 @@ static void mce_timer_fn(unsigned long data)
* polling interval, otherwise increase the polling interval. * polling interval, otherwise increase the polling interval.
*/ */
iv = __this_cpu_read(mce_next_interval); iv = __this_cpu_read(mce_next_interval);
if (mce_notify_irq()) { notify = mce_notify_irq();
notify |= cmc_error_seen();
if (notify) {
iv = max(iv / 2, (unsigned long) HZ/100); iv = max(iv / 2, (unsigned long) HZ/100);
} else { } else {
iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); iv = min(iv * 2, round_jiffies_relative(check_interval * HZ));
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/cpumask.h>
#include <asm/apic.h> #include <asm/apic.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/msr.h> #include <asm/msr.h>
...@@ -137,6 +138,22 @@ unsigned long mce_intel_adjust_timer(unsigned long interval) ...@@ -137,6 +138,22 @@ unsigned long mce_intel_adjust_timer(unsigned long interval)
} }
} }
static void cmci_storm_disable_banks(void)
{
unsigned long flags, *owned;
int bank;
u64 val;
raw_spin_lock_irqsave(&cmci_discover_lock, flags);
owned = __get_cpu_var(mce_banks_owned);
for_each_set_bit(bank, owned, MAX_NR_BANKS) {
rdmsrl(MSR_IA32_MCx_CTL2(bank), val);
val &= ~MCI_CTL2_CMCI_EN;
wrmsrl(MSR_IA32_MCx_CTL2(bank), val);
}
raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
}
static bool cmci_storm_detect(void) static bool cmci_storm_detect(void)
{ {
unsigned int cnt = __this_cpu_read(cmci_storm_cnt); unsigned int cnt = __this_cpu_read(cmci_storm_cnt);
...@@ -158,7 +175,7 @@ static bool cmci_storm_detect(void) ...@@ -158,7 +175,7 @@ static bool cmci_storm_detect(void)
if (cnt <= CMCI_STORM_THRESHOLD) if (cnt <= CMCI_STORM_THRESHOLD)
return false; return false;
cmci_clear(); cmci_storm_disable_banks();
__this_cpu_write(cmci_storm_state, CMCI_STORM_ACTIVE); __this_cpu_write(cmci_storm_state, CMCI_STORM_ACTIVE);
r = atomic_add_return(1, &cmci_storm_on_cpus); r = atomic_add_return(1, &cmci_storm_on_cpus);
mce_timer_kick(CMCI_POLL_INTERVAL); mce_timer_kick(CMCI_POLL_INTERVAL);
......
...@@ -125,7 +125,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) ...@@ -125,7 +125,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%10u ", per_cpu(mce_poll_count, j)); seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
seq_printf(p, " Machine check polls\n"); seq_printf(p, " Machine check polls\n");
#endif #endif
#if defined(CONFIG_HYPERV) || defined(CONFIG_XEN) #if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
seq_printf(p, "%*s: ", prec, "THR"); seq_printf(p, "%*s: ", prec, "THR");
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count); seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count);
......
...@@ -229,6 +229,17 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) ...@@ -229,6 +229,17 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
} }
} }
/*
* On x86-64 we do not support 16-bit segments due to
* IRET leaking the high bits of the kernel stack address.
*/
#ifdef CONFIG_X86_64
if (!ldt_info.seg_32bit) {
error = -EINVAL;
goto out_unlock;
}
#endif
fill_ldt(&ldt, &ldt_info); fill_ldt(&ldt, &ldt_info);
if (oldmode) if (oldmode)
ldt.avl = 0; ldt.avl = 0;
......
...@@ -397,7 +397,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, ...@@ -397,7 +397,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
else else
chunksize = size; chunksize = size;
status = efi_file_read(fh, files[j].handle, status = efi_file_read(files[j].handle,
&chunksize, &chunksize,
(void *)addr); (void *)addr);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
...@@ -408,7 +408,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, ...@@ -408,7 +408,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
size -= chunksize; size -= chunksize;
} }
efi_file_close(fh, files[j].handle); efi_file_close(files[j].handle);
} }
} }
...@@ -425,7 +425,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, ...@@ -425,7 +425,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
close_handles: close_handles:
for (k = j; k < i; k++) for (k = j; k < i; k++)
efi_file_close(fh, files[k].handle); efi_file_close(files[k].handle);
free_files: free_files:
efi_call_early(free_pool, files); efi_call_early(free_pool, files);
fail: fail:
......
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