target/riscv: fix RV32 stateen CSR handling
The RV32 stateen CSRs are split between the low-half CSR and the corresponding xH CSR, but the current implementation still handles some upper-half bits through the low-half write paths and also accepts the xH CSRs on RV64. Fix this by: - rejecting mstateen*h and hstateen*h accesses on RV64 - keeping the RV64-only writable bits in the low-half write paths - handling the RV32 upper-half writable bits in write_mstateen0h() and write_hstateen0h() - dropping unsupported writable bits from write_sstateen0() Signed-off-by: Bruno Sa <bruno.vilaca.sa@gmail.com> Message-ID: <20260410110928.1014170-1-bruno.vilaca.sa@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Bruno Sa committed
Apr 10, 2026 at 12:08 UTC
bd97e076606afc19240bb8914fa5235e358d8124
1 file changed
+83
-34
target/riscv/csr.c
+83
-34
@@ -502,6 +502,15 @@ static RISCVException mstateen(CPURISCVState *env, int csrno)
502
return any(env, csrno);
503
}
504
505
+static RISCVException mstateen_32(CPURISCVState *env, int csrno)
506
+{
507
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
508
+ return RISCV_EXCP_ILLEGAL_INST;
509
+ }
510
+
511
+ return mstateen(env, csrno);
512
+}
513
+
514
static RISCVException hstateen_pred(CPURISCVState *env, int csrno, int base)
515
{
516
if (!riscv_cpu_cfg(env)->ext_smstateen) {
@@ -533,6 +542,10 @@ static RISCVException hstateen(CPURISCVState *env, int csrno)
542
543
static RISCVException hstateenh(CPURISCVState *env, int csrno)
544
{
545
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
546
+ return RISCV_EXCP_ILLEGAL_INST;
547
+ }
548
+
549
return hstateen_pred(env, csrno, CSR_HSTATEEN0H);
550
}
551
@@ -3447,25 +3460,29 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
3460
wr_mask |= SMSTATEEN0_FCSR;
3461
}
3462
3450
- if (env->priv_ver >= PRIV_VERSION_1_13_0) {
3451
- wr_mask |= SMSTATEEN0_P1P13;
3452
- }
3463
+ if (riscv_cpu_mxl(env) == MXL_RV64) {
3464
+ if (env->priv_ver >= PRIV_VERSION_1_13_0) {
3465
+ wr_mask |= SMSTATEEN0_P1P13;
3466
+ }
3467
3454
- if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
3455
- wr_mask |= SMSTATEEN0_SVSLCT;
3456
- }
3468
+ if (riscv_cpu_cfg(env)->ext_smaia ||
3469
+ riscv_cpu_cfg(env)->ext_smcsrind) {
3470
+ wr_mask |= SMSTATEEN0_SVSLCT;
3471
+ }
3472
3458
- /*
3459
- * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
3460
- * implemented. However, that information is with MachineState and we can't
3461
- * figure that out in csr.c. Just enable if Smaia is available.
3462
- */
3463
- if (riscv_cpu_cfg(env)->ext_smaia) {
3464
- wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
3465
- }
3473
+ /*
3474
+ * As per the AIA specification, SMSTATEEN0_IMSIC is valid
3475
+ * only if IMSIC is implemented. However, that information is
3476
+ * with MachineState and we can't figure that out in csr.c.
3477
+ * Just enable if Smaia is available.
3478
+ */
3479
+ if (riscv_cpu_cfg(env)->ext_smaia) {
3480
+ wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
3481
+ }
3482
3467
- if (riscv_cpu_cfg(env)->ext_ssctr) {
3468
- wr_mask |= SMSTATEEN0_CTR;
3483
+ if (riscv_cpu_cfg(env)->ext_ssctr) {
3484
+ wr_mask |= SMSTATEEN0_CTR;
3485
+ }
3486
}
3487
3488
return write_mstateen(env, csrno, wr_mask, new_val);
@@ -3507,6 +3524,20 @@ static RISCVException write_mstateen0h(CPURISCVState *env, int csrno,
3524
wr_mask |= SMSTATEEN0_P1P13;
3525
}
3526
3527
+ if (riscv_cpu_cfg(env)->ext_smaia || riscv_cpu_cfg(env)->ext_smcsrind) {
3528
+ wr_mask |= SMSTATEEN0_SVSLCT;
3529
+ }
3530
+
3531
+ /*
3532
+ * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if
3533
+ * IMSIC is implemented. However, that information is with
3534
+ * MachineState and we can't figure that out in csr.c. Just enable
3535
+ * if Smaia is available.
3536
+ */
3537
+ if (riscv_cpu_cfg(env)->ext_smaia) {
3538
+ wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
3539
+ }
3540
+
3541
if (riscv_cpu_cfg(env)->ext_ssctr) {
3542
wr_mask |= SMSTATEEN0_CTR;
3543
}
@@ -3552,21 +3583,25 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
3583
wr_mask |= SMSTATEEN0_FCSR;
3584
}
3585
3555
- if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
3556
- wr_mask |= SMSTATEEN0_SVSLCT;
3557
- }
3586
+ if (riscv_cpu_mxl(env) == MXL_RV64) {
3587
+ if (riscv_cpu_cfg(env)->ext_ssaia ||
3588
+ riscv_cpu_cfg(env)->ext_sscsrind) {
3589
+ wr_mask |= SMSTATEEN0_SVSLCT;
3590
+ }
3591
3559
- /*
3560
- * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if IMSIC is
3561
- * implemented. However, that information is with MachineState and we can't
3562
- * figure that out in csr.c. Just enable if Ssaia is available.
3563
- */
3564
- if (riscv_cpu_cfg(env)->ext_ssaia) {
3565
- wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
3566
- }
3592
+ /*
3593
+ * As per the AIA specification, SMSTATEEN0_IMSIC is valid
3594
+ * only if IMSIC is implemented. However, that information is
3595
+ * with MachineState and we can't figure that out in csr.c.
3596
+ * Just enable if Ssaia is available.
3597
+ */
3598
+ if (riscv_cpu_cfg(env)->ext_ssaia) {
3599
+ wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
3600
+ }
3601
3568
- if (riscv_cpu_cfg(env)->ext_ssctr) {
3569
- wr_mask |= SMSTATEEN0_CTR;
3602
+ if (riscv_cpu_cfg(env)->ext_ssctr) {
3603
+ wr_mask |= SMSTATEEN0_CTR;
3604
+ }
3605
}
3606
3607
return write_hstateen(env, csrno, wr_mask, new_val);
@@ -3608,6 +3643,20 @@ static RISCVException write_hstateen0h(CPURISCVState *env, int csrno,
3643
{
3644
uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
3645
3646
+ if (riscv_cpu_cfg(env)->ext_ssaia || riscv_cpu_cfg(env)->ext_sscsrind) {
3647
+ wr_mask |= SMSTATEEN0_SVSLCT;
3648
+ }
3649
+
3650
+ /*
3651
+ * As per the AIA specification, SMSTATEEN0_IMSIC is valid only if
3652
+ * IMSIC is implemented. However, that information is with
3653
+ * MachineState and we can't figure that out in csr.c. Just enable
3654
+ * if Ssaia is available.
3655
+ */
3656
+ if (riscv_cpu_cfg(env)->ext_ssaia) {
3657
+ wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
3658
+ }
3659
+
3660
if (riscv_cpu_cfg(env)->ext_ssctr) {
3661
wr_mask |= SMSTATEEN0_CTR;
3662
}
@@ -3657,7 +3706,7 @@ static RISCVException write_sstateen(CPURISCVState *env, int csrno,
3706
static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
3707
target_ulong new_val, uintptr_t ra)
3708
{
3660
- uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
3709
+ uint64_t wr_mask = 0;
3710
3711
if (!riscv_has_ext(env, RVF)) {
3712
wr_mask |= SMSTATEEN0_FCSR;
@@ -5937,25 +5986,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
5986
/* Smstateen extension CSRs */
5987
[CSR_MSTATEEN0] = { "mstateen0", mstateen, read_mstateen, write_mstateen0,
5988
.min_priv_ver = PRIV_VERSION_1_12_0 },
5940
- [CSR_MSTATEEN0H] = { "mstateen0h", mstateen, read_mstateenh,
5989
+ [CSR_MSTATEEN0H] = { "mstateen0h", mstateen_32, read_mstateenh,
5990
write_mstateen0h,
5991
.min_priv_ver = PRIV_VERSION_1_12_0 },
5992
[CSR_MSTATEEN1] = { "mstateen1", mstateen, read_mstateen,
5993
write_mstateen_1_3,
5994
.min_priv_ver = PRIV_VERSION_1_12_0 },
5946
- [CSR_MSTATEEN1H] = { "mstateen1h", mstateen, read_mstateenh,
5995
+ [CSR_MSTATEEN1H] = { "mstateen1h", mstateen_32, read_mstateenh,
5996
write_mstateenh_1_3,
5997
.min_priv_ver = PRIV_VERSION_1_12_0 },
5998
[CSR_MSTATEEN2] = { "mstateen2", mstateen, read_mstateen,
5999
write_mstateen_1_3,
6000
.min_priv_ver = PRIV_VERSION_1_12_0 },
5952
- [CSR_MSTATEEN2H] = { "mstateen2h", mstateen, read_mstateenh,
6001
+ [CSR_MSTATEEN2H] = { "mstateen2h", mstateen_32, read_mstateenh,
6002
write_mstateenh_1_3,
6003
.min_priv_ver = PRIV_VERSION_1_12_0 },
6004
[CSR_MSTATEEN3] = { "mstateen3", mstateen, read_mstateen,
6005
write_mstateen_1_3,
6006
.min_priv_ver = PRIV_VERSION_1_12_0 },
5958
- [CSR_MSTATEEN3H] = { "mstateen3h", mstateen, read_mstateenh,
6007
+ [CSR_MSTATEEN3H] = { "mstateen3h", mstateen_32, read_mstateenh,
6008
write_mstateenh_1_3,
6009
.min_priv_ver = PRIV_VERSION_1_12_0 },
6010
[CSR_HSTATEEN0] = { "hstateen0", hstateen, read_hstateen, write_hstateen0,