summaryrefslogtreecommitdiff
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-28 17:48:37 +0100
committerMark Brown <broonie@kernel.org>2026-07-28 17:48:38 +0100
commit514804e862d3ff0b4353597b5ea84b6c39c09b9f (patch)
tree0937084a6cab11d18cb773fcfe8f9d7551b76d79 /arch/x86/kernel
parent1254e4c63053bfa54261442cc86f3f8e8c03465e (diff)
parent38eccba72916c4939010bc616a88efb88fb81baf (diff)
downloadlinux-next-514804e862d3ff0b4353597b5ea84b6c39c09b9f.tar.gz
linux-next-514804e862d3ff0b4353597b5ea84b6c39c09b9f.zip
Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/acpi/cppc.c7
-rw-r--r--arch/x86/kernel/acpi/sleep.c20
-rw-r--r--arch/x86/kernel/alternative.c202
-rw-r--r--arch/x86/kernel/apic/apic.c39
-rw-r--r--arch/x86/kernel/apic/apic_numachip.c2
-rw-r--r--arch/x86/kernel/apic/local.h4
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c4
-rw-r--r--arch/x86/kernel/apic/x2apic_savic.c5
-rw-r--r--arch/x86/kernel/cpu/amd.c34
-rw-r--r--arch/x86/kernel/cpu/bugs.c10
-rw-r--r--arch/x86/kernel/cpu/cacheinfo.c2
-rw-r--r--arch/x86/kernel/cpu/centaur.c35
-rw-r--r--arch/x86/kernel/cpu/common.c39
-rw-r--r--arch/x86/kernel/cpu/feat_ctl.c25
-rw-r--r--arch/x86/kernel/cpu/hygon.c5
-rw-r--r--arch/x86/kernel/cpu/intel.c43
-rw-r--r--arch/x86/kernel/cpu/match.c30
-rw-r--r--arch/x86/kernel/cpu/mce/amd.c87
-rw-r--r--arch/x86/kernel/cpu/mce/core.c2
-rw-r--r--arch/x86/kernel/cpu/mce/p5.c16
-rw-r--r--arch/x86/kernel/cpu/mce/winchip.c10
-rw-r--r--arch/x86/kernel/cpu/microcode/amd.c3
-rw-r--r--arch/x86/kernel/cpu/microcode/intel.c36
-rw-r--r--arch/x86/kernel/cpu/mtrr/amd.c31
-rw-r--r--arch/x86/kernel/cpu/mtrr/centaur.c18
-rw-r--r--arch/x86/kernel/cpu/mtrr/cleanup.c18
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c97
-rw-r--r--arch/x86/kernel/cpu/mtrr/mtrr.c4
-rw-r--r--arch/x86/kernel/cpu/resctrl/core.c31
-rw-r--r--arch/x86/kernel/cpu/resctrl/ctrlmondata.c4
-rw-r--r--arch/x86/kernel/cpu/resctrl/intel_aet.c5
-rw-r--r--arch/x86/kernel/cpu/resctrl/monitor.c29
-rw-r--r--arch/x86/kernel/cpu/resctrl/pseudo_lock.c12
-rw-r--r--arch/x86/kernel/cpu/resctrl/rdtgroup.c4
-rw-r--r--arch/x86/kernel/cpu/topology.h1
-rw-r--r--arch/x86/kernel/cpu/topology_amd.c6
-rw-r--r--arch/x86/kernel/cpu/topology_common.c17
-rw-r--r--arch/x86/kernel/cpu/transmeta.c10
-rw-r--r--arch/x86/kernel/cpu/zhaoxin.c12
-rw-r--r--arch/x86/kernel/fpu/core.c20
-rw-r--r--arch/x86/kernel/fpu/signal.c2
-rw-r--r--arch/x86/kernel/kprobes/core.c3
-rw-r--r--arch/x86/kernel/kprobes/opt.c3
-rw-r--r--arch/x86/kernel/kvm.c4
-rw-r--r--arch/x86/kernel/ldt.c2
-rw-r--r--arch/x86/kernel/module.c13
-rw-r--r--arch/x86/kernel/msr.c3
-rw-r--r--arch/x86/kernel/process.c10
-rw-r--r--arch/x86/kernel/process_64.c6
-rw-r--r--arch/x86/kernel/signal_32.c2
-rw-r--r--arch/x86/kernel/smpboot.c3
-rw-r--r--arch/x86/kernel/time.c2
-rw-r--r--arch/x86/kernel/tsc.c6
-rw-r--r--arch/x86/kernel/tsc_msr.c15
-rw-r--r--arch/x86/kernel/uprobes.c404
-rw-r--r--arch/x86/kernel/vmlinux.lds.S20
56 files changed, 685 insertions, 792 deletions
diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c
index be4c5e9e5ff6..bbade0da5130 100644
--- a/arch/x86/kernel/acpi/cppc.c
+++ b/arch/x86/kernel/acpi/cppc.c
@@ -241,7 +241,6 @@ EXPORT_SYMBOL_GPL(amd_detect_prefcore);
*/
int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
{
- enum x86_topology_cpu_type core_type = get_topology_cpu_type(&cpu_data(cpu));
bool prefcore;
int ret;
u32 tmp;
@@ -273,16 +272,18 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
/* detect if running on heterogeneous design */
if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) {
- switch (core_type) {
+ switch (cpu_data(cpu).topo.cpu_type) {
case TOPO_CPU_TYPE_UNKNOWN:
+ case TOPO_CPU_TYPE_ANY:
pr_warn("Undefined core type found for cpu %d\n", cpu);
break;
case TOPO_CPU_TYPE_PERFORMANCE:
/* use the max scale for performance cores */
*numerator = CPPC_HIGHEST_PERF_PERFORMANCE;
return 0;
+ case TOPO_CPU_TYPE_LOW_POWER:
case TOPO_CPU_TYPE_EFFICIENCY:
- /* use the highest perf value for efficiency cores */
+ /* use the highest perf value for efficiency and low-power cores */
ret = amd_get_highest_perf(cpu, &tmp);
if (ret)
return ret;
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 91fa262f0e30..8dfe98784bf9 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -61,6 +61,7 @@ int x86_acpi_suspend_lowlevel(void)
{
struct wakeup_header *header =
(struct wakeup_header *) __va(real_mode_header->wakeup_header);
+ struct msr val;
if (header->signature != WAKEUP_HEADER_SIGNATURE) {
printk(KERN_ERR "wakeup header does not match\n");
@@ -82,13 +83,10 @@ int x86_acpi_suspend_lowlevel(void)
* with 2-MB L2 Cache and Intel® Processor A100 and A110 on 90
* nm process with 512-KB L2 Cache Specification Update".
*/
- if (!rdmsr_safe(MSR_EFER,
- &header->pmode_efer_low,
- &header->pmode_efer_high) &&
- !wrmsr_safe(MSR_EFER,
- header->pmode_efer_low,
- header->pmode_efer_high))
+ if (!rdmsrq_safe(MSR_EFER, &val.q) && !wrmsrq_safe(MSR_EFER, val.q))
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
+ header->pmode_efer_low = val.l;
+ header->pmode_efer_high = val.h;
#endif /* !CONFIG_64BIT */
header->pmode_cr0 = read_cr0();
@@ -96,14 +94,12 @@ int x86_acpi_suspend_lowlevel(void)
header->pmode_cr4 = __read_cr4();
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
}
- if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
- &header->pmode_misc_en_low,
- &header->pmode_misc_en_high) &&
- !wrmsr_safe(MSR_IA32_MISC_ENABLE,
- header->pmode_misc_en_low,
- header->pmode_misc_en_high))
+ if (!rdmsrq_safe(MSR_IA32_MISC_ENABLE, &val.q) &&
+ !wrmsrq_safe(MSR_IA32_MISC_ENABLE, val.q))
header->pmode_behavior |=
(1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
+ header->pmode_misc_en_low = val.l;
+ header->pmode_misc_en_high = val.h;
header->realmode_flags = acpi_realmode_flags;
header->real_magic = 0x12345678;
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 62936a3bde19..da97a5c74425 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -41,15 +41,6 @@ static int __init debug_alt(char *str)
}
__setup("debug-alternative", debug_alt);
-static int noreplace_smp;
-
-static int __init setup_noreplace_smp(char *str)
-{
- noreplace_smp = 1;
- return 1;
-}
-__setup("noreplace-smp", setup_noreplace_smp);
-
#define DPRINTK(type, fmt, args...) \
do { \
if (debug_alternative & DA_##type) \
@@ -1775,8 +1766,8 @@ static int cfi_rewrite_callers(s32 *start, s32 *end)
#define FINEIBT_WARN(_f, _v) \
WARN_ONCE((_f) != (_v), "FineIBT: " #_f " %ld != %d\n", _f, _v)
-static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
- s32 *start_cfi, s32 *end_cfi, bool builtin)
+static void __init_or_module __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
+ s32 *start_cfi, s32 *end_cfi, bool builtin)
{
int ret;
@@ -2088,8 +2079,8 @@ bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
#else /* !CONFIG_FINEIBT: */
-static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
- s32 *start_cfi, s32 *end_cfi, bool builtin)
+static void __init_or_module __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
+ s32 *start_cfi, s32 *end_cfi, bool builtin)
{
if (IS_ENABLED(CONFIG_CFI) && builtin)
pr_info("CFI: Using standard kCFI\n");
@@ -2101,167 +2092,14 @@ static void poison_cfi(void *addr) { }
#endif /* !CONFIG_FINEIBT */
-void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
- s32 *start_cfi, s32 *end_cfi)
+void __init_or_module apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
+ s32 *start_cfi, s32 *end_cfi)
{
return __apply_fineibt(start_retpoline, end_retpoline,
start_cfi, end_cfi,
/* .builtin = */ false);
}
-#ifdef CONFIG_SMP
-static void alternatives_smp_lock(const s32 *start, const s32 *end,
- u8 *text, u8 *text_end)
-{
- const s32 *poff;
-
- for (poff = start; poff < end; poff++) {
- u8 *ptr = (u8 *)poff + *poff;
-
- if (!*poff || ptr < text || ptr >= text_end)
- continue;
- /* turn DS segment override prefix into lock prefix */
- if (*ptr == 0x3e)
- text_poke(ptr, ((unsigned char []){0xf0}), 1);
- }
-}
-
-static void alternatives_smp_unlock(const s32 *start, const s32 *end,
- u8 *text, u8 *text_end)
-{
- const s32 *poff;
-
- for (poff = start; poff < end; poff++) {
- u8 *ptr = (u8 *)poff + *poff;
-
- if (!*poff || ptr < text || ptr >= text_end)
- continue;
- /* turn lock prefix into DS segment override prefix */
- if (*ptr == 0xf0)
- text_poke(ptr, ((unsigned char []){0x3E}), 1);
- }
-}
-
-struct smp_alt_module {
- /* what is this ??? */
- struct module *mod;
- char *name;
-
- /* ptrs to lock prefixes */
- const s32 *locks;
- const s32 *locks_end;
-
- /* .text segment, needed to avoid patching init code ;) */
- u8 *text;
- u8 *text_end;
-
- struct list_head next;
-};
-static LIST_HEAD(smp_alt_modules);
-static bool uniproc_patched = false; /* protected by text_mutex */
-
-void __init_or_module alternatives_smp_module_add(struct module *mod,
- char *name,
- void *locks, void *locks_end,
- void *text, void *text_end)
-{
- struct smp_alt_module *smp;
-
- mutex_lock(&text_mutex);
- if (!uniproc_patched)
- goto unlock;
-
- if (num_possible_cpus() == 1)
- /* Don't bother remembering, we'll never have to undo it. */
- goto smp_unlock;
-
- smp = kzalloc_obj(*smp);
- if (NULL == smp)
- /* we'll run the (safe but slow) SMP code then ... */
- goto unlock;
-
- smp->mod = mod;
- smp->name = name;
- smp->locks = locks;
- smp->locks_end = locks_end;
- smp->text = text;
- smp->text_end = text_end;
- DPRINTK(SMP, "locks %p -> %p, text %p -> %p, name %s\n",
- smp->locks, smp->locks_end,
- smp->text, smp->text_end, smp->name);
-
- list_add_tail(&smp->next, &smp_alt_modules);
-smp_unlock:
- alternatives_smp_unlock(locks, locks_end, text, text_end);
-unlock:
- mutex_unlock(&text_mutex);
-}
-
-void __init_or_module alternatives_smp_module_del(struct module *mod)
-{
- struct smp_alt_module *item;
-
- mutex_lock(&text_mutex);
- list_for_each_entry(item, &smp_alt_modules, next) {
- if (mod != item->mod)
- continue;
- list_del(&item->next);
- kfree(item);
- break;
- }
- mutex_unlock(&text_mutex);
-}
-
-void alternatives_enable_smp(void)
-{
- struct smp_alt_module *mod;
-
- /* Why bother if there are no other CPUs? */
- BUG_ON(num_possible_cpus() == 1);
-
- mutex_lock(&text_mutex);
-
- if (uniproc_patched) {
- pr_info("switching to SMP code\n");
- BUG_ON(num_online_cpus() != 1);
- clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
- clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
- list_for_each_entry(mod, &smp_alt_modules, next)
- alternatives_smp_lock(mod->locks, mod->locks_end,
- mod->text, mod->text_end);
- uniproc_patched = false;
- }
- mutex_unlock(&text_mutex);
-}
-
-/*
- * Return 1 if the address range is reserved for SMP-alternatives.
- * Must hold text_mutex.
- */
-int alternatives_text_reserved(void *start, void *end)
-{
- struct smp_alt_module *mod;
- const s32 *poff;
- u8 *text_start = start;
- u8 *text_end = end;
-
- lockdep_assert_held(&text_mutex);
-
- list_for_each_entry(mod, &smp_alt_modules, next) {
- if (mod->text > text_end || mod->text_end < text_start)
- continue;
- for (poff = mod->locks; poff < mod->locks_end; poff++) {
- const u8 *ptr = (const u8 *)poff + *poff;
-
- if (text_start <= ptr && text_end > ptr)
- return 1;
- }
- }
-
- return 0;
-}
-#endif /* CONFIG_SMP */
-
/*
* Self-test for the INT3 based CALL emulation code.
*
@@ -2440,40 +2278,12 @@ void __init alternative_instructions(void)
ibt_restore(ibt);
-#ifdef CONFIG_SMP
- /* Patch to UP if other cpus not imminent. */
- if (!noreplace_smp && (num_present_cpus() == 1 || setup_max_cpus <= 1)) {
- uniproc_patched = true;
- alternatives_smp_module_add(NULL, "core kernel",
- __smp_locks, __smp_locks_end,
- _text, _etext);
- }
-#endif
-
restart_nmi();
alternatives_patched = 1;
alt_reloc_selftest();
}
-#ifdef CONFIG_SMP
-/*
- * With CONFIG_DEFERRED_STRUCT_PAGE_INIT enabled we can free_init_pages() only
- * after the deferred initialization of the memory map is complete.
- */
-static int __init free_smp_locks(void)
-{
- if (!uniproc_patched || num_possible_cpus() == 1) {
- free_init_pages("SMP alternatives",
- (unsigned long)__smp_locks,
- (unsigned long)__smp_locks_end);
- }
-
- return 0;
-}
-arch_initcall(free_smp_locks);
-#endif
-
/**
* text_poke_early - Update instructions on a live kernel at boot time
* @addr: address to modify
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index aa1e19979aa8..90025451ace2 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1191,11 +1191,11 @@ void disable_local_APIC(void)
* restore the disabled state.
*/
if (enabled_via_apicbase) {
- unsigned int l, h;
+ struct msr val;
- rdmsr(MSR_IA32_APICBASE, l, h);
- l &= ~MSR_IA32_APICBASE_ENABLE;
- wrmsr(MSR_IA32_APICBASE, l, h);
+ rdmsrq(MSR_IA32_APICBASE, val.q);
+ val.l &= ~MSR_IA32_APICBASE_ENABLE;
+ wrmsrq(MSR_IA32_APICBASE, val.q);
}
#endif
}
@@ -1960,7 +1960,8 @@ static bool __init detect_init_APIC(void)
static bool __init apic_verify(unsigned long addr)
{
- u32 features, h, l;
+ struct msr val;
+ u32 features;
/*
* The APIC feature bit should now be enabled
@@ -1975,9 +1976,9 @@ static bool __init apic_verify(unsigned long addr)
/* The BIOS may have set up the APIC at some other address */
if (boot_cpu_data.x86 >= 6) {
- rdmsr(MSR_IA32_APICBASE, l, h);
- if (l & MSR_IA32_APICBASE_ENABLE)
- addr = l & MSR_IA32_APICBASE_BASE;
+ rdmsrq(MSR_IA32_APICBASE, val.q);
+ if (val.l & MSR_IA32_APICBASE_ENABLE)
+ addr = val.l & MSR_IA32_APICBASE_BASE;
}
register_lapic_address(addr);
@@ -1987,7 +1988,7 @@ static bool __init apic_verify(unsigned long addr)
bool __init apic_force_enable(unsigned long addr)
{
- u32 h, l;
+ struct msr val;
if (apic_is_disabled)
return false;
@@ -1998,12 +1999,12 @@ bool __init apic_force_enable(unsigned long addr)
* and AMD K7 (Model > 1) or later.
*/
if (boot_cpu_data.x86 >= 6) {
- rdmsr(MSR_IA32_APICBASE, l, h);
- if (!(l & MSR_IA32_APICBASE_ENABLE)) {
+ rdmsrq(MSR_IA32_APICBASE, val.q);
+ if (!(val.l & MSR_IA32_APICBASE_ENABLE)) {
pr_info("Local APIC disabled by BIOS -- reenabling.\n");
- l &= ~MSR_IA32_APICBASE_BASE;
- l |= MSR_IA32_APICBASE_ENABLE | addr;
- wrmsr(MSR_IA32_APICBASE, l, h);
+ val.l &= ~MSR_IA32_APICBASE_BASE;
+ val.l |= MSR_IA32_APICBASE_ENABLE | addr;
+ wrmsrq(MSR_IA32_APICBASE, val.q);
enabled_via_apicbase = 1;
}
}
@@ -2442,7 +2443,7 @@ static int lapic_suspend(void *data)
static void lapic_resume(void *data)
{
- unsigned int l, h;
+ struct msr val;
unsigned long flags;
int maxlvt;
@@ -2475,10 +2476,10 @@ static void lapic_resume(void *data)
* SMP! We'll need to do this as part of the CPU restore!
*/
if (boot_cpu_data.x86 >= 6) {
- rdmsr(MSR_IA32_APICBASE, l, h);
- l &= ~MSR_IA32_APICBASE_BASE;
- l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
- wrmsr(MSR_IA32_APICBASE, l, h);
+ rdmsrq(MSR_IA32_APICBASE, val.q);
+ val.l &= ~MSR_IA32_APICBASE_BASE;
+ val.l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
+ wrmsrq(MSR_IA32_APICBASE, val.q);
}
}
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 5c5be2d58242..a60c8960bbfd 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -31,7 +31,7 @@ static u32 numachip1_get_apic_id(u32 x)
unsigned long value;
unsigned int id = (x >> 24) & 0xff;
- if (static_cpu_has(X86_FEATURE_NODEID_MSR)) {
+ if (cpu_feature_enabled(X86_FEATURE_NODEID_MSR)) {
rdmsrq(MSR_FAM10H_NODE_ID, value);
id |= (value << 2) & 0xff00;
}
diff --git a/arch/x86/kernel/apic/local.h b/arch/x86/kernel/apic/local.h
index 998efd442063..090dd71837aa 100644
--- a/arch/x86/kernel/apic/local.h
+++ b/arch/x86/kernel/apic/local.h
@@ -44,9 +44,7 @@ static inline unsigned int __prepare_ICR(unsigned int shortcut, int vector,
#ifdef CONFIG_X86_X2APIC
static inline void __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
{
- unsigned long cfg = __prepare_ICR(0, vector, dest);
-
- native_x2apic_icr_write(cfg, apicid);
+ native_x2apic_icr_write(__prepare_ICR(0, vector, dest), apicid);
}
#endif
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index 10f79026e8e3..090647cc5a78 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -85,11 +85,9 @@ static void
static void __x2apic_send_IPI_shorthand(int vector, u32 which)
{
- unsigned long cfg = __prepare_ICR(which, vector, 0);
-
/* x2apic MSRs are special and need a special fence: */
weak_wrmsr_fence();
- native_x2apic_icr_write(cfg, 0);
+ native_x2apic_icr_write(__prepare_ICR(which, vector, 0), 0);
}
void x2apic_send_IPI_allbutself(int vector)
diff --git a/arch/x86/kernel/apic/x2apic_savic.c b/arch/x86/kernel/apic/x2apic_savic.c
index dbc5678bc3b6..4bc6d7e018a5 100644
--- a/arch/x86/kernel/apic/x2apic_savic.c
+++ b/arch/x86/kernel/apic/x2apic_savic.c
@@ -243,10 +243,7 @@ static void savic_write(u32 reg, u32 data)
static void send_ipi(u32 dest, unsigned int vector, unsigned int dsh)
{
- unsigned int icr_low;
-
- icr_low = __prepare_ICR(dsh, vector, APIC_DEST_PHYSICAL);
- savic_icr_write(icr_low, dest);
+ savic_icr_write(__prepare_ICR(dsh, vector, APIC_DEST_PHYSICAL), dest);
}
static void savic_send_ipi(int cpu, int vector)
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 487ac147e11f..169e373418bb 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -113,7 +113,7 @@ static void init_amd_k5(struct cpuinfo_x86 *c)
static void init_amd_k6(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_X86_32
- u32 l, h;
+ struct msr val;
int mbytes = get_num_physpages() >> (20-PAGE_SHIFT);
if (c->x86_model < 6) {
@@ -160,13 +160,13 @@ static void init_amd_k6(struct cpuinfo_x86 *c)
if (mbytes > 508)
mbytes = 508;
- rdmsr(MSR_K6_WHCR, l, h);
- if ((l&0x0000FFFF) == 0) {
+ rdmsrq(MSR_K6_WHCR, val.q);
+ if ((val.l & 0x0000FFFF) == 0) {
unsigned long flags;
- l = (1<<0)|((mbytes/4)<<1);
+ val.l = (1 << 0) | ((mbytes / 4) << 1);
local_irq_save(flags);
wbinvd();
- wrmsr(MSR_K6_WHCR, l, h);
+ wrmsrq(MSR_K6_WHCR, val.q);
local_irq_restore(flags);
pr_info("Enabling old style K6 write allocation for %d Mb\n",
mbytes);
@@ -181,13 +181,13 @@ static void init_amd_k6(struct cpuinfo_x86 *c)
if (mbytes > 4092)
mbytes = 4092;
- rdmsr(MSR_K6_WHCR, l, h);
- if ((l&0xFFFF0000) == 0) {
+ rdmsrq(MSR_K6_WHCR, val.q);
+ if ((val.l & 0xFFFF0000) == 0) {
unsigned long flags;
- l = ((mbytes>>2)<<22)|(1<<16);
+ val.l = ((mbytes >> 2) << 22) | (1 << 16);
local_irq_save(flags);
wbinvd();
- wrmsr(MSR_K6_WHCR, l, h);
+ wrmsrq(MSR_K6_WHCR, val.q);
local_irq_restore(flags);
pr_info("Enabling new style K6 write allocation for %d Mb\n",
mbytes);
@@ -207,7 +207,7 @@ static void init_amd_k6(struct cpuinfo_x86 *c)
static void init_amd_k7(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_X86_32
- u32 l, h;
+ struct msr val;
/*
* Bit 15 of Athlon specific MSR 15, needs to be 0
@@ -228,11 +228,12 @@ static void init_amd_k7(struct cpuinfo_x86 *c)
* As per AMD technical note 27212 0.2
*/
if ((c->x86_model == 8 && c->x86_stepping >= 1) || (c->x86_model > 8)) {
- rdmsr(MSR_K7_CLK_CTL, l, h);
- if ((l & 0xfff00000) != 0x20000000) {
+ rdmsrq(MSR_K7_CLK_CTL, val.q);
+ if ((val.l & 0xfff00000) != 0x20000000) {
pr_info("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n",
- l, ((l & 0x000fffff)|0x20000000));
- wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
+ val.l, ((val.l & 0x000fffff) | 0x20000000));
+ val.l = (val.l & 0x000fffff) | 0x20000000;
+ wrmsrq(MSR_K7_CLK_CTL, val.q);
}
}
@@ -614,12 +615,13 @@ clear_sev:
static void early_init_amd(struct cpuinfo_x86 *c)
{
- u32 dummy;
+ u64 val;
if (c->x86 >= 0xf)
set_cpu_cap(c, X86_FEATURE_K8);
- rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
+ rdmsrq_safe(MSR_AMD64_PATCH_LEVEL, &val);
+ c->microcode = (u32)val;
/*
* c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index d9af230c0512..ddf0db5326fa 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -192,8 +192,8 @@ x86_virt_spec_ctrl(u64 guest_virt_spec_ctrl, bool setguest)
* If SSBD is not handled in MSR_SPEC_CTRL on AMD, update
* MSR_AMD64_L2_CFG or MSR_VIRT_SPEC_CTRL if supported.
*/
- if (!static_cpu_has(X86_FEATURE_LS_CFG_SSBD) &&
- !static_cpu_has(X86_FEATURE_VIRT_SSBD))
+ if (!cpu_feature_enabled(X86_FEATURE_LS_CFG_SSBD) &&
+ !cpu_feature_enabled(X86_FEATURE_VIRT_SSBD))
return;
/*
@@ -201,7 +201,7 @@ x86_virt_spec_ctrl(u64 guest_virt_spec_ctrl, bool setguest)
* virtual MSR value. If its not permanently enabled, evaluate
* current's TIF_SSBD thread flag.
*/
- if (static_cpu_has(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE))
+ if (cpu_feature_enabled(X86_FEATURE_SPEC_STORE_BYPASS_DISABLE))
hostval = SPEC_CTRL_SSBD;
else
hostval = ssbd_tif_to_spec_ctrl(ti->flags);
@@ -2499,8 +2499,8 @@ static void __init ssb_apply_mitigation(void)
* Intel uses the SPEC CTRL MSR Bit(2) for this, while AMD may
* use a completely different MSR and bit dependent on family.
*/
- if (!static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) &&
- !static_cpu_has(X86_FEATURE_AMD_SSBD)) {
+ if (!cpu_feature_enabled(X86_FEATURE_SPEC_CTRL_SSBD) &&
+ !cpu_feature_enabled(X86_FEATURE_AMD_SSBD)) {
x86_amd_ssb_disable();
} else {
x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 51a95b07831f..13ed16527905 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -654,7 +654,7 @@ static DEFINE_RAW_SPINLOCK(cache_disable_lock);
*/
static void maybe_flush_caches(void)
{
- if (!static_cpu_has(X86_FEATURE_SELFSNOOP))
+ if (!cpu_feature_enabled(X86_FEATURE_SELFSNOOP))
wbinvd();
}
diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c
index 681d2da49341..513fa1f640f9 100644
--- a/arch/x86/kernel/cpu/centaur.c
+++ b/arch/x86/kernel/cpu/centaur.c
@@ -22,7 +22,7 @@
static void init_c3(struct cpuinfo_x86 *c)
{
- u32 lo, hi;
+ u64 msr;
/* Test for Centaur Extended Feature Flags presence */
if (cpuid_eax(0xC0000000) >= 0xC0000001) {
@@ -30,17 +30,17 @@ static void init_c3(struct cpuinfo_x86 *c)
/* enable ACE unit, if present and disabled */
if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
- rdmsr(MSR_VIA_FCR, lo, hi);
- lo |= ACE_FCR; /* enable ACE unit */
- wrmsr(MSR_VIA_FCR, lo, hi);
+ rdmsrq(MSR_VIA_FCR, msr);
+ /* enable ACE unit */
+ wrmsrq(MSR_VIA_FCR, msr | ACE_FCR);
pr_info("CPU: Enabled ACE h/w crypto\n");
}
/* enable RNG unit, if present and disabled */
if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
- rdmsr(MSR_VIA_RNG, lo, hi);
- lo |= RNG_ENABLE; /* enable RNG unit */
- wrmsr(MSR_VIA_RNG, lo, hi);
+ rdmsrq(MSR_VIA_RNG, msr);
+ /* enable RNG unit */
+ wrmsrq(MSR_VIA_RNG, msr | RNG_ENABLE);
pr_info("CPU: Enabled h/w RNG\n");
}
@@ -52,9 +52,8 @@ static void init_c3(struct cpuinfo_x86 *c)
#ifdef CONFIG_X86_32
/* Cyrix III family needs CX8 & PGE explicitly enabled. */
if (c->x86_model >= 6 && c->x86_model <= 13) {
- rdmsr(MSR_VIA_FCR, lo, hi);
- lo |= (1<<1 | 1<<7);
- wrmsr(MSR_VIA_FCR, lo, hi);
+ rdmsrq(MSR_VIA_FCR, msr);
+ wrmsrq(MSR_VIA_FCR, msr | (1 << 1 | 1 << 7));
set_cpu_cap(c, X86_FEATURE_CX8);
}
@@ -115,8 +114,9 @@ static void init_centaur(struct cpuinfo_x86 *c)
char *name;
u32 fcr_set = 0;
u32 fcr_clr = 0;
- u32 lo, hi, newlo;
+ u32 newlo;
u32 aa, bb, cc, dd;
+ struct msr val;
#endif
early_init_centaur(c);
init_intel_cacheinfo(c);
@@ -169,15 +169,16 @@ static void init_centaur(struct cpuinfo_x86 *c)
name = "??";
}
- rdmsr(MSR_IDT_FCR1, lo, hi);
- newlo = (lo|fcr_set) & (~fcr_clr);
+ rdmsrq(MSR_IDT_FCR1, val.q);
+ newlo = (val.l | fcr_set) & (~fcr_clr);
- if (newlo != lo) {
+ if (newlo != val.l) {
pr_info("Centaur FCR was 0x%X now 0x%X\n",
- lo, newlo);
- wrmsr(MSR_IDT_FCR1, newlo, hi);
+ val.l, newlo);
+ val.l = newlo;
+ wrmsrq(MSR_IDT_FCR1, val.q);
} else {
- pr_info("Centaur FCR is 0x%X\n", lo);
+ pr_info("Centaur FCR is 0x%X\n", val.l);
}
/* Emulate MTRRs using Centaur's MCR. */
set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a3df21d26460..e84ddf6bb10d 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -339,16 +339,16 @@ bool cpuid_feature(void)
static void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
{
- unsigned long lo, hi;
+ struct msr val;
if (!cpu_has(c, X86_FEATURE_PN) || !disable_x86_serial_nr)
return;
/* Disable processor serial number: */
- rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
- lo |= 0x200000;
- wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
+ rdmsrq(MSR_IA32_BBL_CR_CTL, val.q);
+ val.l |= 0x200000;
+ wrmsrq(MSR_IA32_BBL_CR_CTL, val.q);
pr_notice("CPU serial number disabled.\n");
clear_cpu_cap(c, X86_FEATURE_PN);
@@ -1251,9 +1251,6 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
#define VULNBL_INTEL_STEPS(vfm, max_stepping, issues) \
X86_MATCH_VFM_STEPS(vfm, X86_STEP_MIN, max_stepping, issues)
-#define VULNBL_INTEL_TYPE(vfm, cpu_type, issues) \
- X86_MATCH_VFM_CPU_TYPE(vfm, INTEL_CPU_TYPE_##cpu_type, issues)
-
#define VULNBL_AMD(family, blacklist) \
VULNBL(AMD, family, X86_MODEL_ANY, blacklist)
@@ -1316,11 +1313,9 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
VULNBL_INTEL_STEPS(INTEL_TIGERLAKE, X86_STEP_MAX, GDS | ITS | ITS_NATIVE_ONLY),
VULNBL_INTEL_STEPS(INTEL_LAKEFIELD, X86_STEP_MAX, MMIO | MMIO_SBDS | RETBLEED),
VULNBL_INTEL_STEPS(INTEL_ROCKETLAKE, X86_STEP_MAX, MMIO | RETBLEED | GDS | ITS | ITS_NATIVE_ONLY),
- VULNBL_INTEL_TYPE(INTEL_ALDERLAKE, ATOM, RFDS | VMSCAPE),
- VULNBL_INTEL_STEPS(INTEL_ALDERLAKE, X86_STEP_MAX, VMSCAPE),
+ VULNBL_INTEL_STEPS(INTEL_ALDERLAKE, X86_STEP_MAX, RFDS | VMSCAPE),
VULNBL_INTEL_STEPS(INTEL_ALDERLAKE_L, X86_STEP_MAX, RFDS | VMSCAPE),
- VULNBL_INTEL_TYPE(INTEL_RAPTORLAKE, ATOM, RFDS | VMSCAPE),
- VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE, X86_STEP_MAX, VMSCAPE),
+ VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE, X86_STEP_MAX, RFDS | VMSCAPE),
VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE_P, X86_STEP_MAX, RFDS | VMSCAPE),
VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE_S, X86_STEP_MAX, RFDS | VMSCAPE),
VULNBL_INTEL_STEPS(INTEL_METEORLAKE_L, X86_STEP_MAX, VMSCAPE),
@@ -1388,7 +1383,21 @@ static bool __init vulnerable_to_rfds(u64 x86_arch_cap_msr)
return true;
/* Only consult the blacklist when there is no enumeration: */
- return cpu_matches(cpu_vuln_blacklist, RFDS);
+ if (!cpu_matches(cpu_vuln_blacklist, RFDS))
+ return false;
+
+ /*
+ * ADL and RPL are affected only if they have Atom CPUs. Hybrids have
+ * both Core and Atom CPUs. Mark unaffected when Atom CPUs are not
+ * present.
+ */
+ if ((boot_cpu_data.x86_model == 0x97 ||
+ boot_cpu_data.x86_model == 0xB7) &&
+ boot_cpu_data.topo.intel_type != INTEL_CPU_TYPE_ATOM &&
+ !boot_cpu_has(X86_FEATURE_HYBRID_CPU))
+ return false;
+
+ return true;
}
static bool __init vulnerable_to_its(u64 x86_arch_cap_msr)
@@ -1651,7 +1660,7 @@ static inline bool parse_set_clear_cpuid(char *arg, bool set)
int taint = 0;
while (arg) {
- bool found __maybe_unused = false;
+ bool found = false;
unsigned int bit;
opt = strsep(&arg, ",");
@@ -2299,8 +2308,10 @@ static inline void idt_syscall_init(void)
/* May not be marked __init: used by software suspend */
void syscall_init(void)
{
+ struct msr val = { .h = (__USER32_CS << 16) | __KERNEL_CS };
+
/* The default user and kernel segments */
- wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
+ wrmsrq(MSR_STAR, val.q);
/*
* Except the IA32_STAR MSR, there is NO need to setup SYSCALL and
diff --git a/arch/x86/kernel/cpu/feat_ctl.c b/arch/x86/kernel/cpu/feat_ctl.c
index d69757246bde..10a92927a515 100644
--- a/arch/x86/kernel/cpu/feat_ctl.c
+++ b/arch/x86/kernel/cpu/feat_ctl.c
@@ -25,7 +25,8 @@ enum vmx_feature_leafs {
static void init_vmx_capabilities(struct cpuinfo_x86 *c)
{
- u32 supported, funcs, ept, vpid, ign, low, high;
+ struct msr val;
+ u32 supported, funcs, ept, vpid;
BUILD_BUG_ON(NVMXINTS != NR_VMX_FEATURE_WORDS);
@@ -39,25 +40,31 @@ static void init_vmx_capabilities(struct cpuinfo_x86 *c)
* as they exist on any CPU that supports VMX, i.e. we want the WARN if
* the RDMSR faults.
*/
- rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, ign, supported);
+ rdmsrq(MSR_IA32_VMX_PROCBASED_CTLS, val.q);
+ supported = val.h;
c->vmx_capability[PRIMARY_CTLS] = supported;
- rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS2, &ign, &supported);
+ rdmsrq_safe(MSR_IA32_VMX_PROCBASED_CTLS2, &val.q);
+ supported = val.h;
c->vmx_capability[SECONDARY_CTLS] = supported;
/* All 64 bits of tertiary controls MSR are allowed-1 settings. */
- rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &low, &high);
- c->vmx_capability[TERTIARY_CTLS_LOW] = low;
- c->vmx_capability[TERTIARY_CTLS_HIGH] = high;
+ rdmsrq_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &val.q);
+ c->vmx_capability[TERTIARY_CTLS_LOW] = val.l;
+ c->vmx_capability[TERTIARY_CTLS_HIGH] = val.h;
- rdmsr(MSR_IA32_VMX_PINBASED_CTLS, ign, supported);
- rdmsr_safe(MSR_IA32_VMX_VMFUNC, &ign, &funcs);
+ rdmsrq(MSR_IA32_VMX_PINBASED_CTLS, val.q);
+ supported = val.h;
+ rdmsrq_safe(MSR_IA32_VMX_VMFUNC, &val.q);
+ funcs = val.h;
/*
* Except for EPT+VPID, which enumerates support for both in a single
* MSR, low for EPT, high for VPID.
*/
- rdmsr_safe(MSR_IA32_VMX_EPT_VPID_CAP, &ept, &vpid);
+ rdmsrq_safe(MSR_IA32_VMX_EPT_VPID_CAP, &val.q);
+ ept = val.l;
+ vpid = val.h;
/* Pin, EPT, VPID and VM-Func are merged into a single word. */
WARN_ON_ONCE(supported >> 16);
diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c
index 3e8891a9caf2..ec51c2b9a257 100644
--- a/arch/x86/kernel/cpu/hygon.c
+++ b/arch/x86/kernel/cpu/hygon.c
@@ -125,11 +125,12 @@ static void bsp_init_hygon(struct cpuinfo_x86 *c)
static void early_init_hygon(struct cpuinfo_x86 *c)
{
- u32 dummy;
+ u64 val;
set_cpu_cap(c, X86_FEATURE_K8);
- rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
+ rdmsrq_safe(MSR_AMD64_PATCH_LEVEL, &val);
+ c->microcode = (u32)val;
/*
* c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index abb3984336eb..4297ceb2cb24 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -199,6 +199,41 @@ void intel_unlock_cpuid_leafs(struct cpuinfo_x86 *c)
c->cpuid_level = cpuid_eax(0);
}
+/*
+ * Use CPUID to generate a "vfm" value. Useful before cpuinfo_x86
+ * structures are populated.
+ */
+static u32 intel_cpuid_vfm(void)
+{
+ u32 eax = cpuid_eax(1);
+ u32 fam = x86_family(eax);
+ u32 model = x86_model(eax);
+
+ return IFM(fam, model);
+}
+
+u32 intel_get_platform_id(void)
+{
+ unsigned int val[2];
+
+ if (x86_hypervisor_present)
+ return 0;
+
+ /*
+ * This can be called early. Use CPUID directly instead of
+ * relying on cpuinfo_x86 which may not be fully initialized.
+ * The PII does not have MSR_IA32_PLATFORM_ID. Everything
+ * before _it_ has no microcode (for Linux at least).
+ */
+ if (intel_cpuid_vfm() <= INTEL_PENTIUM_II_KLAMATH)
+ return 0;
+
+ /* get processor flags from MSR 0x17 */
+ native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+
+ return (val[1] >> 18) & 7;
+}
+
static void early_init_intel(struct cpuinfo_x86 *c)
{
u64 misc_enable;
@@ -542,12 +577,12 @@ static void init_intel(struct cpuinfo_x86 *c)
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
if (boot_cpu_has(X86_FEATURE_DS)) {
- unsigned int l1, l2;
+ u64 l;
- rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
- if (!(l1 & MSR_IA32_MISC_ENABLE_BTS_UNAVAIL))
+ rdmsrq(MSR_IA32_MISC_ENABLE, l);
+ if (!(l & MSR_IA32_MISC_ENABLE_BTS_UNAVAIL))
set_cpu_cap(c, X86_FEATURE_BTS);
- if (!(l1 & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL))
+ if (!(l & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL))
set_cpu_cap(c, X86_FEATURE_PEBS);
}
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
index 4604802692da..7ab077f0cc66 100644
--- a/arch/x86/kernel/cpu/match.c
+++ b/arch/x86/kernel/cpu/match.c
@@ -6,34 +6,6 @@
#include <linux/slab.h>
/**
- * x86_match_vendor_cpu_type - helper function to match the hardware defined
- * cpu-type for a single entry in the x86_cpu_id
- * table. Note, this function does not match the
- * generic cpu-types TOPO_CPU_TYPE_EFFICIENCY and
- * TOPO_CPU_TYPE_PERFORMANCE.
- * @c: Pointer to the cpuinfo_x86 structure of the CPU to match.
- * @m: Pointer to the x86_cpu_id entry to match against.
- *
- * Return: true if the cpu-type matches, false otherwise.
- */
-static bool x86_match_vendor_cpu_type(struct cpuinfo_x86 *c, const struct x86_cpu_id *m)
-{
- if (m->type == X86_CPU_TYPE_ANY)
- return true;
-
- /* Hybrid CPUs are special, they are assumed to match all cpu-types */
- if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU))
- return true;
-
- if (c->x86_vendor == X86_VENDOR_INTEL)
- return m->type == c->topo.intel_type;
- if (c->x86_vendor == X86_VENDOR_AMD)
- return m->type == c->topo.amd_type;
-
- return false;
-}
-
-/**
* x86_match_cpu - match current CPU against an array of x86_cpu_ids
* @match: Pointer to array of x86_cpu_ids. Last entry terminated with
* {}.
@@ -81,7 +53,7 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
continue;
if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature))
continue;
- if (!x86_match_vendor_cpu_type(c, m))
+ if (m->type != X86_CPU_TYPE_ANY && c->topo.cpu_type != m->type)
continue;
return m;
}
diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c
index 36e0df4d1342..f916fb4c5d13 100644
--- a/arch/x86/kernel/cpu/mce/amd.c
+++ b/arch/x86/kernel/cpu/mce/amd.c
@@ -280,11 +280,11 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
u8 *bank_counts = this_cpu_ptr(smca_bank_counts);
const struct smca_hwid *s_hwid;
unsigned int i, hwid_mcatype;
- u32 high, low;
+ struct msr val;
u32 smca_config = MSR_AMD64_SMCA_MCx_CONFIG(bank);
/* Set appropriate bits in MCA_CONFIG */
- if (!rdmsr_safe(smca_config, &low, &high)) {
+ if (!rdmsrq_safe(smca_config, &val.q)) {
/*
* OS is required to set the MCAX bit to acknowledge that it is
* now using the new MSR ranges and new registers under each
@@ -294,7 +294,7 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
*
* MCA_CONFIG[MCAX] is bit 32 (0 in the high portion of the MSR.)
*/
- high |= BIT(0);
+ val.h |= BIT(0);
/*
* SMCA sets the Deferred Error Interrupt type per bank.
@@ -307,9 +307,9 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
* APIC based interrupt. First, check that no interrupt has been
* set.
*/
- if ((low & BIT(5)) && !((high >> 5) & 0x3) && data->dfr_intr_en) {
+ if ((val.l & BIT(5)) && !((val.h >> 5) & 0x3) && data->dfr_intr_en) {
__set_bit(bank, data->dfr_intr_banks);
- high |= BIT(5);
+ val.h |= BIT(5);
}
/*
@@ -324,33 +324,33 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
* The OS should set this to inform the platform that the OS is ready
* to handle the MCA Thresholding interrupt.
*/
- if ((low & BIT(10)) && data->thr_intr_en) {
+ if ((val.l & BIT(10)) && data->thr_intr_en) {
__set_bit(bank, data->thr_intr_banks);
- high |= BIT(8);
+ val.h |= BIT(8);
}
- this_cpu_ptr(mce_banks_array)[bank].lsb_in_status = !!(low & BIT(8));
+ this_cpu_ptr(mce_banks_array)[bank].lsb_in_status = !!(val.l & BIT(8));
- if (low & MCI_CONFIG_PADDRV)
+ if (val.l & MCI_CONFIG_PADDRV)
this_cpu_ptr(smca_banks)[bank].paddrv = 1;
- wrmsr(smca_config, low, high);
+ wrmsrq(smca_config, val.q);
}
- if (rdmsr_safe(MSR_AMD64_SMCA_MCx_IPID(bank), &low, &high)) {
+ if (rdmsrq_safe(MSR_AMD64_SMCA_MCx_IPID(bank), &val.q)) {
pr_warn("Failed to read MCA_IPID for bank %d\n", bank);
return;
}
- hwid_mcatype = HWID_MCATYPE(high & MCI_IPID_HWID,
- (high & MCI_IPID_MCATYPE) >> 16);
+ hwid_mcatype = HWID_MCATYPE(val.h & MCI_IPID_HWID,
+ (val.h & MCI_IPID_MCATYPE) >> 16);
for (i = 0; i < ARRAY_SIZE(smca_hwid_mcatypes); i++) {
s_hwid = &smca_hwid_mcatypes[i];
if (hwid_mcatype == s_hwid->hwid_mcatype) {
this_cpu_ptr(smca_banks)[bank].hwid = s_hwid;
- this_cpu_ptr(smca_banks)[bank].id = low;
+ this_cpu_ptr(smca_banks)[bank].id = val.l;
this_cpu_ptr(smca_banks)[bank].sysfs_id = bank_counts[s_hwid->bank_type]++;
break;
}
@@ -432,50 +432,50 @@ static bool lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
static void threshold_restart_block(void *_tr)
{
struct thresh_restart *tr = _tr;
- u32 hi, lo;
+ struct msr val;
/* sysfs write might race against an offline operation */
if (!this_cpu_read(threshold_banks) && !tr->set_lvt_off)
return;
- rdmsr(tr->b->address, lo, hi);
+ rdmsrq(tr->b->address, val.q);
/*
* Reset error count and overflow bit.
* This is done during init or after handling an interrupt.
*/
- if (hi & MASK_OVERFLOW_HI || tr->set_lvt_off) {
- hi &= ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI);
- hi |= THRESHOLD_MAX - tr->b->threshold_limit;
+ if (val.h & MASK_OVERFLOW_HI || tr->set_lvt_off) {
+ val.h &= ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI);
+ val.h |= THRESHOLD_MAX - tr->b->threshold_limit;
} else if (tr->old_limit) { /* change limit w/o reset */
- int new_count = (hi & THRESHOLD_MAX) +
+ int new_count = (val.h & THRESHOLD_MAX) +
(tr->old_limit - tr->b->threshold_limit);
- hi = (hi & ~MASK_ERR_COUNT_HI) |
+ val.h = (val.h & ~MASK_ERR_COUNT_HI) |
(new_count & THRESHOLD_MAX);
}
/* clear IntType */
- hi &= ~MASK_INT_TYPE_HI;
+ val.h &= ~MASK_INT_TYPE_HI;
if (!tr->b->interrupt_capable)
goto done;
if (tr->set_lvt_off) {
- if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
+ if (lvt_off_valid(tr->b, tr->lvt_off, val.l, val.h)) {
/* set new lvt offset */
- hi &= ~MASK_LVTOFF_HI;
- hi |= tr->lvt_off << 20;
+ val.h &= ~MASK_LVTOFF_HI;
+ val.h |= tr->lvt_off << 20;
}
}
if (tr->b->interrupt_enable)
- hi |= INT_TYPE_APIC;
+ val.h |= INT_TYPE_APIC;
done:
- hi |= MASK_COUNT_EN_HI;
- wrmsr(tr->b->address, lo, hi);
+ val.h |= MASK_COUNT_EN_HI;
+ wrmsrq(tr->b->address, val.q);
}
static void threshold_restart_bank(unsigned int bank, bool intr_en)
@@ -726,7 +726,8 @@ static void smca_enable_interrupt_vectors(void)
void mce_amd_feature_init(struct cpuinfo_x86 *c)
{
unsigned int bank, block, cpu = smp_processor_id();
- u32 low = 0, high = 0, address = 0;
+ struct msr val = { .q = 0 };
+ u32 address = 0;
int offset = -1;
amd_apply_cpu_quirks(c);
@@ -746,21 +747,21 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
disable_err_thresholding(c, bank);
for (block = 0; block < NR_BLOCKS; ++block) {
- address = get_block_address(address, low, high, bank, block, cpu);
+ address = get_block_address(address, val.l, val.h, bank, block, cpu);
if (!address)
break;
- if (rdmsr_safe(address, &low, &high))
+ if (rdmsrq_safe(address, &val.q))
break;
- if (!(high & MASK_VALID_HI))
+ if (!(val.h & MASK_VALID_HI))
continue;
- if (!(high & MASK_CNTP_HI) ||
- (high & MASK_LOCKED_HI))
+ if (!(val.h & MASK_CNTP_HI) ||
+ (val.h & MASK_LOCKED_HI))
continue;
- offset = prepare_threshold_block(bank, block, address, offset, high);
+ offset = prepare_threshold_block(bank, block, address, offset, val.h);
}
}
}
@@ -1083,24 +1084,24 @@ static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb
u32 address)
{
struct threshold_block *b = NULL;
- u32 low, high;
+ struct msr val;
int err;
if ((bank >= this_cpu_read(mce_num_banks)) || (block >= NR_BLOCKS))
return 0;
- if (rdmsr_safe(address, &low, &high))
+ if (rdmsrq_safe(address, &val.q))
return 0;
- if (!(high & MASK_VALID_HI)) {
+ if (!(val.h & MASK_VALID_HI)) {
if (block)
goto recurse;
else
return 0;
}
- if (!(high & MASK_CNTP_HI) ||
- (high & MASK_LOCKED_HI))
+ if (!(val.h & MASK_CNTP_HI) ||
+ (val.h & MASK_LOCKED_HI))
goto recurse;
b = kzalloc_obj(struct threshold_block);
@@ -1112,7 +1113,7 @@ static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb
b->cpu = cpu;
b->address = address;
b->interrupt_enable = 0;
- b->interrupt_capable = lvt_interrupt_supported(bank, high);
+ b->interrupt_capable = lvt_interrupt_supported(bank, val.h);
b->threshold_limit = get_thr_limit();
if (b->interrupt_capable) {
@@ -1124,13 +1125,13 @@ static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb
list_add(&b->miscj, &tb->miscj);
- mce_threshold_block_init(b, (high & MASK_LVTOFF_HI) >> 20);
+ mce_threshold_block_init(b, (val.h & MASK_LVTOFF_HI) >> 20);
err = kobject_init_and_add(&b->kobj, &threshold_ktype, tb->kobj, get_name(cpu, bank, b));
if (err)
goto out_free;
recurse:
- address = get_block_address(address, low, high, bank, ++block, cpu);
+ address = get_block_address(address, val.l, val.h, bank, ++block, cpu);
if (!address)
return 0;
diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
index 9bba1e2f03af..017aaf57ba47 100644
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -1866,7 +1866,7 @@ static void __mcheck_cpu_init_generic(void)
rdmsrq(MSR_IA32_MCG_CAP, cap);
if (cap & MCG_CTL_P)
- wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+ wrmsrq(MSR_IA32_MCG_CTL, ~0ULL);
}
static void __mcheck_cpu_init_prepare_banks(void)
diff --git a/arch/x86/kernel/cpu/mce/p5.c b/arch/x86/kernel/cpu/mce/p5.c
index 2272ad53fc33..3c2b6cc918b1 100644
--- a/arch/x86/kernel/cpu/mce/p5.c
+++ b/arch/x86/kernel/cpu/mce/p5.c
@@ -23,16 +23,16 @@ int mce_p5_enabled __read_mostly;
/* Machine check handler for Pentium class Intel CPUs: */
noinstr void pentium_machine_check(struct pt_regs *regs)
{
- u32 loaddr, hi, lotype;
+ u64 addr, type;
instrumentation_begin();
- rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
- rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi);
+ rdmsrq(MSR_IA32_P5_MC_ADDR, addr);
+ rdmsrq(MSR_IA32_P5_MC_TYPE, type);
pr_emerg("CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n",
- smp_processor_id(), loaddr, lotype);
+ smp_processor_id(), (u32)addr, (u32)type);
- if (lotype & (1<<5)) {
+ if (type & (1<<5)) {
pr_emerg("CPU#%d: Possible thermal failure (CPU on fire ?).\n",
smp_processor_id());
}
@@ -44,7 +44,7 @@ noinstr void pentium_machine_check(struct pt_regs *regs)
/* Set up machine check reporting for processors with Intel style MCE: */
void intel_p5_mcheck_init(struct cpuinfo_x86 *c)
{
- u32 l, h;
+ u64 __maybe_unused q;
/* Default P5 to off as its often misconnected: */
if (!mce_p5_enabled)
@@ -55,8 +55,8 @@ void intel_p5_mcheck_init(struct cpuinfo_x86 *c)
return;
/* Read registers before enabling: */
- rdmsr(MSR_IA32_P5_MC_ADDR, l, h);
- rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
+ rdmsrq(MSR_IA32_P5_MC_ADDR, q);
+ rdmsrq(MSR_IA32_P5_MC_TYPE, q);
pr_info("Intel old style machine check architecture supported.\n");
/* Enable MCE: */
diff --git a/arch/x86/kernel/cpu/mce/winchip.c b/arch/x86/kernel/cpu/mce/winchip.c
index 6c99f2941909..7040243533d9 100644
--- a/arch/x86/kernel/cpu/mce/winchip.c
+++ b/arch/x86/kernel/cpu/mce/winchip.c
@@ -28,12 +28,12 @@ noinstr void winchip_machine_check(struct pt_regs *regs)
/* Set up machine check reporting on the Winchip C6 series */
void winchip_mcheck_init(struct cpuinfo_x86 *c)
{
- u32 lo, hi;
+ struct msr val;
- rdmsr(MSR_IDT_FCR1, lo, hi);
- lo |= (1<<2); /* Enable EIERRINT (int 18 MCE) */
- lo &= ~(1<<4); /* Enable MCE */
- wrmsr(MSR_IDT_FCR1, lo, hi);
+ rdmsrq(MSR_IDT_FCR1, val.q);
+ val.l |= (1<<2); /* Enable EIERRINT (int 18 MCE) */
+ val.l &= ~(1<<4); /* Enable MCE */
+ wrmsrq(MSR_IDT_FCR1, val.q);
cr4_set_bits(X86_CR4_MCE);
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index 531dfb771c8b..6cdc410e7547 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -136,8 +136,7 @@ struct cont_desc {
* Microcode patch container file is prepended to the initrd in cpio
* format. See Documentation/arch/x86/microcode.rst
*/
-static const char
-ucode_path[] __maybe_unused = "kernel/x86/microcode/AuthenticAMD.bin";
+static const char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin";
/*
* This is CPUID(1).EAX on the BSP. It is used in two ways:
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index f4a444e6114d..1142183c950c 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -121,42 +121,6 @@ static inline unsigned int exttable_size(struct extended_sigtable *et)
return et->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE;
}
-
-/*
- * Use CPUID to generate a "vfm" value. Useful before cpuinfo_x86
- * structures are populated.
- */
-static u32 intel_cpuid_vfm(void)
-{
- u32 eax = cpuid_eax(1);
- u32 fam = x86_family(eax);
- u32 model = x86_model(eax);
-
- return IFM(fam, model);
-}
-
-u32 intel_get_platform_id(void)
-{
- unsigned int val[2];
-
- if (x86_hypervisor_present)
- return 0;
-
- /*
- * This can be called early. Use CPUID directly instead of
- * relying on cpuinfo_x86 which may not be fully initialized.
- * The PII does not have MSR_IA32_PLATFORM_ID. Everything
- * before _it_ has no microcode (for Linux at least).
- */
- if (intel_cpuid_vfm() <= INTEL_PENTIUM_II_KLAMATH)
- return 0;
-
- /* get processor flags from MSR 0x17 */
- native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
-
- return (val[1] >> 18) & 7;
-}
-
void intel_collect_cpu_info(struct cpu_signature *sig)
{
sig->sig = cpuid_eax(1);
diff --git a/arch/x86/kernel/cpu/mtrr/amd.c b/arch/x86/kernel/cpu/mtrr/amd.c
index ef3e8e42b782..a73715d6f05c 100644
--- a/arch/x86/kernel/cpu/mtrr/amd.c
+++ b/arch/x86/kernel/cpu/mtrr/amd.c
@@ -10,20 +10,23 @@ static void
amd_get_mtrr(unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type *type)
{
- unsigned long low, high;
+ unsigned long val;
+ struct msr msr;
- rdmsr(MSR_K6_UWCCR, low, high);
+ rdmsrq(MSR_K6_UWCCR, msr.q);
/* Upper dword is region 1, lower is region 0 */
if (reg == 1)
- low = high;
+ val = msr.h;
+ else
+ val = msr.l;
/* The base masks off on the right alignment */
- *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
+ *base = (val & 0xFFFE0000) >> PAGE_SHIFT;
*type = 0;
- if (low & 1)
+ if (val & 1)
*type = MTRR_TYPE_UNCACHABLE;
- if (low & 2)
+ if (val & 2)
*type = MTRR_TYPE_WRCOMB;
- if (!(low & 3)) {
+ if (!(val & 3)) {
*size = 0;
return;
}
@@ -42,8 +45,8 @@ amd_get_mtrr(unsigned int reg, unsigned long *base,
* +1 000 0000 0000 0100
* *128K ...
*/
- low = (~low) & 0x1FFFC;
- *size = (low + 4) << (15 - PAGE_SHIFT);
+ val = (~val) & 0x1FFFC;
+ *size = (val + 4) << (15 - PAGE_SHIFT);
}
/**
@@ -59,12 +62,16 @@ amd_get_mtrr(unsigned int reg, unsigned long *base,
static void
amd_set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type)
{
+ struct msr msr;
u32 regs[2];
/*
* Low is MTRR0, High MTRR 1
*/
- rdmsr(MSR_K6_UWCCR, regs[0], regs[1]);
+ rdmsrq(MSR_K6_UWCCR, msr.q);
+ regs[0] = msr.l;
+ regs[1] = msr.h;
+
/*
* Blank to disable
*/
@@ -89,7 +96,9 @@ amd_set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type
* disable local interrupts, write back the cache, set the mtrr
*/
wbinvd();
- wrmsr(MSR_K6_UWCCR, regs[0], regs[1]);
+ msr.l = regs[0];
+ msr.h = regs[1];
+ wrmsrq(MSR_K6_UWCCR, msr.q);
}
static int
diff --git a/arch/x86/kernel/cpu/mtrr/centaur.c b/arch/x86/kernel/cpu/mtrr/centaur.c
index 6f6c3ae92943..e32cca1caf59 100644
--- a/arch/x86/kernel/cpu/mtrr/centaur.c
+++ b/arch/x86/kernel/cpu/mtrr/centaur.c
@@ -65,26 +65,26 @@ static void
centaur_set_mcr(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type)
{
- unsigned long low, high;
+ struct msr val;
if (size == 0) {
/* Disable */
- high = low = 0;
+ val.q = 0;
} else {
- high = base << PAGE_SHIFT;
+ val.h = base << PAGE_SHIFT;
if (centaur_mcr_type == 0) {
/* Only support write-combining... */
- low = -size << PAGE_SHIFT | 0x1f;
+ val.l = -size << PAGE_SHIFT | 0x1f;
} else {
if (type == MTRR_TYPE_UNCACHABLE)
- low = -size << PAGE_SHIFT | 0x02; /* NC */
+ val.l = -size << PAGE_SHIFT | 0x02; /* NC */
else
- low = -size << PAGE_SHIFT | 0x09; /* WWO, WC */
+ val.l = -size << PAGE_SHIFT | 0x09; /* WWO, WC */
}
}
- centaur_mcr[reg].high = high;
- centaur_mcr[reg].low = low;
- wrmsr(MSR_IDT_MCR0 + reg, low, high);
+ centaur_mcr[reg].high = val.h;
+ centaur_mcr[reg].low = val.l;
+ wrmsrq(MSR_IDT_MCR0 + reg, val.q);
}
static int
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
index e3eee9ae4141..cd1a6dec4064 100644
--- a/arch/x86/kernel/cpu/mtrr/cleanup.c
+++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -658,8 +658,8 @@ static int __init mtrr_search_optimal_index(void)
int __init mtrr_cleanup(void)
{
unsigned long x_remove_base, x_remove_size;
- unsigned long base, size, def, dummy;
- u64 chunk_size, gran_size;
+ u64 def, chunk_size, gran_size;
+ unsigned long base, size;
mtrr_type type;
int index_good;
int i;
@@ -670,7 +670,7 @@ int __init mtrr_cleanup(void)
if (!cpu_feature_enabled(X86_FEATURE_MTRR) || enable_mtrr_cleanup < 1)
return 0;
- rdmsr(MSR_MTRRdefType, def, dummy);
+ rdmsrq(MSR_MTRRdefType, def);
def &= 0xff;
if (def != MTRR_TYPE_UNCACHABLE)
return 0;
@@ -806,7 +806,7 @@ early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
int __init amd_special_default_mtrr(void)
{
- u32 l, h;
+ u64 q;
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
@@ -814,13 +814,13 @@ int __init amd_special_default_mtrr(void)
if (boot_cpu_data.x86 < 0xf)
return 0;
/* In case some hypervisor doesn't pass SYSCFG through: */
- if (rdmsr_safe(MSR_AMD64_SYSCFG, &l, &h) < 0)
+ if (rdmsrq_safe(MSR_AMD64_SYSCFG, &q) < 0)
return 0;
/*
* Memory between 4GB and top of mem is forced WB by this magic bit.
* Reserved before K8RevF, but should be zero there.
*/
- if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
+ if ((q & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
(Tom2Enabled | Tom2ForceMemTypeWB))
return 1;
return 0;
@@ -854,9 +854,9 @@ real_trim_memory(unsigned long start_pfn, unsigned long limit_pfn)
*/
int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
{
- unsigned long i, base, size, highest_pfn = 0, def, dummy;
+ unsigned long i, base, size, highest_pfn = 0;
mtrr_type type;
- u64 total_trim_size;
+ u64 def, total_trim_size;
/* extra one for all 0 */
int num[MTRR_NUM_TYPES + 1];
@@ -870,7 +870,7 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
if (!cpu_feature_enabled(X86_FEATURE_MTRR) || disable_mtrr_trim)
return 0;
- rdmsr(MSR_MTRRdefType, def, dummy);
+ rdmsrq(MSR_MTRRdefType, def);
def &= MTRR_DEF_TYPE_TYPE;
if (def != MTRR_TYPE_UNCACHABLE)
return 0;
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 3a8317060732..67cf69f24b00 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -103,7 +103,7 @@ u32 phys_hi_rsvd;
*/
static inline void k8_check_syscfg_dram_mod_en(void)
{
- u32 lo, hi;
+ struct msr val;
if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
(boot_cpu_data.x86 >= 0x0f)))
@@ -112,13 +112,13 @@ static inline void k8_check_syscfg_dram_mod_en(void)
if (cc_platform_has(CC_ATTR_HOST_SEV_SNP))
return;
- rdmsr(MSR_AMD64_SYSCFG, lo, hi);
- if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) {
+ rdmsrq(MSR_AMD64_SYSCFG, val.q);
+ if (val.l & K8_MTRRFIXRANGE_DRAM_MODIFY) {
pr_err(FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]"
" not cleared by BIOS, clearing this bit\n",
smp_processor_id());
- lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY;
- mtrr_wrmsr(MSR_AMD64_SYSCFG, lo, hi);
+ val.l &= ~K8_MTRRFIXRANGE_DRAM_MODIFY;
+ mtrr_wrmsr(MSR_AMD64_SYSCFG, val.l, val.h);
}
}
@@ -557,8 +557,14 @@ u8 mtrr_type_lookup(u64 start, u64 end, u8 *uniform)
static void
get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
{
- rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
- rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+ struct msr val;
+
+ rdmsrq(MTRRphysBase_MSR(index), val.q);
+ vr->base_lo = val.l;
+ vr->base_hi = val.h;
+ rdmsrq(MTRRphysMask_MSR(index), val.q);
+ vr->mask_lo = val.l;
+ vr->mask_hi = val.h;
}
/* Fill the MSR pair relating to a var range */
@@ -577,17 +583,17 @@ void fill_mtrr_var_range(unsigned int index,
static void get_fixed_ranges(mtrr_type *frs)
{
- unsigned int *p = (unsigned int *)frs;
+ u64 *p = (u64 *)frs;
int i;
k8_check_syscfg_dram_mod_en();
- rdmsr(MSR_MTRRfix64K_00000, p[0], p[1]);
+ rdmsrq(MSR_MTRRfix64K_00000, p[0]);
for (i = 0; i < 2; i++)
- rdmsr(MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);
+ rdmsrq(MSR_MTRRfix16K_80000 + i, p[1 + i]);
for (i = 0; i < 8; i++)
- rdmsr(MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
+ rdmsrq(MSR_MTRRfix4K_C0000 + i, p[3 + i]);
}
void mtrr_save_fixed_ranges(void *info)
@@ -689,31 +695,26 @@ static void __init print_mtrr_state(void)
bool __init get_mtrr_state(void)
{
struct mtrr_var_range *vrs;
- unsigned lo, dummy;
unsigned int i;
+ u64 q;
vrs = mtrr_state.var_ranges;
- rdmsr(MSR_MTRRcap, lo, dummy);
- mtrr_state.have_fixed = lo & MTRR_CAP_FIX;
+ rdmsrq(MSR_MTRRcap, q);
+ mtrr_state.have_fixed = q & MTRR_CAP_FIX;
for (i = 0; i < num_var_ranges; i++)
get_mtrr_var_range(i, &vrs[i]);
if (mtrr_state.have_fixed)
get_fixed_ranges(mtrr_state.fixed_ranges);
- rdmsr(MSR_MTRRdefType, lo, dummy);
- mtrr_state.def_type = lo & MTRR_DEF_TYPE_TYPE;
- mtrr_state.enabled = (lo & MTRR_DEF_TYPE_ENABLE) >> MTRR_STATE_SHIFT;
+ rdmsrq(MSR_MTRRdefType, q);
+ mtrr_state.def_type = q & MTRR_DEF_TYPE_TYPE;
+ mtrr_state.enabled = (q & MTRR_DEF_TYPE_ENABLE) >> MTRR_STATE_SHIFT;
if (amd_special_default_mtrr()) {
- unsigned low, high;
-
/* TOP_MEM2 */
- rdmsr(MSR_K8_TOP_MEM2, low, high);
- mtrr_tom2 = high;
- mtrr_tom2 <<= 32;
- mtrr_tom2 |= low;
+ rdmsrq(MSR_K8_TOP_MEM2, mtrr_tom2);
mtrr_tom2 &= 0xffffff800000ULL;
}
@@ -750,7 +751,9 @@ void __init mtrr_state_warn(void)
*/
void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
{
- if (wrmsr_safe(msr, a, b) < 0) {
+ struct msr val = { .l = a, .h = b };
+
+ if (wrmsrq_safe(msr, val.q) < 0) {
pr_err("MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
smp_processor_id(), msr, a, b);
}
@@ -765,11 +768,11 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
*/
static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
{
- unsigned lo, hi;
+ struct msr val;
- rdmsr(msr, lo, hi);
+ rdmsrq(msr, val.q);
- if (lo != msrwords[0] || hi != msrwords[1]) {
+ if (val.l != msrwords[0] || val.h != msrwords[1]) {
mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
*changed = true;
}
@@ -806,9 +809,8 @@ generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
static void generic_get_mtrr(unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type *type)
{
- u32 mask_lo, mask_hi, base_lo, base_hi;
+ u64 tmp, mask, base_msr;
unsigned int hi;
- u64 tmp, mask;
/*
* get_mtrr doesn't need to update mtrr_state, also it could be called
@@ -816,9 +818,9 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
*/
get_cpu();
- rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi);
+ rdmsrq(MTRRphysMask_MSR(reg), mask);
- if (!(mask_lo & MTRR_PHYSMASK_V)) {
+ if (!(mask & MTRR_PHYSMASK_V)) {
/* Invalid (i.e. free) range */
*base = 0;
*size = 0;
@@ -826,10 +828,10 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
goto out_put_cpu;
}
- rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
+ rdmsrq(MTRRphysBase_MSR(reg), base_msr);
/* Work out the shifted address mask: */
- tmp = (u64)mask_hi << 32 | (mask_lo & PAGE_MASK);
+ tmp = mask & PAGE_MASK;
mask = (u64)phys_hi_rsvd << 32 | tmp;
/* Expand tmp with high bits to all 1s: */
@@ -849,8 +851,8 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
* contiguous range:
*/
*size = -mask >> PAGE_SHIFT;
- *base = (u64)base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
- *type = base_lo & MTRR_PHYSBASE_TYPE;
+ *base = base_msr >> PAGE_SHIFT;
+ *type = base_msr & MTRR_PHYSBASE_TYPE;
out_put_cpu:
put_cpu();
@@ -884,21 +886,21 @@ static int set_fixed_ranges(mtrr_type *frs)
*/
static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
{
- unsigned int lo, hi;
bool changed = false;
+ struct msr val;
- rdmsr(MTRRphysBase_MSR(index), lo, hi);
- if ((vr->base_lo & ~MTRR_PHYSBASE_RSVD) != (lo & ~MTRR_PHYSBASE_RSVD)
- || (vr->base_hi & ~phys_hi_rsvd) != (hi & ~phys_hi_rsvd)) {
+ rdmsrq(MTRRphysBase_MSR(index), val.q);
+ if ((vr->base_lo & ~MTRR_PHYSBASE_RSVD) != (val.l & ~MTRR_PHYSBASE_RSVD)
+ || (vr->base_hi & ~phys_hi_rsvd) != (val.h & ~phys_hi_rsvd)) {
mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
changed = true;
}
- rdmsr(MTRRphysMask_MSR(index), lo, hi);
+ rdmsrq(MTRRphysMask_MSR(index), val.q);
- if ((vr->mask_lo & ~MTRR_PHYSMASK_RSVD) != (lo & ~MTRR_PHYSMASK_RSVD)
- || (vr->mask_hi & ~phys_hi_rsvd) != (hi & ~phys_hi_rsvd)) {
+ if ((vr->mask_lo & ~MTRR_PHYSMASK_RSVD) != (val.l & ~MTRR_PHYSMASK_RSVD)
+ || (vr->mask_hi & ~phys_hi_rsvd) != (val.h & ~phys_hi_rsvd)) {
mtrr_wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
changed = true;
}
@@ -947,8 +949,12 @@ static unsigned long set_mtrr_state(void)
void mtrr_disable(void)
{
+ struct msr val;
+
/* Save MTRR state */
- rdmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
+ rdmsrq(MSR_MTRRdefType, val.q);
+ deftype_lo = val.l;
+ deftype_hi = val.h;
/* Disable MTRRs, and set the default type to uncached */
mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & MTRR_DEF_TYPE_DISABLE, deftype_hi);
@@ -1057,8 +1063,9 @@ int generic_validate_add_page(unsigned long base, unsigned long size,
static int generic_have_wrcomb(void)
{
- unsigned long config, dummy;
- rdmsr(MSR_MTRRcap, config, dummy);
+ u64 config;
+
+ rdmsrq(MSR_MTRRcap, config);
return config & MTRR_CAP_WC;
}
diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.c b/arch/x86/kernel/cpu/mtrr/mtrr.c
index 4b3d492afe17..468c53b20acf 100644
--- a/arch/x86/kernel/cpu/mtrr/mtrr.c
+++ b/arch/x86/kernel/cpu/mtrr/mtrr.c
@@ -547,7 +547,7 @@ void __init mtrr_bp_init(void)
{
bool generic_mtrrs = cpu_feature_enabled(X86_FEATURE_MTRR);
const char *why = "(not available)";
- unsigned long config, dummy;
+ unsigned long config;
phys_hi_rsvd = GENMASK(31, boot_cpu_data.x86_phys_bits - 32);
@@ -571,7 +571,7 @@ void __init mtrr_bp_init(void)
if (mtrr_enabled()) {
/* Get the number of variable MTRR ranges. */
if (mtrr_if == &generic_mtrr_ops)
- rdmsr(MSR_MTRRcap, config, dummy);
+ rdmsrq(MSR_MTRRcap, config);
else
config = mtrr_if->var_regs;
num_var_ranges = config & MTRR_CAP_VCNT;
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 9c01d2562b7a..55214d6fdc49 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -247,7 +247,11 @@ static __init bool __rdt_get_mem_config_amd(struct rdt_resource *r)
cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx);
hw_res->num_closid = edx + 1;
- r->membw.max_bw = 1 << eax;
+ if (BITS_PER_TYPE(r->membw.max_bw) <= eax) {
+ pr_warn("Unable to support hardware's maximum bandwidth\n");
+ return false;
+ }
+ r->membw.max_bw = BIT(eax);
/* AMD does not use delay */
r->membw.delay_linear = false;
@@ -515,14 +519,12 @@ static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r)
return;
}
- list_add_tail_rcu(&d->hdr.list, add_pos);
-
err = resctrl_online_ctrl_domain(r, d);
if (err) {
- list_del_rcu(&d->hdr.list);
- synchronize_rcu();
ctrl_domain_free(hw_dom);
+ return;
}
+ list_add_tail_rcu(&d->hdr.list, add_pos);
}
static void l3_mon_domain_setup(int cpu, int id, struct rdt_resource *r, struct list_head *add_pos)
@@ -556,14 +558,12 @@ static void l3_mon_domain_setup(int cpu, int id, struct rdt_resource *r, struct
return;
}
- list_add_tail_rcu(&d->hdr.list, add_pos);
-
err = resctrl_online_mon_domain(r, &d->hdr);
if (err) {
- list_del_rcu(&d->hdr.list);
- synchronize_rcu();
l3_mon_domain_free(hw_dom);
+ return;
}
+ list_add_tail_rcu(&d->hdr.list, add_pos);
}
static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)
@@ -642,9 +642,9 @@ static void domain_remove_cpu_ctrl(int cpu, struct rdt_resource *r)
d = container_of(hdr, struct rdt_ctrl_domain, hdr);
hw_dom = resctrl_to_arch_ctrl_dom(d);
- resctrl_offline_ctrl_domain(r, d);
list_del_rcu(&hdr->list);
synchronize_rcu();
+ resctrl_offline_ctrl_domain(r, d);
/*
* rdt_ctrl_domain "d" is going to be freed below, so clear
@@ -689,9 +689,9 @@ static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r)
d = container_of(hdr, struct rdt_l3_mon_domain, hdr);
hw_dom = resctrl_to_arch_mon_dom(d);
- resctrl_offline_mon_domain(r, hdr);
list_del_rcu(&hdr->list);
synchronize_rcu();
+ resctrl_offline_mon_domain(r, hdr);
l3_mon_domain_free(hw_dom);
break;
}
@@ -702,9 +702,9 @@ static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r)
return;
pkgd = container_of(hdr, struct rdt_perf_pkg_mon_domain, hdr);
- resctrl_offline_mon_domain(r, hdr);
list_del_rcu(&hdr->list);
synchronize_rcu();
+ resctrl_offline_mon_domain(r, hdr);
kfree(pkgd);
break;
}
@@ -725,13 +725,16 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
static void clear_closid_rmid(int cpu)
{
struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state);
+ struct msr val = {
+ .l = RESCTRL_RESERVED_RMID,
+ .h = RESCTRL_RESERVED_CLOSID
+ };
state->default_closid = RESCTRL_RESERVED_CLOSID;
state->default_rmid = RESCTRL_RESERVED_RMID;
state->cur_closid = RESCTRL_RESERVED_CLOSID;
state->cur_rmid = RESCTRL_RESERVED_RMID;
- wrmsr(MSR_IA32_PQR_ASSOC, RESCTRL_RESERVED_RMID,
- RESCTRL_RESERVED_CLOSID);
+ wrmsrq(MSR_IA32_PQR_ASSOC, val.q);
}
static int resctrl_arch_online_cpu(unsigned int cpu)
diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
index b20e705606b8..e74f1ed54b86 100644
--- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
+++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
@@ -53,7 +53,7 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
/* Walking r->domains, ensure it can't race with cpuhp */
lockdep_assert_cpus_held();
- list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+ list_for_each_entry_rcu(d, &r->ctrl_domains, hdr.list, lockdep_is_cpus_held()) {
hw_dom = resctrl_to_arch_ctrl_dom(d);
msr_param.res = NULL;
for (t = 0; t < CDP_NUM_TYPES; t++) {
@@ -115,7 +115,7 @@ static void _resctrl_sdciae_enable(struct rdt_resource *r, bool enable)
lockdep_assert_cpus_held();
/* Update MSR_IA32_L3_QOS_EXT_CFG MSR on all the CPUs in all domains */
- list_for_each_entry(d, &r->ctrl_domains, hdr.list)
+ list_for_each_entry_rcu(d, &r->ctrl_domains, hdr.list, lockdep_is_cpus_held())
on_each_cpu_mask(&d->hdr.cpu_mask, resctrl_sdciae_set_one_amd, &enable, 1);
}
diff --git a/arch/x86/kernel/cpu/resctrl/intel_aet.c b/arch/x86/kernel/cpu/resctrl/intel_aet.c
index 89b8b619d5d5..c22c3cf5167d 100644
--- a/arch/x86/kernel/cpu/resctrl/intel_aet.c
+++ b/arch/x86/kernel/cpu/resctrl/intel_aet.c
@@ -398,12 +398,11 @@ void intel_aet_mon_domain_setup(int cpu, int id, struct rdt_resource *r,
d->hdr.type = RESCTRL_MON_DOMAIN;
d->hdr.rid = RDT_RESOURCE_PERF_PKG;
cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
- list_add_tail_rcu(&d->hdr.list, add_pos);
err = resctrl_online_mon_domain(r, &d->hdr);
if (err) {
- list_del_rcu(&d->hdr.list);
- synchronize_rcu();
kfree(d);
+ return;
}
+ list_add_tail_rcu(&d->hdr.list, add_pos);
}
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index 569894d6e5c8..3838e0a13d36 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -136,7 +136,7 @@ static int logical_rmid_to_physical_rmid(int cpu, int lrmid)
static int __rmid_read_phys(u32 prmid, enum resctrl_event_id eventid, u64 *val)
{
- u64 msr_val;
+ struct msr msr_val = { .l = eventid, .h = prmid };
/*
* As per the SDM, when IA32_QM_EVTSEL.EvtID (bits 7:0) is configured
@@ -146,15 +146,15 @@ static int __rmid_read_phys(u32 prmid, enum resctrl_event_id eventid, u64 *val)
* IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
* are error bits.
*/
- wrmsr(MSR_IA32_QM_EVTSEL, eventid, prmid);
- rdmsrq(MSR_IA32_QM_CTR, msr_val);
+ wrmsrq(MSR_IA32_QM_EVTSEL, msr_val.q);
+ rdmsrq(MSR_IA32_QM_CTR, msr_val.q);
- if (msr_val & RMID_VAL_ERROR)
+ if (msr_val.q & RMID_VAL_ERROR)
return -EIO;
- if (msr_val & RMID_VAL_UNAVAIL)
+ if (msr_val.q & RMID_VAL_UNAVAIL)
return -EINVAL;
- *val = msr_val;
+ *val = msr_val.q;
return 0;
}
@@ -283,7 +283,10 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
static int __cntr_id_read(u32 cntr_id, u64 *val)
{
- u64 msr_val;
+ struct msr msr_val = {
+ .l = ABMC_EXTENDED_EVT_ID | ABMC_EVT_ID,
+ .h = cntr_id
+ };
/*
* QM_EVTSEL Register definition:
@@ -306,15 +309,15 @@ static int __cntr_id_read(u32 cntr_id, u64 *val)
* ID is set in the QM_EVTSEL.RMID field. The RMID_VAL_UNAVAIL bit
* is set if the counter data is unavailable.
*/
- wrmsr(MSR_IA32_QM_EVTSEL, ABMC_EXTENDED_EVT_ID | ABMC_EVT_ID, cntr_id);
- rdmsrq(MSR_IA32_QM_CTR, msr_val);
+ wrmsrq(MSR_IA32_QM_EVTSEL, msr_val.q);
+ rdmsrq(MSR_IA32_QM_CTR, msr_val.q);
- if (msr_val & RMID_VAL_ERROR)
+ if (msr_val.q & RMID_VAL_ERROR)
return -EIO;
- if (msr_val & RMID_VAL_UNAVAIL)
+ if (msr_val.q & RMID_VAL_UNAVAIL)
return -EINVAL;
- *val = msr_val;
+ *val = msr_val.q;
return 0;
}
@@ -510,7 +513,7 @@ static void _resctrl_abmc_enable(struct rdt_resource *r, bool enable)
lockdep_assert_cpus_held();
- list_for_each_entry(d, &r->mon_domains, hdr.list) {
+ list_for_each_entry_rcu(d, &r->mon_domains, hdr.list, lockdep_is_cpus_held()) {
on_each_cpu_mask(&d->hdr.cpu_mask, resctrl_abmc_set_one_amd,
&enable, 1);
resctrl_arch_reset_rmid_all(r, d);
diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
index de580eca3363..d7caab0409b6 100644
--- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
+++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
@@ -241,16 +241,16 @@ int resctrl_arch_pseudo_lock_fn(void *_plr)
int resctrl_arch_measure_cycles_lat_fn(void *_plr)
{
struct pseudo_lock_region *plr = _plr;
- u32 saved_low, saved_high;
unsigned long i;
u64 start, end;
void *mem_r;
+ u64 saved;
local_irq_disable();
/*
* Disable hardware prefetchers.
*/
- rdmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
+ rdmsrq(MSR_MISC_FEATURE_CONTROL, saved);
wrmsrq(MSR_MISC_FEATURE_CONTROL, prefetch_disable_bits);
mem_r = READ_ONCE(plr->kmem);
/*
@@ -267,7 +267,7 @@ int resctrl_arch_measure_cycles_lat_fn(void *_plr)
end = rdtsc_ordered();
trace_pseudo_lock_mem_latency((u32)(end - start));
}
- wrmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
+ wrmsrq(MSR_MISC_FEATURE_CONTROL, saved);
local_irq_enable();
plr->thread_done = 1;
wake_up_interruptible(&plr->lock_thread_wq);
@@ -312,11 +312,11 @@ static int measure_residency_fn(struct perf_event_attr *miss_attr,
u64 hits_before = 0, hits_after = 0, miss_before = 0, miss_after = 0;
struct perf_event *miss_event, *hit_event;
int hit_pmcnum, miss_pmcnum;
- u32 saved_low, saved_high;
unsigned int line_size;
unsigned int size;
unsigned long i;
void *mem_r;
+ u64 saved;
u64 tmp;
miss_event = perf_event_create_kernel_counter(miss_attr, plr->cpu,
@@ -346,7 +346,7 @@ static int measure_residency_fn(struct perf_event_attr *miss_attr,
/*
* Disable hardware prefetchers.
*/
- rdmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
+ rdmsrq(MSR_MISC_FEATURE_CONTROL, saved);
wrmsrq(MSR_MISC_FEATURE_CONTROL, prefetch_disable_bits);
/* Initialize rest of local variables */
@@ -405,7 +405,7 @@ static int measure_residency_fn(struct perf_event_attr *miss_attr,
*/
rmb();
/* Re-enable hardware prefetchers */
- wrmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
+ wrmsrq(MSR_MISC_FEATURE_CONTROL, saved);
local_irq_enable();
out_hit:
perf_event_release_kernel(hit_event);
diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index 885026468440..5ffa39fa86fa 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -151,7 +151,7 @@ static int set_cache_qos_cfg(int level, bool enable)
return -ENOMEM;
r_l = &rdt_resources_all[level].r_resctrl;
- list_for_each_entry(d, &r_l->ctrl_domains, hdr.list) {
+ list_for_each_entry_rcu(d, &r_l->ctrl_domains, hdr.list, lockdep_is_cpus_held()) {
if (r_l->cache.arch_has_per_cpu_cfg)
/* Pick all the CPUs in the domain instance */
for_each_cpu(cpu, &d->hdr.cpu_mask)
@@ -249,7 +249,7 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
* CBMs in all ctrl_domains to the maximum mask value. Pick one CPU
* from each domain to update the MSRs below.
*/
- list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+ list_for_each_entry_rcu(d, &r->ctrl_domains, hdr.list, lockdep_is_cpus_held()) {
hw_dom = resctrl_to_arch_ctrl_dom(d);
for (i = 0; i < hw_res->num_closid; i++)
diff --git a/arch/x86/kernel/cpu/topology.h b/arch/x86/kernel/cpu/topology.h
index 37326297f80c..74e02bacd854 100644
--- a/arch/x86/kernel/cpu/topology.h
+++ b/arch/x86/kernel/cpu/topology.h
@@ -22,6 +22,7 @@ void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,
bool cpu_parse_topology_ext(struct topo_scan *tscan);
void cpu_parse_topology_amd(struct topo_scan *tscan);
void cpu_topology_fixup_amd(struct topo_scan *tscan);
+enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c);
static inline u32 topo_shift_apicid(u32 apicid, enum x86_topology_domains dom)
{
diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c
index da080d732e10..c5a6944df86a 100644
--- a/arch/x86/kernel/cpu/topology_amd.c
+++ b/arch/x86/kernel/cpu/topology_amd.c
@@ -177,8 +177,10 @@ static void topoext_fixup(struct topo_scan *tscan)
static void parse_topology_amd(struct topo_scan *tscan)
{
- if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES))
- tscan->c->topo.cpu_type = cpuid_ebx(0x80000026);
+ if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) {
+ tscan->c->topo.hw_cpu_type = cpuid_ebx(0x80000026);
+ tscan->c->topo.cpu_type = get_topology_cpu_type(tscan->c);
+ }
/*
* Try to get SMT, CORE, TILE, and DIE shifts from extended
diff --git a/arch/x86/kernel/cpu/topology_common.c b/arch/x86/kernel/cpu/topology_common.c
index cf7513416b70..6845e3c63fbb 100644
--- a/arch/x86/kernel/cpu/topology_common.c
+++ b/arch/x86/kernel/cpu/topology_common.c
@@ -42,8 +42,9 @@ enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c)
}
if (c->x86_vendor == X86_VENDOR_AMD) {
switch (c->topo.amd_type) {
- case 0: return TOPO_CPU_TYPE_PERFORMANCE;
- case 1: return TOPO_CPU_TYPE_EFFICIENCY;
+ case AMD_CPU_TYPE_PERFORMANCE: return TOPO_CPU_TYPE_PERFORMANCE;
+ case AMD_CPU_TYPE_EFFICIENCY: return TOPO_CPU_TYPE_EFFICIENCY;
+ case AMD_CPU_TYPE_LOW_POWER: return TOPO_CPU_TYPE_LOW_POWER;
}
}
@@ -57,12 +58,14 @@ const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c)
return "performance";
case TOPO_CPU_TYPE_EFFICIENCY:
return "efficiency";
+ case TOPO_CPU_TYPE_LOW_POWER:
+ return "low_power";
default:
return "unknown";
}
}
-static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c)
+static unsigned int parse_num_cores_legacy(struct cpuinfo_x86 *c)
{
struct {
u32 cache_type : 5,
@@ -168,8 +171,12 @@ static void parse_topology(struct topo_scan *tscan, bool early)
case X86_VENDOR_INTEL:
if (!IS_ENABLED(CONFIG_CPU_SUP_INTEL) || !cpu_parse_topology_ext(tscan))
parse_legacy(tscan);
- if (c->cpuid_level >= 0x1a)
- c->topo.cpu_type = cpuid_eax(0x1a);
+
+ if (c->cpuid_level >= 0x1a) {
+ c->topo.hw_cpu_type = cpuid_eax(0x1a);
+ c->topo.cpu_type = get_topology_cpu_type(c);
+ }
+
break;
}
}
diff --git a/arch/x86/kernel/cpu/transmeta.c b/arch/x86/kernel/cpu/transmeta.c
index 1fdcd69c625c..3e04b5d01bf8 100644
--- a/arch/x86/kernel/cpu/transmeta.c
+++ b/arch/x86/kernel/cpu/transmeta.c
@@ -24,7 +24,8 @@ static void early_init_transmeta(struct cpuinfo_x86 *c)
static void init_transmeta(struct cpuinfo_x86 *c)
{
- unsigned int cap_mask, uk, max, dummy;
+ u64 msr;
+ unsigned int max, dummy;
unsigned int cms_rev1, cms_rev2;
unsigned int cpu_rev, cpu_freq = 0, cpu_flags, new_cpu_rev;
char cpu_info[65];
@@ -86,10 +87,11 @@ static void init_transmeta(struct cpuinfo_x86 *c)
}
/* Unhide possibly hidden capability flags */
- rdmsr(0x80860004, cap_mask, uk);
- wrmsr(0x80860004, ~0, uk);
+ rdmsrq(0x80860004, msr);
+ wrmsrq(0x80860004, msr | ~0U);
+ cpuid_refresh_leaf(c, 0x1);
c->x86_capability[CPUID_1_EDX] = cpuid_edx(0x00000001);
- wrmsr(0x80860004, cap_mask, uk);
+ wrmsrq(0x80860004, msr);
/* All Transmeta CPUs have a constant TSC */
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
diff --git a/arch/x86/kernel/cpu/zhaoxin.c b/arch/x86/kernel/cpu/zhaoxin.c
index 761aef5590ac..fe504fd43c77 100644
--- a/arch/x86/kernel/cpu/zhaoxin.c
+++ b/arch/x86/kernel/cpu/zhaoxin.c
@@ -21,7 +21,7 @@
static void init_zhaoxin_cap(struct cpuinfo_x86 *c)
{
- u32 lo, hi;
+ u64 msr;
/* Test for Extended Feature Flags presence */
if (cpuid_eax(0xC0000000) >= 0xC0000001) {
@@ -29,19 +29,17 @@ static void init_zhaoxin_cap(struct cpuinfo_x86 *c)
/* Enable ACE unit, if present and disabled */
if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
- rdmsr(MSR_ZHAOXIN_FCR57, lo, hi);
+ rdmsrq(MSR_ZHAOXIN_FCR57, msr);
/* Enable ACE unit */
- lo |= ACE_FCR;
- wrmsr(MSR_ZHAOXIN_FCR57, lo, hi);
+ wrmsrq(MSR_ZHAOXIN_FCR57, msr | ACE_FCR);
pr_info("CPU: Enabled ACE h/w crypto\n");
}
/* Enable RNG unit, if present and disabled */
if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
- rdmsr(MSR_ZHAOXIN_FCR57, lo, hi);
+ rdmsrq(MSR_ZHAOXIN_FCR57, msr);
/* Enable RNG unit */
- lo |= RNG_ENABLE;
- wrmsr(MSR_ZHAOXIN_FCR57, lo, hi);
+ wrmsrq(MSR_ZHAOXIN_FCR57, msr | RNG_ENABLE);
pr_info("CPU: Enabled h/w RNG\n");
}
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index 584fb9913be4..d1aeecd57f5e 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -294,15 +294,15 @@ void fpu_free_guest_fpstate(struct fpu_guest *gfpu)
}
EXPORT_SYMBOL_FOR_KVM(fpu_free_guest_fpstate);
-/*
- * fpu_enable_guest_xfd_features - Check xfeatures against guest perm and enable
- * @guest_fpu: Pointer to the guest FPU container
- * @xfeatures: Features requested by guest CPUID
- *
- * Enable all dynamic xfeatures according to guest perm and requested CPUID.
- *
- * Return: 0 on success, error code otherwise
- */
+/**
+ * fpu_enable_guest_xfd_features - Check xfeatures against guest perm and enable
+ * @guest_fpu: Pointer to the guest FPU container
+ * @xfeatures: Features requested by guest CPUID
+ *
+ * Enable all dynamic xfeatures according to guest perm and requested CPUID.
+ *
+ * Return: 0 on success, error code otherwise
+ */
int fpu_enable_guest_xfd_features(struct fpu_guest *guest_fpu, u64 xfeatures)
{
lockdep_assert_preemption_enabled();
@@ -874,7 +874,7 @@ void fpu_flush_thread(void)
*/
void switch_fpu_return(void)
{
- if (!static_cpu_has(X86_FEATURE_FPU))
+ if (!cpu_feature_enabled(X86_FEATURE_FPU))
return;
fpregs_restore_userregs();
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
index 20b638c507ca..33e1284bf3e4 100644
--- a/arch/x86/kernel/fpu/signal.c
+++ b/arch/x86/kernel/fpu/signal.c
@@ -187,7 +187,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size, u
ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
IS_ENABLED(CONFIG_IA32_EMULATION));
- if (!static_cpu_has(X86_FEATURE_FPU)) {
+ if (!cpu_feature_enabled(X86_FEATURE_FPU)) {
struct user_i387_ia32_struct fp;
fpregs_soft_get(current, NULL, (struct membuf){.p = &fp,
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index c1fac3a9fecc..4e5f8c1736ec 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -762,9 +762,6 @@ int arch_prepare_kprobe(struct kprobe *p)
{
int ret;
- if (alternatives_text_reserved(p->addr, p->addr))
- return -EINVAL;
-
if (!can_probe((unsigned long)p->addr))
return -EILSEQ;
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c
index 6f826a00eca2..3f8fea52619f 100644
--- a/arch/x86/kernel/kprobes/opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -77,7 +77,7 @@ found:
static void synthesize_clac(kprobe_opcode_t *addr)
{
/*
- * Can't be static_cpu_has() due to how objtool treats this feature bit.
+ * Can't be cpu_feature_enabled() due to how objtool treats this feature bit.
* This isn't a fast path anyway.
*/
if (!boot_cpu_has(X86_FEATURE_SMAP))
@@ -213,7 +213,6 @@ static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real)
}
/* Check whether the address range is reserved */
if (ftrace_text_reserved(src, src + len - 1) ||
- alternatives_text_reserved(src, src + len - 1) ||
jump_label_text_reserved(src, src + len - 1) ||
static_call_text_reserved(src, src + len - 1))
return -EBUSY;
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index dcef84da304b..5b554e480c0e 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -663,8 +663,10 @@ static void kvm_flush_tlb_multi(const struct cpumask *cpumask,
u8 state;
int cpu;
struct kvm_steal_time *src;
- struct cpumask *flushmask = this_cpu_cpumask_var_ptr(__pv_cpu_mask);
+ struct cpumask *flushmask;
+ guard(preempt)();
+ flushmask = this_cpu_cpumask_var_ptr(__pv_cpu_mask);
cpumask_copy(flushmask, cpumask);
/*
* We have to call flush only on online vCPUs. And
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index 40c5bf97dd5c..4fa7a86adece 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -61,7 +61,7 @@ void load_mm_ldt(struct mm_struct *mm)
*/
if (unlikely(ldt)) {
- if (static_cpu_has(X86_FEATURE_PTI)) {
+ if (cpu_feature_enabled(X86_FEATURE_PTI)) {
if (WARN_ON_ONCE((unsigned long)ldt->slot > 1)) {
/*
* Whoops -- either the new LDT isn't mapped
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index b5b4de4f08e6..33080ad889b7 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -227,7 +227,7 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- const Elf_Shdr *s, *alt = NULL, *locks = NULL,
+ const Elf_Shdr *s, *alt = NULL,
*orc = NULL, *orc_ip = NULL,
*retpolines = NULL, *returns = NULL, *ibt_endbr = NULL,
*calls = NULL, *cfi = NULL;
@@ -236,8 +236,6 @@ int module_finalize(const Elf_Ehdr *hdr,
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
if (!strcmp(".altinstructions", secstrings + s->sh_name))
alt = s;
- if (!strcmp(".smp_locks", secstrings + s->sh_name))
- locks = s;
if (!strcmp(".orc_unwind", secstrings + s->sh_name))
orc = s;
if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
@@ -300,14 +298,6 @@ int module_finalize(const Elf_Ehdr *hdr,
void *iseg = (void *)ibt_endbr->sh_addr;
apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size);
}
- if (locks) {
- void *lseg = (void *)locks->sh_addr;
- void *text = me->mem[MOD_TEXT].base;
- void *text_end = text + me->mem[MOD_TEXT].size;
- alternatives_smp_module_add(me, me->name,
- lseg, lseg + locks->sh_size,
- text, text_end);
- }
if (orc && orc_ip)
unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
@@ -318,6 +308,5 @@ int module_finalize(const Elf_Ehdr *hdr,
void module_arch_cleanup(struct module *mod)
{
- alternatives_smp_module_del(mod);
its_free_mod(mod);
}
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index 34bdb752f892..eb988df22521 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -13,6 +13,9 @@
* and then read/write in chunks of 8 bytes. A larger size means multiple
* reads or writes of the same register.
*
+ * Writing the same register multiple times can be useful for MSRs with
+ * I/O-like semantics, e.g. a virtual MSR that accepts logging information.
+ *
* This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
* an SMP box will direct the access to CPU %d.
*/
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 85435044e33c..346c438ac880 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -579,7 +579,7 @@ static __always_inline void amd_set_core_ssb_state(unsigned long tifn)
struct ssb_state *st = this_cpu_ptr(&ssb_state);
u64 msr = x86_amd_ls_cfg_base;
- if (!static_cpu_has(X86_FEATURE_ZEN)) {
+ if (!cpu_feature_enabled(X86_FEATURE_ZEN)) {
msr |= ssbd_tif_to_amd_ls_cfg(tifn);
wrmsrq(MSR_AMD64_LS_CFG, msr);
return;
@@ -646,14 +646,14 @@ static __always_inline void __speculation_ctrl_update(unsigned long tifp,
lockdep_assert_irqs_disabled();
/* Handle change of TIF_SSBD depending on the mitigation method. */
- if (static_cpu_has(X86_FEATURE_VIRT_SSBD)) {
+ if (cpu_feature_enabled(X86_FEATURE_VIRT_SSBD)) {
if (tif_diff & _TIF_SSBD)
amd_set_ssb_virt_state(tifn);
- } else if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) {
+ } else if (cpu_feature_enabled(X86_FEATURE_LS_CFG_SSBD)) {
if (tif_diff & _TIF_SSBD)
amd_set_core_ssb_state(tifn);
- } else if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
- static_cpu_has(X86_FEATURE_AMD_SSBD)) {
+ } else if (cpu_feature_enabled(X86_FEATURE_SPEC_CTRL_SSBD) ||
+ cpu_feature_enabled(X86_FEATURE_AMD_SSBD)) {
updmsr |= !!(tif_diff & _TIF_SSBD);
msr |= ssbd_tif_to_spec_ctrl(tifn);
}
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index d44afbe005bb..2bce7b3f97ed 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -277,7 +277,7 @@ static __always_inline void save_fsgs(struct task_struct *task)
{
savesegment(fs, task->thread.fsindex);
savesegment(gs, task->thread.gsindex);
- if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
+ if (cpu_feature_enabled(X86_FEATURE_FSGSBASE)) {
/*
* If FSGSBASE is enabled, we can't make any useful guesses
* about the base, and user code expects us to save the current
@@ -391,7 +391,7 @@ static __always_inline void x86_pkru_load(struct thread_struct *prev,
static __always_inline void x86_fsgsbase_load(struct thread_struct *prev,
struct thread_struct *next)
{
- if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
+ if (cpu_feature_enabled(X86_FEATURE_FSGSBASE)) {
/* Update the FS and GS selectors if they could have changed. */
if (unlikely(prev->fsindex || next->fsindex))
loadseg(FS, next->fsindex);
@@ -533,7 +533,7 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip,
{
WARN_ON_ONCE(regs != current_pt_regs());
- if (static_cpu_has(X86_BUG_NULL_SEG)) {
+ if (cpu_feature_enabled(X86_BUG_NULL_SEG)) {
/* Loading zero below won't clear the base. */
loadsegment(fs, __USER_DS);
load_gs_index(__USER_DS);
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index e55cf19e68fe..8e87ab586437 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -357,7 +357,7 @@ int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
unsafe_put_user(ptr_to_compat(&frame->uc), &frame->puc, Efault);
/* Create the ucontext. */
- if (static_cpu_has(X86_FEATURE_XSAVE))
+ if (cpu_feature_enabled(X86_FEATURE_XSAVE))
unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
else
unsafe_put_user(0, &frame->uc.uc_flags, Efault);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index cb999feb66b0..ba01a9e919b7 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -991,9 +991,6 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle)
{
int ret;
- /* Just in case we booted with a single CPU. */
- alternatives_enable_smp();
-
per_cpu(current_task, cpu) = idle;
cpu_init_stack_canary(cpu, idle);
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index 52e1f3f0b361..4061430ac74c 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -82,7 +82,7 @@ static __init void x86_late_time_init(void)
x86_init.irqs.intr_mode_init();
tsc_init();
- if (static_cpu_has(X86_FEATURE_WAITPKG))
+ if (cpu_feature_enabled(X86_FEATURE_WAITPKG))
use_tpause_delay();
}
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index ce10ae4b298b..723347e2cf7f 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -1221,11 +1221,11 @@ static void __init check_system_tsc_reliable(void)
if (is_geode_lx()) {
/* RTSC counts during suspend */
#define RTSC_SUSP 0x100
- unsigned long res_low, res_high;
+ u64 res;
- rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high);
+ rdmsrq_safe(MSR_GEODE_BUSCONT_CONF0, &res);
/* Geode_LX - the OLPC CPU has a very reliable TSC */
- if (res_low & RTSC_SUSP)
+ if (res & RTSC_SUSP)
tsc_clocksource_reliable = 1;
}
#endif
diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c
index 48e6cc1cb017..d74743c8d2a4 100644
--- a/arch/x86/kernel/tsc_msr.c
+++ b/arch/x86/kernel/tsc_msr.c
@@ -165,7 +165,8 @@ static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
*/
unsigned long cpu_khz_from_msr(void)
{
- u32 lo, hi, ratio, freq, tscref;
+ u32 ratio, freq, tscref;
+ struct msr val;
const struct freq_desc *freq_desc;
const struct x86_cpu_id *id;
const struct muldiv *md;
@@ -178,16 +179,16 @@ unsigned long cpu_khz_from_msr(void)
freq_desc = (struct freq_desc *)id->driver_data;
if (freq_desc->use_msr_plat) {
- rdmsr(MSR_PLATFORM_INFO, lo, hi);
- ratio = (lo >> 8) & 0xff;
+ rdmsrq(MSR_PLATFORM_INFO, val.q);
+ ratio = (val.l >> 8) & 0xff;
} else {
- rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
- ratio = (hi >> 8) & 0x1f;
+ rdmsrq(MSR_IA32_PERF_STATUS, val.q);
+ ratio = (val.h >> 8) & 0x1f;
}
/* Get FSB FREQ ID */
- rdmsr(MSR_FSB_FREQ, lo, hi);
- index = lo & freq_desc->mask;
+ rdmsrq(MSR_FSB_FREQ, val.q);
+ index = val.l & freq_desc->mask;
md = &freq_desc->muldiv[index];
/*
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 3af979fb41d3..65a2de82ecd2 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -276,15 +276,9 @@ static bool is_prefix_bad(struct insn *insn)
return false;
}
-static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool x86_64)
+static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn)
{
- enum insn_mode m = x86_64 ? INSN_MODE_64 : INSN_MODE_32;
u32 volatile *good_insns;
- int ret;
-
- ret = insn_decode(insn, auprobe->insn, sizeof(auprobe->insn), m);
- if (ret < 0)
- return -ENOEXEC;
if (is_prefix_bad(insn))
return -ENOTSUPP;
@@ -293,7 +287,7 @@ static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool
if (insn_masking_exception(insn))
return -ENOTSUPP;
- if (x86_64)
+ if (insn->x86_64)
good_insns = good_insns_64;
else
good_insns = good_insns_32;
@@ -631,14 +625,29 @@ static struct vm_special_mapping tramp_mapping = {
.pages = tramp_mapping_pages,
};
-struct uprobe_trampoline {
- struct hlist_node node;
- unsigned long vaddr;
-};
+
+#define LEA_INSN_SIZE 5
+#define OPT_INSN_SIZE (LEA_INSN_SIZE + CALL_INSN_SIZE)
+#define REDZONE_SIZE 0x80
+
+static const u8 lea_rsp[] = { 0x48, 0x8d, 0x64, 0x24, 0x80 };
+
+static bool is_opt_insns(const uprobe_opcode_t *insn)
+{
+ return !memcmp(insn, lea_rsp, LEA_INSN_SIZE) &&
+ insn[LEA_INSN_SIZE] == CALL_INSN_OPCODE;
+}
+
+static bool is_swbp_opt_insns(uprobe_opcode_t *insn)
+{
+ return is_swbp_insn(&insn[0]) &&
+ !memcmp(&insn[1], &lea_rsp[1], LEA_INSN_SIZE - 1) &&
+ insn[LEA_INSN_SIZE] == CALL_INSN_OPCODE;
+}
static bool is_reachable_by_call(unsigned long vtramp, unsigned long vaddr)
{
- long delta = (long)(vaddr + 5 - vtramp);
+ long delta = (long)(vaddr + OPT_INSN_SIZE - vtramp);
return delta >= INT_MIN && delta <= INT_MAX;
}
@@ -651,7 +660,7 @@ static unsigned long find_nearest_trampoline(unsigned long vaddr)
};
unsigned long low_limit, high_limit;
unsigned long low_tramp, high_tramp;
- unsigned long call_end = vaddr + 5;
+ unsigned long call_end = vaddr + OPT_INSN_SIZE;
if (check_add_overflow(call_end, INT_MIN, &low_limit))
low_limit = PAGE_SIZE;
@@ -682,83 +691,32 @@ static unsigned long find_nearest_trampoline(unsigned long vaddr)
return high_tramp;
}
-static struct uprobe_trampoline *create_uprobe_trampoline(unsigned long vaddr)
+static struct vm_area_struct *get_uprobe_trampoline(struct mm_struct *mm, unsigned long vaddr,
+ bool *new_mapping)
{
- struct pt_regs *regs = task_pt_regs(current);
- struct mm_struct *mm = current->mm;
- struct uprobe_trampoline *tramp;
+ VMA_ITERATOR(vmi, mm, 0);
struct vm_area_struct *vma;
- if (!user_64bit_mode(regs))
- return NULL;
-
- vaddr = find_nearest_trampoline(vaddr);
- if (IS_ERR_VALUE(vaddr))
- return NULL;
-
- tramp = kzalloc_obj(*tramp);
- if (unlikely(!tramp))
- return NULL;
-
- tramp->vaddr = vaddr;
- vma = _install_special_mapping(mm, tramp->vaddr, PAGE_SIZE,
- VM_READ|VM_EXEC|VM_MAYEXEC|VM_MAYREAD|VM_DONTCOPY|VM_IO,
- &tramp_mapping);
- if (IS_ERR(vma)) {
- kfree(tramp);
- return NULL;
- }
- return tramp;
-}
-
-static struct uprobe_trampoline *get_uprobe_trampoline(unsigned long vaddr, bool *new)
-{
- struct uprobes_state *state = &current->mm->uprobes_state;
- struct uprobe_trampoline *tramp = NULL;
+ *new_mapping = false;
if (vaddr > TASK_SIZE || vaddr < PAGE_SIZE)
- return NULL;
+ return ERR_PTR(-EINVAL);
- hlist_for_each_entry(tramp, &state->head_tramps, node) {
- if (is_reachable_by_call(tramp->vaddr, vaddr)) {
- *new = false;
- return tramp;
- }
+ for_each_vma(vmi, vma) {
+ if (!vma_is_special_mapping(vma, &tramp_mapping))
+ continue;
+ if (is_reachable_by_call(vma->vm_start, vaddr))
+ return vma;
}
- tramp = create_uprobe_trampoline(vaddr);
- if (!tramp)
- return NULL;
-
- *new = true;
- hlist_add_head(&tramp->node, &state->head_tramps);
- return tramp;
-}
-
-static void destroy_uprobe_trampoline(struct uprobe_trampoline *tramp)
-{
- /*
- * We do not unmap and release uprobe trampoline page itself,
- * because there's no easy way to make sure none of the threads
- * is still inside the trampoline.
- */
- hlist_del(&tramp->node);
- kfree(tramp);
-}
-
-void arch_uprobe_init_state(struct mm_struct *mm)
-{
- INIT_HLIST_HEAD(&mm->uprobes_state.head_tramps);
-}
-
-void arch_uprobe_clear_state(struct mm_struct *mm)
-{
- struct uprobes_state *state = &mm->uprobes_state;
- struct uprobe_trampoline *tramp;
- struct hlist_node *n;
+ vaddr = find_nearest_trampoline(vaddr);
+ if (IS_ERR_VALUE(vaddr))
+ return ERR_PTR(vaddr);
- hlist_for_each_entry_safe(tramp, n, &state->head_tramps, node)
- destroy_uprobe_trampoline(tramp);
+ *new_mapping = true;
+ return _install_special_mapping(mm, vaddr, PAGE_SIZE,
+ VM_READ|VM_EXEC|VM_MAYEXEC|VM_MAYREAD|VM_IO,
+ &tramp_mapping);
}
static bool __in_uprobe_trampoline(struct mm_struct *mm, unsigned long ip)
@@ -810,7 +768,7 @@ SYSCALL_DEFINE0(uprobe)
/* Allow execution only from uprobe trampolines. */
if (!in_uprobe_trampoline(regs->ip))
- return -ENXIO;
+ return -EPROTO;
err = copy_from_user(&args, (void __user *)regs->sp, sizeof(args));
if (err)
@@ -826,8 +784,8 @@ SYSCALL_DEFINE0(uprobe)
regs->ax = args.ax;
regs->r11 = args.r11;
regs->cx = args.cx;
- regs->ip = args.retaddr - 5;
- regs->sp += sizeof(args);
+ regs->ip = args.retaddr - OPT_INSN_SIZE;
+ regs->sp += sizeof(args) + REDZONE_SIZE;
regs->orig_ax = -1;
sp = regs->sp;
@@ -844,12 +802,12 @@ SYSCALL_DEFINE0(uprobe)
*/
if (regs->sp != sp) {
/* skip the trampoline call */
- if (args.retaddr - 5 == regs->ip)
- regs->ip += 5;
+ if (args.retaddr - OPT_INSN_SIZE == regs->ip)
+ regs->ip += OPT_INSN_SIZE;
return regs->ax;
}
- regs->sp -= sizeof(args);
+ regs->sp -= sizeof(args) + REDZONE_SIZE;
/* for the case uprobe_consumer has changed ax/r11/cx */
args.ax = regs->ax;
@@ -857,7 +815,7 @@ SYSCALL_DEFINE0(uprobe)
args.cx = regs->cx;
/* keep return address unless we are instructed otherwise */
- if (args.retaddr - 5 != regs->ip)
+ if (args.retaddr - OPT_INSN_SIZE != regs->ip)
args.retaddr = regs->ip;
if (shstk_push(args.retaddr) == -EFAULT)
@@ -891,7 +849,7 @@ asm (
"pop %rax\n"
"pop %r11\n"
"pop %rcx\n"
- "ret\n"
+ "ret $" __stringify(REDZONE_SIZE) "\n"
"int3\n"
".balign " __stringify(PAGE_SIZE) "\n"
".popsection\n"
@@ -909,7 +867,8 @@ late_initcall(arch_uprobes_init);
enum {
EXPECT_SWBP,
- EXPECT_CALL,
+ EXPECT_OPTIMIZED,
+ EXPECT_SWBP_OPTIMIZED,
};
struct write_opcode_ctx {
@@ -917,30 +876,29 @@ struct write_opcode_ctx {
int expect;
};
-static int is_call_insn(uprobe_opcode_t *insn)
-{
- return *insn == CALL_INSN_OPCODE;
-}
-
/*
- * Verification callback used by int3_update uprobe_write calls to make sure
- * the underlying instruction is as expected - either int3 or call.
+ * Verification callback used by uprobe_write calls to make sure the underlying
+ * instruction is in the expected stage of the INT3 update sequence.
*/
static int verify_insn(struct page *page, unsigned long vaddr, uprobe_opcode_t *new_opcode,
int nbytes, void *data)
{
struct write_opcode_ctx *ctx = data;
- uprobe_opcode_t old_opcode[5];
+ uprobe_opcode_t old_opcode[OPT_INSN_SIZE];
- uprobe_copy_from_page(page, ctx->base, (uprobe_opcode_t *) &old_opcode, 5);
+ uprobe_copy_from_page(page, ctx->base, old_opcode, OPT_INSN_SIZE);
switch (ctx->expect) {
case EXPECT_SWBP:
if (is_swbp_insn(&old_opcode[0]))
return 1;
break;
- case EXPECT_CALL:
- if (is_call_insn(&old_opcode[0]))
+ case EXPECT_OPTIMIZED:
+ if (is_opt_insns(&old_opcode[0]))
+ return 1;
+ break;
+ case EXPECT_SWBP_OPTIMIZED:
+ if (is_swbp_opt_insns(&old_opcode[0]))
return 1;
break;
}
@@ -949,48 +907,137 @@ static int verify_insn(struct page *page, unsigned long vaddr, uprobe_opcode_t *
}
/*
- * Modify multi-byte instructions by using INT3 breakpoints on SMP.
+ * Modify the optimized instruction by using INT3 breakpoints on SMP.
* We completely avoid using stop_machine() here, and achieve the
* synchronization using INT3 breakpoints and SMP cross-calls.
* (borrowed comment from smp_text_poke_batch_finish)
*
- * The way it is done:
- * - Add an INT3 trap to the address that will be patched
- * - SMP sync all CPUs
- * - Update all but the first byte of the patched range
- * - SMP sync all CPUs
- * - Replace the first byte (INT3) by the first byte of the replacing opcode
- * - SMP sync all CPUs
+ * For optimization (int3_update_optimize):
+ * 1) Start with the uprobe INT3 trap already installed
+ * 2) Update everything but the first byte
+ * 3) Replace the first INT3 by the first byte of the LEA instruction
+ *
+ * For unoptimization (int3_update_unoptimize):
+ * 1) Start with the optimized uprobe lea/call instructions
+ * 2) Add an INT3 trap to the address that will be patched
+ * 3) Restore the NOP bytes before the call opcode
+ * 4) Replace the first INT3 by the first byte of the NOP instruction
+ *
+ * Note that unoptimization deliberately keeps the call opcode and displacement
+ * in bytes 5..9. Those bytes become operands of the restored 10-byte NOP.
+ *
+ * Since there is only a single target uprobe-trampoline for the given nop10
+ * instruction address, the CALL instruction will not be changed across
+ * unoptimization/optimization cycles.
+ * Therefore, any task that is preempted at the CALL instruction is guaranteed
+ * to observe that CALL and not anything else.
*/
-static int int3_update(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
- unsigned long vaddr, char *insn, bool optimize)
+static int int3_update_optimize(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
+ unsigned long vaddr, uprobe_opcode_t *insn)
{
- uprobe_opcode_t int3 = UPROBE_SWBP_INSN;
struct write_opcode_ctx ctx = {
.base = vaddr,
};
int err;
/*
- * Write int3 trap.
+ * 1) Initial state after set_swbp() installed the uprobe:
+ * cc 2e 0f 1f 84 00 00 00 00 00
*
- * The swbp_optimize path comes with breakpoint already installed,
- * so we can skip this step for optimize == true.
+ * After a previous unoptimization bytes 5..9 may still contain the
+ * old call instruction, which remains valid for threads already there.
*/
- if (!optimize) {
- ctx.expect = EXPECT_CALL;
- err = uprobe_write(auprobe, vma, vaddr, &int3, 1, verify_insn,
- true /* is_register */, false /* do_update_ref_ctr */,
- &ctx);
- if (err)
- return err;
- }
+ smp_text_poke_sync_each_cpu();
+
+ /*
+ * 2) Rewrite the LEA tail and call displacement:
+ * cc [8d 64 24 80 e8 d0 d1 d2 d3]
+ */
+ ctx.expect = EXPECT_SWBP;
+ err = uprobe_write(auprobe, vma, vaddr + 1, insn + 1,
+ OPT_INSN_SIZE - 1, verify_insn,
+ true /* is_register */, false /* do_update_ref_ctr */,
+ &ctx);
+ if (err)
+ return err;
smp_text_poke_sync_each_cpu();
- /* Write all but the first byte of the patched range. */
+ /*
+ * 3) Publish the first LEA byte:
+ * [48] 8d 64 24 80 e8 d0 d1 d2 d3
+ *
+ * From offset 0 this is:
+ * lea -0x80(%rsp), %rsp
+ * call <uprobe-trampoline>
+ */
+ ctx.expect = EXPECT_SWBP_OPTIMIZED;
+ err = uprobe_write(auprobe, vma, vaddr, insn, 1, verify_insn,
+ true /* is_register */, false /* do_update_ref_ctr */,
+ &ctx);
+ if (err)
+ goto error;
+
+ smp_text_poke_sync_each_cpu();
+ return 0;
+
+error:
+ /*
+ * In all intermediate states byte 0 is INT3, so EXPECT_SWBP covers every
+ * case. Restore NOP bytes 1..4, but keep the valid CALL at bytes 5..9
+ * for a thread that had already executed the LEA before a previous
+ * unoptimization.
+ */
ctx.expect = EXPECT_SWBP;
- err = uprobe_write(auprobe, vma, vaddr + 1, insn + 1, 4, verify_insn,
+ uprobe_write(auprobe, vma, vaddr + 1, auprobe->insn + 1,
+ LEA_INSN_SIZE - 1, verify_insn, true, false, &ctx);
+ smp_text_poke_sync_each_cpu();
+ return err;
+}
+
+static int int3_update_unoptimize(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
+ unsigned long vaddr, uprobe_opcode_t *insn)
+{
+ uprobe_opcode_t int3 = UPROBE_SWBP_INSN;
+ struct write_opcode_ctx ctx = {
+ .base = vaddr,
+ .expect = EXPECT_OPTIMIZED,
+ };
+ int err;
+
+ /*
+ * Note the first two uprobe_write calls use is_register=true, because they
+ * are intermediate patching states while the probe is still active, so
+ * we force the exclusive anonymous page for the update.
+ * Also we use do_update_ref_ctr=false because refctr was already updated by
+ * the initial int3 install.
+ *
+ * The last uprobe_write to nop10 instruction is called with is_register=false
+ * and do_update_ref_ctr=true to trigger the refctr update and to instruct
+ * uprobe_write to zap the anonymous page if it now matches the file page.
+ *
+ * 1) Initial optimized state:
+ * 48 8d 64 24 80 e8 d0 d1 d2 d3
+ *
+ * 2) Trap new entries before restoring the NOP bytes:
+ * [cc] 8d 64 24 80 e8 d0 d1 d2 d3
+ */
+ err = uprobe_write(auprobe, vma, vaddr, &int3, 1, verify_insn,
+ true /* is_register */, false /* do_update_ref_ctr */,
+ &ctx);
+ if (err)
+ return err;
+
+ smp_text_poke_sync_each_cpu();
+
+ /*
+ * 3) Restore bytes 1..4 of the original NOP while keeping byte 0 trapped
+ * and byte 5 as CALL:
+ * cc [2e 0f 1f 84] e8 d0 d1 d2 d3
+ */
+ ctx.expect = EXPECT_SWBP_OPTIMIZED;
+ err = uprobe_write(auprobe, vma, vaddr + 1, insn + 1,
+ LEA_INSN_SIZE - 1, verify_insn,
true /* is_register */, false /* do_update_ref_ctr */,
&ctx);
if (err)
@@ -999,13 +1046,16 @@ static int int3_update(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
smp_text_poke_sync_each_cpu();
/*
- * Write first byte.
+ * 4) Publish the first byte of the original NOP:
+ * [66] 2e 0f 1f 84 e8 d0 d1 d2 d3
*
- * The swbp_unoptimize needs to finish uprobe removal together
- * with ref_ctr update, using uprobe_write with proper flags.
+ * From offset 0 this is the restored 10-byte NOP; the CALL opcode and
+ * displacement are now only NOP operands. Offset 5 still decodes as
+ * CALL for a thread that was already there.
*/
+ ctx.expect = EXPECT_SWBP;
err = uprobe_write(auprobe, vma, vaddr, insn, 1, verify_insn,
- optimize /* is_register */, !optimize /* do_update_ref_ctr */,
+ false /* is_register */, true /* do_update_ref_ctr */,
&ctx);
if (err)
return err;
@@ -1017,17 +1067,25 @@ static int int3_update(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
static int swbp_optimize(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
unsigned long vaddr, unsigned long tramp)
{
- u8 call[5];
+ u8 insn[OPT_INSN_SIZE], *call = &insn[LEA_INSN_SIZE];
- __text_gen_insn(call, CALL_INSN_OPCODE, (const void *) vaddr,
+ /*
+ * We have nop10 instruction (with first byte overwritten to int3),
+ * changing it to:
+ * lea -0x80(%rsp), %rsp
+ * call tramp
+ */
+ memcpy(insn, lea_rsp, LEA_INSN_SIZE);
+ __text_gen_insn(call, CALL_INSN_OPCODE,
+ (const void *) (vaddr + LEA_INSN_SIZE),
(const void *) tramp, CALL_INSN_SIZE);
- return int3_update(auprobe, vma, vaddr, call, true /* optimize */);
+ return int3_update_optimize(auprobe, vma, vaddr, insn);
}
static int swbp_unoptimize(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
unsigned long vaddr)
{
- return int3_update(auprobe, vma, vaddr, auprobe->insn, false /* optimize */);
+ return int3_update_unoptimize(auprobe, vma, vaddr, auprobe->insn);
}
static int copy_from_vaddr(struct mm_struct *mm, unsigned long vaddr, void *dst, int len)
@@ -1049,19 +1107,19 @@ static bool __is_optimized(struct mm_struct *mm, uprobe_opcode_t *insn, unsigned
struct __packed __arch_relative_insn {
u8 op;
s32 raddr;
- } *call = (struct __arch_relative_insn *) insn;
+ } *call = (struct __arch_relative_insn *)(insn + LEA_INSN_SIZE);
- if (!is_call_insn(insn))
+ if (!is_opt_insns(insn))
return false;
- return __in_uprobe_trampoline(mm, vaddr + 5 + call->raddr);
+ return __in_uprobe_trampoline(mm, vaddr + OPT_INSN_SIZE + call->raddr);
}
static int is_optimized(struct mm_struct *mm, unsigned long vaddr)
{
- uprobe_opcode_t insn[5];
+ uprobe_opcode_t insn[OPT_INSN_SIZE];
int err;
- err = copy_from_vaddr(mm, vaddr, &insn, 5);
+ err = copy_from_vaddr(mm, vaddr, &insn, OPT_INSN_SIZE);
if (err)
return err;
return __is_optimized(mm, (uprobe_opcode_t *)&insn, vaddr);
@@ -1111,27 +1169,29 @@ int set_orig_insn(struct arch_uprobe *auprobe, struct vm_area_struct *vma,
static int __arch_uprobe_optimize(struct arch_uprobe *auprobe, struct mm_struct *mm,
unsigned long vaddr)
{
- struct uprobe_trampoline *tramp;
- struct vm_area_struct *vma;
- bool new = false;
- int err = 0;
+ struct pt_regs *regs = task_pt_regs(current);
+ struct vm_area_struct *vma, *tramp;
+ bool new_mapping;
+ int ret;
+ if (!user_64bit_mode(regs))
+ return -EINVAL;
vma = find_vma(mm, vaddr);
if (!vma)
return -EINVAL;
- tramp = get_uprobe_trampoline(vaddr, &new);
- if (!tramp)
- return -EINVAL;
- err = swbp_optimize(auprobe, vma, vaddr, tramp->vaddr);
- if (WARN_ON_ONCE(err) && new)
- destroy_uprobe_trampoline(tramp);
- return err;
+ tramp = get_uprobe_trampoline(mm, vaddr, &new_mapping);
+ if (IS_ERR(tramp))
+ return PTR_ERR(tramp);
+ ret = swbp_optimize(auprobe, vma, vaddr, tramp->vm_start);
+ if (WARN_ON_ONCE(ret) && new_mapping)
+ WARN_ON_ONCE(do_munmap(mm, tramp->vm_start, PAGE_SIZE, NULL));
+ return ret;
}
void arch_uprobe_optimize(struct arch_uprobe *auprobe, unsigned long vaddr)
{
struct mm_struct *mm = current->mm;
- uprobe_opcode_t insn[5];
+ uprobe_opcode_t insn[OPT_INSN_SIZE];
if (!should_optimize(auprobe))
return;
@@ -1142,7 +1202,7 @@ void arch_uprobe_optimize(struct arch_uprobe *auprobe, unsigned long vaddr)
* Check if some other thread already optimized the uprobe for us,
* if it's the case just go away silently.
*/
- if (copy_from_vaddr(mm, vaddr, &insn, 5))
+ if (copy_from_vaddr(mm, vaddr, &insn, OPT_INSN_SIZE))
goto unlock;
if (!is_swbp_insn((uprobe_opcode_t*) &insn))
goto unlock;
@@ -1158,16 +1218,32 @@ unlock:
mmap_write_unlock(mm);
}
+static bool is_optimizable_nop10(struct insn *insn)
+{
+ static const u8 nop10_prefix[] = {
+ 0x66, 0x2e, 0x0f, 0x1f, 0x84
+ };
+
+ /*
+ * Restrict this to the 10-byte NOP form whose last 5 bytes are
+ * SIB/displacement operands. Unoptimization keeps the call opcode and
+ * displacement in those bytes, so other NOP encodings are not safe.
+ */
+ return insn->length == OPT_INSN_SIZE &&
+ insn_is_nop(insn) &&
+ !memcmp(insn->kaddr, nop10_prefix, ARRAY_SIZE(nop10_prefix));
+}
+
static bool can_optimize(struct insn *insn, unsigned long vaddr)
{
- if (!insn->x86_64 || insn->length != 5)
+ if (!insn->x86_64)
return false;
- if (!insn_is_nop(insn))
+ if (!is_optimizable_nop10(insn))
return false;
/* We can't do cross page atomic writes yet. */
- return PAGE_SIZE - (vaddr & ~PAGE_MASK) >= 5;
+ return PAGE_SIZE - (vaddr & ~PAGE_MASK) >= OPT_INSN_SIZE;
}
#else /* 32-bit: */
/*
@@ -1549,16 +1625,26 @@ static int push_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
*/
int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr)
{
+ enum insn_mode m = is_64bit_mm(mm) ? INSN_MODE_64 : INSN_MODE_32;
u8 fix_ip_or_call = UPROBE_FIX_IP;
struct insn insn;
int ret;
- ret = uprobe_init_insn(auprobe, &insn, is_64bit_mm(mm));
- if (ret)
- return ret;
+ ret = insn_decode(&insn, auprobe->insn, sizeof(auprobe->insn), m);
+ if (ret < 0)
+ return -ENOEXEC;
- if (can_optimize(&insn, addr))
+ /*
+ * No need to check instruction in uprobe_init_insn in case we
+ * are on top of optimizable nop10.
+ */
+ if (can_optimize(&insn, addr)) {
set_bit(ARCH_UPROBE_FLAG_CAN_OPTIMIZE, &auprobe->flags);
+ } else {
+ ret = uprobe_init_insn(auprobe, &insn);
+ if (ret)
+ return ret;
+ }
ret = branch_setup_xol_ops(auprobe, &insn);
if (ret != -ENOSYS)
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 74e336d7f9dd..2438b89a4620 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -65,9 +65,15 @@ const_cpu_current_top_of_stack = cpu_current_top_of_stack;
__end_rodata_hpage_align = .; \
__end_rodata_aligned = .;
+#if defined(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION) || defined(CONFIG_MITIGATION_SRSO)
#define ALIGN_ENTRY_TEXT_BEGIN . = ALIGN(PMD_SIZE);
#define ALIGN_ENTRY_TEXT_END . = ALIGN(PMD_SIZE);
#else
+#define ALIGN_ENTRY_TEXT_BEGIN
+#define ALIGN_ENTRY_TEXT_END
+#endif
+
+#else
#define X86_ALIGN_RODATA_BEGIN
#define X86_ALIGN_RODATA_END \
@@ -221,7 +227,7 @@ SECTIONS
* references to such code must be patched out by alternatives, normally
* by using X86_FEATURE_ALWAYS CPU feature bit.
*
- * See static_cpu_has() for an example.
+ * See cpu_feature_enabled() for an example.
*/
.altinstr_aux : AT(ADDR(.altinstr_aux) - LOAD_OFFSET) {
*(.altinstr_aux)
@@ -346,18 +352,6 @@ SECTIONS
__init_end = .;
}
- /*
- * smp_locks might be freed after init
- * start/end must be page aligned
- */
- . = ALIGN(PAGE_SIZE);
- .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
- __smp_locks = .;
- *(.smp_locks)
- . = ALIGN(PAGE_SIZE);
- __smp_locks_end = .;
- }
-
#ifdef CONFIG_X86_64
.data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
NOSAVE_DATA