@samitouri / QOSamiQemu / commits / bd97e07660

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,