Merge branch 'x86-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 cleanups and msr updates from Ingo Molnar: "The main change is a performance/latency improvement to /dev/msr access. The rest are misc cleanups" * 'x86-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/msr: Make rdmsrl_safe_on_cpu() scheduling safe as well x86/cpuid: Allow cpuid_read() to schedule x86/msr: Allow rdmsr_safe_on_cpu() to schedule x86/rtc: Stop using deprecated functions x86/dumpstack: Unify show_regs() x86/fault: Do not print IP in show_fault_oops() x86/MSR: Move native_* variants to msr.h
This commit is contained in:
commit
986b37c0ae
12 changed files with 119 additions and 130 deletions
|
@ -6,20 +6,6 @@
|
||||||
#include <linux/earlycpio.h>
|
#include <linux/earlycpio.h>
|
||||||
#include <linux/initrd.h>
|
#include <linux/initrd.h>
|
||||||
|
|
||||||
#define native_rdmsr(msr, val1, val2) \
|
|
||||||
do { \
|
|
||||||
u64 __val = __rdmsr((msr)); \
|
|
||||||
(void)((val1) = (u32)__val); \
|
|
||||||
(void)((val2) = (u32)(__val >> 32)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define native_wrmsr(msr, low, high) \
|
|
||||||
__wrmsr(msr, low, high)
|
|
||||||
|
|
||||||
#define native_wrmsrl(msr, val) \
|
|
||||||
__wrmsr((msr), (u32)((u64)(val)), \
|
|
||||||
(u32)((u64)(val) >> 32))
|
|
||||||
|
|
||||||
struct ucode_patch {
|
struct ucode_patch {
|
||||||
struct list_head plist;
|
struct list_head plist;
|
||||||
void *data; /* Intel uses only this one */
|
void *data; /* Intel uses only this one */
|
||||||
|
|
|
@ -108,6 +108,20 @@ static inline void notrace __wrmsr(unsigned int msr, u32 low, u32 high)
|
||||||
: : "c" (msr), "a"(low), "d" (high) : "memory");
|
: : "c" (msr), "a"(low), "d" (high) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define native_rdmsr(msr, val1, val2) \
|
||||||
|
do { \
|
||||||
|
u64 __val = __rdmsr((msr)); \
|
||||||
|
(void)((val1) = (u32)__val); \
|
||||||
|
(void)((val2) = (u32)(__val >> 32)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define native_wrmsr(msr, low, high) \
|
||||||
|
__wrmsr(msr, low, high)
|
||||||
|
|
||||||
|
#define native_wrmsrl(msr, val) \
|
||||||
|
__wrmsr((msr), (u32)((u64)(val)), \
|
||||||
|
(u32)((u64)(val) >> 32))
|
||||||
|
|
||||||
static inline unsigned long long native_read_msr(unsigned int msr)
|
static inline unsigned long long native_read_msr(unsigned int msr)
|
||||||
{
|
{
|
||||||
unsigned long long val;
|
unsigned long long val;
|
||||||
|
|
|
@ -87,8 +87,6 @@ get_stack_pointer(struct task_struct *task, struct pt_regs *regs)
|
||||||
void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
|
void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
|
||||||
unsigned long *stack, char *log_lvl);
|
unsigned long *stack, char *log_lvl);
|
||||||
|
|
||||||
extern unsigned int code_bytes;
|
|
||||||
|
|
||||||
/* The form of the top of the frame on the stack */
|
/* The form of the top of the frame on the stack */
|
||||||
struct stack_frame {
|
struct stack_frame {
|
||||||
struct stack_frame *next_frame;
|
struct stack_frame *next_frame;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
|
@ -47,19 +48,27 @@
|
||||||
static struct class *cpuid_class;
|
static struct class *cpuid_class;
|
||||||
static enum cpuhp_state cpuhp_cpuid_state;
|
static enum cpuhp_state cpuhp_cpuid_state;
|
||||||
|
|
||||||
|
struct cpuid_regs_done {
|
||||||
|
struct cpuid_regs regs;
|
||||||
|
struct completion done;
|
||||||
|
};
|
||||||
|
|
||||||
static void cpuid_smp_cpuid(void *cmd_block)
|
static void cpuid_smp_cpuid(void *cmd_block)
|
||||||
{
|
{
|
||||||
struct cpuid_regs *cmd = (struct cpuid_regs *)cmd_block;
|
struct cpuid_regs_done *cmd = cmd_block;
|
||||||
|
|
||||||
cpuid_count(cmd->eax, cmd->ecx,
|
cpuid_count(cmd->regs.eax, cmd->regs.ecx,
|
||||||
&cmd->eax, &cmd->ebx, &cmd->ecx, &cmd->edx);
|
&cmd->regs.eax, &cmd->regs.ebx,
|
||||||
|
&cmd->regs.ecx, &cmd->regs.edx);
|
||||||
|
|
||||||
|
complete(&cmd->done);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t cpuid_read(struct file *file, char __user *buf,
|
static ssize_t cpuid_read(struct file *file, char __user *buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
char __user *tmp = buf;
|
char __user *tmp = buf;
|
||||||
struct cpuid_regs cmd;
|
struct cpuid_regs_done cmd;
|
||||||
int cpu = iminor(file_inode(file));
|
int cpu = iminor(file_inode(file));
|
||||||
u64 pos = *ppos;
|
u64 pos = *ppos;
|
||||||
ssize_t bytes = 0;
|
ssize_t bytes = 0;
|
||||||
|
@ -68,19 +77,28 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
|
||||||
if (count % 16)
|
if (count % 16)
|
||||||
return -EINVAL; /* Invalid chunk size */
|
return -EINVAL; /* Invalid chunk size */
|
||||||
|
|
||||||
|
init_completion(&cmd.done);
|
||||||
for (; count; count -= 16) {
|
for (; count; count -= 16) {
|
||||||
cmd.eax = pos;
|
call_single_data_t csd = {
|
||||||
cmd.ecx = pos >> 32;
|
.func = cpuid_smp_cpuid,
|
||||||
err = smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1);
|
.info = &cmd,
|
||||||
|
};
|
||||||
|
|
||||||
|
cmd.regs.eax = pos;
|
||||||
|
cmd.regs.ecx = pos >> 32;
|
||||||
|
|
||||||
|
err = smp_call_function_single_async(cpu, &csd);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
if (copy_to_user(tmp, &cmd, 16)) {
|
wait_for_completion(&cmd.done);
|
||||||
|
if (copy_to_user(tmp, &cmd.regs, 16)) {
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp += 16;
|
tmp += 16;
|
||||||
bytes += 16;
|
bytes += 16;
|
||||||
*ppos = ++pos;
|
*ppos = ++pos;
|
||||||
|
reinit_completion(&cmd.done);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes ? bytes : err;
|
return bytes ? bytes : err;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
int panic_on_unrecovered_nmi;
|
int panic_on_unrecovered_nmi;
|
||||||
int panic_on_io_nmi;
|
int panic_on_io_nmi;
|
||||||
unsigned int code_bytes = 64;
|
static unsigned int code_bytes = 64;
|
||||||
static int die_counter;
|
static int die_counter;
|
||||||
|
|
||||||
bool in_task_stack(unsigned long *stack, struct task_struct *task,
|
bool in_task_stack(unsigned long *stack, struct task_struct *task,
|
||||||
|
@ -375,3 +375,50 @@ static int __init code_bytes_setup(char *s)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
__setup("code_bytes=", code_bytes_setup);
|
__setup("code_bytes=", code_bytes_setup);
|
||||||
|
|
||||||
|
void show_regs(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
bool all = true;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
show_regs_print_info(KERN_DEFAULT);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_X86_32))
|
||||||
|
all = !user_mode(regs);
|
||||||
|
|
||||||
|
__show_regs(regs, all);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When in-kernel, we also print out the stack and code at the
|
||||||
|
* time of the fault..
|
||||||
|
*/
|
||||||
|
if (!user_mode(regs)) {
|
||||||
|
unsigned int code_prologue = code_bytes * 43 / 64;
|
||||||
|
unsigned int code_len = code_bytes;
|
||||||
|
unsigned char c;
|
||||||
|
u8 *ip;
|
||||||
|
|
||||||
|
show_trace_log_lvl(current, regs, NULL, KERN_DEFAULT);
|
||||||
|
|
||||||
|
printk(KERN_DEFAULT "Code: ");
|
||||||
|
|
||||||
|
ip = (u8 *)regs->ip - code_prologue;
|
||||||
|
if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
|
||||||
|
/* try starting at IP */
|
||||||
|
ip = (u8 *)regs->ip;
|
||||||
|
code_len = code_len - code_prologue + 1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < code_len; i++, ip++) {
|
||||||
|
if (ip < (u8 *)PAGE_OFFSET ||
|
||||||
|
probe_kernel_address(ip, c)) {
|
||||||
|
pr_cont(" Bad RIP value.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ip == (u8 *)regs->ip)
|
||||||
|
pr_cont("<%02x> ", c);
|
||||||
|
else
|
||||||
|
pr_cont("%02x ", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pr_cont("\n");
|
||||||
|
}
|
||||||
|
|
|
@ -127,45 +127,3 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
|
||||||
info->type = STACK_TYPE_UNKNOWN;
|
info->type = STACK_TYPE_UNKNOWN;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_regs(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
show_regs_print_info(KERN_EMERG);
|
|
||||||
__show_regs(regs, !user_mode(regs));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When in-kernel, we also print out the stack and code at the
|
|
||||||
* time of the fault..
|
|
||||||
*/
|
|
||||||
if (!user_mode(regs)) {
|
|
||||||
unsigned int code_prologue = code_bytes * 43 / 64;
|
|
||||||
unsigned int code_len = code_bytes;
|
|
||||||
unsigned char c;
|
|
||||||
u8 *ip;
|
|
||||||
|
|
||||||
show_trace_log_lvl(current, regs, NULL, KERN_EMERG);
|
|
||||||
|
|
||||||
pr_emerg("Code:");
|
|
||||||
|
|
||||||
ip = (u8 *)regs->ip - code_prologue;
|
|
||||||
if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
|
|
||||||
/* try starting at IP */
|
|
||||||
ip = (u8 *)regs->ip;
|
|
||||||
code_len = code_len - code_prologue + 1;
|
|
||||||
}
|
|
||||||
for (i = 0; i < code_len; i++, ip++) {
|
|
||||||
if (ip < (u8 *)PAGE_OFFSET ||
|
|
||||||
probe_kernel_address(ip, c)) {
|
|
||||||
pr_cont(" Bad EIP value.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ip == (u8 *)regs->ip)
|
|
||||||
pr_cont(" <%02x>", c);
|
|
||||||
else
|
|
||||||
pr_cont(" %02x", c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pr_cont("\n");
|
|
||||||
}
|
|
||||||
|
|
|
@ -149,45 +149,3 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
|
||||||
info->type = STACK_TYPE_UNKNOWN;
|
info->type = STACK_TYPE_UNKNOWN;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_regs(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
show_regs_print_info(KERN_DEFAULT);
|
|
||||||
__show_regs(regs, 1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When in-kernel, we also print out the stack and code at the
|
|
||||||
* time of the fault..
|
|
||||||
*/
|
|
||||||
if (!user_mode(regs)) {
|
|
||||||
unsigned int code_prologue = code_bytes * 43 / 64;
|
|
||||||
unsigned int code_len = code_bytes;
|
|
||||||
unsigned char c;
|
|
||||||
u8 *ip;
|
|
||||||
|
|
||||||
show_trace_log_lvl(current, regs, NULL, KERN_DEFAULT);
|
|
||||||
|
|
||||||
printk(KERN_DEFAULT "Code: ");
|
|
||||||
|
|
||||||
ip = (u8 *)regs->ip - code_prologue;
|
|
||||||
if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
|
|
||||||
/* try starting at IP */
|
|
||||||
ip = (u8 *)regs->ip;
|
|
||||||
code_len = code_len - code_prologue + 1;
|
|
||||||
}
|
|
||||||
for (i = 0; i < code_len; i++, ip++) {
|
|
||||||
if (ip < (u8 *)PAGE_OFFSET ||
|
|
||||||
probe_kernel_address(ip, c)) {
|
|
||||||
pr_cont(" Bad RIP value.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ip == (u8 *)regs->ip)
|
|
||||||
pr_cont("<%02x> ", c);
|
|
||||||
else
|
|
||||||
pr_cont("%02x ", c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pr_cont("\n");
|
|
||||||
}
|
|
||||||
|
|
|
@ -41,11 +41,11 @@ EXPORT_SYMBOL(rtc_lock);
|
||||||
*/
|
*/
|
||||||
int mach_set_rtc_mmss(const struct timespec *now)
|
int mach_set_rtc_mmss(const struct timespec *now)
|
||||||
{
|
{
|
||||||
unsigned long nowtime = now->tv_sec;
|
unsigned long long nowtime = now->tv_sec;
|
||||||
struct rtc_time tm;
|
struct rtc_time tm;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
rtc_time_to_tm(nowtime, &tm);
|
rtc_time64_to_tm(nowtime, &tm);
|
||||||
if (!rtc_valid_tm(&tm)) {
|
if (!rtc_valid_tm(&tm)) {
|
||||||
retval = mc146818_set_time(&tm);
|
retval = mc146818_set_time(&tm);
|
||||||
if (retval)
|
if (retval)
|
||||||
|
@ -53,7 +53,7 @@ int mach_set_rtc_mmss(const struct timespec *now)
|
||||||
__func__, retval);
|
__func__, retval);
|
||||||
} else {
|
} else {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"%s: Invalid RTC value: write of %lx to RTC failed\n",
|
"%s: Invalid RTC value: write of %llx to RTC failed\n",
|
||||||
__func__, nowtime);
|
__func__, nowtime);
|
||||||
retval = -EINVAL;
|
retval = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
#include <asm/debugreg.h>
|
#include <asm/debugreg.h>
|
||||||
#include <asm/kvm_para.h>
|
#include <asm/kvm_para.h>
|
||||||
#include <asm/irq_remapping.h>
|
#include <asm/irq_remapping.h>
|
||||||
#include <asm/microcode.h>
|
|
||||||
#include <asm/nospec-branch.h>
|
#include <asm/nospec-branch.h>
|
||||||
|
|
||||||
#include <asm/virtext.h>
|
#include <asm/virtext.h>
|
||||||
|
|
|
@ -51,7 +51,6 @@
|
||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
#include <asm/irq_remapping.h>
|
#include <asm/irq_remapping.h>
|
||||||
#include <asm/mmu_context.h>
|
#include <asm/mmu_context.h>
|
||||||
#include <asm/microcode.h>
|
|
||||||
#include <asm/nospec-branch.h>
|
#include <asm/nospec-branch.h>
|
||||||
|
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/preempt.h>
|
#include <linux/preempt.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
|
|
||||||
static void __rdmsr_on_cpu(void *info)
|
static void __rdmsr_on_cpu(void *info)
|
||||||
|
@ -143,13 +144,19 @@ void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(wrmsr_on_cpus);
|
EXPORT_SYMBOL(wrmsr_on_cpus);
|
||||||
|
|
||||||
|
struct msr_info_completion {
|
||||||
|
struct msr_info msr;
|
||||||
|
struct completion done;
|
||||||
|
};
|
||||||
|
|
||||||
/* These "safe" variants are slower and should be used when the target MSR
|
/* These "safe" variants are slower and should be used when the target MSR
|
||||||
may not actually exist. */
|
may not actually exist. */
|
||||||
static void __rdmsr_safe_on_cpu(void *info)
|
static void __rdmsr_safe_on_cpu(void *info)
|
||||||
{
|
{
|
||||||
struct msr_info *rv = info;
|
struct msr_info_completion *rv = info;
|
||||||
|
|
||||||
rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h);
|
rv->msr.err = rdmsr_safe(rv->msr.msr_no, &rv->msr.reg.l, &rv->msr.reg.h);
|
||||||
|
complete(&rv->done);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __wrmsr_safe_on_cpu(void *info)
|
static void __wrmsr_safe_on_cpu(void *info)
|
||||||
|
@ -161,17 +168,26 @@ static void __wrmsr_safe_on_cpu(void *info)
|
||||||
|
|
||||||
int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
|
int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
|
||||||
{
|
{
|
||||||
|
struct msr_info_completion rv;
|
||||||
|
call_single_data_t csd = {
|
||||||
|
.func = __rdmsr_safe_on_cpu,
|
||||||
|
.info = &rv,
|
||||||
|
};
|
||||||
int err;
|
int err;
|
||||||
struct msr_info rv;
|
|
||||||
|
|
||||||
memset(&rv, 0, sizeof(rv));
|
memset(&rv, 0, sizeof(rv));
|
||||||
|
init_completion(&rv.done);
|
||||||
|
rv.msr.msr_no = msr_no;
|
||||||
|
|
||||||
rv.msr_no = msr_no;
|
err = smp_call_function_single_async(cpu, &csd);
|
||||||
err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
|
if (!err) {
|
||||||
*l = rv.reg.l;
|
wait_for_completion(&rv.done);
|
||||||
*h = rv.reg.h;
|
err = rv.msr.err;
|
||||||
|
}
|
||||||
|
*l = rv.msr.reg.l;
|
||||||
|
*h = rv.msr.reg.h;
|
||||||
|
|
||||||
return err ? err : rv.err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rdmsr_safe_on_cpu);
|
EXPORT_SYMBOL(rdmsr_safe_on_cpu);
|
||||||
|
|
||||||
|
@ -209,16 +225,13 @@ EXPORT_SYMBOL(wrmsrl_safe_on_cpu);
|
||||||
|
|
||||||
int rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q)
|
int rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q)
|
||||||
{
|
{
|
||||||
|
u32 low, high;
|
||||||
int err;
|
int err;
|
||||||
struct msr_info rv;
|
|
||||||
|
|
||||||
memset(&rv, 0, sizeof(rv));
|
err = rdmsr_safe_on_cpu(cpu, msr_no, &low, &high);
|
||||||
|
*q = (u64)high << 32 | low;
|
||||||
|
|
||||||
rv.msr_no = msr_no;
|
return err;
|
||||||
err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
|
|
||||||
*q = rv.reg.q;
|
|
||||||
|
|
||||||
return err ? err : rv.err;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rdmsrl_safe_on_cpu);
|
EXPORT_SYMBOL(rdmsrl_safe_on_cpu);
|
||||||
|
|
||||||
|
|
|
@ -699,7 +699,6 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
|
||||||
printk(KERN_CONT "paging request");
|
printk(KERN_CONT "paging request");
|
||||||
|
|
||||||
printk(KERN_CONT " at %px\n", (void *) address);
|
printk(KERN_CONT " at %px\n", (void *) address);
|
||||||
printk(KERN_ALERT "IP: %pS\n", (void *)regs->ip);
|
|
||||||
|
|
||||||
dump_pagetable(address);
|
dump_pagetable(address);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue