]> git.ipfire.org Git - thirdparty/kernel/linux.git/blame - arch/arm64/kernel/ssbd.c
arm64: ssbd: explicitly depend on <linux/prctl.h>
[thirdparty/kernel/linux.git] / arch / arm64 / kernel / ssbd.c
CommitLineData
9cdc0108
MZ
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
4 */
5
8f04e8e6 6#include <linux/compat.h>
9cdc0108 7#include <linux/errno.h>
adeaa21a 8#include <linux/prctl.h>
9cdc0108 9#include <linux/sched.h>
8f04e8e6 10#include <linux/sched/task_stack.h>
9cdc0108
MZ
11#include <linux/thread_info.h>
12
13#include <asm/cpufeature.h>
14
8f04e8e6
WD
15static void ssbd_ssbs_enable(struct task_struct *task)
16{
17 u64 val = is_compat_thread(task_thread_info(task)) ?
18 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
19
20 task_pt_regs(task)->pstate |= val;
21}
22
23static void ssbd_ssbs_disable(struct task_struct *task)
24{
25 u64 val = is_compat_thread(task_thread_info(task)) ?
26 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
27
28 task_pt_regs(task)->pstate &= ~val;
29}
30
9cdc0108
MZ
31/*
32 * prctl interface for SSBD
9cdc0108 33 */
9cdc0108
MZ
34static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
35{
36 int state = arm64_get_ssbd_state();
37
38 /* Unsupported */
39 if (state == ARM64_SSBD_UNKNOWN)
40 return -EINVAL;
41
42 /* Treat the unaffected/mitigated state separately */
43 if (state == ARM64_SSBD_MITIGATED) {
44 switch (ctrl) {
45 case PR_SPEC_ENABLE:
46 return -EPERM;
47 case PR_SPEC_DISABLE:
48 case PR_SPEC_FORCE_DISABLE:
49 return 0;
50 }
51 }
52
53 /*
54 * Things are a bit backward here: the arm64 internal API
55 * *enables the mitigation* when the userspace API *disables
56 * speculation*. So much fun.
57 */
58 switch (ctrl) {
59 case PR_SPEC_ENABLE:
60 /* If speculation is force disabled, enable is not allowed */
61 if (state == ARM64_SSBD_FORCE_ENABLE ||
62 task_spec_ssb_force_disable(task))
63 return -EPERM;
64 task_clear_spec_ssb_disable(task);
65 clear_tsk_thread_flag(task, TIF_SSBD);
8f04e8e6 66 ssbd_ssbs_enable(task);
9cdc0108
MZ
67 break;
68 case PR_SPEC_DISABLE:
69 if (state == ARM64_SSBD_FORCE_DISABLE)
70 return -EPERM;
71 task_set_spec_ssb_disable(task);
72 set_tsk_thread_flag(task, TIF_SSBD);
8f04e8e6 73 ssbd_ssbs_disable(task);
9cdc0108
MZ
74 break;
75 case PR_SPEC_FORCE_DISABLE:
76 if (state == ARM64_SSBD_FORCE_DISABLE)
77 return -EPERM;
78 task_set_spec_ssb_disable(task);
79 task_set_spec_ssb_force_disable(task);
80 set_tsk_thread_flag(task, TIF_SSBD);
8f04e8e6 81 ssbd_ssbs_disable(task);
9cdc0108
MZ
82 break;
83 default:
84 return -ERANGE;
85 }
86
87 return 0;
88}
89
90int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
91 unsigned long ctrl)
92{
93 switch (which) {
94 case PR_SPEC_STORE_BYPASS:
95 return ssbd_prctl_set(task, ctrl);
96 default:
97 return -ENODEV;
98 }
99}
100
101static int ssbd_prctl_get(struct task_struct *task)
102{
103 switch (arm64_get_ssbd_state()) {
104 case ARM64_SSBD_UNKNOWN:
105 return -EINVAL;
106 case ARM64_SSBD_FORCE_ENABLE:
107 return PR_SPEC_DISABLE;
108 case ARM64_SSBD_KERNEL:
109 if (task_spec_ssb_force_disable(task))
110 return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
111 if (task_spec_ssb_disable(task))
112 return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
113 return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
114 case ARM64_SSBD_FORCE_DISABLE:
115 return PR_SPEC_ENABLE;
116 default:
117 return PR_SPEC_NOT_AFFECTED;
118 }
119}
120
121int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
122{
123 switch (which) {
124 case PR_SPEC_STORE_BYPASS:
125 return ssbd_prctl_get(task);
126 default:
127 return -ENODEV;
128 }
129}