|
9 | 9 | #include <linux/slab.h> |
10 | 10 | #include <linux/sched.h> |
11 | 11 | #include <linux/uaccess.h> |
| 12 | +#include <linux/prctl.h> |
12 | 13 |
|
13 | 14 | #include <asm/thread_info.h> |
14 | 15 | #include <asm/processor.h> |
|
19 | 20 | #include <asm/ptrace.h> |
20 | 21 | #include <asm/bug.h> |
21 | 22 |
|
| 23 | +static bool riscv_v_implicit_uacc = IS_ENABLED(CONFIG_RISCV_ISA_V_DEFAULT_ENABLE); |
| 24 | + |
22 | 25 | unsigned long riscv_v_vsize __read_mostly; |
23 | 26 | EXPORT_SYMBOL_GPL(riscv_v_vsize); |
24 | 27 |
|
@@ -91,6 +94,43 @@ static int riscv_v_thread_zalloc(void) |
91 | 94 | return 0; |
92 | 95 | } |
93 | 96 |
|
| 97 | +#define VSTATE_CTRL_GET_CUR(x) ((x) & PR_RISCV_V_VSTATE_CTRL_CUR_MASK) |
| 98 | +#define VSTATE_CTRL_GET_NEXT(x) (((x) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) >> 2) |
| 99 | +#define VSTATE_CTRL_MAKE_NEXT(x) (((x) << 2) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) |
| 100 | +#define VSTATE_CTRL_GET_INHERIT(x) (!!((x) & PR_RISCV_V_VSTATE_CTRL_INHERIT)) |
| 101 | +static inline int riscv_v_ctrl_get_cur(struct task_struct *tsk) |
| 102 | +{ |
| 103 | + return VSTATE_CTRL_GET_CUR(tsk->thread.vstate_ctrl); |
| 104 | +} |
| 105 | + |
| 106 | +static inline int riscv_v_ctrl_get_next(struct task_struct *tsk) |
| 107 | +{ |
| 108 | + return VSTATE_CTRL_GET_NEXT(tsk->thread.vstate_ctrl); |
| 109 | +} |
| 110 | + |
| 111 | +static inline bool riscv_v_ctrl_test_inherit(struct task_struct *tsk) |
| 112 | +{ |
| 113 | + return VSTATE_CTRL_GET_INHERIT(tsk->thread.vstate_ctrl); |
| 114 | +} |
| 115 | + |
| 116 | +static inline void riscv_v_ctrl_set(struct task_struct *tsk, int cur, int nxt, |
| 117 | + bool inherit) |
| 118 | +{ |
| 119 | + unsigned long ctrl; |
| 120 | + |
| 121 | + ctrl = cur & PR_RISCV_V_VSTATE_CTRL_CUR_MASK; |
| 122 | + ctrl |= VSTATE_CTRL_MAKE_NEXT(nxt); |
| 123 | + if (inherit) |
| 124 | + ctrl |= PR_RISCV_V_VSTATE_CTRL_INHERIT; |
| 125 | + tsk->thread.vstate_ctrl = ctrl; |
| 126 | +} |
| 127 | + |
| 128 | +bool riscv_v_vstate_ctrl_user_allowed(void) |
| 129 | +{ |
| 130 | + return riscv_v_ctrl_get_cur(current) == PR_RISCV_V_VSTATE_CTRL_ON; |
| 131 | +} |
| 132 | +EXPORT_SYMBOL_GPL(riscv_v_vstate_ctrl_user_allowed); |
| 133 | + |
94 | 134 | bool riscv_v_first_use_handler(struct pt_regs *regs) |
95 | 135 | { |
96 | 136 | u32 __user *epc = (u32 __user *)regs->epc; |
@@ -129,3 +169,77 @@ bool riscv_v_first_use_handler(struct pt_regs *regs) |
129 | 169 | riscv_v_vstate_on(regs); |
130 | 170 | return true; |
131 | 171 | } |
| 172 | + |
| 173 | +void riscv_v_vstate_ctrl_init(struct task_struct *tsk) |
| 174 | +{ |
| 175 | + bool inherit; |
| 176 | + int cur, next; |
| 177 | + |
| 178 | + if (!has_vector()) |
| 179 | + return; |
| 180 | + |
| 181 | + next = riscv_v_ctrl_get_next(tsk); |
| 182 | + if (!next) { |
| 183 | + if (riscv_v_implicit_uacc) |
| 184 | + cur = PR_RISCV_V_VSTATE_CTRL_ON; |
| 185 | + else |
| 186 | + cur = PR_RISCV_V_VSTATE_CTRL_OFF; |
| 187 | + } else { |
| 188 | + cur = next; |
| 189 | + } |
| 190 | + /* Clear next mask if inherit-bit is not set */ |
| 191 | + inherit = riscv_v_ctrl_test_inherit(tsk); |
| 192 | + if (!inherit) |
| 193 | + next = PR_RISCV_V_VSTATE_CTRL_DEFAULT; |
| 194 | + |
| 195 | + riscv_v_ctrl_set(tsk, cur, next, inherit); |
| 196 | +} |
| 197 | + |
| 198 | +long riscv_v_vstate_ctrl_get_current(void) |
| 199 | +{ |
| 200 | + if (!has_vector()) |
| 201 | + return -EINVAL; |
| 202 | + |
| 203 | + return current->thread.vstate_ctrl & PR_RISCV_V_VSTATE_CTRL_MASK; |
| 204 | +} |
| 205 | + |
| 206 | +long riscv_v_vstate_ctrl_set_current(unsigned long arg) |
| 207 | +{ |
| 208 | + bool inherit; |
| 209 | + int cur, next; |
| 210 | + |
| 211 | + if (!has_vector()) |
| 212 | + return -EINVAL; |
| 213 | + |
| 214 | + if (arg & ~PR_RISCV_V_VSTATE_CTRL_MASK) |
| 215 | + return -EINVAL; |
| 216 | + |
| 217 | + cur = VSTATE_CTRL_GET_CUR(arg); |
| 218 | + switch (cur) { |
| 219 | + case PR_RISCV_V_VSTATE_CTRL_OFF: |
| 220 | + /* Do not allow user to turn off V if current is not off */ |
| 221 | + if (riscv_v_ctrl_get_cur(current) != PR_RISCV_V_VSTATE_CTRL_OFF) |
| 222 | + return -EPERM; |
| 223 | + |
| 224 | + break; |
| 225 | + case PR_RISCV_V_VSTATE_CTRL_ON: |
| 226 | + break; |
| 227 | + case PR_RISCV_V_VSTATE_CTRL_DEFAULT: |
| 228 | + cur = riscv_v_ctrl_get_cur(current); |
| 229 | + break; |
| 230 | + default: |
| 231 | + return -EINVAL; |
| 232 | + } |
| 233 | + |
| 234 | + next = VSTATE_CTRL_GET_NEXT(arg); |
| 235 | + inherit = VSTATE_CTRL_GET_INHERIT(arg); |
| 236 | + switch (next) { |
| 237 | + case PR_RISCV_V_VSTATE_CTRL_DEFAULT: |
| 238 | + case PR_RISCV_V_VSTATE_CTRL_OFF: |
| 239 | + case PR_RISCV_V_VSTATE_CTRL_ON: |
| 240 | + riscv_v_ctrl_set(current, cur, next, inherit); |
| 241 | + return 0; |
| 242 | + } |
| 243 | + |
| 244 | + return -EINVAL; |
| 245 | +} |
0 commit comments