Skip to content

Commit 3f33085

Browse files
marcanjannau
authored andcommitted
arm64: Implement PR_{GET,SET}_MEM_MODEL for always-TSO CPUs
Some ARM64 implementations are known to always use the TSO memory model. Add trivial support for the PR_{GET,SET}_MEM_MODEL prctl, which allows userspace to learn this fact. Known TSO implementations: - Nvidia Denver - Nvidia Carmel - Fujitsu A64FX Signed-off-by: Hector Martin <marcan@marcan.st> Reviewed-by: Neal Gompa <neal@gompa.dev>
1 parent e7f6647 commit 3f33085

7 files changed

Lines changed: 84 additions & 6 deletions

File tree

arch/arm64/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,15 @@ config ARM64_DEBUG_PRIORITY_MASKING
22072207
If unsure, say N
22082208
endif # ARM64_PSEUDO_NMI
22092209

2210+
config ARM64_MEMORY_MODEL_CONTROL
2211+
bool "Runtime memory model control"
2212+
help
2213+
Some ARM64 CPUs support runtime switching of the CPU memory
2214+
model, which can be useful to emulate other CPU architectures
2215+
which have different memory models. Say Y to enable support
2216+
for the PR_SET_MEM_MODEL/PR_GET_MEM_MODEL prctl() calls on
2217+
CPUs with this feature.
2218+
22102219
config RELOCATABLE
22112220
bool "Build a relocatable kernel image" if EXPERT
22122221
select ARCH_HAS_RELR

arch/arm64/include/asm/cpufeature.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,10 @@ static inline bool cpu_has_lpa2(void)
10321032
#endif
10331033
}
10341034

1035+
void __init init_cpucap_indirect_list_impdef(void);
1036+
void __init init_cpucap_indirect_list_from_array(const struct arm64_cpu_capabilities *caps);
1037+
bool cpufeature_matches(u64 reg, const struct arm64_cpu_capabilities *entry);
1038+
10351039
#endif /* __ASSEMBLY__ */
10361040

10371041
#endif

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)
@@ -3494,6 +3494,7 @@ void __init setup_boot_cpu_features(void)
34943494
* handle the boot CPU.
34953495
*/
34963496
init_cpucap_indirect_list();
3497+
init_cpucap_indirect_list_impdef();
34973498

34983499
/*
34993500
* Detect broken pseudo-NMI. Must be called _before_ the call to
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Contains implementation-defined CPU feature definitions.
4+
*/
5+
6+
#include <asm/cpufeature.h>
7+
8+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
9+
static bool has_tso_fixed(const struct arm64_cpu_capabilities *entry, int scope)
10+
{
11+
/* List of CPUs that always use the TSO memory model */
12+
static const struct midr_range fixed_tso_list[] = {
13+
MIDR_ALL_VERSIONS(MIDR_NVIDIA_DENVER),
14+
MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL),
15+
MIDR_ALL_VERSIONS(MIDR_FUJITSU_A64FX),
16+
{ /* sentinel */ }
17+
};
18+
19+
return is_midr_in_range_list(read_cpuid_id(), fixed_tso_list);
20+
}
21+
#endif
22+
23+
static const struct arm64_cpu_capabilities arm64_impdef_features[] = {
24+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
25+
{
26+
.desc = "TSO memory model (Fixed)",
27+
.capability = ARM64_HAS_TSO_FIXED,
28+
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
29+
.matches = has_tso_fixed,
30+
},
31+
#endif
32+
{},
33+
};
34+
35+
void __init init_cpucap_indirect_list_impdef(void)
36+
{
37+
init_cpucap_indirect_list_from_array(arm64_impdef_features);
38+
}

arch/arm64/kernel/process.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
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>
4647
#include <asm/compat.h>
@@ -513,6 +514,25 @@ void update_sctlr_el1(u64 sctlr)
513514
isb();
514515
}
515516

517+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
518+
int arch_prctl_mem_model_get(struct task_struct *t)
519+
{
520+
return PR_SET_MEM_MODEL_DEFAULT;
521+
}
522+
523+
int arch_prctl_mem_model_set(struct task_struct *t, unsigned long val)
524+
{
525+
if (alternative_has_cap_unlikely(ARM64_HAS_TSO_FIXED) &&
526+
val == PR_SET_MEM_MODEL_TSO)
527+
return 0;
528+
529+
if (val == PR_SET_MEM_MODEL_DEFAULT)
530+
return 0;
531+
532+
return -EINVAL;
533+
}
534+
#endif
535+
516536
/*
517537
* Thread switching.
518538
*/
@@ -651,6 +671,10 @@ void arch_setup_new_exec(void)
651671
arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
652672
PR_SPEC_ENABLE);
653673
}
674+
675+
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
676+
arch_prctl_mem_model_set(current, PR_SET_MEM_MODEL_DEFAULT);
677+
#endif
654678
}
655679

656680
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI

arch/arm64/tools/cpucaps

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ HAS_STAGE2_FWB
5252
HAS_TCR2
5353
HAS_TIDCP1
5454
HAS_TLB_RANGE
55+
HAS_TSO_FIXED
5556
HAS_VA52
5657
HAS_VIRT_HOST_EXTN
5758
HAS_WFXT

0 commit comments

Comments
 (0)