Skip to content

Commit 023c63e

Browse files
committed
Merge branch 'bits/220-tso' into asahi-wip
2 parents 69a27db + 1fcbc13 commit 023c63e

File tree

15 files changed

+339
-9
lines changed

15 files changed

+339
-9
lines changed

arch/arm64/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,9 @@ config KASAN_SHADOW_OFFSET
411411
config UNWIND_TABLES
412412
bool
413413

414+
config ARM64_ACTLR_STATE
415+
bool
416+
414417
source "arch/arm64/Kconfig.platforms"
415418

416419
menu "Kernel Features"
@@ -2206,6 +2209,17 @@ config ARM64_DEBUG_PRIORITY_MASKING
22062209
If unsure, say N
22072210
endif # ARM64_PSEUDO_NMI
22082211

2212+
config ARM64_MEMORY_MODEL_CONTROL
2213+
bool "Runtime memory model control"
2214+
default ARCH_APPLE
2215+
select ARM64_ACTLR_STATE
2216+
help
2217+
Some ARM64 CPUs support runtime switching of the CPU memory
2218+
model, which can be useful to emulate other CPU architectures
2219+
which have different memory models. Say Y to enable support
2220+
for the PR_SET_MEM_MODEL/PR_GET_MEM_MODEL prctl() calls on
2221+
CPUs with this feature.
2222+
22092223
config RELOCATABLE
22102224
bool "Build a relocatable kernel image" if EXPERT
22112225
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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
8080
{
8181
if (!vcpu_has_run_once(vcpu))
8282
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
83+
if (IS_ENABLED(CONFIG_ARM64_ACTLR_STATE) && (
84+
alternative_has_cap_unlikely(ARM64_HAS_ACTLR_VIRT) ||
85+
alternative_has_cap_unlikely(ARM64_HAS_ACTLR_VIRT_APPLE)
86+
))
87+
vcpu->arch.hcr_el2 &= ~HCR_TACR;
8388

8489
/*
8590
* For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C

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: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
10291029
extern const struct arm64_cpu_capabilities arm64_errata[];
10301030
static const struct arm64_cpu_capabilities arm64_features[];
10311031

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

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

1598-
return feature_matches(val, entry);
1598+
return cpufeature_matches(val, entry);
15991599
}
16001600

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

16081608
const struct cpumask *system_32bit_el0_cpumask(void)
@@ -3144,10 +3144,38 @@ static void update_cpu_capabilities(u16 scope_mask)
31443144

31453145
scope_mask &= ARM64_CPUCAP_SCOPE_MASK;
31463146
for (i = 0; i < ARM64_NCAPS; i++) {
3147+
bool matches;
3148+
31473149
caps = cpucap_ptrs[i];
3148-
if (!caps || !(caps->type & scope_mask) ||
3149-
cpus_have_cap(caps->capability) ||
3150-
!caps->matches(caps, cpucap_default_scope(caps)))
3150+
if (!caps || !(caps->type & scope_mask))
3151+
continue;
3152+
3153+
if (!(scope_mask & SCOPE_LOCAL_CPU) && cpus_have_cap(caps->capability))
3154+
continue;
3155+
3156+
matches = caps->matches(caps, cpucap_default_scope(caps));
3157+
3158+
if (matches == cpus_have_cap(caps->capability))
3159+
continue;
3160+
3161+
if (!matches) {
3162+
/*
3163+
* Cap detected on boot CPU but not this CPU,
3164+
* disable it if not optional.
3165+
*/
3166+
if (!cpucap_late_cpu_optional(caps)) {
3167+
__clear_bit(caps->capability, system_cpucaps);
3168+
pr_info("missing on secondary: %s\n", caps->desc);
3169+
}
3170+
continue;
3171+
}
3172+
3173+
if (!(scope_mask & (SCOPE_BOOT_CPU | SCOPE_SYSTEM)) &&
3174+
cpucap_late_cpu_permitted(caps))
3175+
/*
3176+
* Cap detected on this CPU but not boot CPU,
3177+
* skip it if permitted for late CPUs.
3178+
*/
31513179
continue;
31523180

31533181
if (caps->desc && !caps->cpus)
@@ -3495,6 +3523,7 @@ void __init setup_boot_cpu_features(void)
34953523
* handle the boot CPU.
34963524
*/
34973525
init_cpucap_indirect_list();
3526+
init_cpucap_indirect_list_impdef();
34983527

34993528
/*
35003529
* Detect broken pseudo-NMI. Must be called _before_ the call to
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Contains implementation-defined CPU feature definitions.
4+
*/
5+
6+
#define pr_fmt(fmt) "CPU features: " fmt
7+
8+
#include <asm/cpufeature.h>
9+
#include <asm/apple_cpufeature.h>
10+
#include <linux/irqflags.h>
11+
#include <linux/preempt.h>
12+
#include <linux/printk.h>
13+
14+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
15+
static bool has_apple_feature(const struct arm64_cpu_capabilities *entry, int scope)
16+
{
17+
u64 val;
18+
WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible());
19+
20+
if (read_cpuid_implementor() != ARM_CPU_IMP_APPLE)
21+
return false;
22+
23+
val = read_sysreg(aidr_el1);
24+
return cpufeature_matches(val, entry);
25+
}
26+
27+
static bool has_apple_tso(const struct arm64_cpu_capabilities *entry, int scope)
28+
{
29+
u64 val;
30+
31+
if (!has_apple_feature(entry, scope))
32+
return false;
33+
34+
/*
35+
* KVM and old versions of the macOS hypervisor will advertise TSO in
36+
* AIDR_EL1, but then ignore writes to ACTLR_EL1. Test that the bit is
37+
* actually writable before enabling TSO.
38+
*/
39+
40+
val = read_sysreg(actlr_el1);
41+
write_sysreg(val ^ ACTLR_APPLE_TSO, actlr_el1);
42+
if (!((val ^ read_sysreg(actlr_el1)) & ACTLR_APPLE_TSO)) {
43+
pr_info_once("CPU advertises Apple TSO but it is broken, ignoring\n");
44+
return false;
45+
}
46+
47+
write_sysreg(val, actlr_el1);
48+
return true;
49+
}
50+
51+
static bool has_tso_fixed(const struct arm64_cpu_capabilities *entry, int scope)
52+
{
53+
/* List of CPUs that always use the TSO memory model */
54+
static const struct midr_range fixed_tso_list[] = {
55+
MIDR_ALL_VERSIONS(MIDR_NVIDIA_DENVER),
56+
MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL),
57+
MIDR_ALL_VERSIONS(MIDR_FUJITSU_A64FX),
58+
{ /* sentinel */ }
59+
};
60+
61+
return is_midr_in_range_list(read_cpuid_id(), fixed_tso_list);
62+
}
63+
#endif
64+
65+
static bool has_apple_actlr_virt_impdef(const struct arm64_cpu_capabilities *entry, int scope)
66+
{
67+
u64 midr = read_cpuid_id() & MIDR_CPU_MODEL_MASK;
68+
69+
return midr >= MIDR_APPLE_M1_ICESTORM && midr <= MIDR_APPLE_M1_FIRESTORM_MAX;
70+
}
71+
72+
static bool has_apple_actlr_virt(const struct arm64_cpu_capabilities *entry, int scope)
73+
{
74+
u64 midr = read_cpuid_id() & MIDR_CPU_MODEL_MASK;
75+
76+
return midr >= MIDR_APPLE_M2_BLIZZARD && midr <= MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, 0xfff);
77+
}
78+
79+
static const struct arm64_cpu_capabilities arm64_impdef_features[] = {
80+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
81+
{
82+
.desc = "TSO memory model (Apple)",
83+
.capability = ARM64_HAS_TSO_APPLE,
84+
.type = SCOPE_LOCAL_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU,
85+
.matches = has_apple_tso,
86+
.field_pos = AIDR_APPLE_TSO_SHIFT,
87+
.field_width = 1,
88+
.sign = FTR_UNSIGNED,
89+
.min_field_value = 1,
90+
.max_field_value = 1,
91+
},
92+
{
93+
.desc = "TSO memory model (Fixed)",
94+
.capability = ARM64_HAS_TSO_FIXED,
95+
.type = SCOPE_LOCAL_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU,
96+
.matches = has_tso_fixed,
97+
},
98+
#endif
99+
{
100+
.desc = "ACTLR virtualization (IMPDEF, Apple)",
101+
.capability = ARM64_HAS_ACTLR_VIRT_APPLE,
102+
.type = SCOPE_LOCAL_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU,
103+
.matches = has_apple_actlr_virt_impdef,
104+
},
105+
{
106+
.desc = "ACTLR virtualization (architectural?)",
107+
.capability = ARM64_HAS_ACTLR_VIRT,
108+
.type = SCOPE_LOCAL_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU,
109+
.matches = has_apple_actlr_virt,
110+
},
111+
{},
112+
};
113+
114+
void __init init_cpucap_indirect_list_impdef(void)
115+
{
116+
init_cpucap_indirect_list_from_array(arm64_impdef_features);
117+
}

0 commit comments

Comments
 (0)