mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
x86/alternative: Drop smp_locks glue
This was there to be able to patch out locking instructions when running a SMP kernel build on a UP CPU. The times are long gone when single-CPU x86 machines were relevant so drop that machinery and simplify the code considerably. LOCK_PREFIX needs to stay for when one wants to do a UP build for whatever reason. That'll go away when CONFIG_SMP becomes unconditional. Kill a bunch of leftover, unused prototypes while at it. Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Link: https://lore.kernel.org/r/20260328081634.797552-1-rppt@kernel.org
This commit is contained in:
@@ -4587,9 +4587,6 @@ Kernel parameters
|
||||
norandmaps Don't use address space randomization. Equivalent to
|
||||
echo 0 > /proc/sys/kernel/randomize_va_space
|
||||
|
||||
noreplace-smp [X86-32,SMP] Don't replace SMP instructions
|
||||
with UP alternatives
|
||||
|
||||
noresume [SWSUSP] Disables resume and restores original swap
|
||||
space.
|
||||
|
||||
|
||||
@@ -451,18 +451,6 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
|
||||
{
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SMP)
|
||||
void alternatives_smp_module_add(struct module *mod, char *name,
|
||||
void *locks, void *locks_end,
|
||||
void *text, void *text_end)
|
||||
{
|
||||
}
|
||||
|
||||
void alternatives_smp_module_del(struct module *mod)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void *text_poke(void *addr, const void *opcode, size_t len)
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -20,39 +20,9 @@
|
||||
|
||||
#include <linux/stddef.h>
|
||||
|
||||
/*
|
||||
* Alternative inline assembly for SMP.
|
||||
*
|
||||
* The LOCK_PREFIX macro defined here replaces the LOCK and
|
||||
* LOCK_PREFIX macros used everywhere in the source tree.
|
||||
*
|
||||
* SMP alternatives use the same data structures as the other
|
||||
* alternatives and the X86_FEATURE_UP flag to indicate the case of a
|
||||
* UP system running a SMP kernel. The existing apply_alternatives()
|
||||
* works fine for patching a SMP kernel for UP.
|
||||
*
|
||||
* The SMP alternative tables can be kept after boot and contain both
|
||||
* UP and SMP versions of the instructions to allow switching back to
|
||||
* SMP at runtime, when hotplugging in a new CPU, which is especially
|
||||
* useful in virtualized environments.
|
||||
*
|
||||
* The very common lock prefix is handled as special case in a
|
||||
* separate table which is a pure address list without replacement ptr
|
||||
* and size information. That keeps the table sizes small.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#define LOCK_PREFIX_HERE \
|
||||
".pushsection .smp_locks,\"a\"\n" \
|
||||
".balign 4\n" \
|
||||
".long 671f - .\n" /* offset */ \
|
||||
".popsection\n" \
|
||||
"671:"
|
||||
|
||||
#define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock "
|
||||
|
||||
#else /* ! CONFIG_SMP */
|
||||
#define LOCK_PREFIX_HERE ""
|
||||
#define LOCK_PREFIX "lock "
|
||||
#else
|
||||
#define LOCK_PREFIX ""
|
||||
#endif
|
||||
|
||||
@@ -87,7 +57,6 @@ extern s32 __retpoline_sites[], __retpoline_sites_end[];
|
||||
extern s32 __return_sites[], __return_sites_end[];
|
||||
extern s32 __cfi_sites[], __cfi_sites_end[];
|
||||
extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[];
|
||||
extern s32 __smp_locks[], __smp_locks_end[];
|
||||
|
||||
/*
|
||||
* Debug flag that can be tested to see whether alternative
|
||||
@@ -162,26 +131,6 @@ static __always_inline bool cpu_wants_rethunk_at(void *addr)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern void alternatives_smp_module_add(struct module *mod, char *name,
|
||||
void *locks, void *locks_end,
|
||||
void *text, void *text_end);
|
||||
extern void alternatives_smp_module_del(struct module *mod);
|
||||
extern void alternatives_enable_smp(void);
|
||||
extern int alternatives_text_reserved(void *start, void *end);
|
||||
extern bool skip_smp_alternatives;
|
||||
#else
|
||||
static inline void alternatives_smp_module_add(struct module *mod, char *name,
|
||||
void *locks, void *locks_end,
|
||||
void *text, void *text_end) {}
|
||||
static inline void alternatives_smp_module_del(struct module *mod) {}
|
||||
static inline void alternatives_enable_smp(void) {}
|
||||
static inline int alternatives_text_reserved(void *start, void *end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
#define ALT_CALL_INSTR "call BUG_func"
|
||||
|
||||
#define alt_slen "772b-771b"
|
||||
@@ -319,18 +268,11 @@ void nop_func(void);
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
|
||||
.macro LOCK_PREFIX
|
||||
#ifdef CONFIG_SMP
|
||||
.macro LOCK_PREFIX
|
||||
672: lock
|
||||
.pushsection .smp_locks,"a"
|
||||
.balign 4
|
||||
.long 672b - .
|
||||
.popsection
|
||||
.endm
|
||||
#else
|
||||
.macro LOCK_PREFIX
|
||||
.endm
|
||||
lock
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Issue one struct alt_instr descriptor entry (need to put it into
|
||||
|
||||
@@ -104,7 +104,7 @@ static __always_inline bool __try_cmpxchg64_local(volatile u64 *ptr, u64 *oldp,
|
||||
|
||||
static __always_inline u64 arch_cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
|
||||
{
|
||||
return __arch_cmpxchg64_emu(ptr, old, new, LOCK_PREFIX_HERE, "lock ");
|
||||
return __arch_cmpxchg64_emu(ptr, old, new, , "lock ");
|
||||
}
|
||||
#define arch_cmpxchg64 arch_cmpxchg64
|
||||
|
||||
@@ -138,7 +138,7 @@ static __always_inline u64 arch_cmpxchg64_local(volatile u64 *ptr, u64 old, u64
|
||||
|
||||
static __always_inline bool arch_try_cmpxchg64(volatile u64 *ptr, u64 *oldp, u64 new)
|
||||
{
|
||||
return __arch_try_cmpxchg64_emu(ptr, oldp, new, LOCK_PREFIX_HERE, "lock ");
|
||||
return __arch_try_cmpxchg64_emu(ptr, oldp, new, , "lock ");
|
||||
}
|
||||
#define arch_try_cmpxchg64 arch_try_cmpxchg64
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
#define X86_FEATURE_ZEN6 ( 3*32+ 6) /* CPU based on Zen6 microarchitecture */
|
||||
/* Free ( 3*32+ 7) */
|
||||
#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* "constant_tsc" TSC ticks at a constant rate */
|
||||
#define X86_FEATURE_UP ( 3*32+ 9) /* "up" SMP kernel running on UP */
|
||||
/* free: was #define X86_FEATURE_UP ( 3*32+ 9) * "up" SMP kernel running on UP */
|
||||
#define X86_FEATURE_ART ( 3*32+10) /* "art" Always running timer (ART) */
|
||||
#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* "arch_perfmon" Intel Architectural PerfMon */
|
||||
#define X86_FEATURE_PEBS ( 3*32+12) /* "pebs" Precise-Event Based Sampling */
|
||||
|
||||
@@ -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) \
|
||||
@@ -2109,159 +2100,6 @@ void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
|
||||
/* .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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -346,18 +346,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
|
||||
|
||||
@@ -73,7 +73,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
|
||||
"^(__init_(begin|end)|"
|
||||
"__x86_cpu_dev_(start|end)|"
|
||||
"__alt_instructions(_end)?|"
|
||||
"(__iommu_table|__apicdrivers|__smp_locks)(_end)?|"
|
||||
"(__iommu_table|__apicdrivers)(_end)?|"
|
||||
"__(start|end)_pci_.*|"
|
||||
#if CONFIG_FW_LOADER
|
||||
"__(start|end)_builtin_fw|"
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
#define X86_FEATURE_ZEN6 ( 3*32+ 6) /* CPU based on Zen6 microarchitecture */
|
||||
/* Free ( 3*32+ 7) */
|
||||
#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* "constant_tsc" TSC ticks at a constant rate */
|
||||
#define X86_FEATURE_UP ( 3*32+ 9) /* "up" SMP kernel running on UP */
|
||||
/* free: was #define X86_FEATURE_UP ( 3*32+ 9) * "up" SMP kernel running on UP */
|
||||
#define X86_FEATURE_ART ( 3*32+10) /* "art" Always running timer (ART) */
|
||||
#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* "arch_perfmon" Intel Architectural PerfMon */
|
||||
#define X86_FEATURE_PEBS ( 3*32+12) /* "pebs" Precise-Event Based Sampling */
|
||||
|
||||
@@ -4644,7 +4644,6 @@ static int validate_ibt(struct objtool_file *file)
|
||||
!strcmp(sec->name, ".kcfi_traps") ||
|
||||
!strcmp(sec->name, ".orc_unwind_ip") ||
|
||||
!strcmp(sec->name, ".retpoline_sites") ||
|
||||
!strcmp(sec->name, ".smp_locks") ||
|
||||
!strcmp(sec->name, ".static_call_sites") ||
|
||||
!strcmp(sec->name, "_error_injection_whitelist") ||
|
||||
!strcmp(sec->name, "_kprobe_blacklist") ||
|
||||
|
||||
@@ -297,7 +297,6 @@ static bool is_special_section(struct section *sec)
|
||||
static const char * const specials[] = {
|
||||
".altinstructions",
|
||||
".kcfi_traps",
|
||||
".smp_locks",
|
||||
"__bug_table",
|
||||
"__ex_table",
|
||||
"__jump_table",
|
||||
|
||||
Reference in New Issue
Block a user