]>
Commit | Line | Data |
---|---|---|
c7b95171 MC |
1 | /* |
2 | * RISC-V Control and Status Registers. | |
3 | * | |
4 | * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu | |
5 | * Copyright (c) 2017-2018 SiFive, Inc. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms and conditions of the GNU General Public License, | |
9 | * version 2 or later, as published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include "qemu/osdep.h" | |
21 | #include "qemu/log.h" | |
b8012ecf | 22 | #include "qemu/timer.h" |
c7b95171 | 23 | #include "cpu.h" |
3780e337 | 24 | #include "pmu.h" |
c7b95171 MC |
25 | #include "qemu/main-loop.h" |
26 | #include "exec/exec-all.h" | |
03ff4f8d | 27 | #include "sysemu/cpu-timers.h" |
77442380 WL |
28 | #include "qemu/guest-random.h" |
29 | #include "qapi/error.h" | |
c7b95171 | 30 | |
c7b95171 MC |
31 | /* CSR function table public API */ |
32 | void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops) | |
33 | { | |
34 | *ops = csr_ops[csrno & (CSR_TABLE_SIZE - 1)]; | |
35 | } | |
36 | ||
37 | void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) | |
38 | { | |
39 | csr_ops[csrno & (CSR_TABLE_SIZE - 1)] = *ops; | |
40 | } | |
41 | ||
a88365c1 | 42 | /* Predicates */ |
0e62f92e | 43 | static RISCVException fs(CPURISCVState *env, int csrno) |
a88365c1 MC |
44 | { |
45 | #if !defined(CONFIG_USER_ONLY) | |
c163b3ba WL |
46 | if (!env->debugger && !riscv_cpu_fp_enabled(env) && |
47 | !RISCV_CPU(env_cpu(env))->cfg.ext_zfinx) { | |
0e62f92e | 48 | return RISCV_EXCP_ILLEGAL_INST; |
a88365c1 MC |
49 | } |
50 | #endif | |
0e62f92e | 51 | return RISCV_EXCP_NONE; |
a88365c1 MC |
52 | } |
53 | ||
0e62f92e | 54 | static RISCVException vs(CPURISCVState *env, int csrno) |
8e3a1f18 | 55 | { |
b4a99d40 FC |
56 | CPUState *cs = env_cpu(env); |
57 | RISCVCPU *cpu = RISCV_CPU(cs); | |
58 | ||
59 | if (env->misa_ext & RVV || | |
32e579b8 | 60 | cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) { |
6bc3dfa9 FC |
61 | #if !defined(CONFIG_USER_ONLY) |
62 | if (!env->debugger && !riscv_cpu_vector_enabled(env)) { | |
63 | return RISCV_EXCP_ILLEGAL_INST; | |
64 | } | |
65 | #endif | |
0e62f92e | 66 | return RISCV_EXCP_NONE; |
8e3a1f18 | 67 | } |
0e62f92e | 68 | return RISCV_EXCP_ILLEGAL_INST; |
8e3a1f18 LZ |
69 | } |
70 | ||
0e62f92e | 71 | static RISCVException ctr(CPURISCVState *env, int csrno) |
a88365c1 MC |
72 | { |
73 | #if !defined(CONFIG_USER_ONLY) | |
0a13a5b8 AF |
74 | CPUState *cs = env_cpu(env); |
75 | RISCVCPU *cpu = RISCV_CPU(cs); | |
562009e4 | 76 | int ctr_index; |
18d6d89e AP |
77 | int base_csrno = CSR_HPMCOUNTER3; |
78 | bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false; | |
0a13a5b8 | 79 | |
18d6d89e AP |
80 | if (rv32 && csrno >= CSR_CYCLEH) { |
81 | /* Offset for RV32 hpmcounternh counters */ | |
82 | base_csrno += 0x80; | |
83 | } | |
84 | ctr_index = csrno - base_csrno; | |
85 | ||
86 | if (!cpu->cfg.pmu_num || ctr_index >= (cpu->cfg.pmu_num)) { | |
87 | /* No counter is enabled in PMU or the counter is out of range */ | |
0e62f92e | 88 | return RISCV_EXCP_ILLEGAL_INST; |
0a13a5b8 | 89 | } |
e39a8320 | 90 | |
a5a92fd6 AP |
91 | if (env->priv == PRV_S) { |
92 | switch (csrno) { | |
93 | case CSR_CYCLE: | |
94 | if (!get_field(env->mcounteren, COUNTEREN_CY)) { | |
95 | return RISCV_EXCP_ILLEGAL_INST; | |
96 | } | |
97 | break; | |
98 | case CSR_TIME: | |
99 | if (!get_field(env->mcounteren, COUNTEREN_TM)) { | |
100 | return RISCV_EXCP_ILLEGAL_INST; | |
101 | } | |
102 | break; | |
103 | case CSR_INSTRET: | |
104 | if (!get_field(env->mcounteren, COUNTEREN_IR)) { | |
105 | return RISCV_EXCP_ILLEGAL_INST; | |
106 | } | |
107 | break; | |
108 | case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: | |
109 | ctr_index = csrno - CSR_CYCLE; | |
110 | if (!get_field(env->mcounteren, 1 << ctr_index)) { | |
111 | return RISCV_EXCP_ILLEGAL_INST; | |
112 | } | |
113 | break; | |
114 | } | |
18d6d89e | 115 | if (rv32) { |
a5a92fd6 AP |
116 | switch (csrno) { |
117 | case CSR_CYCLEH: | |
118 | if (!get_field(env->mcounteren, COUNTEREN_CY)) { | |
119 | return RISCV_EXCP_ILLEGAL_INST; | |
120 | } | |
121 | break; | |
122 | case CSR_TIMEH: | |
123 | if (!get_field(env->mcounteren, COUNTEREN_TM)) { | |
124 | return RISCV_EXCP_ILLEGAL_INST; | |
125 | } | |
126 | break; | |
127 | case CSR_INSTRETH: | |
128 | if (!get_field(env->mcounteren, COUNTEREN_IR)) { | |
129 | return RISCV_EXCP_ILLEGAL_INST; | |
130 | } | |
131 | break; | |
132 | case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: | |
133 | ctr_index = csrno - CSR_CYCLEH; | |
134 | if (!get_field(env->mcounteren, 1 << ctr_index)) { | |
135 | return RISCV_EXCP_ILLEGAL_INST; | |
136 | } | |
137 | break; | |
138 | } | |
139 | } | |
140 | } | |
141 | ||
e39a8320 AF |
142 | if (riscv_cpu_virt_enabled(env)) { |
143 | switch (csrno) { | |
144 | case CSR_CYCLE: | |
db70794e BM |
145 | if (!get_field(env->hcounteren, COUNTEREN_CY) && |
146 | get_field(env->mcounteren, COUNTEREN_CY)) { | |
0e62f92e | 147 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
e39a8320 AF |
148 | } |
149 | break; | |
150 | case CSR_TIME: | |
db70794e BM |
151 | if (!get_field(env->hcounteren, COUNTEREN_TM) && |
152 | get_field(env->mcounteren, COUNTEREN_TM)) { | |
0e62f92e | 153 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
e39a8320 AF |
154 | } |
155 | break; | |
156 | case CSR_INSTRET: | |
db70794e BM |
157 | if (!get_field(env->hcounteren, COUNTEREN_IR) && |
158 | get_field(env->mcounteren, COUNTEREN_IR)) { | |
0e62f92e | 159 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
e39a8320 AF |
160 | } |
161 | break; | |
162 | case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: | |
562009e4 AP |
163 | ctr_index = csrno - CSR_CYCLE; |
164 | if (!get_field(env->hcounteren, 1 << ctr_index) && | |
165 | get_field(env->mcounteren, 1 << ctr_index)) { | |
0e62f92e | 166 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
e39a8320 AF |
167 | } |
168 | break; | |
8987cdc4 | 169 | } |
18d6d89e | 170 | if (rv32) { |
8987cdc4 AF |
171 | switch (csrno) { |
172 | case CSR_CYCLEH: | |
db70794e BM |
173 | if (!get_field(env->hcounteren, COUNTEREN_CY) && |
174 | get_field(env->mcounteren, COUNTEREN_CY)) { | |
0e62f92e | 175 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
8987cdc4 AF |
176 | } |
177 | break; | |
178 | case CSR_TIMEH: | |
db70794e BM |
179 | if (!get_field(env->hcounteren, COUNTEREN_TM) && |
180 | get_field(env->mcounteren, COUNTEREN_TM)) { | |
0e62f92e | 181 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
8987cdc4 AF |
182 | } |
183 | break; | |
184 | case CSR_INSTRETH: | |
db70794e BM |
185 | if (!get_field(env->hcounteren, COUNTEREN_IR) && |
186 | get_field(env->mcounteren, COUNTEREN_IR)) { | |
0e62f92e | 187 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
8987cdc4 AF |
188 | } |
189 | break; | |
190 | case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: | |
562009e4 AP |
191 | ctr_index = csrno - CSR_CYCLEH; |
192 | if (!get_field(env->hcounteren, 1 << ctr_index) && | |
193 | get_field(env->mcounteren, 1 << ctr_index)) { | |
0e62f92e | 194 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; |
8987cdc4 AF |
195 | } |
196 | break; | |
e39a8320 | 197 | } |
e39a8320 AF |
198 | } |
199 | } | |
a88365c1 | 200 | #endif |
0e62f92e | 201 | return RISCV_EXCP_NONE; |
a88365c1 MC |
202 | } |
203 | ||
0e62f92e | 204 | static RISCVException ctr32(CPURISCVState *env, int csrno) |
8987cdc4 | 205 | { |
db23e5d9 | 206 | if (riscv_cpu_mxl(env) != MXL_RV32) { |
0e62f92e | 207 | return RISCV_EXCP_ILLEGAL_INST; |
8987cdc4 AF |
208 | } |
209 | ||
210 | return ctr(env, csrno); | |
211 | } | |
212 | ||
a88365c1 | 213 | #if !defined(CONFIG_USER_ONLY) |
18d6d89e AP |
214 | static RISCVException mctr(CPURISCVState *env, int csrno) |
215 | { | |
216 | CPUState *cs = env_cpu(env); | |
217 | RISCVCPU *cpu = RISCV_CPU(cs); | |
218 | int ctr_index; | |
219 | int base_csrno = CSR_MHPMCOUNTER3; | |
220 | ||
221 | if ((riscv_cpu_mxl(env) == MXL_RV32) && csrno >= CSR_MCYCLEH) { | |
222 | /* Offset for RV32 mhpmcounternh counters */ | |
223 | base_csrno += 0x80; | |
224 | } | |
225 | ctr_index = csrno - base_csrno; | |
226 | if (!cpu->cfg.pmu_num || ctr_index >= cpu->cfg.pmu_num) { | |
227 | /* The PMU is not enabled or counter is out of range*/ | |
228 | return RISCV_EXCP_ILLEGAL_INST; | |
229 | } | |
230 | ||
231 | return RISCV_EXCP_NONE; | |
232 | } | |
233 | ||
621f35bb AP |
234 | static RISCVException mctr32(CPURISCVState *env, int csrno) |
235 | { | |
236 | if (riscv_cpu_mxl(env) != MXL_RV32) { | |
237 | return RISCV_EXCP_ILLEGAL_INST; | |
238 | } | |
239 | ||
240 | return mctr(env, csrno); | |
241 | } | |
242 | ||
0e62f92e | 243 | static RISCVException any(CPURISCVState *env, int csrno) |
a88365c1 | 244 | { |
0e62f92e | 245 | return RISCV_EXCP_NONE; |
a88365c1 MC |
246 | } |
247 | ||
0e62f92e | 248 | static RISCVException any32(CPURISCVState *env, int csrno) |
8987cdc4 | 249 | { |
db23e5d9 | 250 | if (riscv_cpu_mxl(env) != MXL_RV32) { |
0e62f92e | 251 | return RISCV_EXCP_ILLEGAL_INST; |
8987cdc4 AF |
252 | } |
253 | ||
254 | return any(env, csrno); | |
255 | ||
256 | } | |
257 | ||
d0237b4d AP |
258 | static int aia_any(CPURISCVState *env, int csrno) |
259 | { | |
dc9acc9c AP |
260 | RISCVCPU *cpu = env_archcpu(env); |
261 | ||
262 | if (!cpu->cfg.ext_smaia) { | |
d0237b4d AP |
263 | return RISCV_EXCP_ILLEGAL_INST; |
264 | } | |
265 | ||
266 | return any(env, csrno); | |
267 | } | |
268 | ||
d028ac75 AP |
269 | static int aia_any32(CPURISCVState *env, int csrno) |
270 | { | |
dc9acc9c AP |
271 | RISCVCPU *cpu = env_archcpu(env); |
272 | ||
273 | if (!cpu->cfg.ext_smaia) { | |
d028ac75 AP |
274 | return RISCV_EXCP_ILLEGAL_INST; |
275 | } | |
276 | ||
277 | return any32(env, csrno); | |
278 | } | |
279 | ||
0e62f92e | 280 | static RISCVException smode(CPURISCVState *env, int csrno) |
a88365c1 | 281 | { |
0e62f92e AF |
282 | if (riscv_has_ext(env, RVS)) { |
283 | return RISCV_EXCP_NONE; | |
284 | } | |
285 | ||
286 | return RISCV_EXCP_ILLEGAL_INST; | |
a88365c1 MC |
287 | } |
288 | ||
d028ac75 AP |
289 | static int smode32(CPURISCVState *env, int csrno) |
290 | { | |
291 | if (riscv_cpu_mxl(env) != MXL_RV32) { | |
292 | return RISCV_EXCP_ILLEGAL_INST; | |
293 | } | |
294 | ||
295 | return smode(env, csrno); | |
296 | } | |
297 | ||
c7de92b4 AP |
298 | static int aia_smode(CPURISCVState *env, int csrno) |
299 | { | |
dc9acc9c AP |
300 | RISCVCPU *cpu = env_archcpu(env); |
301 | ||
302 | if (!cpu->cfg.ext_ssaia) { | |
c7de92b4 AP |
303 | return RISCV_EXCP_ILLEGAL_INST; |
304 | } | |
305 | ||
306 | return smode(env, csrno); | |
307 | } | |
308 | ||
d028ac75 AP |
309 | static int aia_smode32(CPURISCVState *env, int csrno) |
310 | { | |
dc9acc9c AP |
311 | RISCVCPU *cpu = env_archcpu(env); |
312 | ||
313 | if (!cpu->cfg.ext_ssaia) { | |
d028ac75 AP |
314 | return RISCV_EXCP_ILLEGAL_INST; |
315 | } | |
316 | ||
317 | return smode32(env, csrno); | |
318 | } | |
319 | ||
0e62f92e | 320 | static RISCVException hmode(CPURISCVState *env, int csrno) |
ff2cc129 | 321 | { |
62a09b9b | 322 | if (riscv_has_ext(env, RVH)) { |
5de12453 | 323 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
324 | } |
325 | ||
0e62f92e | 326 | return RISCV_EXCP_ILLEGAL_INST; |
ff2cc129 AF |
327 | } |
328 | ||
0e62f92e | 329 | static RISCVException hmode32(CPURISCVState *env, int csrno) |
8987cdc4 | 330 | { |
db23e5d9 | 331 | if (riscv_cpu_mxl(env) != MXL_RV32) { |
62a09b9b | 332 | return RISCV_EXCP_ILLEGAL_INST; |
8987cdc4 AF |
333 | } |
334 | ||
335 | return hmode(env, csrno); | |
336 | ||
337 | } | |
338 | ||
c126f83c WL |
339 | static RISCVException umode(CPURISCVState *env, int csrno) |
340 | { | |
341 | if (riscv_has_ext(env, RVU)) { | |
342 | return RISCV_EXCP_NONE; | |
343 | } | |
344 | ||
345 | return RISCV_EXCP_ILLEGAL_INST; | |
346 | } | |
347 | ||
348 | static RISCVException umode32(CPURISCVState *env, int csrno) | |
349 | { | |
350 | if (riscv_cpu_mxl(env) != MXL_RV32) { | |
351 | return RISCV_EXCP_ILLEGAL_INST; | |
352 | } | |
353 | ||
354 | return umode(env, csrno); | |
355 | } | |
356 | ||
4bbe8033 AB |
357 | /* Checks if PointerMasking registers could be accessed */ |
358 | static RISCVException pointer_masking(CPURISCVState *env, int csrno) | |
359 | { | |
360 | /* Check if j-ext is present */ | |
361 | if (riscv_has_ext(env, RVJ)) { | |
362 | return RISCV_EXCP_NONE; | |
363 | } | |
364 | return RISCV_EXCP_ILLEGAL_INST; | |
365 | } | |
366 | ||
2b602398 AP |
367 | static int aia_hmode(CPURISCVState *env, int csrno) |
368 | { | |
dc9acc9c AP |
369 | RISCVCPU *cpu = env_archcpu(env); |
370 | ||
371 | if (!cpu->cfg.ext_ssaia) { | |
2b602398 AP |
372 | return RISCV_EXCP_ILLEGAL_INST; |
373 | } | |
374 | ||
375 | return hmode(env, csrno); | |
376 | } | |
377 | ||
d028ac75 AP |
378 | static int aia_hmode32(CPURISCVState *env, int csrno) |
379 | { | |
dc9acc9c AP |
380 | RISCVCPU *cpu = env_archcpu(env); |
381 | ||
382 | if (!cpu->cfg.ext_ssaia) { | |
d028ac75 AP |
383 | return RISCV_EXCP_ILLEGAL_INST; |
384 | } | |
385 | ||
386 | return hmode32(env, csrno); | |
387 | } | |
388 | ||
0e62f92e | 389 | static RISCVException pmp(CPURISCVState *env, int csrno) |
a88365c1 | 390 | { |
0e62f92e AF |
391 | if (riscv_feature(env, RISCV_FEATURE_PMP)) { |
392 | return RISCV_EXCP_NONE; | |
393 | } | |
394 | ||
395 | return RISCV_EXCP_ILLEGAL_INST; | |
a88365c1 | 396 | } |
2582a95c HW |
397 | |
398 | static RISCVException epmp(CPURISCVState *env, int csrno) | |
399 | { | |
400 | if (env->priv == PRV_M && riscv_feature(env, RISCV_FEATURE_EPMP)) { | |
401 | return RISCV_EXCP_NONE; | |
402 | } | |
403 | ||
404 | return RISCV_EXCP_ILLEGAL_INST; | |
405 | } | |
b6092544 BM |
406 | |
407 | static RISCVException debug(CPURISCVState *env, int csrno) | |
408 | { | |
409 | if (riscv_feature(env, RISCV_FEATURE_DEBUG)) { | |
410 | return RISCV_EXCP_NONE; | |
411 | } | |
412 | ||
413 | return RISCV_EXCP_ILLEGAL_INST; | |
414 | } | |
a88365c1 MC |
415 | #endif |
416 | ||
77442380 WL |
417 | static RISCVException seed(CPURISCVState *env, int csrno) |
418 | { | |
419 | RISCVCPU *cpu = env_archcpu(env); | |
420 | ||
421 | if (!cpu->cfg.ext_zkr) { | |
422 | return RISCV_EXCP_ILLEGAL_INST; | |
423 | } | |
424 | ||
425 | #if !defined(CONFIG_USER_ONLY) | |
426 | /* | |
427 | * With a CSR read-write instruction: | |
428 | * 1) The seed CSR is always available in machine mode as normal. | |
429 | * 2) Attempted access to seed from virtual modes VS and VU always raises | |
430 | * an exception(virtual instruction exception only if mseccfg.sseed=1). | |
431 | * 3) Without the corresponding access control bit set to 1, any attempted | |
432 | * access to seed from U, S or HS modes will raise an illegal instruction | |
433 | * exception. | |
434 | */ | |
435 | if (env->priv == PRV_M) { | |
436 | return RISCV_EXCP_NONE; | |
437 | } else if (riscv_cpu_virt_enabled(env)) { | |
438 | if (env->mseccfg & MSECCFG_SSEED) { | |
439 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; | |
440 | } else { | |
441 | return RISCV_EXCP_ILLEGAL_INST; | |
442 | } | |
443 | } else { | |
444 | if (env->priv == PRV_S && (env->mseccfg & MSECCFG_SSEED)) { | |
445 | return RISCV_EXCP_NONE; | |
446 | } else if (env->priv == PRV_U && (env->mseccfg & MSECCFG_USEED)) { | |
447 | return RISCV_EXCP_NONE; | |
448 | } else { | |
449 | return RISCV_EXCP_ILLEGAL_INST; | |
450 | } | |
451 | } | |
452 | #else | |
453 | return RISCV_EXCP_NONE; | |
454 | #endif | |
455 | } | |
456 | ||
c7b95171 | 457 | /* User Floating-Point CSRs */ |
605def6e AF |
458 | static RISCVException read_fflags(CPURISCVState *env, int csrno, |
459 | target_ulong *val) | |
c7b95171 | 460 | { |
fb738839 | 461 | *val = riscv_cpu_get_fflags(env); |
605def6e | 462 | return RISCV_EXCP_NONE; |
c7b95171 MC |
463 | } |
464 | ||
605def6e AF |
465 | static RISCVException write_fflags(CPURISCVState *env, int csrno, |
466 | target_ulong val) | |
c7b95171 MC |
467 | { |
468 | #if !defined(CONFIG_USER_ONLY) | |
c163b3ba WL |
469 | if (riscv_has_ext(env, RVF)) { |
470 | env->mstatus |= MSTATUS_FS; | |
471 | } | |
c7b95171 | 472 | #endif |
fb738839 | 473 | riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT)); |
605def6e | 474 | return RISCV_EXCP_NONE; |
c7b95171 MC |
475 | } |
476 | ||
605def6e AF |
477 | static RISCVException read_frm(CPURISCVState *env, int csrno, |
478 | target_ulong *val) | |
c7b95171 | 479 | { |
c7b95171 | 480 | *val = env->frm; |
605def6e | 481 | return RISCV_EXCP_NONE; |
c7b95171 MC |
482 | } |
483 | ||
605def6e AF |
484 | static RISCVException write_frm(CPURISCVState *env, int csrno, |
485 | target_ulong val) | |
c7b95171 MC |
486 | { |
487 | #if !defined(CONFIG_USER_ONLY) | |
c163b3ba WL |
488 | if (riscv_has_ext(env, RVF)) { |
489 | env->mstatus |= MSTATUS_FS; | |
490 | } | |
c7b95171 MC |
491 | #endif |
492 | env->frm = val & (FSR_RD >> FSR_RD_SHIFT); | |
605def6e | 493 | return RISCV_EXCP_NONE; |
c7b95171 MC |
494 | } |
495 | ||
605def6e AF |
496 | static RISCVException read_fcsr(CPURISCVState *env, int csrno, |
497 | target_ulong *val) | |
c7b95171 | 498 | { |
fb738839 | 499 | *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT) |
c7b95171 | 500 | | (env->frm << FSR_RD_SHIFT); |
605def6e | 501 | return RISCV_EXCP_NONE; |
c7b95171 MC |
502 | } |
503 | ||
605def6e AF |
504 | static RISCVException write_fcsr(CPURISCVState *env, int csrno, |
505 | target_ulong val) | |
c7b95171 MC |
506 | { |
507 | #if !defined(CONFIG_USER_ONLY) | |
c163b3ba WL |
508 | if (riscv_has_ext(env, RVF)) { |
509 | env->mstatus |= MSTATUS_FS; | |
510 | } | |
c7b95171 MC |
511 | #endif |
512 | env->frm = (val & FSR_RD) >> FSR_RD_SHIFT; | |
fb738839 | 513 | riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT); |
605def6e | 514 | return RISCV_EXCP_NONE; |
c7b95171 MC |
515 | } |
516 | ||
605def6e AF |
517 | static RISCVException read_vtype(CPURISCVState *env, int csrno, |
518 | target_ulong *val) | |
8e3a1f18 | 519 | { |
d96a271a LZ |
520 | uint64_t vill; |
521 | switch (env->xl) { | |
522 | case MXL_RV32: | |
523 | vill = (uint32_t)env->vill << 31; | |
524 | break; | |
525 | case MXL_RV64: | |
526 | vill = (uint64_t)env->vill << 63; | |
527 | break; | |
528 | default: | |
529 | g_assert_not_reached(); | |
530 | } | |
531 | *val = (target_ulong)vill | env->vtype; | |
605def6e | 532 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
533 | } |
534 | ||
605def6e AF |
535 | static RISCVException read_vl(CPURISCVState *env, int csrno, |
536 | target_ulong *val) | |
8e3a1f18 LZ |
537 | { |
538 | *val = env->vl; | |
605def6e | 539 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
540 | } |
541 | ||
2e565054 GH |
542 | static int read_vlenb(CPURISCVState *env, int csrno, target_ulong *val) |
543 | { | |
544 | *val = env_archcpu(env)->cfg.vlen >> 3; | |
545 | return RISCV_EXCP_NONE; | |
546 | } | |
547 | ||
605def6e AF |
548 | static RISCVException read_vxrm(CPURISCVState *env, int csrno, |
549 | target_ulong *val) | |
8e3a1f18 LZ |
550 | { |
551 | *val = env->vxrm; | |
605def6e | 552 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
553 | } |
554 | ||
605def6e AF |
555 | static RISCVException write_vxrm(CPURISCVState *env, int csrno, |
556 | target_ulong val) | |
8e3a1f18 | 557 | { |
61b4b69d LZ |
558 | #if !defined(CONFIG_USER_ONLY) |
559 | env->mstatus |= MSTATUS_VS; | |
560 | #endif | |
8e3a1f18 | 561 | env->vxrm = val; |
605def6e | 562 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
563 | } |
564 | ||
605def6e AF |
565 | static RISCVException read_vxsat(CPURISCVState *env, int csrno, |
566 | target_ulong *val) | |
8e3a1f18 LZ |
567 | { |
568 | *val = env->vxsat; | |
605def6e | 569 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
570 | } |
571 | ||
605def6e AF |
572 | static RISCVException write_vxsat(CPURISCVState *env, int csrno, |
573 | target_ulong val) | |
8e3a1f18 | 574 | { |
61b4b69d LZ |
575 | #if !defined(CONFIG_USER_ONLY) |
576 | env->mstatus |= MSTATUS_VS; | |
577 | #endif | |
8e3a1f18 | 578 | env->vxsat = val; |
605def6e | 579 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
580 | } |
581 | ||
605def6e AF |
582 | static RISCVException read_vstart(CPURISCVState *env, int csrno, |
583 | target_ulong *val) | |
8e3a1f18 LZ |
584 | { |
585 | *val = env->vstart; | |
605def6e | 586 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
587 | } |
588 | ||
605def6e AF |
589 | static RISCVException write_vstart(CPURISCVState *env, int csrno, |
590 | target_ulong val) | |
8e3a1f18 | 591 | { |
61b4b69d LZ |
592 | #if !defined(CONFIG_USER_ONLY) |
593 | env->mstatus |= MSTATUS_VS; | |
594 | #endif | |
f714361e FC |
595 | /* |
596 | * The vstart CSR is defined to have only enough writable bits | |
597 | * to hold the largest element index, i.e. lg2(VLEN) bits. | |
598 | */ | |
599 | env->vstart = val & ~(~0ULL << ctzl(env_archcpu(env)->cfg.vlen)); | |
605def6e | 600 | return RISCV_EXCP_NONE; |
8e3a1f18 LZ |
601 | } |
602 | ||
4594fa5a LZ |
603 | static int read_vcsr(CPURISCVState *env, int csrno, target_ulong *val) |
604 | { | |
605 | *val = (env->vxrm << VCSR_VXRM_SHIFT) | (env->vxsat << VCSR_VXSAT_SHIFT); | |
606 | return RISCV_EXCP_NONE; | |
607 | } | |
608 | ||
609 | static int write_vcsr(CPURISCVState *env, int csrno, target_ulong val) | |
610 | { | |
611 | #if !defined(CONFIG_USER_ONLY) | |
612 | env->mstatus |= MSTATUS_VS; | |
613 | #endif | |
614 | env->vxrm = (val & VCSR_VXRM) >> VCSR_VXRM_SHIFT; | |
615 | env->vxsat = (val & VCSR_VXSAT) >> VCSR_VXSAT_SHIFT; | |
616 | return RISCV_EXCP_NONE; | |
617 | } | |
618 | ||
c7b95171 | 619 | /* User Timers and Counters */ |
3780e337 | 620 | static target_ulong get_ticks(bool shift) |
c7b95171 | 621 | { |
3780e337 AP |
622 | int64_t val; |
623 | target_ulong result; | |
624 | ||
c7b95171 | 625 | #if !defined(CONFIG_USER_ONLY) |
740b1759 | 626 | if (icount_enabled()) { |
3780e337 | 627 | val = icount_get(); |
c7b95171 | 628 | } else { |
3780e337 | 629 | val = cpu_get_host_ticks(); |
c7b95171 MC |
630 | } |
631 | #else | |
3780e337 | 632 | val = cpu_get_host_ticks(); |
c7b95171 | 633 | #endif |
c7b95171 | 634 | |
3780e337 AP |
635 | if (shift) { |
636 | result = val >> 32; | |
c7b95171 | 637 | } else { |
3780e337 | 638 | result = val; |
c7b95171 | 639 | } |
3780e337 AP |
640 | |
641 | return result; | |
c7b95171 | 642 | } |
c7b95171 MC |
643 | |
644 | #if defined(CONFIG_USER_ONLY) | |
605def6e AF |
645 | static RISCVException read_time(CPURISCVState *env, int csrno, |
646 | target_ulong *val) | |
c7b95171 MC |
647 | { |
648 | *val = cpu_get_host_ticks(); | |
605def6e | 649 | return RISCV_EXCP_NONE; |
c7b95171 MC |
650 | } |
651 | ||
605def6e AF |
652 | static RISCVException read_timeh(CPURISCVState *env, int csrno, |
653 | target_ulong *val) | |
c7b95171 MC |
654 | { |
655 | *val = cpu_get_host_ticks() >> 32; | |
605def6e | 656 | return RISCV_EXCP_NONE; |
c7b95171 | 657 | } |
c7b95171 | 658 | |
3780e337 AP |
659 | static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) |
660 | { | |
661 | *val = get_ticks(false); | |
662 | return RISCV_EXCP_NONE; | |
663 | } | |
664 | ||
665 | static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) | |
666 | { | |
667 | *val = get_ticks(true); | |
668 | return RISCV_EXCP_NONE; | |
669 | } | |
670 | ||
c7b95171 MC |
671 | #else /* CONFIG_USER_ONLY */ |
672 | ||
621f35bb AP |
673 | static int read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) |
674 | { | |
3780e337 | 675 | int evt_index = csrno - CSR_MCOUNTINHIBIT; |
621f35bb AP |
676 | |
677 | *val = env->mhpmevent_val[evt_index]; | |
678 | ||
679 | return RISCV_EXCP_NONE; | |
680 | } | |
681 | ||
682 | static int write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val) | |
683 | { | |
3780e337 | 684 | int evt_index = csrno - CSR_MCOUNTINHIBIT; |
621f35bb AP |
685 | |
686 | env->mhpmevent_val[evt_index] = val; | |
687 | ||
688 | return RISCV_EXCP_NONE; | |
689 | } | |
690 | ||
691 | static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val) | |
692 | { | |
3780e337 AP |
693 | int ctr_idx = csrno - CSR_MCYCLE; |
694 | PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; | |
621f35bb | 695 | |
3780e337 AP |
696 | counter->mhpmcounter_val = val; |
697 | if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || | |
698 | riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { | |
699 | counter->mhpmcounter_prev = get_ticks(false); | |
700 | } else { | |
701 | /* Other counters can keep incrementing from the given value */ | |
702 | counter->mhpmcounter_prev = val; | |
703 | } | |
621f35bb AP |
704 | |
705 | return RISCV_EXCP_NONE; | |
706 | } | |
707 | ||
708 | static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val) | |
709 | { | |
3780e337 AP |
710 | int ctr_idx = csrno - CSR_MCYCLEH; |
711 | PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; | |
621f35bb | 712 | |
3780e337 AP |
713 | counter->mhpmcounterh_val = val; |
714 | if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || | |
715 | riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { | |
716 | counter->mhpmcounterh_prev = get_ticks(true); | |
717 | } else { | |
718 | counter->mhpmcounterh_prev = val; | |
719 | } | |
720 | ||
721 | return RISCV_EXCP_NONE; | |
722 | } | |
723 | ||
724 | static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, | |
725 | bool upper_half, uint32_t ctr_idx) | |
726 | { | |
727 | PMUCTRState counter = env->pmu_ctrs[ctr_idx]; | |
728 | target_ulong ctr_prev = upper_half ? counter.mhpmcounterh_prev : | |
729 | counter.mhpmcounter_prev; | |
730 | target_ulong ctr_val = upper_half ? counter.mhpmcounterh_val : | |
731 | counter.mhpmcounter_val; | |
732 | ||
733 | if (get_field(env->mcountinhibit, BIT(ctr_idx))) { | |
734 | /** | |
735 | * Counter should not increment if inhibit bit is set. We can't really | |
736 | * stop the icount counting. Just return the counter value written by | |
737 | * the supervisor to indicate that counter was not incremented. | |
738 | */ | |
739 | if (!counter.started) { | |
740 | *val = ctr_val; | |
741 | return RISCV_EXCP_NONE; | |
742 | } else { | |
743 | /* Mark that the counter has been stopped */ | |
744 | counter.started = false; | |
745 | } | |
746 | } | |
747 | ||
748 | /** | |
749 | * The kernel computes the perf delta by subtracting the current value from | |
750 | * the value it initialized previously (ctr_val). | |
751 | */ | |
752 | if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || | |
753 | riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { | |
754 | *val = get_ticks(upper_half) - ctr_prev + ctr_val; | |
755 | } else { | |
756 | *val = ctr_val; | |
757 | } | |
621f35bb AP |
758 | |
759 | return RISCV_EXCP_NONE; | |
760 | } | |
761 | ||
762 | static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) | |
763 | { | |
3780e337 | 764 | uint16_t ctr_index; |
621f35bb AP |
765 | |
766 | if (csrno >= CSR_MCYCLE && csrno <= CSR_MHPMCOUNTER31) { | |
3780e337 | 767 | ctr_index = csrno - CSR_MCYCLE; |
621f35bb | 768 | } else if (csrno >= CSR_CYCLE && csrno <= CSR_HPMCOUNTER31) { |
3780e337 | 769 | ctr_index = csrno - CSR_CYCLE; |
621f35bb AP |
770 | } else { |
771 | return RISCV_EXCP_ILLEGAL_INST; | |
772 | } | |
621f35bb | 773 | |
3780e337 | 774 | return riscv_pmu_read_ctr(env, val, false, ctr_index); |
621f35bb AP |
775 | } |
776 | ||
777 | static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) | |
778 | { | |
3780e337 | 779 | uint16_t ctr_index; |
621f35bb AP |
780 | |
781 | if (csrno >= CSR_MCYCLEH && csrno <= CSR_MHPMCOUNTER31H) { | |
3780e337 | 782 | ctr_index = csrno - CSR_MCYCLEH; |
621f35bb | 783 | } else if (csrno >= CSR_CYCLEH && csrno <= CSR_HPMCOUNTER31H) { |
3780e337 | 784 | ctr_index = csrno - CSR_CYCLEH; |
621f35bb AP |
785 | } else { |
786 | return RISCV_EXCP_ILLEGAL_INST; | |
787 | } | |
621f35bb | 788 | |
3780e337 | 789 | return riscv_pmu_read_ctr(env, val, true, ctr_index); |
621f35bb AP |
790 | } |
791 | ||
605def6e AF |
792 | static RISCVException read_time(CPURISCVState *env, int csrno, |
793 | target_ulong *val) | |
c6957248 AP |
794 | { |
795 | uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; | |
796 | ||
797 | if (!env->rdtime_fn) { | |
605def6e | 798 | return RISCV_EXCP_ILLEGAL_INST; |
c6957248 AP |
799 | } |
800 | ||
a47ef6e9 | 801 | *val = env->rdtime_fn(env->rdtime_fn_arg) + delta; |
605def6e | 802 | return RISCV_EXCP_NONE; |
c6957248 AP |
803 | } |
804 | ||
605def6e AF |
805 | static RISCVException read_timeh(CPURISCVState *env, int csrno, |
806 | target_ulong *val) | |
c6957248 AP |
807 | { |
808 | uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; | |
809 | ||
810 | if (!env->rdtime_fn) { | |
605def6e | 811 | return RISCV_EXCP_ILLEGAL_INST; |
c6957248 AP |
812 | } |
813 | ||
a47ef6e9 | 814 | *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32; |
605def6e | 815 | return RISCV_EXCP_NONE; |
c6957248 | 816 | } |
c6957248 | 817 | |
c7b95171 MC |
818 | /* Machine constants */ |
819 | ||
d028ac75 AP |
820 | #define M_MODE_INTERRUPTS ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP)) |
821 | #define S_MODE_INTERRUPTS ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP)) | |
822 | #define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) | |
823 | #define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS)) | |
c7b95171 | 824 | |
c7de92b4 AP |
825 | #define VSTOPI_NUM_SRCS 5 |
826 | ||
d028ac75 | 827 | static const uint64_t delegable_ints = S_MODE_INTERRUPTS | |
d0e53ce3 | 828 | VS_MODE_INTERRUPTS; |
d028ac75 AP |
829 | static const uint64_t vs_delegable_ints = VS_MODE_INTERRUPTS; |
830 | static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | | |
881df35d | 831 | HS_MODE_INTERRUPTS; |
bc083a51 JM |
832 | #define DELEGABLE_EXCPS ((1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | \ |
833 | (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | \ | |
834 | (1ULL << (RISCV_EXCP_ILLEGAL_INST)) | \ | |
835 | (1ULL << (RISCV_EXCP_BREAKPOINT)) | \ | |
836 | (1ULL << (RISCV_EXCP_LOAD_ADDR_MIS)) | \ | |
837 | (1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT)) | \ | |
838 | (1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS)) | \ | |
839 | (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) | \ | |
840 | (1ULL << (RISCV_EXCP_U_ECALL)) | \ | |
841 | (1ULL << (RISCV_EXCP_S_ECALL)) | \ | |
842 | (1ULL << (RISCV_EXCP_VS_ECALL)) | \ | |
843 | (1ULL << (RISCV_EXCP_M_ECALL)) | \ | |
844 | (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | \ | |
845 | (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | \ | |
846 | (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | \ | |
847 | (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | \ | |
848 | (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | \ | |
849 | (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | \ | |
850 | (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT))) | |
851 | static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS & | |
852 | ~((1ULL << (RISCV_EXCP_S_ECALL)) | | |
853 | (1ULL << (RISCV_EXCP_VS_ECALL)) | | |
854 | (1ULL << (RISCV_EXCP_M_ECALL)) | | |
855 | (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | | |
856 | (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | | |
857 | (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | | |
858 | (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT))); | |
c7b95171 MC |
859 | static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | |
860 | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | | |
f310df58 | 861 | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS; |
087b051a | 862 | static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; |
e89b631c GK |
863 | static const target_ulong hip_writable_mask = MIP_VSSIP; |
864 | static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; | |
8747c9ee | 865 | static const target_ulong vsip_writable_mask = MIP_VSSIP; |
c7b95171 | 866 | |
8987cdc4 | 867 | static const char valid_vm_1_10_32[16] = { |
c7b95171 MC |
868 | [VM_1_10_MBARE] = 1, |
869 | [VM_1_10_SV32] = 1 | |
870 | }; | |
8987cdc4 AF |
871 | |
872 | static const char valid_vm_1_10_64[16] = { | |
c7b95171 MC |
873 | [VM_1_10_MBARE] = 1, |
874 | [VM_1_10_SV39] = 1, | |
875 | [VM_1_10_SV48] = 1, | |
876 | [VM_1_10_SV57] = 1 | |
877 | }; | |
c7b95171 MC |
878 | |
879 | /* Machine Information Registers */ | |
605def6e AF |
880 | static RISCVException read_zero(CPURISCVState *env, int csrno, |
881 | target_ulong *val) | |
c7b95171 | 882 | { |
605def6e AF |
883 | *val = 0; |
884 | return RISCV_EXCP_NONE; | |
c7b95171 MC |
885 | } |
886 | ||
d0237b4d AP |
887 | static RISCVException write_ignore(CPURISCVState *env, int csrno, |
888 | target_ulong val) | |
889 | { | |
890 | return RISCV_EXCP_NONE; | |
891 | } | |
892 | ||
9951ba94 FC |
893 | static RISCVException read_mvendorid(CPURISCVState *env, int csrno, |
894 | target_ulong *val) | |
895 | { | |
896 | CPUState *cs = env_cpu(env); | |
897 | RISCVCPU *cpu = RISCV_CPU(cs); | |
898 | ||
899 | *val = cpu->cfg.mvendorid; | |
900 | return RISCV_EXCP_NONE; | |
901 | } | |
902 | ||
903 | static RISCVException read_marchid(CPURISCVState *env, int csrno, | |
904 | target_ulong *val) | |
905 | { | |
906 | CPUState *cs = env_cpu(env); | |
907 | RISCVCPU *cpu = RISCV_CPU(cs); | |
908 | ||
909 | *val = cpu->cfg.marchid; | |
910 | return RISCV_EXCP_NONE; | |
911 | } | |
912 | ||
075eeda9 FC |
913 | static RISCVException read_mimpid(CPURISCVState *env, int csrno, |
914 | target_ulong *val) | |
9951ba94 FC |
915 | { |
916 | CPUState *cs = env_cpu(env); | |
917 | RISCVCPU *cpu = RISCV_CPU(cs); | |
918 | ||
075eeda9 | 919 | *val = cpu->cfg.mimpid; |
9951ba94 FC |
920 | return RISCV_EXCP_NONE; |
921 | } | |
922 | ||
605def6e AF |
923 | static RISCVException read_mhartid(CPURISCVState *env, int csrno, |
924 | target_ulong *val) | |
c7b95171 MC |
925 | { |
926 | *val = env->mhartid; | |
605def6e | 927 | return RISCV_EXCP_NONE; |
c7b95171 MC |
928 | } |
929 | ||
930 | /* Machine Trap Setup */ | |
b550f894 RH |
931 | |
932 | /* We do not store SD explicitly, only compute it on demand. */ | |
933 | static uint64_t add_status_sd(RISCVMXL xl, uint64_t status) | |
934 | { | |
935 | if ((status & MSTATUS_FS) == MSTATUS_FS || | |
c36b2f1a | 936 | (status & MSTATUS_VS) == MSTATUS_VS || |
b550f894 RH |
937 | (status & MSTATUS_XS) == MSTATUS_XS) { |
938 | switch (xl) { | |
939 | case MXL_RV32: | |
940 | return status | MSTATUS32_SD; | |
941 | case MXL_RV64: | |
942 | return status | MSTATUS64_SD; | |
457c360f FP |
943 | case MXL_RV128: |
944 | return MSTATUSH128_SD; | |
b550f894 RH |
945 | default: |
946 | g_assert_not_reached(); | |
947 | } | |
948 | } | |
949 | return status; | |
950 | } | |
951 | ||
605def6e AF |
952 | static RISCVException read_mstatus(CPURISCVState *env, int csrno, |
953 | target_ulong *val) | |
c7b95171 | 954 | { |
b550f894 | 955 | *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus); |
605def6e | 956 | return RISCV_EXCP_NONE; |
c7b95171 MC |
957 | } |
958 | ||
959 | static int validate_vm(CPURISCVState *env, target_ulong vm) | |
960 | { | |
db23e5d9 | 961 | if (riscv_cpu_mxl(env) == MXL_RV32) { |
8987cdc4 AF |
962 | return valid_vm_1_10_32[vm & 0xf]; |
963 | } else { | |
964 | return valid_vm_1_10_64[vm & 0xf]; | |
965 | } | |
c7b95171 MC |
966 | } |
967 | ||
605def6e AF |
968 | static RISCVException write_mstatus(CPURISCVState *env, int csrno, |
969 | target_ulong val) | |
c7b95171 | 970 | { |
284d697c YJ |
971 | uint64_t mstatus = env->mstatus; |
972 | uint64_t mask = 0; | |
f310df58 | 973 | RISCVMXL xl = riscv_cpu_mxl(env); |
c7b95171 MC |
974 | |
975 | /* flush tlb on mstatus fields that affect VM */ | |
1a9540d1 AF |
976 | if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV | |
977 | MSTATUS_MPRV | MSTATUS_SUM)) { | |
978 | tlb_flush(env_cpu(env)); | |
c7b95171 | 979 | } |
1a9540d1 | 980 | mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE | |
c163b3ba | 981 | MSTATUS_SPP | MSTATUS_MPRV | MSTATUS_SUM | |
1a9540d1 | 982 | MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR | |
61b4b69d | 983 | MSTATUS_TW | MSTATUS_VS; |
8987cdc4 | 984 | |
c163b3ba WL |
985 | if (riscv_has_ext(env, RVF)) { |
986 | mask |= MSTATUS_FS; | |
987 | } | |
988 | ||
f297245f | 989 | if (xl != MXL_RV32 || env->debugger) { |
8987cdc4 AF |
990 | /* |
991 | * RV32: MPV and GVA are not in mstatus. The current plan is to | |
992 | * add them to mstatush. For now, we just don't support it. | |
993 | */ | |
994 | mask |= MSTATUS_MPV | MSTATUS_GVA; | |
f310df58 LZ |
995 | if ((val & MSTATUS64_UXL) != 0) { |
996 | mask |= MSTATUS64_UXL; | |
997 | } | |
8987cdc4 | 998 | } |
c7b95171 MC |
999 | |
1000 | mstatus = (mstatus & ~mask) | (val & mask); | |
1001 | ||
457c360f | 1002 | if (xl > MXL_RV32) { |
f310df58 | 1003 | /* SXL field is for now read only */ |
457c360f | 1004 | mstatus = set_field(mstatus, MSTATUS64_SXL, xl); |
4fd7455b | 1005 | } |
c7b95171 | 1006 | env->mstatus = mstatus; |
440544e1 | 1007 | env->xl = cpu_recompute_xl(env); |
c7b95171 | 1008 | |
605def6e | 1009 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1010 | } |
1011 | ||
605def6e AF |
1012 | static RISCVException read_mstatush(CPURISCVState *env, int csrno, |
1013 | target_ulong *val) | |
551fa7e8 | 1014 | { |
284d697c | 1015 | *val = env->mstatus >> 32; |
605def6e | 1016 | return RISCV_EXCP_NONE; |
551fa7e8 AF |
1017 | } |
1018 | ||
605def6e AF |
1019 | static RISCVException write_mstatush(CPURISCVState *env, int csrno, |
1020 | target_ulong val) | |
551fa7e8 | 1021 | { |
284d697c YJ |
1022 | uint64_t valh = (uint64_t)val << 32; |
1023 | uint64_t mask = MSTATUS_MPV | MSTATUS_GVA; | |
1024 | ||
1025 | if ((valh ^ env->mstatus) & (MSTATUS_MPV)) { | |
551fa7e8 AF |
1026 | tlb_flush(env_cpu(env)); |
1027 | } | |
1028 | ||
284d697c | 1029 | env->mstatus = (env->mstatus & ~mask) | (valh & mask); |
551fa7e8 | 1030 | |
605def6e | 1031 | return RISCV_EXCP_NONE; |
551fa7e8 | 1032 | } |
551fa7e8 | 1033 | |
457c360f FP |
1034 | static RISCVException read_mstatus_i128(CPURISCVState *env, int csrno, |
1035 | Int128 *val) | |
1036 | { | |
1037 | *val = int128_make128(env->mstatus, add_status_sd(MXL_RV128, env->mstatus)); | |
1038 | return RISCV_EXCP_NONE; | |
1039 | } | |
1040 | ||
1041 | static RISCVException read_misa_i128(CPURISCVState *env, int csrno, | |
1042 | Int128 *val) | |
1043 | { | |
1044 | *val = int128_make128(env->misa_ext, (uint64_t)MXL_RV128 << 62); | |
1045 | return RISCV_EXCP_NONE; | |
1046 | } | |
1047 | ||
605def6e AF |
1048 | static RISCVException read_misa(CPURISCVState *env, int csrno, |
1049 | target_ulong *val) | |
c7b95171 | 1050 | { |
e91a7227 RH |
1051 | target_ulong misa; |
1052 | ||
1053 | switch (env->misa_mxl) { | |
1054 | case MXL_RV32: | |
1055 | misa = (target_ulong)MXL_RV32 << 30; | |
1056 | break; | |
1057 | #ifdef TARGET_RISCV64 | |
1058 | case MXL_RV64: | |
1059 | misa = (target_ulong)MXL_RV64 << 62; | |
1060 | break; | |
1061 | #endif | |
1062 | default: | |
1063 | g_assert_not_reached(); | |
1064 | } | |
1065 | ||
1066 | *val = misa | env->misa_ext; | |
605def6e | 1067 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1068 | } |
1069 | ||
605def6e AF |
1070 | static RISCVException write_misa(CPURISCVState *env, int csrno, |
1071 | target_ulong val) | |
f18637cd MC |
1072 | { |
1073 | if (!riscv_feature(env, RISCV_FEATURE_MISA)) { | |
1074 | /* drop write to misa */ | |
605def6e | 1075 | return RISCV_EXCP_NONE; |
f18637cd MC |
1076 | } |
1077 | ||
1078 | /* 'I' or 'E' must be present */ | |
1079 | if (!(val & (RVI | RVE))) { | |
1080 | /* It is not, drop write to misa */ | |
605def6e | 1081 | return RISCV_EXCP_NONE; |
f18637cd MC |
1082 | } |
1083 | ||
1084 | /* 'E' excludes all other extensions */ | |
1085 | if (val & RVE) { | |
1086 | /* when we support 'E' we can do "val = RVE;" however | |
1087 | * for now we just drop writes if 'E' is present. | |
1088 | */ | |
605def6e | 1089 | return RISCV_EXCP_NONE; |
f18637cd MC |
1090 | } |
1091 | ||
e91a7227 RH |
1092 | /* |
1093 | * misa.MXL writes are not supported by QEMU. | |
1094 | * Drop writes to those bits. | |
1095 | */ | |
1096 | ||
f18637cd | 1097 | /* Mask extensions that are not supported by this hart */ |
e91a7227 | 1098 | val &= env->misa_ext_mask; |
f18637cd MC |
1099 | |
1100 | /* Mask extensions that are not supported by QEMU */ | |
7b07a37c | 1101 | val &= (RVI | RVE | RVM | RVA | RVF | RVD | RVC | RVS | RVU | RVV); |
f18637cd MC |
1102 | |
1103 | /* 'D' depends on 'F', so clear 'D' if 'F' is not present */ | |
1104 | if ((val & RVD) && !(val & RVF)) { | |
1105 | val &= ~RVD; | |
1106 | } | |
1107 | ||
1108 | /* Suppress 'C' if next instruction is not aligned | |
1109 | * TODO: this should check next_pc | |
1110 | */ | |
1111 | if ((val & RVC) && (GETPC() & ~3) != 0) { | |
1112 | val &= ~RVC; | |
1113 | } | |
1114 | ||
e91a7227 RH |
1115 | /* If nothing changed, do nothing. */ |
1116 | if (val == env->misa_ext) { | |
1117 | return RISCV_EXCP_NONE; | |
4fd7455b | 1118 | } |
f18637cd | 1119 | |
c163b3ba WL |
1120 | if (!(val & RVF)) { |
1121 | env->mstatus &= ~MSTATUS_FS; | |
1122 | } | |
1123 | ||
f18637cd | 1124 | /* flush translation cache */ |
e91a7227 RH |
1125 | tb_flush(env_cpu(env)); |
1126 | env->misa_ext = val; | |
440544e1 | 1127 | env->xl = riscv_cpu_mxl(env); |
605def6e | 1128 | return RISCV_EXCP_NONE; |
f18637cd MC |
1129 | } |
1130 | ||
605def6e AF |
1131 | static RISCVException read_medeleg(CPURISCVState *env, int csrno, |
1132 | target_ulong *val) | |
c7b95171 MC |
1133 | { |
1134 | *val = env->medeleg; | |
605def6e | 1135 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1136 | } |
1137 | ||
605def6e AF |
1138 | static RISCVException write_medeleg(CPURISCVState *env, int csrno, |
1139 | target_ulong val) | |
c7b95171 | 1140 | { |
bc083a51 | 1141 | env->medeleg = (env->medeleg & ~DELEGABLE_EXCPS) | (val & DELEGABLE_EXCPS); |
605def6e | 1142 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1143 | } |
1144 | ||
d028ac75 AP |
1145 | static RISCVException rmw_mideleg64(CPURISCVState *env, int csrno, |
1146 | uint64_t *ret_val, | |
1147 | uint64_t new_val, uint64_t wr_mask) | |
c7b95171 | 1148 | { |
d028ac75 AP |
1149 | uint64_t mask = wr_mask & delegable_ints; |
1150 | ||
1151 | if (ret_val) { | |
1152 | *ret_val = env->mideleg; | |
1153 | } | |
1154 | ||
1155 | env->mideleg = (env->mideleg & ~mask) | (new_val & mask); | |
c7b95171 | 1156 | |
713d8363 | 1157 | if (riscv_has_ext(env, RVH)) { |
881df35d | 1158 | env->mideleg |= HS_MODE_INTERRUPTS; |
713d8363 | 1159 | } |
d028ac75 | 1160 | |
605def6e | 1161 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1162 | } |
1163 | ||
d028ac75 AP |
1164 | static RISCVException rmw_mideleg(CPURISCVState *env, int csrno, |
1165 | target_ulong *ret_val, | |
1166 | target_ulong new_val, target_ulong wr_mask) | |
c7b95171 | 1167 | { |
d028ac75 AP |
1168 | uint64_t rval; |
1169 | RISCVException ret; | |
1170 | ||
1171 | ret = rmw_mideleg64(env, csrno, &rval, new_val, wr_mask); | |
1172 | if (ret_val) { | |
1173 | *ret_val = rval; | |
1174 | } | |
1175 | ||
1176 | return ret; | |
c7b95171 MC |
1177 | } |
1178 | ||
d028ac75 AP |
1179 | static RISCVException rmw_midelegh(CPURISCVState *env, int csrno, |
1180 | target_ulong *ret_val, | |
1181 | target_ulong new_val, | |
1182 | target_ulong wr_mask) | |
c7b95171 | 1183 | { |
d028ac75 AP |
1184 | uint64_t rval; |
1185 | RISCVException ret; | |
1186 | ||
1187 | ret = rmw_mideleg64(env, csrno, &rval, | |
1188 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
1189 | if (ret_val) { | |
1190 | *ret_val = rval >> 32; | |
1191 | } | |
1192 | ||
1193 | return ret; | |
1194 | } | |
1195 | ||
1196 | static RISCVException rmw_mie64(CPURISCVState *env, int csrno, | |
1197 | uint64_t *ret_val, | |
1198 | uint64_t new_val, uint64_t wr_mask) | |
1199 | { | |
1200 | uint64_t mask = wr_mask & all_ints; | |
1201 | ||
1202 | if (ret_val) { | |
1203 | *ret_val = env->mie; | |
1204 | } | |
1205 | ||
1206 | env->mie = (env->mie & ~mask) | (new_val & mask); | |
1207 | ||
881df35d | 1208 | if (!riscv_has_ext(env, RVH)) { |
d028ac75 | 1209 | env->mie &= ~((uint64_t)MIP_SGEIP); |
881df35d | 1210 | } |
d028ac75 | 1211 | |
605def6e | 1212 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1213 | } |
1214 | ||
d028ac75 AP |
1215 | static RISCVException rmw_mie(CPURISCVState *env, int csrno, |
1216 | target_ulong *ret_val, | |
1217 | target_ulong new_val, target_ulong wr_mask) | |
1218 | { | |
1219 | uint64_t rval; | |
1220 | RISCVException ret; | |
1221 | ||
1222 | ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask); | |
1223 | if (ret_val) { | |
1224 | *ret_val = rval; | |
1225 | } | |
1226 | ||
1227 | return ret; | |
1228 | } | |
1229 | ||
1230 | static RISCVException rmw_mieh(CPURISCVState *env, int csrno, | |
1231 | target_ulong *ret_val, | |
1232 | target_ulong new_val, target_ulong wr_mask) | |
1233 | { | |
1234 | uint64_t rval; | |
1235 | RISCVException ret; | |
1236 | ||
1237 | ret = rmw_mie64(env, csrno, &rval, | |
1238 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
1239 | if (ret_val) { | |
1240 | *ret_val = rval >> 32; | |
1241 | } | |
1242 | ||
1243 | return ret; | |
1244 | } | |
1245 | ||
c7de92b4 AP |
1246 | static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) |
1247 | { | |
1248 | int irq; | |
1249 | uint8_t iprio; | |
1250 | ||
1251 | irq = riscv_cpu_mirq_pending(env); | |
1252 | if (irq <= 0 || irq > 63) { | |
1253 | *val = 0; | |
1254 | } else { | |
1255 | iprio = env->miprio[irq]; | |
1256 | if (!iprio) { | |
1257 | if (riscv_cpu_default_priority(irq) > IPRIO_DEFAULT_M) { | |
1258 | iprio = IPRIO_MMAXIPRIO; | |
1259 | } | |
1260 | } | |
1261 | *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; | |
1262 | *val |= iprio; | |
1263 | } | |
1264 | ||
1265 | return RISCV_EXCP_NONE; | |
1266 | } | |
1267 | ||
d1ceff40 AP |
1268 | static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno) |
1269 | { | |
1270 | if (!riscv_cpu_virt_enabled(env)) { | |
1271 | return csrno; | |
1272 | } | |
1273 | ||
1274 | switch (csrno) { | |
1275 | case CSR_SISELECT: | |
1276 | return CSR_VSISELECT; | |
1277 | case CSR_SIREG: | |
1278 | return CSR_VSIREG; | |
ac4b0302 AP |
1279 | case CSR_STOPEI: |
1280 | return CSR_VSTOPEI; | |
d1ceff40 AP |
1281 | default: |
1282 | return csrno; | |
1283 | }; | |
1284 | } | |
1285 | ||
1286 | static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, | |
1287 | target_ulong new_val, target_ulong wr_mask) | |
1288 | { | |
1289 | target_ulong *iselect; | |
1290 | ||
1291 | /* Translate CSR number for VS-mode */ | |
1292 | csrno = aia_xlate_vs_csrno(env, csrno); | |
1293 | ||
1294 | /* Find the iselect CSR based on CSR number */ | |
1295 | switch (csrno) { | |
1296 | case CSR_MISELECT: | |
1297 | iselect = &env->miselect; | |
1298 | break; | |
1299 | case CSR_SISELECT: | |
1300 | iselect = &env->siselect; | |
1301 | break; | |
1302 | case CSR_VSISELECT: | |
1303 | iselect = &env->vsiselect; | |
1304 | break; | |
1305 | default: | |
1306 | return RISCV_EXCP_ILLEGAL_INST; | |
1307 | }; | |
1308 | ||
1309 | if (val) { | |
1310 | *val = *iselect; | |
1311 | } | |
1312 | ||
1313 | wr_mask &= ISELECT_MASK; | |
1314 | if (wr_mask) { | |
1315 | *iselect = (*iselect & ~wr_mask) | (new_val & wr_mask); | |
1316 | } | |
1317 | ||
1318 | return RISCV_EXCP_NONE; | |
1319 | } | |
1320 | ||
1321 | static int rmw_iprio(target_ulong xlen, | |
1322 | target_ulong iselect, uint8_t *iprio, | |
1323 | target_ulong *val, target_ulong new_val, | |
1324 | target_ulong wr_mask, int ext_irq_no) | |
1325 | { | |
1326 | int i, firq, nirqs; | |
1327 | target_ulong old_val; | |
1328 | ||
1329 | if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) { | |
1330 | return -EINVAL; | |
1331 | } | |
1332 | if (xlen != 32 && iselect & 0x1) { | |
1333 | return -EINVAL; | |
1334 | } | |
1335 | ||
1336 | nirqs = 4 * (xlen / 32); | |
1337 | firq = ((iselect - ISELECT_IPRIO0) / (xlen / 32)) * (nirqs); | |
1338 | ||
1339 | old_val = 0; | |
1340 | for (i = 0; i < nirqs; i++) { | |
1341 | old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i); | |
1342 | } | |
1343 | ||
1344 | if (val) { | |
1345 | *val = old_val; | |
1346 | } | |
1347 | ||
1348 | if (wr_mask) { | |
1349 | new_val = (old_val & ~wr_mask) | (new_val & wr_mask); | |
1350 | for (i = 0; i < nirqs; i++) { | |
1351 | /* | |
1352 | * M-level and S-level external IRQ priority always read-only | |
1353 | * zero. This means default priority order is always preferred | |
1354 | * for M-level and S-level external IRQs. | |
1355 | */ | |
1356 | if ((firq + i) == ext_irq_no) { | |
1357 | continue; | |
1358 | } | |
1359 | iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff; | |
1360 | } | |
1361 | } | |
1362 | ||
1363 | return 0; | |
1364 | } | |
1365 | ||
1366 | static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val, | |
1367 | target_ulong new_val, target_ulong wr_mask) | |
1368 | { | |
1369 | bool virt; | |
1370 | uint8_t *iprio; | |
1371 | int ret = -EINVAL; | |
1372 | target_ulong priv, isel, vgein; | |
1373 | ||
1374 | /* Translate CSR number for VS-mode */ | |
1375 | csrno = aia_xlate_vs_csrno(env, csrno); | |
1376 | ||
1377 | /* Decode register details from CSR number */ | |
1378 | virt = false; | |
1379 | switch (csrno) { | |
1380 | case CSR_MIREG: | |
1381 | iprio = env->miprio; | |
1382 | isel = env->miselect; | |
1383 | priv = PRV_M; | |
1384 | break; | |
1385 | case CSR_SIREG: | |
1386 | iprio = env->siprio; | |
1387 | isel = env->siselect; | |
1388 | priv = PRV_S; | |
1389 | break; | |
1390 | case CSR_VSIREG: | |
1391 | iprio = env->hviprio; | |
1392 | isel = env->vsiselect; | |
1393 | priv = PRV_S; | |
1394 | virt = true; | |
1395 | break; | |
1396 | default: | |
1397 | goto done; | |
1398 | }; | |
1399 | ||
1400 | /* Find the selected guest interrupt file */ | |
1401 | vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; | |
1402 | ||
1403 | if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) { | |
1404 | /* Local interrupt priority registers not available for VS-mode */ | |
1405 | if (!virt) { | |
1406 | ret = rmw_iprio(riscv_cpu_mxl_bits(env), | |
1407 | isel, iprio, val, new_val, wr_mask, | |
1408 | (priv == PRV_M) ? IRQ_M_EXT : IRQ_S_EXT); | |
1409 | } | |
1410 | } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) { | |
1411 | /* IMSIC registers only available when machine implements it. */ | |
1412 | if (env->aia_ireg_rmw_fn[priv]) { | |
1413 | /* Selected guest interrupt file should not be zero */ | |
1414 | if (virt && (!vgein || env->geilen < vgein)) { | |
1415 | goto done; | |
1416 | } | |
1417 | /* Call machine specific IMSIC register emulation */ | |
1418 | ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], | |
1419 | AIA_MAKE_IREG(isel, priv, virt, vgein, | |
1420 | riscv_cpu_mxl_bits(env)), | |
1421 | val, new_val, wr_mask); | |
1422 | } | |
1423 | } | |
1424 | ||
1425 | done: | |
1426 | if (ret) { | |
1427 | return (riscv_cpu_virt_enabled(env) && virt) ? | |
1428 | RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; | |
1429 | } | |
1430 | return RISCV_EXCP_NONE; | |
1431 | } | |
1432 | ||
ac4b0302 AP |
1433 | static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val, |
1434 | target_ulong new_val, target_ulong wr_mask) | |
1435 | { | |
1436 | bool virt; | |
1437 | int ret = -EINVAL; | |
1438 | target_ulong priv, vgein; | |
1439 | ||
1440 | /* Translate CSR number for VS-mode */ | |
1441 | csrno = aia_xlate_vs_csrno(env, csrno); | |
1442 | ||
1443 | /* Decode register details from CSR number */ | |
1444 | virt = false; | |
1445 | switch (csrno) { | |
1446 | case CSR_MTOPEI: | |
1447 | priv = PRV_M; | |
1448 | break; | |
1449 | case CSR_STOPEI: | |
1450 | priv = PRV_S; | |
1451 | break; | |
1452 | case CSR_VSTOPEI: | |
1453 | priv = PRV_S; | |
1454 | virt = true; | |
1455 | break; | |
1456 | default: | |
1457 | goto done; | |
1458 | }; | |
1459 | ||
1460 | /* IMSIC CSRs only available when machine implements IMSIC. */ | |
1461 | if (!env->aia_ireg_rmw_fn[priv]) { | |
1462 | goto done; | |
1463 | } | |
1464 | ||
1465 | /* Find the selected guest interrupt file */ | |
1466 | vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; | |
1467 | ||
1468 | /* Selected guest interrupt file should be valid */ | |
1469 | if (virt && (!vgein || env->geilen < vgein)) { | |
1470 | goto done; | |
1471 | } | |
1472 | ||
1473 | /* Call machine specific IMSIC register emulation for TOPEI */ | |
1474 | ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], | |
1475 | AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein, | |
1476 | riscv_cpu_mxl_bits(env)), | |
1477 | val, new_val, wr_mask); | |
1478 | ||
1479 | done: | |
1480 | if (ret) { | |
1481 | return (riscv_cpu_virt_enabled(env) && virt) ? | |
1482 | RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; | |
1483 | } | |
1484 | return RISCV_EXCP_NONE; | |
1485 | } | |
1486 | ||
605def6e AF |
1487 | static RISCVException read_mtvec(CPURISCVState *env, int csrno, |
1488 | target_ulong *val) | |
c7b95171 MC |
1489 | { |
1490 | *val = env->mtvec; | |
605def6e | 1491 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1492 | } |
1493 | ||
605def6e AF |
1494 | static RISCVException write_mtvec(CPURISCVState *env, int csrno, |
1495 | target_ulong val) | |
c7b95171 MC |
1496 | { |
1497 | /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ | |
acbbb94e MC |
1498 | if ((val & 3) < 2) { |
1499 | env->mtvec = val; | |
c7b95171 | 1500 | } else { |
acbbb94e | 1501 | qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n"); |
c7b95171 | 1502 | } |
605def6e | 1503 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1504 | } |
1505 | ||
b1675eeb AP |
1506 | static RISCVException read_mcountinhibit(CPURISCVState *env, int csrno, |
1507 | target_ulong *val) | |
1508 | { | |
b1675eeb AP |
1509 | *val = env->mcountinhibit; |
1510 | return RISCV_EXCP_NONE; | |
1511 | } | |
1512 | ||
1513 | static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, | |
1514 | target_ulong val) | |
1515 | { | |
3780e337 AP |
1516 | int cidx; |
1517 | PMUCTRState *counter; | |
1518 | ||
b1675eeb | 1519 | env->mcountinhibit = val; |
3780e337 AP |
1520 | |
1521 | /* Check if any other counter is also monitoring cycles/instructions */ | |
1522 | for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) { | |
1523 | if (!get_field(env->mcountinhibit, BIT(cidx))) { | |
1524 | counter = &env->pmu_ctrs[cidx]; | |
1525 | counter->started = true; | |
1526 | } | |
1527 | } | |
1528 | ||
b1675eeb AP |
1529 | return RISCV_EXCP_NONE; |
1530 | } | |
1531 | ||
605def6e AF |
1532 | static RISCVException read_mcounteren(CPURISCVState *env, int csrno, |
1533 | target_ulong *val) | |
c7b95171 | 1534 | { |
c7b95171 | 1535 | *val = env->mcounteren; |
605def6e | 1536 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1537 | } |
1538 | ||
605def6e AF |
1539 | static RISCVException write_mcounteren(CPURISCVState *env, int csrno, |
1540 | target_ulong val) | |
c7b95171 | 1541 | { |
c7b95171 | 1542 | env->mcounteren = val; |
605def6e | 1543 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1544 | } |
1545 | ||
c7b95171 | 1546 | /* Machine Trap Handling */ |
457c360f FP |
1547 | static RISCVException read_mscratch_i128(CPURISCVState *env, int csrno, |
1548 | Int128 *val) | |
1549 | { | |
1550 | *val = int128_make128(env->mscratch, env->mscratchh); | |
1551 | return RISCV_EXCP_NONE; | |
1552 | } | |
1553 | ||
1554 | static RISCVException write_mscratch_i128(CPURISCVState *env, int csrno, | |
1555 | Int128 val) | |
1556 | { | |
1557 | env->mscratch = int128_getlo(val); | |
1558 | env->mscratchh = int128_gethi(val); | |
1559 | return RISCV_EXCP_NONE; | |
1560 | } | |
1561 | ||
605def6e AF |
1562 | static RISCVException read_mscratch(CPURISCVState *env, int csrno, |
1563 | target_ulong *val) | |
c7b95171 MC |
1564 | { |
1565 | *val = env->mscratch; | |
605def6e | 1566 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1567 | } |
1568 | ||
605def6e AF |
1569 | static RISCVException write_mscratch(CPURISCVState *env, int csrno, |
1570 | target_ulong val) | |
c7b95171 MC |
1571 | { |
1572 | env->mscratch = val; | |
605def6e | 1573 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1574 | } |
1575 | ||
605def6e AF |
1576 | static RISCVException read_mepc(CPURISCVState *env, int csrno, |
1577 | target_ulong *val) | |
c7b95171 MC |
1578 | { |
1579 | *val = env->mepc; | |
605def6e | 1580 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1581 | } |
1582 | ||
605def6e AF |
1583 | static RISCVException write_mepc(CPURISCVState *env, int csrno, |
1584 | target_ulong val) | |
c7b95171 MC |
1585 | { |
1586 | env->mepc = val; | |
605def6e | 1587 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1588 | } |
1589 | ||
605def6e AF |
1590 | static RISCVException read_mcause(CPURISCVState *env, int csrno, |
1591 | target_ulong *val) | |
c7b95171 MC |
1592 | { |
1593 | *val = env->mcause; | |
605def6e | 1594 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1595 | } |
1596 | ||
605def6e AF |
1597 | static RISCVException write_mcause(CPURISCVState *env, int csrno, |
1598 | target_ulong val) | |
c7b95171 MC |
1599 | { |
1600 | env->mcause = val; | |
605def6e | 1601 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1602 | } |
1603 | ||
605def6e AF |
1604 | static RISCVException read_mtval(CPURISCVState *env, int csrno, |
1605 | target_ulong *val) | |
c7b95171 | 1606 | { |
ac12b601 | 1607 | *val = env->mtval; |
605def6e | 1608 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1609 | } |
1610 | ||
605def6e AF |
1611 | static RISCVException write_mtval(CPURISCVState *env, int csrno, |
1612 | target_ulong val) | |
c7b95171 | 1613 | { |
ac12b601 | 1614 | env->mtval = val; |
605def6e | 1615 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1616 | } |
1617 | ||
29a9ec9b AP |
1618 | /* Execution environment configuration setup */ |
1619 | static RISCVException read_menvcfg(CPURISCVState *env, int csrno, | |
1620 | target_ulong *val) | |
1621 | { | |
1622 | *val = env->menvcfg; | |
1623 | return RISCV_EXCP_NONE; | |
1624 | } | |
1625 | ||
1626 | static RISCVException write_menvcfg(CPURISCVState *env, int csrno, | |
1627 | target_ulong val) | |
1628 | { | |
1629 | uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | MENVCFG_CBZE; | |
1630 | ||
1631 | if (riscv_cpu_mxl(env) == MXL_RV64) { | |
1632 | mask |= MENVCFG_PBMTE | MENVCFG_STCE; | |
1633 | } | |
1634 | env->menvcfg = (env->menvcfg & ~mask) | (val & mask); | |
1635 | ||
1636 | return RISCV_EXCP_NONE; | |
1637 | } | |
1638 | ||
1639 | static RISCVException read_menvcfgh(CPURISCVState *env, int csrno, | |
1640 | target_ulong *val) | |
1641 | { | |
1642 | *val = env->menvcfg >> 32; | |
1643 | return RISCV_EXCP_NONE; | |
1644 | } | |
1645 | ||
1646 | static RISCVException write_menvcfgh(CPURISCVState *env, int csrno, | |
1647 | target_ulong val) | |
1648 | { | |
1649 | uint64_t mask = MENVCFG_PBMTE | MENVCFG_STCE; | |
1650 | uint64_t valh = (uint64_t)val << 32; | |
1651 | ||
1652 | env->menvcfg = (env->menvcfg & ~mask) | (valh & mask); | |
1653 | ||
1654 | return RISCV_EXCP_NONE; | |
1655 | } | |
1656 | ||
1657 | static RISCVException read_senvcfg(CPURISCVState *env, int csrno, | |
1658 | target_ulong *val) | |
1659 | { | |
1660 | *val = env->senvcfg; | |
1661 | return RISCV_EXCP_NONE; | |
1662 | } | |
1663 | ||
1664 | static RISCVException write_senvcfg(CPURISCVState *env, int csrno, | |
1665 | target_ulong val) | |
1666 | { | |
1667 | uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE; | |
1668 | ||
1669 | env->senvcfg = (env->senvcfg & ~mask) | (val & mask); | |
1670 | ||
1671 | return RISCV_EXCP_NONE; | |
1672 | } | |
1673 | ||
1674 | static RISCVException read_henvcfg(CPURISCVState *env, int csrno, | |
1675 | target_ulong *val) | |
1676 | { | |
1677 | *val = env->henvcfg; | |
1678 | return RISCV_EXCP_NONE; | |
1679 | } | |
1680 | ||
1681 | static RISCVException write_henvcfg(CPURISCVState *env, int csrno, | |
1682 | target_ulong val) | |
1683 | { | |
1684 | uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; | |
1685 | ||
1686 | if (riscv_cpu_mxl(env) == MXL_RV64) { | |
1687 | mask |= HENVCFG_PBMTE | HENVCFG_STCE; | |
1688 | } | |
1689 | ||
1690 | env->henvcfg = (env->henvcfg & ~mask) | (val & mask); | |
1691 | ||
1692 | return RISCV_EXCP_NONE; | |
1693 | } | |
1694 | ||
1695 | static RISCVException read_henvcfgh(CPURISCVState *env, int csrno, | |
1696 | target_ulong *val) | |
1697 | { | |
1698 | *val = env->henvcfg >> 32; | |
1699 | return RISCV_EXCP_NONE; | |
1700 | } | |
1701 | ||
1702 | static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, | |
1703 | target_ulong val) | |
1704 | { | |
1705 | uint64_t mask = HENVCFG_PBMTE | HENVCFG_STCE; | |
1706 | uint64_t valh = (uint64_t)val << 32; | |
1707 | ||
1708 | env->henvcfg = (env->henvcfg & ~mask) | (valh & mask); | |
1709 | ||
1710 | return RISCV_EXCP_NONE; | |
1711 | } | |
1712 | ||
d028ac75 AP |
1713 | static RISCVException rmw_mip64(CPURISCVState *env, int csrno, |
1714 | uint64_t *ret_val, | |
1715 | uint64_t new_val, uint64_t wr_mask) | |
c7b95171 | 1716 | { |
3109cd98 | 1717 | RISCVCPU *cpu = env_archcpu(env); |
33fe584f | 1718 | uint64_t old_mip, mask = wr_mask & delegable_ints; |
d028ac75 | 1719 | uint32_t gin; |
71877e29 | 1720 | |
33fe584f AF |
1721 | if (mask & MIP_SEIP) { |
1722 | env->software_seip = new_val & MIP_SEIP; | |
1723 | new_val |= env->external_seip * MIP_SEIP; | |
1724 | } | |
1725 | ||
71877e29 | 1726 | if (mask) { |
d028ac75 | 1727 | old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask)); |
71877e29 | 1728 | } else { |
7ec5d303 | 1729 | old_mip = env->mip; |
71877e29 | 1730 | } |
c7b95171 | 1731 | |
cd032fe7 AP |
1732 | if (csrno != CSR_HVIP) { |
1733 | gin = get_field(env->hstatus, HSTATUS_VGEIN); | |
1734 | old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0; | |
1735 | } | |
1736 | ||
d028ac75 AP |
1737 | if (ret_val) { |
1738 | *ret_val = old_mip; | |
71877e29 | 1739 | } |
c7b95171 | 1740 | |
605def6e | 1741 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1742 | } |
1743 | ||
d028ac75 AP |
1744 | static RISCVException rmw_mip(CPURISCVState *env, int csrno, |
1745 | target_ulong *ret_val, | |
1746 | target_ulong new_val, target_ulong wr_mask) | |
1747 | { | |
1748 | uint64_t rval; | |
1749 | RISCVException ret; | |
1750 | ||
1751 | ret = rmw_mip64(env, csrno, &rval, new_val, wr_mask); | |
1752 | if (ret_val) { | |
1753 | *ret_val = rval; | |
1754 | } | |
1755 | ||
1756 | return ret; | |
1757 | } | |
1758 | ||
1759 | static RISCVException rmw_miph(CPURISCVState *env, int csrno, | |
1760 | target_ulong *ret_val, | |
1761 | target_ulong new_val, target_ulong wr_mask) | |
1762 | { | |
1763 | uint64_t rval; | |
1764 | RISCVException ret; | |
1765 | ||
1766 | ret = rmw_mip64(env, csrno, &rval, | |
1767 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
1768 | if (ret_val) { | |
1769 | *ret_val = rval >> 32; | |
1770 | } | |
1771 | ||
1772 | return ret; | |
1773 | } | |
1774 | ||
c7b95171 | 1775 | /* Supervisor Trap Setup */ |
457c360f FP |
1776 | static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno, |
1777 | Int128 *val) | |
1778 | { | |
1779 | uint64_t mask = sstatus_v1_10_mask; | |
1780 | uint64_t sstatus = env->mstatus & mask; | |
f297245f | 1781 | if (env->xl != MXL_RV32 || env->debugger) { |
f310df58 LZ |
1782 | mask |= SSTATUS64_UXL; |
1783 | } | |
457c360f FP |
1784 | |
1785 | *val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus)); | |
1786 | return RISCV_EXCP_NONE; | |
1787 | } | |
1788 | ||
605def6e AF |
1789 | static RISCVException read_sstatus(CPURISCVState *env, int csrno, |
1790 | target_ulong *val) | |
c7b95171 | 1791 | { |
1a9540d1 | 1792 | target_ulong mask = (sstatus_v1_10_mask); |
f297245f | 1793 | if (env->xl != MXL_RV32 || env->debugger) { |
f310df58 LZ |
1794 | mask |= SSTATUS64_UXL; |
1795 | } | |
b550f894 RH |
1796 | /* TODO: Use SXL not MXL. */ |
1797 | *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask); | |
605def6e | 1798 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1799 | } |
1800 | ||
605def6e AF |
1801 | static RISCVException write_sstatus(CPURISCVState *env, int csrno, |
1802 | target_ulong val) | |
c7b95171 | 1803 | { |
1a9540d1 | 1804 | target_ulong mask = (sstatus_v1_10_mask); |
f310df58 | 1805 | |
f297245f | 1806 | if (env->xl != MXL_RV32 || env->debugger) { |
f310df58 LZ |
1807 | if ((val & SSTATUS64_UXL) != 0) { |
1808 | mask |= SSTATUS64_UXL; | |
1809 | } | |
1810 | } | |
c7b95171 MC |
1811 | target_ulong newval = (env->mstatus & ~mask) | (val & mask); |
1812 | return write_mstatus(env, CSR_MSTATUS, newval); | |
1813 | } | |
1814 | ||
d028ac75 AP |
1815 | static RISCVException rmw_vsie64(CPURISCVState *env, int csrno, |
1816 | uint64_t *ret_val, | |
1817 | uint64_t new_val, uint64_t wr_mask) | |
9d5451e0 | 1818 | { |
d028ac75 AP |
1819 | RISCVException ret; |
1820 | uint64_t rval, vsbits, mask = env->hideleg & VS_MODE_INTERRUPTS; | |
1821 | ||
1822 | /* Bring VS-level bits to correct position */ | |
1823 | vsbits = new_val & (VS_MODE_INTERRUPTS >> 1); | |
1824 | new_val &= ~(VS_MODE_INTERRUPTS >> 1); | |
1825 | new_val |= vsbits << 1; | |
1826 | vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1); | |
1827 | wr_mask &= ~(VS_MODE_INTERRUPTS >> 1); | |
1828 | wr_mask |= vsbits << 1; | |
1829 | ||
1830 | ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask & mask); | |
1831 | if (ret_val) { | |
1832 | rval &= mask; | |
1833 | vsbits = rval & VS_MODE_INTERRUPTS; | |
1834 | rval &= ~VS_MODE_INTERRUPTS; | |
1835 | *ret_val = rval | (vsbits >> 1); | |
1836 | } | |
1837 | ||
1838 | return ret; | |
9d5451e0 GK |
1839 | } |
1840 | ||
d028ac75 AP |
1841 | static RISCVException rmw_vsie(CPURISCVState *env, int csrno, |
1842 | target_ulong *ret_val, | |
1843 | target_ulong new_val, target_ulong wr_mask) | |
c7b95171 | 1844 | { |
d028ac75 AP |
1845 | uint64_t rval; |
1846 | RISCVException ret; | |
1847 | ||
1848 | ret = rmw_vsie64(env, csrno, &rval, new_val, wr_mask); | |
1849 | if (ret_val) { | |
1850 | *ret_val = rval; | |
d0e53ce3 | 1851 | } |
d028ac75 AP |
1852 | |
1853 | return ret; | |
c7b95171 MC |
1854 | } |
1855 | ||
d028ac75 AP |
1856 | static RISCVException rmw_vsieh(CPURISCVState *env, int csrno, |
1857 | target_ulong *ret_val, | |
1858 | target_ulong new_val, target_ulong wr_mask) | |
c7b95171 | 1859 | { |
d028ac75 AP |
1860 | uint64_t rval; |
1861 | RISCVException ret; | |
1862 | ||
1863 | ret = rmw_vsie64(env, csrno, &rval, | |
1864 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
1865 | if (ret_val) { | |
1866 | *ret_val = rval >> 32; | |
1867 | } | |
1868 | ||
1869 | return ret; | |
9d5451e0 | 1870 | } |
d0e53ce3 | 1871 | |
d028ac75 AP |
1872 | static RISCVException rmw_sie64(CPURISCVState *env, int csrno, |
1873 | uint64_t *ret_val, | |
1874 | uint64_t new_val, uint64_t wr_mask) | |
9d5451e0 | 1875 | { |
d028ac75 AP |
1876 | RISCVException ret; |
1877 | uint64_t mask = env->mideleg & S_MODE_INTERRUPTS; | |
1878 | ||
d0e53ce3 | 1879 | if (riscv_cpu_virt_enabled(env)) { |
2b602398 AP |
1880 | if (env->hvictl & HVICTL_VTI) { |
1881 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; | |
1882 | } | |
d028ac75 | 1883 | ret = rmw_vsie64(env, CSR_VSIE, ret_val, new_val, wr_mask); |
d0e53ce3 | 1884 | } else { |
d028ac75 | 1885 | ret = rmw_mie64(env, csrno, ret_val, new_val, wr_mask & mask); |
d0e53ce3 AF |
1886 | } |
1887 | ||
d028ac75 AP |
1888 | if (ret_val) { |
1889 | *ret_val &= mask; | |
1890 | } | |
1891 | ||
1892 | return ret; | |
1893 | } | |
1894 | ||
1895 | static RISCVException rmw_sie(CPURISCVState *env, int csrno, | |
1896 | target_ulong *ret_val, | |
1897 | target_ulong new_val, target_ulong wr_mask) | |
1898 | { | |
1899 | uint64_t rval; | |
1900 | RISCVException ret; | |
1901 | ||
1902 | ret = rmw_sie64(env, csrno, &rval, new_val, wr_mask); | |
2b602398 | 1903 | if (ret == RISCV_EXCP_NONE && ret_val) { |
d028ac75 AP |
1904 | *ret_val = rval; |
1905 | } | |
1906 | ||
1907 | return ret; | |
1908 | } | |
1909 | ||
1910 | static RISCVException rmw_sieh(CPURISCVState *env, int csrno, | |
1911 | target_ulong *ret_val, | |
1912 | target_ulong new_val, target_ulong wr_mask) | |
1913 | { | |
1914 | uint64_t rval; | |
1915 | RISCVException ret; | |
1916 | ||
1917 | ret = rmw_sie64(env, csrno, &rval, | |
1918 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
1919 | if (ret_val) { | |
1920 | *ret_val = rval >> 32; | |
1921 | } | |
1922 | ||
1923 | return ret; | |
c7b95171 MC |
1924 | } |
1925 | ||
605def6e AF |
1926 | static RISCVException read_stvec(CPURISCVState *env, int csrno, |
1927 | target_ulong *val) | |
c7b95171 MC |
1928 | { |
1929 | *val = env->stvec; | |
605def6e | 1930 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1931 | } |
1932 | ||
605def6e AF |
1933 | static RISCVException write_stvec(CPURISCVState *env, int csrno, |
1934 | target_ulong val) | |
c7b95171 MC |
1935 | { |
1936 | /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ | |
acbbb94e MC |
1937 | if ((val & 3) < 2) { |
1938 | env->stvec = val; | |
c7b95171 | 1939 | } else { |
acbbb94e | 1940 | qemu_log_mask(LOG_UNIMP, "CSR_STVEC: reserved mode not supported\n"); |
c7b95171 | 1941 | } |
605def6e | 1942 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1943 | } |
1944 | ||
605def6e AF |
1945 | static RISCVException read_scounteren(CPURISCVState *env, int csrno, |
1946 | target_ulong *val) | |
c7b95171 | 1947 | { |
c7b95171 | 1948 | *val = env->scounteren; |
605def6e | 1949 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1950 | } |
1951 | ||
605def6e AF |
1952 | static RISCVException write_scounteren(CPURISCVState *env, int csrno, |
1953 | target_ulong val) | |
c7b95171 | 1954 | { |
c7b95171 | 1955 | env->scounteren = val; |
605def6e | 1956 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1957 | } |
1958 | ||
1959 | /* Supervisor Trap Handling */ | |
457c360f FP |
1960 | static RISCVException read_sscratch_i128(CPURISCVState *env, int csrno, |
1961 | Int128 *val) | |
1962 | { | |
1963 | *val = int128_make128(env->sscratch, env->sscratchh); | |
1964 | return RISCV_EXCP_NONE; | |
1965 | } | |
1966 | ||
1967 | static RISCVException write_sscratch_i128(CPURISCVState *env, int csrno, | |
1968 | Int128 val) | |
1969 | { | |
1970 | env->sscratch = int128_getlo(val); | |
1971 | env->sscratchh = int128_gethi(val); | |
1972 | return RISCV_EXCP_NONE; | |
1973 | } | |
1974 | ||
605def6e AF |
1975 | static RISCVException read_sscratch(CPURISCVState *env, int csrno, |
1976 | target_ulong *val) | |
c7b95171 MC |
1977 | { |
1978 | *val = env->sscratch; | |
605def6e | 1979 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1980 | } |
1981 | ||
605def6e AF |
1982 | static RISCVException write_sscratch(CPURISCVState *env, int csrno, |
1983 | target_ulong val) | |
c7b95171 MC |
1984 | { |
1985 | env->sscratch = val; | |
605def6e | 1986 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1987 | } |
1988 | ||
605def6e AF |
1989 | static RISCVException read_sepc(CPURISCVState *env, int csrno, |
1990 | target_ulong *val) | |
c7b95171 MC |
1991 | { |
1992 | *val = env->sepc; | |
605def6e | 1993 | return RISCV_EXCP_NONE; |
c7b95171 MC |
1994 | } |
1995 | ||
605def6e AF |
1996 | static RISCVException write_sepc(CPURISCVState *env, int csrno, |
1997 | target_ulong val) | |
c7b95171 MC |
1998 | { |
1999 | env->sepc = val; | |
605def6e | 2000 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2001 | } |
2002 | ||
605def6e AF |
2003 | static RISCVException read_scause(CPURISCVState *env, int csrno, |
2004 | target_ulong *val) | |
c7b95171 MC |
2005 | { |
2006 | *val = env->scause; | |
605def6e | 2007 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2008 | } |
2009 | ||
605def6e AF |
2010 | static RISCVException write_scause(CPURISCVState *env, int csrno, |
2011 | target_ulong val) | |
c7b95171 MC |
2012 | { |
2013 | env->scause = val; | |
605def6e | 2014 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2015 | } |
2016 | ||
605def6e AF |
2017 | static RISCVException read_stval(CPURISCVState *env, int csrno, |
2018 | target_ulong *val) | |
c7b95171 | 2019 | { |
ac12b601 | 2020 | *val = env->stval; |
605def6e | 2021 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2022 | } |
2023 | ||
605def6e AF |
2024 | static RISCVException write_stval(CPURISCVState *env, int csrno, |
2025 | target_ulong val) | |
c7b95171 | 2026 | { |
ac12b601 | 2027 | env->stval = val; |
605def6e | 2028 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2029 | } |
2030 | ||
d028ac75 AP |
2031 | static RISCVException rmw_vsip64(CPURISCVState *env, int csrno, |
2032 | uint64_t *ret_val, | |
2033 | uint64_t new_val, uint64_t wr_mask) | |
2034 | { | |
2035 | RISCVException ret; | |
2036 | uint64_t rval, vsbits, mask = env->hideleg & vsip_writable_mask; | |
2037 | ||
2038 | /* Bring VS-level bits to correct position */ | |
2039 | vsbits = new_val & (VS_MODE_INTERRUPTS >> 1); | |
2040 | new_val &= ~(VS_MODE_INTERRUPTS >> 1); | |
2041 | new_val |= vsbits << 1; | |
2042 | vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1); | |
2043 | wr_mask &= ~(VS_MODE_INTERRUPTS >> 1); | |
2044 | wr_mask |= vsbits << 1; | |
2045 | ||
2046 | ret = rmw_mip64(env, csrno, &rval, new_val, wr_mask & mask); | |
2047 | if (ret_val) { | |
2048 | rval &= mask; | |
2049 | vsbits = rval & VS_MODE_INTERRUPTS; | |
2050 | rval &= ~VS_MODE_INTERRUPTS; | |
2051 | *ret_val = rval | (vsbits >> 1); | |
2052 | } | |
2053 | ||
2054 | return ret; | |
2055 | } | |
2056 | ||
605def6e | 2057 | static RISCVException rmw_vsip(CPURISCVState *env, int csrno, |
d028ac75 AP |
2058 | target_ulong *ret_val, |
2059 | target_ulong new_val, target_ulong wr_mask) | |
9d5451e0 | 2060 | { |
d028ac75 AP |
2061 | uint64_t rval; |
2062 | RISCVException ret; | |
33979526 | 2063 | |
d028ac75 AP |
2064 | ret = rmw_vsip64(env, csrno, &rval, new_val, wr_mask); |
2065 | if (ret_val) { | |
2066 | *ret_val = rval; | |
33979526 | 2067 | } |
d028ac75 | 2068 | |
9d5451e0 GK |
2069 | return ret; |
2070 | } | |
2071 | ||
d028ac75 AP |
2072 | static RISCVException rmw_vsiph(CPURISCVState *env, int csrno, |
2073 | target_ulong *ret_val, | |
2074 | target_ulong new_val, target_ulong wr_mask) | |
c7b95171 | 2075 | { |
d028ac75 AP |
2076 | uint64_t rval; |
2077 | RISCVException ret; | |
2078 | ||
2079 | ret = rmw_vsip64(env, csrno, &rval, | |
2080 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
2081 | if (ret_val) { | |
2082 | *ret_val = rval >> 32; | |
2083 | } | |
2084 | ||
2085 | return ret; | |
2086 | } | |
2087 | ||
2088 | static RISCVException rmw_sip64(CPURISCVState *env, int csrno, | |
2089 | uint64_t *ret_val, | |
2090 | uint64_t new_val, uint64_t wr_mask) | |
2091 | { | |
2092 | RISCVException ret; | |
2093 | uint64_t mask = env->mideleg & sip_writable_mask; | |
a2e9f57d AF |
2094 | |
2095 | if (riscv_cpu_virt_enabled(env)) { | |
2b602398 AP |
2096 | if (env->hvictl & HVICTL_VTI) { |
2097 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; | |
2098 | } | |
d028ac75 | 2099 | ret = rmw_vsip64(env, CSR_VSIP, ret_val, new_val, wr_mask); |
a2e9f57d | 2100 | } else { |
d028ac75 | 2101 | ret = rmw_mip64(env, csrno, ret_val, new_val, wr_mask & mask); |
a2e9f57d AF |
2102 | } |
2103 | ||
d028ac75 AP |
2104 | if (ret_val) { |
2105 | *ret_val &= env->mideleg & S_MODE_INTERRUPTS; | |
2106 | } | |
2107 | ||
2108 | return ret; | |
2109 | } | |
2110 | ||
2111 | static RISCVException rmw_sip(CPURISCVState *env, int csrno, | |
2112 | target_ulong *ret_val, | |
2113 | target_ulong new_val, target_ulong wr_mask) | |
2114 | { | |
2115 | uint64_t rval; | |
2116 | RISCVException ret; | |
2117 | ||
2118 | ret = rmw_sip64(env, csrno, &rval, new_val, wr_mask); | |
2119 | if (ret_val) { | |
2120 | *ret_val = rval; | |
33979526 | 2121 | } |
d028ac75 AP |
2122 | |
2123 | return ret; | |
2124 | } | |
2125 | ||
2126 | static RISCVException rmw_siph(CPURISCVState *env, int csrno, | |
2127 | target_ulong *ret_val, | |
2128 | target_ulong new_val, target_ulong wr_mask) | |
2129 | { | |
2130 | uint64_t rval; | |
2131 | RISCVException ret; | |
2132 | ||
2133 | ret = rmw_sip64(env, csrno, &rval, | |
2134 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
2135 | if (ret_val) { | |
2136 | *ret_val = rval >> 32; | |
2137 | } | |
2138 | ||
087b051a | 2139 | return ret; |
c7b95171 MC |
2140 | } |
2141 | ||
2142 | /* Supervisor Protection and Translation */ | |
605def6e AF |
2143 | static RISCVException read_satp(CPURISCVState *env, int csrno, |
2144 | target_ulong *val) | |
c7b95171 MC |
2145 | { |
2146 | if (!riscv_feature(env, RISCV_FEATURE_MMU)) { | |
2147 | *val = 0; | |
605def6e | 2148 | return RISCV_EXCP_NONE; |
1a9540d1 AF |
2149 | } |
2150 | ||
2151 | if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { | |
605def6e | 2152 | return RISCV_EXCP_ILLEGAL_INST; |
c7b95171 | 2153 | } else { |
1a9540d1 | 2154 | *val = env->satp; |
c7b95171 | 2155 | } |
1a9540d1 | 2156 | |
605def6e | 2157 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2158 | } |
2159 | ||
605def6e AF |
2160 | static RISCVException write_satp(CPURISCVState *env, int csrno, |
2161 | target_ulong val) | |
c7b95171 | 2162 | { |
5242ef88 | 2163 | target_ulong vm, mask; |
419ddf00 | 2164 | |
c7b95171 | 2165 | if (!riscv_feature(env, RISCV_FEATURE_MMU)) { |
605def6e | 2166 | return RISCV_EXCP_NONE; |
c7b95171 | 2167 | } |
419ddf00 | 2168 | |
db23e5d9 | 2169 | if (riscv_cpu_mxl(env) == MXL_RV32) { |
419ddf00 AF |
2170 | vm = validate_vm(env, get_field(val, SATP32_MODE)); |
2171 | mask = (val ^ env->satp) & (SATP32_MODE | SATP32_ASID | SATP32_PPN); | |
419ddf00 AF |
2172 | } else { |
2173 | vm = validate_vm(env, get_field(val, SATP64_MODE)); | |
2174 | mask = (val ^ env->satp) & (SATP64_MODE | SATP64_ASID | SATP64_PPN); | |
419ddf00 AF |
2175 | } |
2176 | ||
2177 | if (vm && mask) { | |
7f2b5ff1 | 2178 | if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { |
605def6e | 2179 | return RISCV_EXCP_ILLEGAL_INST; |
7f2b5ff1 | 2180 | } else { |
5242ef88 PD |
2181 | /* |
2182 | * The ISA defines SATP.MODE=Bare as "no translation", but we still | |
2183 | * pass these through QEMU's TLB emulation as it improves | |
2184 | * performance. Flushing the TLB on SATP writes with paging | |
2185 | * enabled avoids leaking those invalid cached mappings. | |
2186 | */ | |
2187 | tlb_flush(env_cpu(env)); | |
7f2b5ff1 MC |
2188 | env->satp = val; |
2189 | } | |
c7b95171 | 2190 | } |
605def6e | 2191 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2192 | } |
2193 | ||
c7de92b4 AP |
2194 | static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) |
2195 | { | |
2196 | int irq, ret; | |
2197 | target_ulong topei; | |
2198 | uint64_t vseip, vsgein; | |
2199 | uint32_t iid, iprio, hviid, hviprio, gein; | |
2200 | uint32_t s, scount = 0, siid[VSTOPI_NUM_SRCS], siprio[VSTOPI_NUM_SRCS]; | |
2201 | ||
2202 | gein = get_field(env->hstatus, HSTATUS_VGEIN); | |
2203 | hviid = get_field(env->hvictl, HVICTL_IID); | |
2204 | hviprio = get_field(env->hvictl, HVICTL_IPRIO); | |
2205 | ||
2206 | if (gein) { | |
2207 | vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; | |
2208 | vseip = env->mie & (env->mip | vsgein) & MIP_VSEIP; | |
2209 | if (gein <= env->geilen && vseip) { | |
2210 | siid[scount] = IRQ_S_EXT; | |
2211 | siprio[scount] = IPRIO_MMAXIPRIO + 1; | |
2212 | if (env->aia_ireg_rmw_fn[PRV_S]) { | |
2213 | /* | |
2214 | * Call machine specific IMSIC register emulation for | |
2215 | * reading TOPEI. | |
2216 | */ | |
2217 | ret = env->aia_ireg_rmw_fn[PRV_S]( | |
2218 | env->aia_ireg_rmw_fn_arg[PRV_S], | |
2219 | AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, PRV_S, true, gein, | |
2220 | riscv_cpu_mxl_bits(env)), | |
2221 | &topei, 0, 0); | |
2222 | if (!ret && topei) { | |
2223 | siprio[scount] = topei & IMSIC_TOPEI_IPRIO_MASK; | |
2224 | } | |
2225 | } | |
2226 | scount++; | |
2227 | } | |
2228 | } else { | |
2229 | if (hviid == IRQ_S_EXT && hviprio) { | |
2230 | siid[scount] = IRQ_S_EXT; | |
2231 | siprio[scount] = hviprio; | |
2232 | scount++; | |
2233 | } | |
2234 | } | |
2235 | ||
2236 | if (env->hvictl & HVICTL_VTI) { | |
2237 | if (hviid != IRQ_S_EXT) { | |
2238 | siid[scount] = hviid; | |
2239 | siprio[scount] = hviprio; | |
2240 | scount++; | |
2241 | } | |
2242 | } else { | |
2243 | irq = riscv_cpu_vsirq_pending(env); | |
2244 | if (irq != IRQ_S_EXT && 0 < irq && irq <= 63) { | |
2245 | siid[scount] = irq; | |
2246 | siprio[scount] = env->hviprio[irq]; | |
2247 | scount++; | |
2248 | } | |
2249 | } | |
2250 | ||
2251 | iid = 0; | |
2252 | iprio = UINT_MAX; | |
2253 | for (s = 0; s < scount; s++) { | |
2254 | if (siprio[s] < iprio) { | |
2255 | iid = siid[s]; | |
2256 | iprio = siprio[s]; | |
2257 | } | |
2258 | } | |
2259 | ||
2260 | if (iid) { | |
2261 | if (env->hvictl & HVICTL_IPRIOM) { | |
2262 | if (iprio > IPRIO_MMAXIPRIO) { | |
2263 | iprio = IPRIO_MMAXIPRIO; | |
2264 | } | |
2265 | if (!iprio) { | |
2266 | if (riscv_cpu_default_priority(iid) > IPRIO_DEFAULT_S) { | |
2267 | iprio = IPRIO_MMAXIPRIO; | |
2268 | } | |
2269 | } | |
2270 | } else { | |
2271 | iprio = 1; | |
2272 | } | |
2273 | } else { | |
2274 | iprio = 0; | |
2275 | } | |
2276 | ||
2277 | *val = (iid & TOPI_IID_MASK) << TOPI_IID_SHIFT; | |
2278 | *val |= iprio; | |
2279 | return RISCV_EXCP_NONE; | |
2280 | } | |
2281 | ||
2282 | static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) | |
2283 | { | |
2284 | int irq; | |
2285 | uint8_t iprio; | |
2286 | ||
2287 | if (riscv_cpu_virt_enabled(env)) { | |
2288 | return read_vstopi(env, CSR_VSTOPI, val); | |
2289 | } | |
2290 | ||
2291 | irq = riscv_cpu_sirq_pending(env); | |
2292 | if (irq <= 0 || irq > 63) { | |
2293 | *val = 0; | |
2294 | } else { | |
2295 | iprio = env->siprio[irq]; | |
2296 | if (!iprio) { | |
2297 | if (riscv_cpu_default_priority(irq) > IPRIO_DEFAULT_S) { | |
2298 | iprio = IPRIO_MMAXIPRIO; | |
2299 | } | |
2300 | } | |
2301 | *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; | |
2302 | *val |= iprio; | |
2303 | } | |
2304 | ||
2305 | return RISCV_EXCP_NONE; | |
2306 | } | |
2307 | ||
ff2cc129 | 2308 | /* Hypervisor Extensions */ |
605def6e AF |
2309 | static RISCVException read_hstatus(CPURISCVState *env, int csrno, |
2310 | target_ulong *val) | |
ff2cc129 AF |
2311 | { |
2312 | *val = env->hstatus; | |
db23e5d9 | 2313 | if (riscv_cpu_mxl(env) != MXL_RV32) { |
8987cdc4 AF |
2314 | /* We only support 64-bit VSXL */ |
2315 | *val = set_field(*val, HSTATUS_VSXL, 2); | |
2316 | } | |
30f663b1 AF |
2317 | /* We only support little endian */ |
2318 | *val = set_field(*val, HSTATUS_VSBE, 0); | |
605def6e | 2319 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2320 | } |
2321 | ||
605def6e AF |
2322 | static RISCVException write_hstatus(CPURISCVState *env, int csrno, |
2323 | target_ulong val) | |
ff2cc129 AF |
2324 | { |
2325 | env->hstatus = val; | |
db23e5d9 | 2326 | if (riscv_cpu_mxl(env) != MXL_RV32 && get_field(val, HSTATUS_VSXL) != 2) { |
f8dc878e AF |
2327 | qemu_log_mask(LOG_UNIMP, "QEMU does not support mixed HSXLEN options."); |
2328 | } | |
30f663b1 AF |
2329 | if (get_field(val, HSTATUS_VSBE) != 0) { |
2330 | qemu_log_mask(LOG_UNIMP, "QEMU does not support big endian guests."); | |
2331 | } | |
605def6e | 2332 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2333 | } |
2334 | ||
605def6e AF |
2335 | static RISCVException read_hedeleg(CPURISCVState *env, int csrno, |
2336 | target_ulong *val) | |
ff2cc129 AF |
2337 | { |
2338 | *val = env->hedeleg; | |
605def6e | 2339 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2340 | } |
2341 | ||
605def6e AF |
2342 | static RISCVException write_hedeleg(CPURISCVState *env, int csrno, |
2343 | target_ulong val) | |
ff2cc129 | 2344 | { |
bc083a51 | 2345 | env->hedeleg = val & vs_delegable_excps; |
605def6e | 2346 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2347 | } |
2348 | ||
d028ac75 AP |
2349 | static RISCVException rmw_hideleg64(CPURISCVState *env, int csrno, |
2350 | uint64_t *ret_val, | |
2351 | uint64_t new_val, uint64_t wr_mask) | |
ff2cc129 | 2352 | { |
d028ac75 AP |
2353 | uint64_t mask = wr_mask & vs_delegable_ints; |
2354 | ||
2355 | if (ret_val) { | |
2356 | *ret_val = env->hideleg & vs_delegable_ints; | |
2357 | } | |
2358 | ||
2359 | env->hideleg = (env->hideleg & ~mask) | (new_val & mask); | |
605def6e | 2360 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2361 | } |
2362 | ||
d028ac75 AP |
2363 | static RISCVException rmw_hideleg(CPURISCVState *env, int csrno, |
2364 | target_ulong *ret_val, | |
2365 | target_ulong new_val, target_ulong wr_mask) | |
ff2cc129 | 2366 | { |
d028ac75 AP |
2367 | uint64_t rval; |
2368 | RISCVException ret; | |
2369 | ||
2370 | ret = rmw_hideleg64(env, csrno, &rval, new_val, wr_mask); | |
2371 | if (ret_val) { | |
2372 | *ret_val = rval; | |
2373 | } | |
2374 | ||
2375 | return ret; | |
2376 | } | |
2377 | ||
2378 | static RISCVException rmw_hidelegh(CPURISCVState *env, int csrno, | |
2379 | target_ulong *ret_val, | |
2380 | target_ulong new_val, target_ulong wr_mask) | |
2381 | { | |
2382 | uint64_t rval; | |
2383 | RISCVException ret; | |
2384 | ||
2385 | ret = rmw_hideleg64(env, csrno, &rval, | |
2386 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
2387 | if (ret_val) { | |
2388 | *ret_val = rval >> 32; | |
2389 | } | |
2390 | ||
2391 | return ret; | |
2392 | } | |
2393 | ||
2394 | static RISCVException rmw_hvip64(CPURISCVState *env, int csrno, | |
2395 | uint64_t *ret_val, | |
2396 | uint64_t new_val, uint64_t wr_mask) | |
2397 | { | |
2398 | RISCVException ret; | |
2399 | ||
2400 | ret = rmw_mip64(env, csrno, ret_val, new_val, | |
2401 | wr_mask & hvip_writable_mask); | |
2402 | if (ret_val) { | |
2403 | *ret_val &= VS_MODE_INTERRUPTS; | |
2404 | } | |
2405 | ||
2406 | return ret; | |
ff2cc129 AF |
2407 | } |
2408 | ||
605def6e | 2409 | static RISCVException rmw_hvip(CPURISCVState *env, int csrno, |
d028ac75 AP |
2410 | target_ulong *ret_val, |
2411 | target_ulong new_val, target_ulong wr_mask) | |
83028098 | 2412 | { |
d028ac75 AP |
2413 | uint64_t rval; |
2414 | RISCVException ret; | |
83028098 | 2415 | |
d028ac75 AP |
2416 | ret = rmw_hvip64(env, csrno, &rval, new_val, wr_mask); |
2417 | if (ret_val) { | |
2418 | *ret_val = rval; | |
2419 | } | |
2420 | ||
2421 | return ret; | |
2422 | } | |
2423 | ||
2424 | static RISCVException rmw_hviph(CPURISCVState *env, int csrno, | |
2425 | target_ulong *ret_val, | |
2426 | target_ulong new_val, target_ulong wr_mask) | |
2427 | { | |
2428 | uint64_t rval; | |
2429 | RISCVException ret; | |
2430 | ||
2431 | ret = rmw_hvip64(env, csrno, &rval, | |
2432 | ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); | |
2433 | if (ret_val) { | |
2434 | *ret_val = rval >> 32; | |
33979526 | 2435 | } |
d028ac75 | 2436 | |
83028098 AF |
2437 | return ret; |
2438 | } | |
2439 | ||
605def6e AF |
2440 | static RISCVException rmw_hip(CPURISCVState *env, int csrno, |
2441 | target_ulong *ret_value, | |
2442 | target_ulong new_value, target_ulong write_mask) | |
ff2cc129 | 2443 | { |
cd032fe7 | 2444 | int ret = rmw_mip(env, csrno, ret_value, new_value, |
ff2cc129 AF |
2445 | write_mask & hip_writable_mask); |
2446 | ||
33979526 | 2447 | if (ret_value) { |
881df35d | 2448 | *ret_value &= HS_MODE_INTERRUPTS; |
33979526 | 2449 | } |
ff2cc129 AF |
2450 | return ret; |
2451 | } | |
2452 | ||
d028ac75 AP |
2453 | static RISCVException rmw_hie(CPURISCVState *env, int csrno, |
2454 | target_ulong *ret_val, | |
2455 | target_ulong new_val, target_ulong wr_mask) | |
ff2cc129 | 2456 | { |
d028ac75 AP |
2457 | uint64_t rval; |
2458 | RISCVException ret; | |
ff2cc129 | 2459 | |
d028ac75 AP |
2460 | ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask & HS_MODE_INTERRUPTS); |
2461 | if (ret_val) { | |
2462 | *ret_val = rval & HS_MODE_INTERRUPTS; | |
2463 | } | |
2464 | ||
2465 | return ret; | |
ff2cc129 AF |
2466 | } |
2467 | ||
605def6e AF |
2468 | static RISCVException read_hcounteren(CPURISCVState *env, int csrno, |
2469 | target_ulong *val) | |
ff2cc129 AF |
2470 | { |
2471 | *val = env->hcounteren; | |
605def6e | 2472 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2473 | } |
2474 | ||
605def6e AF |
2475 | static RISCVException write_hcounteren(CPURISCVState *env, int csrno, |
2476 | target_ulong val) | |
ff2cc129 AF |
2477 | { |
2478 | env->hcounteren = val; | |
605def6e | 2479 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2480 | } |
2481 | ||
cd032fe7 AP |
2482 | static RISCVException read_hgeie(CPURISCVState *env, int csrno, |
2483 | target_ulong *val) | |
83028098 | 2484 | { |
377cbb4b | 2485 | if (val) { |
cd032fe7 | 2486 | *val = env->hgeie; |
377cbb4b | 2487 | } |
605def6e | 2488 | return RISCV_EXCP_NONE; |
83028098 AF |
2489 | } |
2490 | ||
cd032fe7 AP |
2491 | static RISCVException write_hgeie(CPURISCVState *env, int csrno, |
2492 | target_ulong val) | |
2493 | { | |
2494 | /* Only GEILEN:1 bits implemented and BIT0 is never implemented */ | |
2495 | val &= ((((target_ulong)1) << env->geilen) - 1) << 1; | |
2496 | env->hgeie = val; | |
2497 | /* Update mip.SGEIP bit */ | |
2498 | riscv_cpu_update_mip(env_archcpu(env), MIP_SGEIP, | |
2499 | BOOL_TO_MASK(!!(env->hgeie & env->hgeip))); | |
2500 | return RISCV_EXCP_NONE; | |
2501 | } | |
2502 | ||
605def6e AF |
2503 | static RISCVException read_htval(CPURISCVState *env, int csrno, |
2504 | target_ulong *val) | |
ff2cc129 AF |
2505 | { |
2506 | *val = env->htval; | |
605def6e | 2507 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2508 | } |
2509 | ||
605def6e AF |
2510 | static RISCVException write_htval(CPURISCVState *env, int csrno, |
2511 | target_ulong val) | |
ff2cc129 AF |
2512 | { |
2513 | env->htval = val; | |
605def6e | 2514 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2515 | } |
2516 | ||
605def6e AF |
2517 | static RISCVException read_htinst(CPURISCVState *env, int csrno, |
2518 | target_ulong *val) | |
ff2cc129 AF |
2519 | { |
2520 | *val = env->htinst; | |
605def6e | 2521 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2522 | } |
2523 | ||
605def6e AF |
2524 | static RISCVException write_htinst(CPURISCVState *env, int csrno, |
2525 | target_ulong val) | |
ff2cc129 | 2526 | { |
605def6e | 2527 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2528 | } |
2529 | ||
cd032fe7 AP |
2530 | static RISCVException read_hgeip(CPURISCVState *env, int csrno, |
2531 | target_ulong *val) | |
83028098 | 2532 | { |
377cbb4b | 2533 | if (val) { |
cd032fe7 | 2534 | *val = env->hgeip; |
377cbb4b | 2535 | } |
605def6e | 2536 | return RISCV_EXCP_NONE; |
83028098 AF |
2537 | } |
2538 | ||
605def6e AF |
2539 | static RISCVException read_hgatp(CPURISCVState *env, int csrno, |
2540 | target_ulong *val) | |
ff2cc129 AF |
2541 | { |
2542 | *val = env->hgatp; | |
605def6e | 2543 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2544 | } |
2545 | ||
605def6e AF |
2546 | static RISCVException write_hgatp(CPURISCVState *env, int csrno, |
2547 | target_ulong val) | |
ff2cc129 AF |
2548 | { |
2549 | env->hgatp = val; | |
605def6e | 2550 | return RISCV_EXCP_NONE; |
ff2cc129 AF |
2551 | } |
2552 | ||
605def6e AF |
2553 | static RISCVException read_htimedelta(CPURISCVState *env, int csrno, |
2554 | target_ulong *val) | |
c6957248 AP |
2555 | { |
2556 | if (!env->rdtime_fn) { | |
605def6e | 2557 | return RISCV_EXCP_ILLEGAL_INST; |
c6957248 AP |
2558 | } |
2559 | ||
c6957248 | 2560 | *val = env->htimedelta; |
605def6e | 2561 | return RISCV_EXCP_NONE; |
c6957248 AP |
2562 | } |
2563 | ||
605def6e AF |
2564 | static RISCVException write_htimedelta(CPURISCVState *env, int csrno, |
2565 | target_ulong val) | |
c6957248 AP |
2566 | { |
2567 | if (!env->rdtime_fn) { | |
605def6e | 2568 | return RISCV_EXCP_ILLEGAL_INST; |
c6957248 AP |
2569 | } |
2570 | ||
db23e5d9 | 2571 | if (riscv_cpu_mxl(env) == MXL_RV32) { |
8987cdc4 AF |
2572 | env->htimedelta = deposit64(env->htimedelta, 0, 32, (uint64_t)val); |
2573 | } else { | |
2574 | env->htimedelta = val; | |
2575 | } | |
605def6e | 2576 | return RISCV_EXCP_NONE; |
c6957248 AP |
2577 | } |
2578 | ||
605def6e AF |
2579 | static RISCVException read_htimedeltah(CPURISCVState *env, int csrno, |
2580 | target_ulong *val) | |
c6957248 AP |
2581 | { |
2582 | if (!env->rdtime_fn) { | |
605def6e | 2583 | return RISCV_EXCP_ILLEGAL_INST; |
c6957248 AP |
2584 | } |
2585 | ||
2586 | *val = env->htimedelta >> 32; | |
605def6e | 2587 | return RISCV_EXCP_NONE; |
c6957248 AP |
2588 | } |
2589 | ||
605def6e AF |
2590 | static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, |
2591 | target_ulong val) | |
c6957248 AP |
2592 | { |
2593 | if (!env->rdtime_fn) { | |
605def6e | 2594 | return RISCV_EXCP_ILLEGAL_INST; |
c6957248 AP |
2595 | } |
2596 | ||
2597 | env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val); | |
605def6e | 2598 | return RISCV_EXCP_NONE; |
c6957248 | 2599 | } |
c6957248 | 2600 | |
2b602398 AP |
2601 | static int read_hvictl(CPURISCVState *env, int csrno, target_ulong *val) |
2602 | { | |
2603 | *val = env->hvictl; | |
2604 | return RISCV_EXCP_NONE; | |
2605 | } | |
2606 | ||
2607 | static int write_hvictl(CPURISCVState *env, int csrno, target_ulong val) | |
2608 | { | |
2609 | env->hvictl = val & HVICTL_VALID_MASK; | |
2610 | return RISCV_EXCP_NONE; | |
2611 | } | |
2612 | ||
2613 | static int read_hvipriox(CPURISCVState *env, int first_index, | |
2614 | uint8_t *iprio, target_ulong *val) | |
2615 | { | |
2616 | int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32); | |
2617 | ||
2618 | /* First index has to be a multiple of number of irqs per register */ | |
2619 | if (first_index % num_irqs) { | |
2620 | return (riscv_cpu_virt_enabled(env)) ? | |
2621 | RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; | |
2622 | } | |
2623 | ||
2624 | /* Fill-up return value */ | |
2625 | *val = 0; | |
2626 | for (i = 0; i < num_irqs; i++) { | |
2627 | if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) { | |
2628 | continue; | |
2629 | } | |
2630 | if (rdzero) { | |
2631 | continue; | |
2632 | } | |
2633 | *val |= ((target_ulong)iprio[irq]) << (i * 8); | |
2634 | } | |
2635 | ||
2636 | return RISCV_EXCP_NONE; | |
2637 | } | |
2638 | ||
2639 | static int write_hvipriox(CPURISCVState *env, int first_index, | |
2640 | uint8_t *iprio, target_ulong val) | |
2641 | { | |
2642 | int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32); | |
2643 | ||
2644 | /* First index has to be a multiple of number of irqs per register */ | |
2645 | if (first_index % num_irqs) { | |
2646 | return (riscv_cpu_virt_enabled(env)) ? | |
2647 | RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; | |
2648 | } | |
2649 | ||
2650 | /* Fill-up priority arrary */ | |
2651 | for (i = 0; i < num_irqs; i++) { | |
2652 | if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) { | |
2653 | continue; | |
2654 | } | |
2655 | if (rdzero) { | |
2656 | iprio[irq] = 0; | |
2657 | } else { | |
2658 | iprio[irq] = (val >> (i * 8)) & 0xff; | |
2659 | } | |
2660 | } | |
2661 | ||
2662 | return RISCV_EXCP_NONE; | |
2663 | } | |
2664 | ||
2665 | static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val) | |
2666 | { | |
2667 | return read_hvipriox(env, 0, env->hviprio, val); | |
2668 | } | |
2669 | ||
2670 | static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val) | |
2671 | { | |
2672 | return write_hvipriox(env, 0, env->hviprio, val); | |
2673 | } | |
2674 | ||
2675 | static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val) | |
2676 | { | |
2677 | return read_hvipriox(env, 4, env->hviprio, val); | |
2678 | } | |
2679 | ||
2680 | static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val) | |
2681 | { | |
2682 | return write_hvipriox(env, 4, env->hviprio, val); | |
2683 | } | |
2684 | ||
2685 | static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val) | |
2686 | { | |
2687 | return read_hvipriox(env, 8, env->hviprio, val); | |
2688 | } | |
2689 | ||
2690 | static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val) | |
2691 | { | |
2692 | return write_hvipriox(env, 8, env->hviprio, val); | |
2693 | } | |
2694 | ||
2695 | static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val) | |
2696 | { | |
2697 | return read_hvipriox(env, 12, env->hviprio, val); | |
2698 | } | |
2699 | ||
2700 | static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val) | |
2701 | { | |
2702 | return write_hvipriox(env, 12, env->hviprio, val); | |
2703 | } | |
2704 | ||
8747c9ee | 2705 | /* Virtual CSR Registers */ |
605def6e AF |
2706 | static RISCVException read_vsstatus(CPURISCVState *env, int csrno, |
2707 | target_ulong *val) | |
8747c9ee AF |
2708 | { |
2709 | *val = env->vsstatus; | |
605def6e | 2710 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2711 | } |
2712 | ||
605def6e AF |
2713 | static RISCVException write_vsstatus(CPURISCVState *env, int csrno, |
2714 | target_ulong val) | |
8747c9ee | 2715 | { |
284d697c | 2716 | uint64_t mask = (target_ulong)-1; |
f310df58 LZ |
2717 | if ((val & VSSTATUS64_UXL) == 0) { |
2718 | mask &= ~VSSTATUS64_UXL; | |
2719 | } | |
284d697c | 2720 | env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val; |
605def6e | 2721 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2722 | } |
2723 | ||
8747c9ee AF |
2724 | static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val) |
2725 | { | |
2726 | *val = env->vstvec; | |
605def6e | 2727 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2728 | } |
2729 | ||
605def6e AF |
2730 | static RISCVException write_vstvec(CPURISCVState *env, int csrno, |
2731 | target_ulong val) | |
8747c9ee AF |
2732 | { |
2733 | env->vstvec = val; | |
605def6e | 2734 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2735 | } |
2736 | ||
605def6e AF |
2737 | static RISCVException read_vsscratch(CPURISCVState *env, int csrno, |
2738 | target_ulong *val) | |
8747c9ee AF |
2739 | { |
2740 | *val = env->vsscratch; | |
605def6e | 2741 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2742 | } |
2743 | ||
605def6e AF |
2744 | static RISCVException write_vsscratch(CPURISCVState *env, int csrno, |
2745 | target_ulong val) | |
8747c9ee AF |
2746 | { |
2747 | env->vsscratch = val; | |
605def6e | 2748 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2749 | } |
2750 | ||
605def6e AF |
2751 | static RISCVException read_vsepc(CPURISCVState *env, int csrno, |
2752 | target_ulong *val) | |
8747c9ee AF |
2753 | { |
2754 | *val = env->vsepc; | |
605def6e | 2755 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2756 | } |
2757 | ||
605def6e AF |
2758 | static RISCVException write_vsepc(CPURISCVState *env, int csrno, |
2759 | target_ulong val) | |
8747c9ee AF |
2760 | { |
2761 | env->vsepc = val; | |
605def6e | 2762 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2763 | } |
2764 | ||
605def6e AF |
2765 | static RISCVException read_vscause(CPURISCVState *env, int csrno, |
2766 | target_ulong *val) | |
8747c9ee AF |
2767 | { |
2768 | *val = env->vscause; | |
605def6e | 2769 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2770 | } |
2771 | ||
605def6e AF |
2772 | static RISCVException write_vscause(CPURISCVState *env, int csrno, |
2773 | target_ulong val) | |
8747c9ee AF |
2774 | { |
2775 | env->vscause = val; | |
605def6e | 2776 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2777 | } |
2778 | ||
605def6e AF |
2779 | static RISCVException read_vstval(CPURISCVState *env, int csrno, |
2780 | target_ulong *val) | |
8747c9ee AF |
2781 | { |
2782 | *val = env->vstval; | |
605def6e | 2783 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2784 | } |
2785 | ||
605def6e AF |
2786 | static RISCVException write_vstval(CPURISCVState *env, int csrno, |
2787 | target_ulong val) | |
8747c9ee AF |
2788 | { |
2789 | env->vstval = val; | |
605def6e | 2790 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2791 | } |
2792 | ||
605def6e AF |
2793 | static RISCVException read_vsatp(CPURISCVState *env, int csrno, |
2794 | target_ulong *val) | |
8747c9ee AF |
2795 | { |
2796 | *val = env->vsatp; | |
605def6e | 2797 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2798 | } |
2799 | ||
605def6e AF |
2800 | static RISCVException write_vsatp(CPURISCVState *env, int csrno, |
2801 | target_ulong val) | |
8747c9ee AF |
2802 | { |
2803 | env->vsatp = val; | |
605def6e | 2804 | return RISCV_EXCP_NONE; |
8747c9ee AF |
2805 | } |
2806 | ||
605def6e AF |
2807 | static RISCVException read_mtval2(CPURISCVState *env, int csrno, |
2808 | target_ulong *val) | |
34cfb5f6 AF |
2809 | { |
2810 | *val = env->mtval2; | |
605def6e | 2811 | return RISCV_EXCP_NONE; |
34cfb5f6 AF |
2812 | } |
2813 | ||
605def6e AF |
2814 | static RISCVException write_mtval2(CPURISCVState *env, int csrno, |
2815 | target_ulong val) | |
34cfb5f6 AF |
2816 | { |
2817 | env->mtval2 = val; | |
605def6e | 2818 | return RISCV_EXCP_NONE; |
34cfb5f6 AF |
2819 | } |
2820 | ||
605def6e AF |
2821 | static RISCVException read_mtinst(CPURISCVState *env, int csrno, |
2822 | target_ulong *val) | |
34cfb5f6 AF |
2823 | { |
2824 | *val = env->mtinst; | |
605def6e | 2825 | return RISCV_EXCP_NONE; |
34cfb5f6 AF |
2826 | } |
2827 | ||
605def6e AF |
2828 | static RISCVException write_mtinst(CPURISCVState *env, int csrno, |
2829 | target_ulong val) | |
34cfb5f6 AF |
2830 | { |
2831 | env->mtinst = val; | |
605def6e | 2832 | return RISCV_EXCP_NONE; |
34cfb5f6 AF |
2833 | } |
2834 | ||
c7b95171 | 2835 | /* Physical Memory Protection */ |
2582a95c HW |
2836 | static RISCVException read_mseccfg(CPURISCVState *env, int csrno, |
2837 | target_ulong *val) | |
2838 | { | |
2839 | *val = mseccfg_csr_read(env); | |
2840 | return RISCV_EXCP_NONE; | |
2841 | } | |
2842 | ||
2843 | static RISCVException write_mseccfg(CPURISCVState *env, int csrno, | |
2844 | target_ulong val) | |
2845 | { | |
2846 | mseccfg_csr_write(env, val); | |
2847 | return RISCV_EXCP_NONE; | |
2848 | } | |
2849 | ||
79f26b3b LZ |
2850 | static bool check_pmp_reg_index(CPURISCVState *env, uint32_t reg_index) |
2851 | { | |
2852 | /* TODO: RV128 restriction check */ | |
2853 | if ((reg_index & 1) && (riscv_cpu_mxl(env) == MXL_RV64)) { | |
2854 | return false; | |
2855 | } | |
2856 | return true; | |
2857 | } | |
2858 | ||
605def6e AF |
2859 | static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, |
2860 | target_ulong *val) | |
c7b95171 | 2861 | { |
79f26b3b LZ |
2862 | uint32_t reg_index = csrno - CSR_PMPCFG0; |
2863 | ||
2864 | if (!check_pmp_reg_index(env, reg_index)) { | |
2865 | return RISCV_EXCP_ILLEGAL_INST; | |
2866 | } | |
c7b95171 | 2867 | *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0); |
605def6e | 2868 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2869 | } |
2870 | ||
605def6e AF |
2871 | static RISCVException write_pmpcfg(CPURISCVState *env, int csrno, |
2872 | target_ulong val) | |
c7b95171 | 2873 | { |
79f26b3b LZ |
2874 | uint32_t reg_index = csrno - CSR_PMPCFG0; |
2875 | ||
2876 | if (!check_pmp_reg_index(env, reg_index)) { | |
2877 | return RISCV_EXCP_ILLEGAL_INST; | |
2878 | } | |
c7b95171 | 2879 | pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val); |
605def6e | 2880 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2881 | } |
2882 | ||
605def6e AF |
2883 | static RISCVException read_pmpaddr(CPURISCVState *env, int csrno, |
2884 | target_ulong *val) | |
c7b95171 MC |
2885 | { |
2886 | *val = pmpaddr_csr_read(env, csrno - CSR_PMPADDR0); | |
605def6e | 2887 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2888 | } |
2889 | ||
605def6e AF |
2890 | static RISCVException write_pmpaddr(CPURISCVState *env, int csrno, |
2891 | target_ulong val) | |
c7b95171 MC |
2892 | { |
2893 | pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val); | |
605def6e | 2894 | return RISCV_EXCP_NONE; |
c7b95171 MC |
2895 | } |
2896 | ||
b6092544 BM |
2897 | static RISCVException read_tselect(CPURISCVState *env, int csrno, |
2898 | target_ulong *val) | |
2899 | { | |
2900 | *val = tselect_csr_read(env); | |
2901 | return RISCV_EXCP_NONE; | |
2902 | } | |
2903 | ||
2904 | static RISCVException write_tselect(CPURISCVState *env, int csrno, | |
2905 | target_ulong val) | |
2906 | { | |
2907 | tselect_csr_write(env, val); | |
2908 | return RISCV_EXCP_NONE; | |
2909 | } | |
2910 | ||
2911 | static RISCVException read_tdata(CPURISCVState *env, int csrno, | |
2912 | target_ulong *val) | |
2913 | { | |
2914 | /* return 0 in tdata1 to end the trigger enumeration */ | |
2915 | if (env->trigger_cur >= TRIGGER_NUM && csrno == CSR_TDATA1) { | |
2916 | *val = 0; | |
2917 | return RISCV_EXCP_NONE; | |
2918 | } | |
2919 | ||
2920 | if (!tdata_available(env, csrno - CSR_TDATA1)) { | |
2921 | return RISCV_EXCP_ILLEGAL_INST; | |
2922 | } | |
2923 | ||
2924 | *val = tdata_csr_read(env, csrno - CSR_TDATA1); | |
2925 | return RISCV_EXCP_NONE; | |
2926 | } | |
2927 | ||
2928 | static RISCVException write_tdata(CPURISCVState *env, int csrno, | |
2929 | target_ulong val) | |
2930 | { | |
2931 | if (!tdata_available(env, csrno - CSR_TDATA1)) { | |
2932 | return RISCV_EXCP_ILLEGAL_INST; | |
2933 | } | |
2934 | ||
2935 | tdata_csr_write(env, csrno - CSR_TDATA1, val); | |
2936 | return RISCV_EXCP_NONE; | |
2937 | } | |
2938 | ||
4bbe8033 AB |
2939 | /* |
2940 | * Functions to access Pointer Masking feature registers | |
2941 | * We have to check if current priv lvl could modify | |
2942 | * csr in given mode | |
2943 | */ | |
2944 | static bool check_pm_current_disabled(CPURISCVState *env, int csrno) | |
2945 | { | |
2946 | int csr_priv = get_field(csrno, 0x300); | |
2947 | int pm_current; | |
2948 | ||
47bdec82 LZ |
2949 | if (env->debugger) { |
2950 | return false; | |
2951 | } | |
4bbe8033 AB |
2952 | /* |
2953 | * If priv lvls differ that means we're accessing csr from higher priv lvl, | |
2954 | * so allow the access | |
2955 | */ | |
2956 | if (env->priv != csr_priv) { | |
2957 | return false; | |
2958 | } | |
2959 | switch (env->priv) { | |
2960 | case PRV_M: | |
2961 | pm_current = get_field(env->mmte, M_PM_CURRENT); | |
2962 | break; | |
2963 | case PRV_S: | |
2964 | pm_current = get_field(env->mmte, S_PM_CURRENT); | |
2965 | break; | |
2966 | case PRV_U: | |
2967 | pm_current = get_field(env->mmte, U_PM_CURRENT); | |
2968 | break; | |
2969 | default: | |
2970 | g_assert_not_reached(); | |
2971 | } | |
2972 | /* It's same priv lvl, so we allow to modify csr only if pm.current==1 */ | |
2973 | return !pm_current; | |
2974 | } | |
2975 | ||
2976 | static RISCVException read_mmte(CPURISCVState *env, int csrno, | |
2977 | target_ulong *val) | |
2978 | { | |
2979 | *val = env->mmte & MMTE_MASK; | |
2980 | return RISCV_EXCP_NONE; | |
2981 | } | |
2982 | ||
2983 | static RISCVException write_mmte(CPURISCVState *env, int csrno, | |
2984 | target_ulong val) | |
2985 | { | |
2986 | uint64_t mstatus; | |
2987 | target_ulong wpri_val = val & MMTE_MASK; | |
2988 | ||
2989 | if (val != wpri_val) { | |
2990 | qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n", | |
2991 | "MMTE: WPRI violation written 0x", val, | |
2992 | "vs expected 0x", wpri_val); | |
2993 | } | |
2994 | /* for machine mode pm.current is hardwired to 1 */ | |
2995 | wpri_val |= MMTE_M_PM_CURRENT; | |
2996 | ||
2997 | /* hardwiring pm.instruction bit to 0, since it's not supported yet */ | |
2998 | wpri_val &= ~(MMTE_M_PM_INSN | MMTE_S_PM_INSN | MMTE_U_PM_INSN); | |
2999 | env->mmte = wpri_val | PM_EXT_DIRTY; | |
40bfa5f6 | 3000 | riscv_cpu_update_mask(env); |
4bbe8033 AB |
3001 | |
3002 | /* Set XS and SD bits, since PM CSRs are dirty */ | |
3003 | mstatus = env->mstatus | MSTATUS_XS; | |
3004 | write_mstatus(env, csrno, mstatus); | |
3005 | return RISCV_EXCP_NONE; | |
3006 | } | |
3007 | ||
3008 | static RISCVException read_smte(CPURISCVState *env, int csrno, | |
3009 | target_ulong *val) | |
3010 | { | |
3011 | *val = env->mmte & SMTE_MASK; | |
3012 | return RISCV_EXCP_NONE; | |
3013 | } | |
3014 | ||
3015 | static RISCVException write_smte(CPURISCVState *env, int csrno, | |
3016 | target_ulong val) | |
3017 | { | |
3018 | target_ulong wpri_val = val & SMTE_MASK; | |
3019 | ||
3020 | if (val != wpri_val) { | |
3021 | qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n", | |
3022 | "SMTE: WPRI violation written 0x", val, | |
3023 | "vs expected 0x", wpri_val); | |
3024 | } | |
3025 | ||
3026 | /* if pm.current==0 we can't modify current PM CSRs */ | |
3027 | if (check_pm_current_disabled(env, csrno)) { | |
3028 | return RISCV_EXCP_NONE; | |
3029 | } | |
3030 | ||
3031 | wpri_val |= (env->mmte & ~SMTE_MASK); | |
3032 | write_mmte(env, csrno, wpri_val); | |
3033 | return RISCV_EXCP_NONE; | |
3034 | } | |
3035 | ||
3036 | static RISCVException read_umte(CPURISCVState *env, int csrno, | |
3037 | target_ulong *val) | |
3038 | { | |
3039 | *val = env->mmte & UMTE_MASK; | |
3040 | return RISCV_EXCP_NONE; | |
3041 | } | |
3042 | ||
3043 | static RISCVException write_umte(CPURISCVState *env, int csrno, | |
3044 | target_ulong val) | |
3045 | { | |
3046 | target_ulong wpri_val = val & UMTE_MASK; | |
3047 | ||
3048 | if (val != wpri_val) { | |
3049 | qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n", | |
3050 | "UMTE: WPRI violation written 0x", val, | |
3051 | "vs expected 0x", wpri_val); | |
3052 | } | |
3053 | ||
3054 | if (check_pm_current_disabled(env, csrno)) { | |
3055 | return RISCV_EXCP_NONE; | |
3056 | } | |
3057 | ||
3058 | wpri_val |= (env->mmte & ~UMTE_MASK); | |
3059 | write_mmte(env, csrno, wpri_val); | |
3060 | return RISCV_EXCP_NONE; | |
3061 | } | |
3062 | ||
3063 | static RISCVException read_mpmmask(CPURISCVState *env, int csrno, | |
3064 | target_ulong *val) | |
3065 | { | |
3066 | *val = env->mpmmask; | |
3067 | return RISCV_EXCP_NONE; | |
3068 | } | |
3069 | ||
3070 | static RISCVException write_mpmmask(CPURISCVState *env, int csrno, | |
3071 | target_ulong val) | |
3072 | { | |
3073 | uint64_t mstatus; | |
3074 | ||
3075 | env->mpmmask = val; | |
40bfa5f6 LZ |
3076 | if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) { |
3077 | env->cur_pmmask = val; | |
3078 | } | |
4bbe8033 AB |
3079 | env->mmte |= PM_EXT_DIRTY; |
3080 | ||
3081 | /* Set XS and SD bits, since PM CSRs are dirty */ | |
3082 | mstatus = env->mstatus | MSTATUS_XS; | |
3083 | write_mstatus(env, csrno, mstatus); | |
3084 | return RISCV_EXCP_NONE; | |
3085 | } | |
3086 | ||
3087 | static RISCVException read_spmmask(CPURISCVState *env, int csrno, | |
3088 | target_ulong *val) | |
3089 | { | |
3090 | *val = env->spmmask; | |
3091 | return RISCV_EXCP_NONE; | |
3092 | } | |
3093 | ||
3094 | static RISCVException write_spmmask(CPURISCVState *env, int csrno, | |
3095 | target_ulong val) | |
3096 | { | |
3097 | uint64_t mstatus; | |
3098 | ||
3099 | /* if pm.current==0 we can't modify current PM CSRs */ | |
3100 | if (check_pm_current_disabled(env, csrno)) { | |
3101 | return RISCV_EXCP_NONE; | |
3102 | } | |
3103 | env->spmmask = val; | |
40bfa5f6 LZ |
3104 | if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) { |
3105 | env->cur_pmmask = val; | |
3106 | } | |
4bbe8033 AB |
3107 | env->mmte |= PM_EXT_DIRTY; |
3108 | ||
3109 | /* Set XS and SD bits, since PM CSRs are dirty */ | |
3110 | mstatus = env->mstatus | MSTATUS_XS; | |
3111 | write_mstatus(env, csrno, mstatus); | |
3112 | return RISCV_EXCP_NONE; | |
3113 | } | |
3114 | ||
3115 | static RISCVException read_upmmask(CPURISCVState *env, int csrno, | |
3116 | target_ulong *val) | |
3117 | { | |
3118 | *val = env->upmmask; | |
3119 | return RISCV_EXCP_NONE; | |
3120 | } | |
3121 | ||
3122 | static RISCVException write_upmmask(CPURISCVState *env, int csrno, | |
3123 | target_ulong val) | |
3124 | { | |
3125 | uint64_t mstatus; | |
3126 | ||
3127 | /* if pm.current==0 we can't modify current PM CSRs */ | |
3128 | if (check_pm_current_disabled(env, csrno)) { | |
3129 | return RISCV_EXCP_NONE; | |
3130 | } | |
3131 | env->upmmask = val; | |
40bfa5f6 LZ |
3132 | if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) { |
3133 | env->cur_pmmask = val; | |
3134 | } | |
4bbe8033 AB |
3135 | env->mmte |= PM_EXT_DIRTY; |
3136 | ||
3137 | /* Set XS and SD bits, since PM CSRs are dirty */ | |
3138 | mstatus = env->mstatus | MSTATUS_XS; | |
3139 | write_mstatus(env, csrno, mstatus); | |
3140 | return RISCV_EXCP_NONE; | |
3141 | } | |
3142 | ||
3143 | static RISCVException read_mpmbase(CPURISCVState *env, int csrno, | |
3144 | target_ulong *val) | |
3145 | { | |
3146 | *val = env->mpmbase; | |
3147 | return RISCV_EXCP_NONE; | |
3148 | } | |
3149 | ||
3150 | static RISCVException write_mpmbase(CPURISCVState *env, int csrno, | |
3151 | target_ulong val) | |
3152 | { | |
3153 | uint64_t mstatus; | |
3154 | ||
3155 | env->mpmbase = val; | |
40bfa5f6 LZ |
3156 | if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) { |
3157 | env->cur_pmbase = val; | |
3158 | } | |
4bbe8033 AB |
3159 | env->mmte |= PM_EXT_DIRTY; |
3160 | ||
3161 | /* Set XS and SD bits, since PM CSRs are dirty */ | |
3162 | mstatus = env->mstatus | MSTATUS_XS; | |
3163 | write_mstatus(env, csrno, mstatus); | |
3164 | return RISCV_EXCP_NONE; | |
3165 | } | |
3166 | ||
3167 | static RISCVException read_spmbase(CPURISCVState *env, int csrno, | |
3168 | target_ulong *val) | |
3169 | { | |
3170 | *val = env->spmbase; | |
3171 | return RISCV_EXCP_NONE; | |
3172 | } | |
3173 | ||
3174 | static RISCVException write_spmbase(CPURISCVState *env, int csrno, | |
3175 | target_ulong val) | |
3176 | { | |
3177 | uint64_t mstatus; | |
3178 | ||
3179 | /* if pm.current==0 we can't modify current PM CSRs */ | |
3180 | if (check_pm_current_disabled(env, csrno)) { | |
3181 | return RISCV_EXCP_NONE; | |
3182 | } | |
3183 | env->spmbase = val; | |
40bfa5f6 LZ |
3184 | if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) { |
3185 | env->cur_pmbase = val; | |
3186 | } | |
4bbe8033 AB |
3187 | env->mmte |= PM_EXT_DIRTY; |
3188 | ||
3189 | /* Set XS and SD bits, since PM CSRs are dirty */ | |
3190 | mstatus = env->mstatus | MSTATUS_XS; | |
3191 | write_mstatus(env, csrno, mstatus); | |
3192 | return RISCV_EXCP_NONE; | |
3193 | } | |
3194 | ||
3195 | static RISCVException read_upmbase(CPURISCVState *env, int csrno, | |
3196 | target_ulong *val) | |
3197 | { | |
3198 | *val = env->upmbase; | |
3199 | return RISCV_EXCP_NONE; | |
3200 | } | |
3201 | ||
3202 | static RISCVException write_upmbase(CPURISCVState *env, int csrno, | |
3203 | target_ulong val) | |
3204 | { | |
3205 | uint64_t mstatus; | |
3206 | ||
3207 | /* if pm.current==0 we can't modify current PM CSRs */ | |
3208 | if (check_pm_current_disabled(env, csrno)) { | |
3209 | return RISCV_EXCP_NONE; | |
3210 | } | |
3211 | env->upmbase = val; | |
40bfa5f6 LZ |
3212 | if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) { |
3213 | env->cur_pmbase = val; | |
3214 | } | |
4bbe8033 AB |
3215 | env->mmte |= PM_EXT_DIRTY; |
3216 | ||
3217 | /* Set XS and SD bits, since PM CSRs are dirty */ | |
3218 | mstatus = env->mstatus | MSTATUS_XS; | |
3219 | write_mstatus(env, csrno, mstatus); | |
3220 | return RISCV_EXCP_NONE; | |
3221 | } | |
3222 | ||
c7b95171 MC |
3223 | #endif |
3224 | ||
77442380 WL |
3225 | /* Crypto Extension */ |
3226 | static RISCVException rmw_seed(CPURISCVState *env, int csrno, | |
3227 | target_ulong *ret_value, | |
3228 | target_ulong new_value, | |
3229 | target_ulong write_mask) | |
3230 | { | |
3231 | uint16_t random_v; | |
3232 | Error *random_e = NULL; | |
3233 | int random_r; | |
3234 | target_ulong rval; | |
3235 | ||
3236 | random_r = qemu_guest_getrandom(&random_v, 2, &random_e); | |
3237 | if (unlikely(random_r < 0)) { | |
3238 | /* | |
3239 | * Failed, for unknown reasons in the crypto subsystem. | |
3240 | * The best we can do is log the reason and return a | |
3241 | * failure indication to the guest. There is no reason | |
3242 | * we know to expect the failure to be transitory, so | |
3243 | * indicate DEAD to avoid having the guest spin on WAIT. | |
3244 | */ | |
3245 | qemu_log_mask(LOG_UNIMP, "%s: Crypto failure: %s", | |
3246 | __func__, error_get_pretty(random_e)); | |
3247 | error_free(random_e); | |
3248 | rval = SEED_OPST_DEAD; | |
3249 | } else { | |
3250 | rval = random_v | SEED_OPST_ES16; | |
3251 | } | |
3252 | ||
3253 | if (ret_value) { | |
3254 | *ret_value = rval; | |
3255 | } | |
3256 | ||
3257 | return RISCV_EXCP_NONE; | |
3258 | } | |
3259 | ||
c7b95171 MC |
3260 | /* |
3261 | * riscv_csrrw - read and/or update control and status register | |
3262 | * | |
3263 | * csrr <-> riscv_csrrw(env, csrno, ret_value, 0, 0); | |
3264 | * csrrw <-> riscv_csrrw(env, csrno, ret_value, value, -1); | |
3265 | * csrrs <-> riscv_csrrw(env, csrno, ret_value, -1, value); | |
3266 | * csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value); | |
3267 | */ | |
3268 | ||
457c360f FP |
3269 | static inline RISCVException riscv_csrrw_check(CPURISCVState *env, |
3270 | int csrno, | |
3271 | bool write_mask, | |
3272 | RISCVCPU *cpu) | |
c7b95171 | 3273 | { |
65e728a2 | 3274 | /* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */ |
457c360f | 3275 | int read_only = get_field(csrno, 0xC00) == 3; |
7100fe6c | 3276 | int csr_min_priv = csr_ops[csrno].min_priv_ver; |
eacaf440 WL |
3277 | |
3278 | /* ensure the CSR extension is enabled. */ | |
3279 | if (!cpu->cfg.ext_icsr) { | |
3280 | return RISCV_EXCP_ILLEGAL_INST; | |
3281 | } | |
3282 | ||
3283 | if (env->priv_ver < csr_min_priv) { | |
3284 | return RISCV_EXCP_ILLEGAL_INST; | |
3285 | } | |
3286 | ||
3287 | /* check predicate */ | |
3288 | if (!csr_ops[csrno].predicate) { | |
3289 | return RISCV_EXCP_ILLEGAL_INST; | |
3290 | } | |
3291 | ||
3292 | if (write_mask && read_only) { | |
3293 | return RISCV_EXCP_ILLEGAL_INST; | |
3294 | } | |
3295 | ||
3296 | RISCVException ret = csr_ops[csrno].predicate(env, csrno); | |
3297 | if (ret != RISCV_EXCP_NONE) { | |
3298 | return ret; | |
3299 | } | |
3300 | ||
c7b95171 | 3301 | #if !defined(CONFIG_USER_ONLY) |
c1fbcecb | 3302 | int csr_priv, effective_priv = env->priv; |
0a42f4c4 | 3303 | |
5de12453 WL |
3304 | if (riscv_has_ext(env, RVH) && env->priv == PRV_S && |
3305 | !riscv_cpu_virt_enabled(env)) { | |
0a42f4c4 | 3306 | /* |
5de12453 WL |
3307 | * We are in HS mode. Add 1 to the effective privledge level to |
3308 | * allow us to access the Hypervisor CSRs. | |
0a42f4c4 AF |
3309 | */ |
3310 | effective_priv++; | |
e6e03dcf | 3311 | } |
0a42f4c4 | 3312 | |
c1fbcecb AP |
3313 | csr_priv = get_field(csrno, 0x300); |
3314 | if (!env->debugger && (effective_priv < csr_priv)) { | |
3315 | if (csr_priv == (PRV_S + 1) && riscv_cpu_virt_enabled(env)) { | |
3316 | return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; | |
3317 | } | |
533c91e8 | 3318 | return RISCV_EXCP_ILLEGAL_INST; |
c7b95171 MC |
3319 | } |
3320 | #endif | |
eacaf440 | 3321 | return RISCV_EXCP_NONE; |
457c360f FP |
3322 | } |
3323 | ||
3324 | static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, | |
3325 | target_ulong *ret_value, | |
3326 | target_ulong new_value, | |
3327 | target_ulong write_mask) | |
3328 | { | |
3329 | RISCVException ret; | |
3330 | target_ulong old_value; | |
a88365c1 | 3331 | |
c7b95171 MC |
3332 | /* execute combined read/write operation if it exists */ |
3333 | if (csr_ops[csrno].op) { | |
533c91e8 | 3334 | return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask); |
c7b95171 MC |
3335 | } |
3336 | ||
3337 | /* if no accessor exists then return failure */ | |
3338 | if (!csr_ops[csrno].read) { | |
533c91e8 | 3339 | return RISCV_EXCP_ILLEGAL_INST; |
c7b95171 | 3340 | } |
c7b95171 MC |
3341 | /* read old value */ |
3342 | ret = csr_ops[csrno].read(env, csrno, &old_value); | |
605def6e | 3343 | if (ret != RISCV_EXCP_NONE) { |
533c91e8 | 3344 | return ret; |
c7b95171 MC |
3345 | } |
3346 | ||
3347 | /* write value if writable and write mask set, otherwise drop writes */ | |
3348 | if (write_mask) { | |
3349 | new_value = (old_value & ~write_mask) | (new_value & write_mask); | |
3350 | if (csr_ops[csrno].write) { | |
3351 | ret = csr_ops[csrno].write(env, csrno, new_value); | |
605def6e | 3352 | if (ret != RISCV_EXCP_NONE) { |
533c91e8 | 3353 | return ret; |
c7b95171 MC |
3354 | } |
3355 | } | |
3356 | } | |
3357 | ||
3358 | /* return old value */ | |
3359 | if (ret_value) { | |
3360 | *ret_value = old_value; | |
3361 | } | |
3362 | ||
533c91e8 | 3363 | return RISCV_EXCP_NONE; |
c7b95171 MC |
3364 | } |
3365 | ||
457c360f FP |
3366 | RISCVException riscv_csrrw(CPURISCVState *env, int csrno, |
3367 | target_ulong *ret_value, | |
3368 | target_ulong new_value, target_ulong write_mask) | |
3369 | { | |
3370 | RISCVCPU *cpu = env_archcpu(env); | |
3371 | ||
3372 | RISCVException ret = riscv_csrrw_check(env, csrno, write_mask, cpu); | |
3373 | if (ret != RISCV_EXCP_NONE) { | |
3374 | return ret; | |
3375 | } | |
3376 | ||
3377 | return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask); | |
3378 | } | |
3379 | ||
3380 | static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, | |
3381 | Int128 *ret_value, | |
3382 | Int128 new_value, | |
3383 | Int128 write_mask) | |
961738ff | 3384 | { |
457c360f FP |
3385 | RISCVException ret; |
3386 | Int128 old_value; | |
3387 | ||
3388 | /* read old value */ | |
3389 | ret = csr_ops[csrno].read128(env, csrno, &old_value); | |
3390 | if (ret != RISCV_EXCP_NONE) { | |
3391 | return ret; | |
3392 | } | |
3393 | ||
3394 | /* write value if writable and write mask set, otherwise drop writes */ | |
3395 | if (int128_nz(write_mask)) { | |
3396 | new_value = int128_or(int128_and(old_value, int128_not(write_mask)), | |
3397 | int128_and(new_value, write_mask)); | |
3398 | if (csr_ops[csrno].write128) { | |
3399 | ret = csr_ops[csrno].write128(env, csrno, new_value); | |
3400 | if (ret != RISCV_EXCP_NONE) { | |
3401 | return ret; | |
3402 | } | |
3403 | } else if (csr_ops[csrno].write) { | |
3404 | /* avoids having to write wrappers for all registers */ | |
3405 | ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value)); | |
3406 | if (ret != RISCV_EXCP_NONE) { | |
3407 | return ret; | |
3408 | } | |
3409 | } | |
3410 | } | |
961738ff | 3411 | |
457c360f | 3412 | /* return old value */ |
961738ff | 3413 | if (ret_value) { |
457c360f FP |
3414 | *ret_value = old_value; |
3415 | } | |
3416 | ||
3417 | return RISCV_EXCP_NONE; | |
3418 | } | |
3419 | ||
3420 | RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, | |
3421 | Int128 *ret_value, | |
3422 | Int128 new_value, Int128 write_mask) | |
3423 | { | |
3424 | RISCVException ret; | |
3425 | RISCVCPU *cpu = env_archcpu(env); | |
3426 | ||
3427 | ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask), cpu); | |
3428 | if (ret != RISCV_EXCP_NONE) { | |
3429 | return ret; | |
961738ff FP |
3430 | } |
3431 | ||
457c360f FP |
3432 | if (csr_ops[csrno].read128) { |
3433 | return riscv_csrrw_do128(env, csrno, ret_value, new_value, write_mask); | |
3434 | } | |
3435 | ||
3436 | /* | |
3437 | * Fall back to 64-bit version for now, if the 128-bit alternative isn't | |
3438 | * at all defined. | |
3439 | * Note, some CSRs don't need to extend to MXLEN (64 upper bits non | |
3440 | * significant), for those, this fallback is correctly handling the accesses | |
3441 | */ | |
3442 | target_ulong old_value; | |
3443 | ret = riscv_csrrw_do64(env, csrno, &old_value, | |
3444 | int128_getlo(new_value), | |
3445 | int128_getlo(write_mask)); | |
3446 | if (ret == RISCV_EXCP_NONE && ret_value) { | |
3447 | *ret_value = int128_make64(old_value); | |
3448 | } | |
961738ff FP |
3449 | return ret; |
3450 | } | |
3451 | ||
753e3fe2 JW |
3452 | /* |
3453 | * Debugger support. If not in user mode, set env->debugger before the | |
3454 | * riscv_csrrw call and clear it after the call. | |
3455 | */ | |
533c91e8 AF |
3456 | RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, |
3457 | target_ulong *ret_value, | |
3458 | target_ulong new_value, | |
3459 | target_ulong write_mask) | |
753e3fe2 | 3460 | { |
533c91e8 | 3461 | RISCVException ret; |
753e3fe2 JW |
3462 | #if !defined(CONFIG_USER_ONLY) |
3463 | env->debugger = true; | |
3464 | #endif | |
3465 | ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask); | |
3466 | #if !defined(CONFIG_USER_ONLY) | |
3467 | env->debugger = false; | |
3468 | #endif | |
3469 | return ret; | |
3470 | } | |
3471 | ||
c7b95171 | 3472 | /* Control and Status Register function table */ |
56118ee8 | 3473 | riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { |
c7b95171 | 3474 | /* User Floating-Point CSRs */ |
8ceac5dc BM |
3475 | [CSR_FFLAGS] = { "fflags", fs, read_fflags, write_fflags }, |
3476 | [CSR_FRM] = { "frm", fs, read_frm, write_frm }, | |
3477 | [CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr }, | |
8e3a1f18 | 3478 | /* Vector CSRs */ |
108c4f26 WL |
3479 | [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart, |
3480 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3481 | [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat, | |
3482 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3483 | [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm, | |
3484 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3485 | [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr, | |
3486 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3487 | [CSR_VL] = { "vl", vs, read_vl, | |
3488 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3489 | [CSR_VTYPE] = { "vtype", vs, read_vtype, | |
3490 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3491 | [CSR_VLENB] = { "vlenb", vs, read_vlenb, | |
3492 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
c7b95171 | 3493 | /* User Timers and Counters */ |
3780e337 AP |
3494 | [CSR_CYCLE] = { "cycle", ctr, read_hpmcounter }, |
3495 | [CSR_INSTRET] = { "instret", ctr, read_hpmcounter }, | |
3496 | [CSR_CYCLEH] = { "cycleh", ctr32, read_hpmcounterh }, | |
3497 | [CSR_INSTRETH] = { "instreth", ctr32, read_hpmcounterh }, | |
8ceac5dc BM |
3498 | |
3499 | /* | |
3500 | * In privileged mode, the monitor will have to emulate TIME CSRs only if | |
3501 | * rdtime callback is not provided by machine/platform emulation. | |
3502 | */ | |
3503 | [CSR_TIME] = { "time", ctr, read_time }, | |
3504 | [CSR_TIMEH] = { "timeh", ctr32, read_timeh }, | |
c7b95171 | 3505 | |
77442380 WL |
3506 | /* Crypto Extension */ |
3507 | [CSR_SEED] = { "seed", seed, NULL, NULL, rmw_seed }, | |
3508 | ||
c7b95171 MC |
3509 | #if !defined(CONFIG_USER_ONLY) |
3510 | /* Machine Timers and Counters */ | |
108c4f26 WL |
3511 | [CSR_MCYCLE] = { "mcycle", any, read_hpmcounter, |
3512 | write_mhpmcounter }, | |
3513 | [CSR_MINSTRET] = { "minstret", any, read_hpmcounter, | |
3514 | write_mhpmcounter }, | |
3515 | [CSR_MCYCLEH] = { "mcycleh", any32, read_hpmcounterh, | |
3516 | write_mhpmcounterh }, | |
3517 | [CSR_MINSTRETH] = { "minstreth", any32, read_hpmcounterh, | |
3518 | write_mhpmcounterh }, | |
c7b95171 MC |
3519 | |
3520 | /* Machine Information Registers */ | |
9951ba94 FC |
3521 | [CSR_MVENDORID] = { "mvendorid", any, read_mvendorid }, |
3522 | [CSR_MARCHID] = { "marchid", any, read_marchid }, | |
075eeda9 | 3523 | [CSR_MIMPID] = { "mimpid", any, read_mimpid }, |
9951ba94 | 3524 | [CSR_MHARTID] = { "mhartid", any, read_mhartid }, |
c7b95171 | 3525 | |
3e6a417c | 3526 | [CSR_MCONFIGPTR] = { "mconfigptr", any, read_zero, |
108c4f26 | 3527 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
c7b95171 | 3528 | /* Machine Trap Setup */ |
108c4f26 WL |
3529 | [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus, |
3530 | NULL, read_mstatus_i128 }, | |
3531 | [CSR_MISA] = { "misa", any, read_misa, write_misa, | |
3532 | NULL, read_misa_i128 }, | |
3533 | [CSR_MIDELEG] = { "mideleg", any, NULL, NULL, rmw_mideleg }, | |
3534 | [CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg }, | |
3535 | [CSR_MIE] = { "mie", any, NULL, NULL, rmw_mie }, | |
3536 | [CSR_MTVEC] = { "mtvec", any, read_mtvec, write_mtvec }, | |
c126f83c | 3537 | [CSR_MCOUNTEREN] = { "mcounteren", umode, read_mcounteren, |
108c4f26 WL |
3538 | write_mcounteren }, |
3539 | ||
3540 | [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, | |
3541 | write_mstatush }, | |
551fa7e8 | 3542 | |
c7b95171 | 3543 | /* Machine Trap Handling */ |
108c4f26 WL |
3544 | [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch, |
3545 | NULL, read_mscratch_i128, write_mscratch_i128 }, | |
8ceac5dc BM |
3546 | [CSR_MEPC] = { "mepc", any, read_mepc, write_mepc }, |
3547 | [CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause }, | |
ac12b601 | 3548 | [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval }, |
8ceac5dc | 3549 | [CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip }, |
c7b95171 | 3550 | |
d1ceff40 AP |
3551 | /* Machine-Level Window to Indirectly Accessed Registers (AIA) */ |
3552 | [CSR_MISELECT] = { "miselect", aia_any, NULL, NULL, rmw_xiselect }, | |
3553 | [CSR_MIREG] = { "mireg", aia_any, NULL, NULL, rmw_xireg }, | |
3554 | ||
c7de92b4 | 3555 | /* Machine-Level Interrupts (AIA) */ |
108c4f26 WL |
3556 | [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei }, |
3557 | [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, | |
ac4b0302 | 3558 | |
d0237b4d | 3559 | /* Virtual Interrupts for Supervisor Level (AIA) */ |
108c4f26 WL |
3560 | [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, |
3561 | [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, | |
d0237b4d | 3562 | |
d028ac75 AP |
3563 | /* Machine-Level High-Half CSRs (AIA) */ |
3564 | [CSR_MIDELEGH] = { "midelegh", aia_any32, NULL, NULL, rmw_midelegh }, | |
3565 | [CSR_MIEH] = { "mieh", aia_any32, NULL, NULL, rmw_mieh }, | |
d0237b4d AP |
3566 | [CSR_MVIENH] = { "mvienh", aia_any32, read_zero, write_ignore }, |
3567 | [CSR_MVIPH] = { "mviph", aia_any32, read_zero, write_ignore }, | |
d028ac75 AP |
3568 | [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, |
3569 | ||
29a9ec9b | 3570 | /* Execution environment configuration */ |
c126f83c | 3571 | [CSR_MENVCFG] = { "menvcfg", umode, read_menvcfg, write_menvcfg, |
108c4f26 | 3572 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
c126f83c | 3573 | [CSR_MENVCFGH] = { "menvcfgh", umode32, read_menvcfgh, write_menvcfgh, |
108c4f26 | 3574 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
29a9ec9b | 3575 | [CSR_SENVCFG] = { "senvcfg", smode, read_senvcfg, write_senvcfg, |
108c4f26 | 3576 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
29a9ec9b | 3577 | [CSR_HENVCFG] = { "henvcfg", hmode, read_henvcfg, write_henvcfg, |
108c4f26 | 3578 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
29a9ec9b | 3579 | [CSR_HENVCFGH] = { "henvcfgh", hmode32, read_henvcfgh, write_henvcfgh, |
108c4f26 | 3580 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
29a9ec9b | 3581 | |
c7b95171 | 3582 | /* Supervisor Trap Setup */ |
108c4f26 WL |
3583 | [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus, |
3584 | NULL, read_sstatus_i128 }, | |
3585 | [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie }, | |
3586 | [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec }, | |
3587 | [CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, | |
3588 | write_scounteren }, | |
c7b95171 MC |
3589 | |
3590 | /* Supervisor Trap Handling */ | |
108c4f26 WL |
3591 | [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch, |
3592 | NULL, read_sscratch_i128, write_sscratch_i128 }, | |
8ceac5dc BM |
3593 | [CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc }, |
3594 | [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause }, | |
108c4f26 | 3595 | [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, |
8ceac5dc | 3596 | [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip }, |
c7b95171 MC |
3597 | |
3598 | /* Supervisor Protection and Translation */ | |
108c4f26 | 3599 | [CSR_SATP] = { "satp", smode, read_satp, write_satp }, |
8ceac5dc | 3600 | |
d1ceff40 AP |
3601 | /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */ |
3602 | [CSR_SISELECT] = { "siselect", aia_smode, NULL, NULL, rmw_xiselect }, | |
3603 | [CSR_SIREG] = { "sireg", aia_smode, NULL, NULL, rmw_xireg }, | |
3604 | ||
c7de92b4 | 3605 | /* Supervisor-Level Interrupts (AIA) */ |
ac4b0302 | 3606 | [CSR_STOPEI] = { "stopei", aia_smode, NULL, NULL, rmw_xtopei }, |
df01af33 | 3607 | [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, |
ac4b0302 | 3608 | |
d028ac75 AP |
3609 | /* Supervisor-Level High-Half CSRs (AIA) */ |
3610 | [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, | |
3611 | [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, | |
3612 | ||
108c4f26 WL |
3613 | [CSR_HSTATUS] = { "hstatus", hmode, read_hstatus, write_hstatus, |
3614 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3615 | [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg, | |
3616 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
a4b2fa43 | 3617 | [CSR_HIDELEG] = { "hideleg", hmode, NULL, NULL, rmw_hideleg, |
108c4f26 WL |
3618 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
3619 | [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip, | |
3620 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3621 | [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip, | |
3622 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3623 | [CSR_HIE] = { "hie", hmode, NULL, NULL, rmw_hie, | |
3624 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3625 | [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, | |
3626 | write_hcounteren, | |
3627 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3628 | [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie, | |
3629 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3630 | [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval, | |
3631 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3632 | [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst, | |
3633 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
a4b2fa43 | 3634 | [CSR_HGEIP] = { "hgeip", hmode, read_hgeip, |
108c4f26 WL |
3635 | .min_priv_ver = PRIV_VERSION_1_12_0 }, |
3636 | [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp, | |
3637 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3638 | [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, | |
3639 | write_htimedelta, | |
3640 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3641 | [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, | |
3642 | write_htimedeltah, | |
3643 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3644 | ||
3645 | [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus, | |
3646 | write_vsstatus, | |
3647 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3648 | [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip, | |
3649 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3650 | [CSR_VSIE] = { "vsie", hmode, NULL, NULL, rmw_vsie , | |
3651 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3652 | [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec, | |
3653 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3654 | [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch, | |
3655 | write_vsscratch, | |
3656 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3657 | [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc, | |
3658 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3659 | [CSR_VSCAUSE] = { "vscause", hmode, read_vscause, write_vscause, | |
3660 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3661 | [CSR_VSTVAL] = { "vstval", hmode, read_vstval, write_vstval, | |
3662 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3663 | [CSR_VSATP] = { "vsatp", hmode, read_vsatp, write_vsatp, | |
3664 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3665 | ||
3666 | [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2, | |
3667 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
3668 | [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst, | |
3669 | .min_priv_ver = PRIV_VERSION_1_12_0 }, | |
34cfb5f6 | 3670 | |
2b602398 | 3671 | /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ |
d0237b4d | 3672 | [CSR_HVIEN] = { "hvien", aia_hmode, read_zero, write_ignore }, |
108c4f26 WL |
3673 | [CSR_HVICTL] = { "hvictl", aia_hmode, read_hvictl, |
3674 | write_hvictl }, | |
3675 | [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, | |
3676 | write_hviprio1 }, | |
3677 | [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, | |
3678 | write_hviprio2 }, | |
2b602398 | 3679 | |
d1ceff40 AP |
3680 | /* |
3681 | * VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) | |
3682 | */ | |
108c4f26 WL |
3683 | [CSR_VSISELECT] = { "vsiselect", aia_hmode, NULL, NULL, |
3684 | rmw_xiselect }, | |
3685 | [CSR_VSIREG] = { "vsireg", aia_hmode, NULL, NULL, rmw_xireg }, | |
d1ceff40 | 3686 | |
c7de92b4 | 3687 | /* VS-Level Interrupts (H-extension with AIA) */ |
ac4b0302 | 3688 | [CSR_VSTOPEI] = { "vstopei", aia_hmode, NULL, NULL, rmw_xtopei }, |
df01af33 | 3689 | [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, |
ac4b0302 | 3690 | |
d028ac75 | 3691 | /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ |
108c4f26 WL |
3692 | [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, |
3693 | rmw_hidelegh }, | |
3694 | [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero, | |
3695 | write_ignore }, | |
d028ac75 | 3696 | [CSR_HVIPH] = { "hviph", aia_hmode32, NULL, NULL, rmw_hviph }, |
108c4f26 WL |
3697 | [CSR_HVIPRIO1H] = { "hviprio1h", aia_hmode32, read_hviprio1h, |
3698 | write_hviprio1h }, | |
3699 | [CSR_HVIPRIO2H] = { "hviprio2h", aia_hmode32, read_hviprio2h, | |
3700 | write_hviprio2h }, | |
d028ac75 AP |
3701 | [CSR_VSIEH] = { "vsieh", aia_hmode32, NULL, NULL, rmw_vsieh }, |
3702 | [CSR_VSIPH] = { "vsiph", aia_hmode32, NULL, NULL, rmw_vsiph }, | |
3703 | ||
c7b95171 | 3704 | /* Physical Memory Protection */ |
a4b2fa43 | 3705 | [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg, |
108c4f26 | 3706 | .min_priv_ver = PRIV_VERSION_1_11_0 }, |
8ceac5dc BM |
3707 | [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, |
3708 | [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, | |
3709 | [CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg }, | |
3710 | [CSR_PMPCFG3] = { "pmpcfg3", pmp, read_pmpcfg, write_pmpcfg }, | |
3711 | [CSR_PMPADDR0] = { "pmpaddr0", pmp, read_pmpaddr, write_pmpaddr }, | |
3712 | [CSR_PMPADDR1] = { "pmpaddr1", pmp, read_pmpaddr, write_pmpaddr }, | |
3713 | [CSR_PMPADDR2] = { "pmpaddr2", pmp, read_pmpaddr, write_pmpaddr }, | |
3714 | [CSR_PMPADDR3] = { "pmpaddr3", pmp, read_pmpaddr, write_pmpaddr }, | |
3715 | [CSR_PMPADDR4] = { "pmpaddr4", pmp, read_pmpaddr, write_pmpaddr }, | |
3716 | [CSR_PMPADDR5] = { "pmpaddr5", pmp, read_pmpaddr, write_pmpaddr }, | |
3717 | [CSR_PMPADDR6] = { "pmpaddr6", pmp, read_pmpaddr, write_pmpaddr }, | |
3718 | [CSR_PMPADDR7] = { "pmpaddr7", pmp, read_pmpaddr, write_pmpaddr }, | |
3719 | [CSR_PMPADDR8] = { "pmpaddr8", pmp, read_pmpaddr, write_pmpaddr }, | |
3720 | [CSR_PMPADDR9] = { "pmpaddr9", pmp, read_pmpaddr, write_pmpaddr }, | |
3721 | [CSR_PMPADDR10] = { "pmpaddr10", pmp, read_pmpaddr, write_pmpaddr }, | |
3722 | [CSR_PMPADDR11] = { "pmpaddr11", pmp, read_pmpaddr, write_pmpaddr }, | |
3723 | [CSR_PMPADDR12] = { "pmpaddr12", pmp, read_pmpaddr, write_pmpaddr }, | |
3724 | [CSR_PMPADDR13] = { "pmpaddr13", pmp, read_pmpaddr, write_pmpaddr }, | |
3725 | [CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr }, | |
3726 | [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr }, | |
c7b95171 | 3727 | |
b6092544 BM |
3728 | /* Debug CSRs */ |
3729 | [CSR_TSELECT] = { "tselect", debug, read_tselect, write_tselect }, | |
3730 | [CSR_TDATA1] = { "tdata1", debug, read_tdata, write_tdata }, | |
3731 | [CSR_TDATA2] = { "tdata2", debug, read_tdata, write_tdata }, | |
3732 | [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata }, | |
3733 | ||
4bbe8033 | 3734 | /* User Pointer Masking */ |
108c4f26 WL |
3735 | [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte }, |
3736 | [CSR_UPMMASK] = { "upmmask", pointer_masking, read_upmmask, | |
3737 | write_upmmask }, | |
3738 | [CSR_UPMBASE] = { "upmbase", pointer_masking, read_upmbase, | |
3739 | write_upmbase }, | |
4bbe8033 | 3740 | /* Machine Pointer Masking */ |
108c4f26 WL |
3741 | [CSR_MMTE] = { "mmte", pointer_masking, read_mmte, write_mmte }, |
3742 | [CSR_MPMMASK] = { "mpmmask", pointer_masking, read_mpmmask, | |
3743 | write_mpmmask }, | |
3744 | [CSR_MPMBASE] = { "mpmbase", pointer_masking, read_mpmbase, | |
3745 | write_mpmbase }, | |
4bbe8033 | 3746 | /* Supervisor Pointer Masking */ |
108c4f26 WL |
3747 | [CSR_SMTE] = { "smte", pointer_masking, read_smte, write_smte }, |
3748 | [CSR_SPMMASK] = { "spmmask", pointer_masking, read_spmmask, | |
3749 | write_spmmask }, | |
3750 | [CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase, | |
3751 | write_spmbase }, | |
4bbe8033 | 3752 | |
c7b95171 | 3753 | /* Performance Counters */ |
621f35bb AP |
3754 | [CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_hpmcounter }, |
3755 | [CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_hpmcounter }, | |
3756 | [CSR_HPMCOUNTER5] = { "hpmcounter5", ctr, read_hpmcounter }, | |
3757 | [CSR_HPMCOUNTER6] = { "hpmcounter6", ctr, read_hpmcounter }, | |
3758 | [CSR_HPMCOUNTER7] = { "hpmcounter7", ctr, read_hpmcounter }, | |
3759 | [CSR_HPMCOUNTER8] = { "hpmcounter8", ctr, read_hpmcounter }, | |
3760 | [CSR_HPMCOUNTER9] = { "hpmcounter9", ctr, read_hpmcounter }, | |
3761 | [CSR_HPMCOUNTER10] = { "hpmcounter10", ctr, read_hpmcounter }, | |
3762 | [CSR_HPMCOUNTER11] = { "hpmcounter11", ctr, read_hpmcounter }, | |
3763 | [CSR_HPMCOUNTER12] = { "hpmcounter12", ctr, read_hpmcounter }, | |
3764 | [CSR_HPMCOUNTER13] = { "hpmcounter13", ctr, read_hpmcounter }, | |
3765 | [CSR_HPMCOUNTER14] = { "hpmcounter14", ctr, read_hpmcounter }, | |
3766 | [CSR_HPMCOUNTER15] = { "hpmcounter15", ctr, read_hpmcounter }, | |
3767 | [CSR_HPMCOUNTER16] = { "hpmcounter16", ctr, read_hpmcounter }, | |
3768 | [CSR_HPMCOUNTER17] = { "hpmcounter17", ctr, read_hpmcounter }, | |
3769 | [CSR_HPMCOUNTER18] = { "hpmcounter18", ctr, read_hpmcounter }, | |
3770 | [CSR_HPMCOUNTER19] = { "hpmcounter19", ctr, read_hpmcounter }, | |
3771 | [CSR_HPMCOUNTER20] = { "hpmcounter20", ctr, read_hpmcounter }, | |
3772 | [CSR_HPMCOUNTER21] = { "hpmcounter21", ctr, read_hpmcounter }, | |
3773 | [CSR_HPMCOUNTER22] = { "hpmcounter22", ctr, read_hpmcounter }, | |
3774 | [CSR_HPMCOUNTER23] = { "hpmcounter23", ctr, read_hpmcounter }, | |
3775 | [CSR_HPMCOUNTER24] = { "hpmcounter24", ctr, read_hpmcounter }, | |
3776 | [CSR_HPMCOUNTER25] = { "hpmcounter25", ctr, read_hpmcounter }, | |
3777 | [CSR_HPMCOUNTER26] = { "hpmcounter26", ctr, read_hpmcounter }, | |
3778 | [CSR_HPMCOUNTER27] = { "hpmcounter27", ctr, read_hpmcounter }, | |
3779 | [CSR_HPMCOUNTER28] = { "hpmcounter28", ctr, read_hpmcounter }, | |
3780 | [CSR_HPMCOUNTER29] = { "hpmcounter29", ctr, read_hpmcounter }, | |
3781 | [CSR_HPMCOUNTER30] = { "hpmcounter30", ctr, read_hpmcounter }, | |
3782 | [CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_hpmcounter }, | |
3783 | ||
3784 | [CSR_MHPMCOUNTER3] = { "mhpmcounter3", mctr, read_hpmcounter, | |
108c4f26 | 3785 | write_mhpmcounter }, |
621f35bb | 3786 | [CSR_MHPMCOUNTER4] = { "mhpmcounter4", mctr, read_hpmcounter, |
108c4f26 | 3787 | write_mhpmcounter }, |
621f35bb | 3788 | [CSR_MHPMCOUNTER5] = { "mhpmcounter5", mctr, read_hpmcounter, |
108c4f26 | 3789 | write_mhpmcounter }, |
621f35bb | 3790 | [CSR_MHPMCOUNTER6] = { "mhpmcounter6", mctr, read_hpmcounter, |
108c4f26 | 3791 | write_mhpmcounter }, |
621f35bb | 3792 | [CSR_MHPMCOUNTER7] = { "mhpmcounter7", mctr, read_hpmcounter, |
108c4f26 | 3793 | write_mhpmcounter }, |
621f35bb | 3794 | [CSR_MHPMCOUNTER8] = { "mhpmcounter8", mctr, read_hpmcounter, |
108c4f26 | 3795 | write_mhpmcounter }, |
621f35bb | 3796 | [CSR_MHPMCOUNTER9] = { "mhpmcounter9", mctr, read_hpmcounter, |
108c4f26 | 3797 | write_mhpmcounter }, |
621f35bb | 3798 | [CSR_MHPMCOUNTER10] = { "mhpmcounter10", mctr, read_hpmcounter, |
108c4f26 | 3799 | write_mhpmcounter }, |
621f35bb | 3800 | [CSR_MHPMCOUNTER11] = { "mhpmcounter11", mctr, read_hpmcounter, |
108c4f26 | 3801 | write_mhpmcounter }, |
621f35bb | 3802 | [CSR_MHPMCOUNTER12] = { "mhpmcounter12", mctr, read_hpmcounter, |
108c4f26 | 3803 | write_mhpmcounter }, |
621f35bb | 3804 | [CSR_MHPMCOUNTER13] = { "mhpmcounter13", mctr, read_hpmcounter, |
108c4f26 | 3805 | write_mhpmcounter }, |
621f35bb | 3806 | [CSR_MHPMCOUNTER14] = { "mhpmcounter14", mctr, read_hpmcounter, |
108c4f26 | 3807 | write_mhpmcounter }, |
621f35bb | 3808 | [CSR_MHPMCOUNTER15] = { "mhpmcounter15", mctr, read_hpmcounter, |
108c4f26 | 3809 | write_mhpmcounter }, |
621f35bb | 3810 | [CSR_MHPMCOUNTER16] = { "mhpmcounter16", mctr, read_hpmcounter, |
108c4f26 | 3811 | write_mhpmcounter }, |
621f35bb | 3812 | [CSR_MHPMCOUNTER17] = { "mhpmcounter17", mctr, read_hpmcounter, |
108c4f26 | 3813 | write_mhpmcounter }, |
621f35bb | 3814 | [CSR_MHPMCOUNTER18] = { "mhpmcounter18", mctr, read_hpmcounter, |
108c4f26 | 3815 | write_mhpmcounter }, |
621f35bb | 3816 | [CSR_MHPMCOUNTER19] = { "mhpmcounter19", mctr, read_hpmcounter, |
108c4f26 | 3817 | write_mhpmcounter }, |
621f35bb | 3818 | [CSR_MHPMCOUNTER20] = { "mhpmcounter20", mctr, read_hpmcounter, |
108c4f26 | 3819 | write_mhpmcounter }, |
621f35bb | 3820 | [CSR_MHPMCOUNTER21] = { "mhpmcounter21", mctr, read_hpmcounter, |
108c4f26 | 3821 | write_mhpmcounter }, |
621f35bb | 3822 | [CSR_MHPMCOUNTER22] = { "mhpmcounter22", mctr, read_hpmcounter, |
108c4f26 | 3823 | write_mhpmcounter }, |
621f35bb | 3824 | [CSR_MHPMCOUNTER23] = { "mhpmcounter23", mctr, read_hpmcounter, |
108c4f26 | 3825 | write_mhpmcounter }, |
621f35bb | 3826 | [CSR_MHPMCOUNTER24] = { "mhpmcounter24", mctr, read_hpmcounter, |
108c4f26 | 3827 | write_mhpmcounter }, |
621f35bb | 3828 | [CSR_MHPMCOUNTER25] = { "mhpmcounter25", mctr, read_hpmcounter, |
108c4f26 | 3829 | write_mhpmcounter }, |
621f35bb | 3830 | [CSR_MHPMCOUNTER26] = { "mhpmcounter26", mctr, read_hpmcounter, |
108c4f26 | 3831 | write_mhpmcounter }, |
621f35bb | 3832 | [CSR_MHPMCOUNTER27] = { "mhpmcounter27", mctr, read_hpmcounter, |
108c4f26 | 3833 | write_mhpmcounter }, |
621f35bb | 3834 | [CSR_MHPMCOUNTER28] = { "mhpmcounter28", mctr, read_hpmcounter, |
108c4f26 | 3835 | write_mhpmcounter }, |
621f35bb | 3836 | [CSR_MHPMCOUNTER29] = { "mhpmcounter29", mctr, read_hpmcounter, |
108c4f26 | 3837 | write_mhpmcounter }, |
621f35bb | 3838 | [CSR_MHPMCOUNTER30] = { "mhpmcounter30", mctr, read_hpmcounter, |
108c4f26 | 3839 | write_mhpmcounter }, |
621f35bb | 3840 | [CSR_MHPMCOUNTER31] = { "mhpmcounter31", mctr, read_hpmcounter, |
108c4f26 | 3841 | write_mhpmcounter }, |
621f35bb AP |
3842 | |
3843 | [CSR_MCOUNTINHIBIT] = { "mcountinhibit", any, read_mcountinhibit, | |
108c4f26 WL |
3844 | write_mcountinhibit, |
3845 | .min_priv_ver = PRIV_VERSION_1_11_0 }, | |
621f35bb AP |
3846 | |
3847 | [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_mhpmevent, | |
108c4f26 | 3848 | write_mhpmevent }, |
621f35bb | 3849 | [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_mhpmevent, |
108c4f26 | 3850 | write_mhpmevent }, |
621f35bb | 3851 | [CSR_MHPMEVENT5] = { "mhpmevent5", any, read_mhpmevent, |
108c4f26 | 3852 | write_mhpmevent }, |
621f35bb | 3853 | [CSR_MHPMEVENT6] = { "mhpmevent6", any, read_mhpmevent, |
108c4f26 | 3854 | write_mhpmevent }, |
621f35bb | 3855 | [CSR_MHPMEVENT7] = { "mhpmevent7", any, read_mhpmevent, |
108c4f26 | 3856 | write_mhpmevent }, |
621f35bb | 3857 | [CSR_MHPMEVENT8] = { "mhpmevent8", any, read_mhpmevent, |
108c4f26 | 3858 | write_mhpmevent }, |
621f35bb | 3859 | [CSR_MHPMEVENT9] = { "mhpmevent9", any, read_mhpmevent, |
108c4f26 | 3860 | write_mhpmevent }, |
621f35bb | 3861 | [CSR_MHPMEVENT10] = { "mhpmevent10", any, read_mhpmevent, |
108c4f26 | 3862 | write_mhpmevent }, |
621f35bb | 3863 | [CSR_MHPMEVENT11] = { "mhpmevent11", any, read_mhpmevent, |
108c4f26 | 3864 | write_mhpmevent }, |
621f35bb | 3865 | [CSR_MHPMEVENT12] = { "mhpmevent12", any, read_mhpmevent, |
108c4f26 | 3866 | write_mhpmevent }, |
621f35bb | 3867 | [CSR_MHPMEVENT13] = { "mhpmevent13", any, read_mhpmevent, |
108c4f26 | 3868 | write_mhpmevent }, |
621f35bb | 3869 | [CSR_MHPMEVENT14] = { "mhpmevent14", any, read_mhpmevent, |
108c4f26 | 3870 | write_mhpmevent }, |
621f35bb | 3871 | [CSR_MHPMEVENT15] = { "mhpmevent15", any, read_mhpmevent, |
108c4f26 | 3872 | write_mhpmevent }, |
621f35bb | 3873 | [CSR_MHPMEVENT16] = { "mhpmevent16", any, read_mhpmevent, |
108c4f26 | 3874 | write_mhpmevent }, |
621f35bb | 3875 | [CSR_MHPMEVENT17] = { "mhpmevent17", any, read_mhpmevent, |
108c4f26 | 3876 | write_mhpmevent }, |
621f35bb | 3877 | [CSR_MHPMEVENT18] = { "mhpmevent18", any, read_mhpmevent, |
108c4f26 | 3878 | write_mhpmevent }, |
621f35bb | 3879 | [CSR_MHPMEVENT19] = { "mhpmevent19", any, read_mhpmevent, |
108c4f26 | 3880 | write_mhpmevent }, |
621f35bb | 3881 | [CSR_MHPMEVENT20] = { "mhpmevent20", any, read_mhpmevent, |
108c4f26 | 3882 | write_mhpmevent }, |
621f35bb | 3883 | [CSR_MHPMEVENT21] = { "mhpmevent21", any, read_mhpmevent, |
108c4f26 | 3884 | write_mhpmevent }, |
621f35bb | 3885 | [CSR_MHPMEVENT22] = { "mhpmevent22", any, read_mhpmevent, |
108c4f26 | 3886 | write_mhpmevent }, |
621f35bb | 3887 | [CSR_MHPMEVENT23] = { "mhpmevent23", any, read_mhpmevent, |
108c4f26 | 3888 | write_mhpmevent }, |
621f35bb | 3889 | [CSR_MHPMEVENT24] = { "mhpmevent24", any, read_mhpmevent, |
108c4f26 | 3890 | write_mhpmevent }, |
621f35bb | 3891 | [CSR_MHPMEVENT25] = { "mhpmevent25", any, read_mhpmevent, |
108c4f26 | 3892 | write_mhpmevent }, |
621f35bb | 3893 | [CSR_MHPMEVENT26] = { "mhpmevent26", any, read_mhpmevent, |
108c4f26 | 3894 | write_mhpmevent }, |
621f35bb | 3895 | [CSR_MHPMEVENT27] = { "mhpmevent27", any, read_mhpmevent, |
108c4f26 | 3896 | write_mhpmevent }, |
621f35bb | 3897 | [CSR_MHPMEVENT28] = { "mhpmevent28", any, read_mhpmevent, |
108c4f26 | 3898 | write_mhpmevent }, |
621f35bb | 3899 | [CSR_MHPMEVENT29] = { "mhpmevent29", any, read_mhpmevent, |
108c4f26 | 3900 | write_mhpmevent }, |
621f35bb | 3901 | [CSR_MHPMEVENT30] = { "mhpmevent30", any, read_mhpmevent, |
108c4f26 | 3902 | write_mhpmevent }, |
621f35bb | 3903 | [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent, |
108c4f26 | 3904 | write_mhpmevent }, |
621f35bb AP |
3905 | |
3906 | [CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_hpmcounterh }, | |
3907 | [CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_hpmcounterh }, | |
3908 | [CSR_HPMCOUNTER5H] = { "hpmcounter5h", ctr32, read_hpmcounterh }, | |
3909 | [CSR_HPMCOUNTER6H] = { "hpmcounter6h", ctr32, read_hpmcounterh }, | |
3910 | [CSR_HPMCOUNTER7H] = { "hpmcounter7h", ctr32, read_hpmcounterh }, | |
3911 | [CSR_HPMCOUNTER8H] = { "hpmcounter8h", ctr32, read_hpmcounterh }, | |
3912 | [CSR_HPMCOUNTER9H] = { "hpmcounter9h", ctr32, read_hpmcounterh }, | |
3913 | [CSR_HPMCOUNTER10H] = { "hpmcounter10h", ctr32, read_hpmcounterh }, | |
3914 | [CSR_HPMCOUNTER11H] = { "hpmcounter11h", ctr32, read_hpmcounterh }, | |
3915 | [CSR_HPMCOUNTER12H] = { "hpmcounter12h", ctr32, read_hpmcounterh }, | |
3916 | [CSR_HPMCOUNTER13H] = { "hpmcounter13h", ctr32, read_hpmcounterh }, | |
3917 | [CSR_HPMCOUNTER14H] = { "hpmcounter14h", ctr32, read_hpmcounterh }, | |
3918 | [CSR_HPMCOUNTER15H] = { "hpmcounter15h", ctr32, read_hpmcounterh }, | |
3919 | [CSR_HPMCOUNTER16H] = { "hpmcounter16h", ctr32, read_hpmcounterh }, | |
3920 | [CSR_HPMCOUNTER17H] = { "hpmcounter17h", ctr32, read_hpmcounterh }, | |
3921 | [CSR_HPMCOUNTER18H] = { "hpmcounter18h", ctr32, read_hpmcounterh }, | |
3922 | [CSR_HPMCOUNTER19H] = { "hpmcounter19h", ctr32, read_hpmcounterh }, | |
3923 | [CSR_HPMCOUNTER20H] = { "hpmcounter20h", ctr32, read_hpmcounterh }, | |
3924 | [CSR_HPMCOUNTER21H] = { "hpmcounter21h", ctr32, read_hpmcounterh }, | |
3925 | [CSR_HPMCOUNTER22H] = { "hpmcounter22h", ctr32, read_hpmcounterh }, | |
3926 | [CSR_HPMCOUNTER23H] = { "hpmcounter23h", ctr32, read_hpmcounterh }, | |
3927 | [CSR_HPMCOUNTER24H] = { "hpmcounter24h", ctr32, read_hpmcounterh }, | |
3928 | [CSR_HPMCOUNTER25H] = { "hpmcounter25h", ctr32, read_hpmcounterh }, | |
3929 | [CSR_HPMCOUNTER26H] = { "hpmcounter26h", ctr32, read_hpmcounterh }, | |
3930 | [CSR_HPMCOUNTER27H] = { "hpmcounter27h", ctr32, read_hpmcounterh }, | |
3931 | [CSR_HPMCOUNTER28H] = { "hpmcounter28h", ctr32, read_hpmcounterh }, | |
3932 | [CSR_HPMCOUNTER29H] = { "hpmcounter29h", ctr32, read_hpmcounterh }, | |
3933 | [CSR_HPMCOUNTER30H] = { "hpmcounter30h", ctr32, read_hpmcounterh }, | |
3934 | [CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_hpmcounterh }, | |
3935 | ||
3936 | [CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", mctr32, read_hpmcounterh, | |
108c4f26 | 3937 | write_mhpmcounterh }, |
621f35bb | 3938 | [CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", mctr32, read_hpmcounterh, |
108c4f26 | 3939 | write_mhpmcounterh }, |
621f35bb | 3940 | [CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", mctr32, read_hpmcounterh, |
108c4f26 | 3941 | write_mhpmcounterh }, |
621f35bb | 3942 | [CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", mctr32, read_hpmcounterh, |
108c4f26 | 3943 | write_mhpmcounterh }, |
621f35bb | 3944 | [CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", mctr32, read_hpmcounterh, |
108c4f26 | 3945 | write_mhpmcounterh }, |
621f35bb | 3946 | [CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", mctr32, read_hpmcounterh, |
108c4f26 | 3947 | write_mhpmcounterh }, |
621f35bb | 3948 | [CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", mctr32, read_hpmcounterh, |
108c4f26 | 3949 | write_mhpmcounterh }, |
621f35bb | 3950 | [CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", mctr32, read_hpmcounterh, |
108c4f26 | 3951 | write_mhpmcounterh }, |
621f35bb | 3952 | [CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", mctr32, read_hpmcounterh, |
108c4f26 | 3953 | write_mhpmcounterh }, |
621f35bb | 3954 | [CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", mctr32, read_hpmcounterh, |
108c4f26 | 3955 | write_mhpmcounterh }, |
621f35bb | 3956 | [CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", mctr32, read_hpmcounterh, |
108c4f26 | 3957 | write_mhpmcounterh }, |
621f35bb | 3958 | [CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", mctr32, read_hpmcounterh, |
108c4f26 | 3959 | write_mhpmcounterh }, |
621f35bb | 3960 | [CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", mctr32, read_hpmcounterh, |
108c4f26 | 3961 | write_mhpmcounterh }, |
621f35bb | 3962 | [CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", mctr32, read_hpmcounterh, |
108c4f26 | 3963 | write_mhpmcounterh }, |
621f35bb | 3964 | [CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", mctr32, read_hpmcounterh, |
108c4f26 | 3965 | write_mhpmcounterh }, |
621f35bb | 3966 | [CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", mctr32, read_hpmcounterh, |
108c4f26 | 3967 | write_mhpmcounterh }, |
621f35bb | 3968 | [CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", mctr32, read_hpmcounterh, |
108c4f26 | 3969 | write_mhpmcounterh }, |
621f35bb | 3970 | [CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", mctr32, read_hpmcounterh, |
108c4f26 | 3971 | write_mhpmcounterh }, |
621f35bb | 3972 | [CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", mctr32, read_hpmcounterh, |
108c4f26 | 3973 | write_mhpmcounterh }, |
621f35bb | 3974 | [CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", mctr32, read_hpmcounterh, |
108c4f26 | 3975 | write_mhpmcounterh }, |
621f35bb | 3976 | [CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", mctr32, read_hpmcounterh, |
108c4f26 | 3977 | write_mhpmcounterh }, |
621f35bb | 3978 | [CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", mctr32, read_hpmcounterh, |
108c4f26 | 3979 | write_mhpmcounterh }, |
621f35bb | 3980 | [CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", mctr32, read_hpmcounterh, |
108c4f26 | 3981 | write_mhpmcounterh }, |
621f35bb | 3982 | [CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", mctr32, read_hpmcounterh, |
108c4f26 | 3983 | write_mhpmcounterh }, |
621f35bb | 3984 | [CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", mctr32, read_hpmcounterh, |
108c4f26 | 3985 | write_mhpmcounterh }, |
621f35bb | 3986 | [CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", mctr32, read_hpmcounterh, |
108c4f26 | 3987 | write_mhpmcounterh }, |
621f35bb | 3988 | [CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", mctr32, read_hpmcounterh, |
108c4f26 | 3989 | write_mhpmcounterh }, |
621f35bb | 3990 | [CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", mctr32, read_hpmcounterh, |
108c4f26 | 3991 | write_mhpmcounterh }, |
621f35bb | 3992 | [CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", mctr32, read_hpmcounterh, |
108c4f26 | 3993 | write_mhpmcounterh }, |
c7b95171 MC |
3994 | #endif /* !CONFIG_USER_ONLY */ |
3995 | }; |