Merge branch 'for-4.19/i2c-hid' into for-linus
[sfrench/cifs-2.6.git] / arch / arm64 / kernel / ssbd.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
4  */
5
6 #include <linux/errno.h>
7 #include <linux/sched.h>
8 #include <linux/thread_info.h>
9
10 #include <asm/cpufeature.h>
11
12 /*
13  * prctl interface for SSBD
14  * FIXME: Drop the below ifdefery once merged in 4.18.
15  */
16 #ifdef PR_SPEC_STORE_BYPASS
17 static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
18 {
19         int state = arm64_get_ssbd_state();
20
21         /* Unsupported */
22         if (state == ARM64_SSBD_UNKNOWN)
23                 return -EINVAL;
24
25         /* Treat the unaffected/mitigated state separately */
26         if (state == ARM64_SSBD_MITIGATED) {
27                 switch (ctrl) {
28                 case PR_SPEC_ENABLE:
29                         return -EPERM;
30                 case PR_SPEC_DISABLE:
31                 case PR_SPEC_FORCE_DISABLE:
32                         return 0;
33                 }
34         }
35
36         /*
37          * Things are a bit backward here: the arm64 internal API
38          * *enables the mitigation* when the userspace API *disables
39          * speculation*. So much fun.
40          */
41         switch (ctrl) {
42         case PR_SPEC_ENABLE:
43                 /* If speculation is force disabled, enable is not allowed */
44                 if (state == ARM64_SSBD_FORCE_ENABLE ||
45                     task_spec_ssb_force_disable(task))
46                         return -EPERM;
47                 task_clear_spec_ssb_disable(task);
48                 clear_tsk_thread_flag(task, TIF_SSBD);
49                 break;
50         case PR_SPEC_DISABLE:
51                 if (state == ARM64_SSBD_FORCE_DISABLE)
52                         return -EPERM;
53                 task_set_spec_ssb_disable(task);
54                 set_tsk_thread_flag(task, TIF_SSBD);
55                 break;
56         case PR_SPEC_FORCE_DISABLE:
57                 if (state == ARM64_SSBD_FORCE_DISABLE)
58                         return -EPERM;
59                 task_set_spec_ssb_disable(task);
60                 task_set_spec_ssb_force_disable(task);
61                 set_tsk_thread_flag(task, TIF_SSBD);
62                 break;
63         default:
64                 return -ERANGE;
65         }
66
67         return 0;
68 }
69
70 int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
71                              unsigned long ctrl)
72 {
73         switch (which) {
74         case PR_SPEC_STORE_BYPASS:
75                 return ssbd_prctl_set(task, ctrl);
76         default:
77                 return -ENODEV;
78         }
79 }
80
81 static int ssbd_prctl_get(struct task_struct *task)
82 {
83         switch (arm64_get_ssbd_state()) {
84         case ARM64_SSBD_UNKNOWN:
85                 return -EINVAL;
86         case ARM64_SSBD_FORCE_ENABLE:
87                 return PR_SPEC_DISABLE;
88         case ARM64_SSBD_KERNEL:
89                 if (task_spec_ssb_force_disable(task))
90                         return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
91                 if (task_spec_ssb_disable(task))
92                         return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
93                 return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
94         case ARM64_SSBD_FORCE_DISABLE:
95                 return PR_SPEC_ENABLE;
96         default:
97                 return PR_SPEC_NOT_AFFECTED;
98         }
99 }
100
101 int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
102 {
103         switch (which) {
104         case PR_SPEC_STORE_BYPASS:
105                 return ssbd_prctl_get(task);
106         default:
107                 return -ENODEV;
108         }
109 }
110 #endif  /* PR_SPEC_STORE_BYPASS */