Skip to content

Commit

Permalink
Merge branch 'refs/heads/bits/220-tso' into asahi-wip
Browse files Browse the repository at this point in the history
  • Loading branch information
marcan committed Jun 17, 2023
2 parents 70aab69 + 38015ad commit b5c05cb
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 3 deletions.
14 changes: 14 additions & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,9 @@ config KASAN_SHADOW_OFFSET
config UNWIND_TABLES
bool

config ARM64_ACTLR_STATE
bool

source "arch/arm64/Kconfig.platforms"

menu "Kernel Features"
Expand Down Expand Up @@ -2128,6 +2131,17 @@ config ARM64_DEBUG_PRIORITY_MASKING
If unsure, say N
endif # ARM64_PSEUDO_NMI

config ARM64_MEMORY_MODEL_CONTROL
bool "Runtime memory model control"
default ARCH_APPLE
select ARM64_ACTLR_STATE
help
Some ARM64 CPUs support runtime switching of the CPU memory
model, which can be useful to emulate other CPU architectures
which have different memory models. Say Y to enable support
for the PR_SET_MEM_MODEL/PR_GET_MEM_MODEL prctl() calls on
CPUs with this feature.

config RELOCATABLE
bool "Build a relocatable kernel image" if EXPERT
select ARCH_HAS_RELR
Expand Down
15 changes: 15 additions & 0 deletions arch/arm64/include/asm/apple_cpufeature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0

#ifndef __ASM_APPLE_CPUFEATURES_H
#define __ASM_APPLE_CPUFEATURES_H

#include <linux/bits.h>
#include <asm/sysreg.h>

#define AIDR_APPLE_TSO_SHIFT 9
#define AIDR_APPLE_TSO BIT(9)

#define ACTLR_APPLE_TSO_SHIFT 1
#define ACTLR_APPLE_TSO BIT(1)

#endif
6 changes: 6 additions & 0 deletions arch/arm64/include/asm/cpufeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,12 @@ static inline unsigned int get_vmid_bits(u64 mmfr1)
return 8;
}

static __always_inline bool system_has_actlr_state(void)
{
return IS_ENABLED(CONFIG_ARM64_ACTLR_STATE) &&
cpus_have_const_cap(ARM64_HAS_TSO_APPLE);
}

struct arm64_ftr_reg *get_arm64_ftr_reg(u32 sys_id);

extern struct arm64_ftr_override id_aa64mmfr1_override;
Expand Down
3 changes: 3 additions & 0 deletions arch/arm64/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ struct thread_struct {
u64 sctlr_user;
u64 svcr;
u64 tpidr2_el0;
#ifdef CONFIG_ARM64_ACTLR_STATE
u64 actlr;
#endif
};

static inline unsigned int thread_get_vl(struct thread_struct *thread,
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
cpufeature.o alternative.o cacheinfo.o \
smp.o smp_spin_table.o topology.o smccc-call.o \
syscall.o proton-pack.o idreg-override.o idle.o \
patching.o
patching.o cpufeature_impdef.o

obj-$(CONFIG_COMPAT) += sys32.o signal32.o \
sys_compat.o
Expand Down
7 changes: 5 additions & 2 deletions arch/arm64/kernel/cpufeature.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ DEFINE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
*/
static cpumask_var_t cpu_32bit_el0_mask __cpumask_var_read_mostly;

void __init init_cpu_hwcaps_indirect_list_impdef(void);

void dump_cpu_features(void)
{
/* file-wide pr_fmt adds "CPU features: " prefix */
Expand Down Expand Up @@ -946,7 +948,7 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
extern const struct arm64_cpu_capabilities arm64_errata[];
static const struct arm64_cpu_capabilities arm64_features[];

static void __init
void __init
init_cpu_hwcaps_indirect_list_from_array(const struct arm64_cpu_capabilities *caps)
{
for (; caps->matches; caps++) {
Expand Down Expand Up @@ -1046,6 +1048,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
* before we handle the boot CPU below.
*/
init_cpu_hwcaps_indirect_list();
init_cpu_hwcaps_indirect_list_impdef();

/*
* Detect and enable early CPU capabilities based on the boot CPU,
Expand Down Expand Up @@ -1414,7 +1417,7 @@ has_always(const struct arm64_cpu_capabilities *entry, int scope)
return true;
}

static bool
bool
feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
{
int val = cpuid_feature_extract_field_width(reg, entry->field_pos,
Expand Down
62 changes: 62 additions & 0 deletions arch/arm64/kernel/cpufeature_impdef.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Contains implementation-defined CPU feature definitions.
*/

#include <asm/cpufeature.h>
#include <asm/apple_cpufeature.h>

void __init init_cpu_hwcaps_indirect_list_from_array(const struct arm64_cpu_capabilities *caps);
bool feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry);

bool has_apple_feature(const struct arm64_cpu_capabilities *entry, int scope)
{
u64 val;
WARN_ON(scope != SCOPE_SYSTEM);

if (read_cpuid_implementor() != ARM_CPU_IMP_APPLE)
return false;

val = read_sysreg(aidr_el1);
return feature_matches(val, entry);
}

bool has_tso_fixed(const struct arm64_cpu_capabilities *entry, int scope)
{
/* List of CPUs that always use the TSO memory model */
static const struct midr_range fixed_tso_list[] = {
MIDR_ALL_VERSIONS(MIDR_NVIDIA_DENVER),
MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL),
MIDR_ALL_VERSIONS(MIDR_FUJITSU_A64FX),
{ /* sentinel */ }
};

return is_midr_in_range_list(read_cpuid_id(), fixed_tso_list);
}

static const struct arm64_cpu_capabilities arm64_impdef_features[] = {
#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
{
.desc = "TSO memory model (Apple)",
.capability = ARM64_HAS_TSO_APPLE,
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_apple_feature,
.field_pos = AIDR_APPLE_TSO_SHIFT,
.field_width = 1,
.sign = FTR_UNSIGNED,
.min_field_value = 1,
},
{
.desc = "TSO memory model (Fixed)",
.capability = ARM64_HAS_TSO_FIXED,
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_tso_fixed,
},
#endif
{},
};

void __init init_cpu_hwcaps_indirect_list_impdef(void)
{
init_cpu_hwcaps_indirect_list_from_array(arm64_impdef_features);
}
61 changes: 61 additions & 0 deletions arch/arm64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <linux/stacktrace.h>

#include <asm/alternative.h>
#include <asm/apple_cpufeature.h>
#include <asm/compat.h>
#include <asm/cpufeature.h>
#include <asm/cacheflush.h>
Expand Down Expand Up @@ -374,6 +375,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
if (system_supports_tpidr2())
p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);

if (system_has_actlr_state())
p->thread.actlr = read_sysreg(actlr_el1);

if (stack_start) {
if (is_compat_thread(task_thread_info(p)))
childregs->compat_sp = stack_start;
Expand Down Expand Up @@ -516,6 +520,58 @@ void update_sctlr_el1(u64 sctlr)
isb();
}

/*
* IMPDEF control register ACTLR_EL1 handling. Some CPUs use this to
* expose features that can be controlled by userspace.
*/
static void actlr_thread_switch(struct task_struct *next)
{
if (!system_has_actlr_state())
return;

current->thread.actlr = read_sysreg(actlr_el1);
write_sysreg(next->thread.actlr, actlr_el1);
}

#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
int arch_prctl_mem_model_get(struct task_struct *t)
{
if (cpus_have_const_cap(ARM64_HAS_TSO_APPLE) &&
t->thread.actlr & ACTLR_APPLE_TSO)
return PR_SET_MEM_MODEL_TSO;

return PR_SET_MEM_MODEL_DEFAULT;
}

int arch_prctl_mem_model_set(struct task_struct *t, unsigned long val)
{
if (cpus_have_const_cap(ARM64_HAS_TSO_FIXED) && val == PR_SET_MEM_MODEL_TSO)
return 0;

if (cpus_have_const_cap(ARM64_HAS_TSO_APPLE)) {
WARN_ON(!system_has_actlr_state());

switch (val) {
case PR_SET_MEM_MODEL_TSO:
t->thread.actlr |= ACTLR_APPLE_TSO;
break;
case PR_SET_MEM_MODEL_DEFAULT:
t->thread.actlr &= ~ACTLR_APPLE_TSO;
break;
default:
return -EINVAL;
}
write_sysreg(t->thread.actlr, actlr_el1);
return 0;
}

if (val == PR_SET_MEM_MODEL_DEFAULT)
return 0;

return -EINVAL;
}
#endif

/*
* Thread switching.
*/
Expand All @@ -533,6 +589,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
ssbs_thread_switch(next);
erratum_1418040_thread_switch(next);
ptrauth_thread_switch_user(next);
actlr_thread_switch(next);

/*
* Complete any pending TLB or cache maintenance on this CPU in case
Expand Down Expand Up @@ -654,6 +711,10 @@ void arch_setup_new_exec(void)
arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
PR_SPEC_ENABLE);
}

if (IS_ENABLED(CONFIG_ARM64_MEMORY_MODEL_CONTROL)) {
arch_prctl_mem_model_set(current, PR_SET_MEM_MODEL_DEFAULT);

This comment has been minimized.

Copy link
@wrenger

wrenger Sep 19, 2023

@marcan is this the reason why TSO is disabled after execve? It would be nice if it remains enabled...

}
}

#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
Expand Down
8 changes: 8 additions & 0 deletions arch/arm64/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,14 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
*/
init_task.thread_info.ttbr0 = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
#endif
#ifdef CONFIG_ARM64_ACTLR_STATE
/* Store the boot CPU ACTLR_EL1 value as the default. This will only
* be actually restored during context switching iff the platform is
* known to use ACTLR_EL1 for exposable features and its layout is
* known to be the same on all CPUs.
*/
init_task.thread.actlr = read_sysreg(actlr_el1);
#endif

if (boot_args[1] || boot_args[2] || boot_args[3]) {
pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n"
Expand Down
2 changes: 2 additions & 0 deletions arch/arm64/tools/cpucaps
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ HAS_SB
HAS_STAGE2_FWB
HAS_TIDCP1
HAS_TLB_RANGE
HAS_TSO_APPLE
HAS_TSO_FIXED
HAS_VIRT_HOST_EXTN
HAS_WFXT
HW_DBM
Expand Down
5 changes: 5 additions & 0 deletions include/uapi/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,9 @@ struct prctl_mm_map {
#define PR_SET_VMA 0x53564d41
# define PR_SET_VMA_ANON_NAME 0

#define PR_GET_MEM_MODEL 0x6d4d444c
#define PR_SET_MEM_MODEL 0x4d4d444c
# define PR_SET_MEM_MODEL_DEFAULT 0
# define PR_SET_MEM_MODEL_TSO 1

#endif /* _LINUX_PRCTL_H */
20 changes: 20 additions & 0 deletions kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,16 @@ static inline int prctl_get_mdwe(unsigned long arg2, unsigned long arg3,
PR_MDWE_REFUSE_EXEC_GAIN : 0;
}

int __weak arch_prctl_mem_model_get(struct task_struct *t)
{
return -EINVAL;
}

int __weak arch_prctl_mem_model_set(struct task_struct *t, unsigned long val)
{
return -EINVAL;
}

SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
{
Expand Down Expand Up @@ -2672,6 +2682,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_SET_VMA:
error = prctl_set_vma(arg2, arg3, arg4, arg5);
break;
case PR_GET_MEM_MODEL:
if (arg2 || arg3 || arg4 || arg5)
return -EINVAL;
error = arch_prctl_mem_model_get(me);
break;
case PR_SET_MEM_MODEL:
if (arg3 || arg4 || arg5)
return -EINVAL;
error = arch_prctl_mem_model_set(me, arg2);
break;
default:
error = -EINVAL;
break;
Expand Down

0 comments on commit b5c05cb

Please sign in to comment.