Skip to content

Commit 59379bb

Browse files
committed
Merge branch 'bits/220-tso' into asahi-wip
2 parents 87c3e89 + 54feb6c commit 59379bb

File tree

15 files changed

+241
-6
lines changed

15 files changed

+241
-6
lines changed

arch/arm64/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,9 @@ config KASAN_SHADOW_OFFSET
408408
config UNWIND_TABLES
409409
bool
410410

411+
config ARM64_ACTLR_STATE
412+
bool
413+
411414
source "arch/arm64/Kconfig.platforms"
412415

413416
menu "Kernel Features"
@@ -2162,6 +2165,17 @@ config ARM64_DEBUG_PRIORITY_MASKING
21622165
If unsure, say N
21632166
endif # ARM64_PSEUDO_NMI
21642167

2168+
config ARM64_MEMORY_MODEL_CONTROL
2169+
bool "Runtime memory model control"
2170+
default ARCH_APPLE
2171+
select ARM64_ACTLR_STATE
2172+
help
2173+
Some ARM64 CPUs support runtime switching of the CPU memory
2174+
model, which can be useful to emulate other CPU architectures
2175+
which have different memory models. Say Y to enable support
2176+
for the PR_SET_MEM_MODEL/PR_GET_MEM_MODEL prctl() calls on
2177+
CPUs with this feature.
2178+
21652179
config RELOCATABLE
21662180
bool "Build a relocatable kernel image" if EXPERT
21672181
select ARCH_HAS_RELR
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#ifndef __ASM_APPLE_CPUFEATURES_H
4+
#define __ASM_APPLE_CPUFEATURES_H
5+
6+
#include <linux/bits.h>
7+
#include <asm/sysreg.h>
8+
9+
#define AIDR_APPLE_TSO_SHIFT 9
10+
#define AIDR_APPLE_TSO BIT(9)
11+
12+
#define ACTLR_APPLE_TSO_SHIFT 1
13+
#define ACTLR_APPLE_TSO BIT(1)
14+
15+
#endif

arch/arm64/include/asm/cpufeature.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,12 @@ static inline unsigned int get_vmid_bits(u64 mmfr1)
909909
return 8;
910910
}
911911

912+
static __always_inline bool system_has_actlr_state(void)
913+
{
914+
return IS_ENABLED(CONFIG_ARM64_ACTLR_STATE) &&
915+
alternative_has_cap_unlikely(ARM64_HAS_TSO_APPLE);
916+
}
917+
912918
s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new, s64 cur);
913919
struct arm64_ftr_reg *get_arm64_ftr_reg(u32 sys_id);
914920

@@ -1032,6 +1038,10 @@ static inline bool cpu_has_lpa2(void)
10321038
#endif
10331039
}
10341040

1041+
void __init init_cpucap_indirect_list_impdef(void);
1042+
void __init init_cpucap_indirect_list_from_array(const struct arm64_cpu_capabilities *caps);
1043+
bool cpufeature_matches(u64 reg, const struct arm64_cpu_capabilities *entry);
1044+
10351045
#endif /* __ASSEMBLY__ */
10361046

10371047
#endif

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
7272
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
7373
if (has_vhe() || has_hvhe())
7474
vcpu->arch.hcr_el2 |= HCR_E2H;
75+
if (IS_ENABLED(CONFIG_ARM64_ACTLR_STATE) &&
76+
alternative_has_cap_unlikely(ARM64_HAS_TSO_APPLE))
77+
vcpu->arch.hcr_el2 &= ~HCR_TACR;
7578
if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN)) {
7679
/* route synchronous external abort exceptions to EL2 */
7780
vcpu->arch.hcr_el2 |= HCR_TEA;

arch/arm64/include/asm/processor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ struct thread_struct {
184184
u64 sctlr_user;
185185
u64 svcr;
186186
u64 tpidr2_el0;
187+
#ifdef CONFIG_ARM64_ACTLR_STATE
188+
u64 actlr;
189+
#endif
187190
};
188191

189192
static inline unsigned int thread_get_vl(struct thread_struct *thread,

arch/arm64/kernel/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
3333
return_address.o cpuinfo.o cpu_errata.o \
3434
cpufeature.o alternative.o cacheinfo.o \
3535
smp.o smp_spin_table.o topology.o smccc-call.o \
36-
syscall.o proton-pack.o idle.o patching.o pi/
36+
syscall.o proton-pack.o idle.o patching.o \
37+
cpufeature_impdef.o pi/
3738

3839
obj-$(CONFIG_COMPAT) += sys32.o signal32.o \
3940
sys_compat.o

arch/arm64/kernel/cpufeature.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
10281028
extern const struct arm64_cpu_capabilities arm64_errata[];
10291029
static const struct arm64_cpu_capabilities arm64_features[];
10301030

1031-
static void __init
1031+
void __init
10321032
init_cpucap_indirect_list_from_array(const struct arm64_cpu_capabilities *caps)
10331033
{
10341034
for (; caps->matches; caps++) {
@@ -1540,8 +1540,8 @@ has_always(const struct arm64_cpu_capabilities *entry, int scope)
15401540
return true;
15411541
}
15421542

1543-
static bool
1544-
feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
1543+
bool
1544+
cpufeature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
15451545
{
15461546
int val, min, max;
15471547
u64 tmp;
@@ -1594,14 +1594,14 @@ has_user_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
15941594
if (!mask)
15951595
return false;
15961596

1597-
return feature_matches(val, entry);
1597+
return cpufeature_matches(val, entry);
15981598
}
15991599

16001600
static bool
16011601
has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
16021602
{
16031603
u64 val = read_scoped_sysreg(entry, scope);
1604-
return feature_matches(val, entry);
1604+
return cpufeature_matches(val, entry);
16051605
}
16061606

16071607
const struct cpumask *system_32bit_el0_cpumask(void)
@@ -3486,6 +3486,7 @@ void __init setup_boot_cpu_features(void)
34863486
* handle the boot CPU.
34873487
*/
34883488
init_cpucap_indirect_list();
3489+
init_cpucap_indirect_list_impdef();
34893490

34903491
/*
34913492
* Detect broken pseudo-NMI. Must be called _before_ the call to
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Contains implementation-defined CPU feature definitions.
4+
*/
5+
6+
#include <asm/cpufeature.h>
7+
#include <asm/apple_cpufeature.h>
8+
9+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
10+
static bool has_apple_feature(const struct arm64_cpu_capabilities *entry, int scope)
11+
{
12+
u64 val;
13+
WARN_ON(scope != SCOPE_SYSTEM);
14+
15+
if (read_cpuid_implementor() != ARM_CPU_IMP_APPLE)
16+
return false;
17+
18+
val = read_sysreg(aidr_el1);
19+
return cpufeature_matches(val, entry);
20+
}
21+
22+
static bool has_tso_fixed(const struct arm64_cpu_capabilities *entry, int scope)
23+
{
24+
/* List of CPUs that always use the TSO memory model */
25+
static const struct midr_range fixed_tso_list[] = {
26+
MIDR_ALL_VERSIONS(MIDR_NVIDIA_DENVER),
27+
MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL),
28+
MIDR_ALL_VERSIONS(MIDR_FUJITSU_A64FX),
29+
{ /* sentinel */ }
30+
};
31+
32+
return is_midr_in_range_list(read_cpuid_id(), fixed_tso_list);
33+
}
34+
#endif
35+
36+
static const struct arm64_cpu_capabilities arm64_impdef_features[] = {
37+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
38+
{
39+
.desc = "TSO memory model (Apple)",
40+
.capability = ARM64_HAS_TSO_APPLE,
41+
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
42+
.matches = has_apple_feature,
43+
.field_pos = AIDR_APPLE_TSO_SHIFT,
44+
.field_width = 1,
45+
.sign = FTR_UNSIGNED,
46+
.min_field_value = 1,
47+
},
48+
{
49+
.desc = "TSO memory model (Fixed)",
50+
.capability = ARM64_HAS_TSO_FIXED,
51+
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
52+
.matches = has_tso_fixed,
53+
},
54+
#endif
55+
{},
56+
};
57+
58+
void __init init_cpucap_indirect_list_impdef(void)
59+
{
60+
init_cpucap_indirect_list_from_array(arm64_impdef_features);
61+
}

arch/arm64/kernel/process.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
#include <linux/thread_info.h>
4242
#include <linux/prctl.h>
4343
#include <linux/stacktrace.h>
44+
#include <linux/memory_ordering_model.h>
4445

4546
#include <asm/alternative.h>
47+
#include <asm/apple_cpufeature.h>
4648
#include <asm/compat.h>
4749
#include <asm/cpufeature.h>
4850
#include <asm/cacheflush.h>
@@ -371,6 +373,11 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
371373
if (system_supports_tpidr2())
372374
p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
373375

376+
#ifdef CONFIG_ARM64_ACTLR_STATE
377+
if (system_has_actlr_state())
378+
p->thread.actlr = read_sysreg(actlr_el1);
379+
#endif
380+
374381
if (stack_start) {
375382
if (is_compat_thread(task_thread_info(p)))
376383
childregs->compat_sp = stack_start;
@@ -513,6 +520,65 @@ void update_sctlr_el1(u64 sctlr)
513520
isb();
514521
}
515522

523+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
524+
int arch_prctl_mem_model_get(struct task_struct *t)
525+
{
526+
if (alternative_has_cap_unlikely(ARM64_HAS_TSO_APPLE) &&
527+
t->thread.actlr & ACTLR_APPLE_TSO)
528+
return PR_SET_MEM_MODEL_TSO;
529+
530+
return PR_SET_MEM_MODEL_DEFAULT;
531+
}
532+
533+
int arch_prctl_mem_model_set(struct task_struct *t, unsigned long val)
534+
{
535+
if (alternative_has_cap_unlikely(ARM64_HAS_TSO_FIXED) &&
536+
val == PR_SET_MEM_MODEL_TSO)
537+
return 0;
538+
539+
if (alternative_has_cap_unlikely(ARM64_HAS_TSO_APPLE)) {
540+
WARN_ON(!system_has_actlr_state());
541+
542+
switch (val) {
543+
case PR_SET_MEM_MODEL_TSO:
544+
t->thread.actlr |= ACTLR_APPLE_TSO;
545+
break;
546+
case PR_SET_MEM_MODEL_DEFAULT:
547+
t->thread.actlr &= ~ACTLR_APPLE_TSO;
548+
break;
549+
default:
550+
return -EINVAL;
551+
}
552+
write_sysreg(t->thread.actlr, actlr_el1);
553+
return 0;
554+
}
555+
556+
if (val == PR_SET_MEM_MODEL_DEFAULT)
557+
return 0;
558+
559+
return -EINVAL;
560+
}
561+
#endif
562+
563+
#ifdef CONFIG_ARM64_ACTLR_STATE
564+
/*
565+
* IMPDEF control register ACTLR_EL1 handling. Some CPUs use this to
566+
* expose features that can be controlled by userspace.
567+
*/
568+
static void actlr_thread_switch(struct task_struct *next)
569+
{
570+
if (!system_has_actlr_state())
571+
return;
572+
573+
current->thread.actlr = read_sysreg(actlr_el1);
574+
write_sysreg(next->thread.actlr, actlr_el1);
575+
}
576+
#else
577+
static inline void actlr_thread_switch(struct task_struct *next)
578+
{
579+
}
580+
#endif
581+
516582
/*
517583
* Thread switching.
518584
*/
@@ -530,6 +596,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
530596
ssbs_thread_switch(next);
531597
erratum_1418040_thread_switch(next);
532598
ptrauth_thread_switch_user(next);
599+
actlr_thread_switch(next);
533600

534601
/*
535602
* Complete any pending TLB or cache maintenance on this CPU in case
@@ -651,6 +718,10 @@ void arch_setup_new_exec(void)
651718
arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
652719
PR_SPEC_ENABLE);
653720
}
721+
722+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
723+
arch_prctl_mem_model_set(current, PR_SET_MEM_MODEL_DEFAULT);
724+
#endif
654725
}
655726

656727
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI

arch/arm64/kernel/setup.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,14 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
359359
*/
360360
init_task.thread_info.ttbr0 = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
361361
#endif
362+
#ifdef CONFIG_ARM64_ACTLR_STATE
363+
/* Store the boot CPU ACTLR_EL1 value as the default. This will only
364+
* be actually restored during context switching iff the platform is
365+
* known to use ACTLR_EL1 for exposable features and its layout is
366+
* known to be the same on all CPUs.
367+
*/
368+
init_task.thread.actlr = read_sysreg(actlr_el1);
369+
#endif
362370

363371
if (boot_args[1] || boot_args[2] || boot_args[3]) {
364372
pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n"

0 commit comments

Comments
 (0)