Skip to content

Commit e7f6647

Browse files
marcanjannau
authored andcommitted
prctl: Introduce PR_{SET,GET}_MEM_MODEL
On some architectures, it is possible to query and/or change the CPU memory model. This allows userspace to switch to a stricter memory model for performance reasons, such as when emulating code for another architecture where that model is the default. Introduce two prctls to allow userspace to query and set the memory model for a thread. Two models are initially defined: - PR_SET_MEM_MODEL_DEFAULT requests the default memory model for the architecture. - PR_SET_MEM_MODEL_TSO requests the x86 TSO memory model. PR_SET_MEM_MODEL is allowed to set a stricter memory model than requested if available, in which case it will return successfully. If the requested memory model cannot be fulfilled, it will return an error. The memory model that was actually set can be queried by a subsequent call to PR_GET_MEM_MODEL. Examples: - On a CPU with not support for a memory model at least as strong as TSO, PR_SET_MEM_MODEL(PR_SET_MEM_MODEL_TSO) fails. - On a CPU with runtime-configurable TSO support, PR_SET_MEM_MODEL can toggle the memory model between DEFAULT and TSO at will. - On a CPU where the only memory model is at least as strict as TSO, PR_GET_MEM_MODEL will return PR_SET_MEM_MODEL_DEFAULT, and PR_SET_MEM_MODEL(PR_SET_MEM_MODEL_TSO) will return success but leave the memory model at PR_SET_MEM_MODEL_DEFAULT. This implies that the default is in fact at least as strict as TSO. Signed-off-by: Hector Martin <marcan@marcan.st> Reviewed-by: Neal Gompa <neal@gompa.dev>
1 parent 0c38364 commit e7f6647

3 files changed

Lines changed: 38 additions & 1 deletion

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __ASM_MEMORY_ORDERING_MODEL_H
3+
#define __ASM_MEMORY_ORDERING_MODEL_H
4+
5+
/* Arch hooks to implement the PR_{GET_SET}_MEM_MODEL prctls */
6+
7+
struct task_struct;
8+
int arch_prctl_mem_model_get(struct task_struct *t);
9+
int arch_prctl_mem_model_set(struct task_struct *t, unsigned long val);
10+
11+
#endif

include/uapi/linux/prctl.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,9 @@ struct prctl_mm_map {
328328
# define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC 0x10 /* Clear the aspect on exec */
329329
# define PR_PPC_DEXCR_CTRL_MASK 0x1f
330330

331-
#endif /* _LINUX_PRCTL_H */
331+
#define PR_GET_MEM_MODEL 0x6d4d444c
332+
#define PR_SET_MEM_MODEL 0x4d4d444c
333+
# define PR_SET_MEM_MODEL_DEFAULT 0
334+
# define PR_SET_MEM_MODEL_TSO 1
335+
336+
endif /* _LINUX_PRCTL_H */

kernel/sys.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <linux/version.h>
4646
#include <linux/ctype.h>
4747
#include <linux/syscall_user_dispatch.h>
48+
#include <linux/memory_ordering_model.h>
4849

4950
#include <linux/compat.h>
5051
#include <linux/syscalls.h>
@@ -2454,6 +2455,16 @@ static int prctl_get_auxv(void __user *addr, unsigned long len)
24542455
return sizeof(mm->saved_auxv);
24552456
}
24562457

2458+
int __weak arch_prctl_mem_model_get(struct task_struct *t)
2459+
{
2460+
return -EINVAL;
2461+
}
2462+
2463+
int __weak arch_prctl_mem_model_set(struct task_struct *t, unsigned long val)
2464+
{
2465+
return -EINVAL;
2466+
}
2467+
24572468
SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
24582469
unsigned long, arg4, unsigned long, arg5)
24592470
{
@@ -2782,6 +2793,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
27822793
case PR_RISCV_SET_ICACHE_FLUSH_CTX:
27832794
error = RISCV_SET_ICACHE_FLUSH_CTX(arg2, arg3);
27842795
break;
2796+
case PR_GET_MEM_MODEL:
2797+
if (arg2 || arg3 || arg4 || arg5)
2798+
return -EINVAL;
2799+
error = arch_prctl_mem_model_get(me);
2800+
break;
2801+
case PR_SET_MEM_MODEL:
2802+
if (arg3 || arg4 || arg5)
2803+
return -EINVAL;
2804+
error = arch_prctl_mem_model_set(me, arg2);
2805+
break;
27852806
default:
27862807
error = -EINVAL;
27872808
break;

0 commit comments

Comments
 (0)