1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
6 #include <linux/errno.h>
7 #include <linux/prctl.h>
8 #include <linux/sched.h>
9 #include <linux/thread_info.h>
11 #include <asm/cpufeature.h>
14 * prctl interface for SSBD
16 static int ssbd_prctl_set(struct task_struct
*task
, unsigned long ctrl
)
18 int state
= arm64_get_ssbd_state();
21 if (state
== ARM64_SSBD_UNKNOWN
)
24 /* Treat the unaffected/mitigated state separately */
25 if (state
== ARM64_SSBD_MITIGATED
) {
30 case PR_SPEC_FORCE_DISABLE
:
36 * Things are a bit backward here: the arm64 internal API
37 * *enables the mitigation* when the userspace API *disables
38 * speculation*. So much fun.
42 /* If speculation is force disabled, enable is not allowed */
43 if (state
== ARM64_SSBD_FORCE_ENABLE
||
44 task_spec_ssb_force_disable(task
))
46 task_clear_spec_ssb_disable(task
);
47 clear_tsk_thread_flag(task
, TIF_SSBD
);
50 if (state
== ARM64_SSBD_FORCE_DISABLE
)
52 task_set_spec_ssb_disable(task
);
53 set_tsk_thread_flag(task
, TIF_SSBD
);
55 case PR_SPEC_FORCE_DISABLE
:
56 if (state
== ARM64_SSBD_FORCE_DISABLE
)
58 task_set_spec_ssb_disable(task
);
59 task_set_spec_ssb_force_disable(task
);
60 set_tsk_thread_flag(task
, TIF_SSBD
);
69 int arch_prctl_spec_ctrl_set(struct task_struct
*task
, unsigned long which
,
73 case PR_SPEC_STORE_BYPASS
:
74 return ssbd_prctl_set(task
, ctrl
);
80 static int ssbd_prctl_get(struct task_struct
*task
)
82 switch (arm64_get_ssbd_state()) {
83 case ARM64_SSBD_UNKNOWN
:
85 case ARM64_SSBD_FORCE_ENABLE
:
86 return PR_SPEC_DISABLE
;
87 case ARM64_SSBD_KERNEL
:
88 if (task_spec_ssb_force_disable(task
))
89 return PR_SPEC_PRCTL
| PR_SPEC_FORCE_DISABLE
;
90 if (task_spec_ssb_disable(task
))
91 return PR_SPEC_PRCTL
| PR_SPEC_DISABLE
;
92 return PR_SPEC_PRCTL
| PR_SPEC_ENABLE
;
93 case ARM64_SSBD_FORCE_DISABLE
:
94 return PR_SPEC_ENABLE
;
96 return PR_SPEC_NOT_AFFECTED
;
100 int arch_prctl_spec_ctrl_get(struct task_struct
*task
, unsigned long which
)
103 case PR_SPEC_STORE_BYPASS
:
104 return ssbd_prctl_get(task
);