The number of implemented SDID bits is UNSPECIFIED and may be zero. The
number of implemented SDID bits, termed SDIDLEN, may be determined by
writing one to every bit position in the SDID field, then reading back
the value in mmpt to see which bit positions in the SDID field hold a
one. The least-significant bits of SDID are implemented first: that is,
if SDIDLEN > 0, SDID[SDIDLEN-1:0] is writable. The maximal value of
SDIDLEN, termed SDIDMAX, is 6.

Model this by adding a configurable "smmpt-sdidlen" CPU property. The value
defaults to SDIDMAX (6) to preserve the current behaviour. The mmpt write
handler now keeps only the low SDIDLEN bits of the SDID field, making the
SDIDLEN discovery sequence work as specified.

Signed-off-by: LIU Zhiwei <[email protected]>
---
 target/riscv/cpu.c                | 45 +++++++++++++++++++++++++++++++
 target/riscv/cpu_bits.h           |  3 +++
 target/riscv/cpu_cfg_fields.h.inc |  1 +
 target/riscv/tcg/csr.c            | 11 ++++++--
 4 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5a82e6563b..0f96e487fa 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1434,6 +1434,7 @@ static void riscv_cpu_init(Object *obj)
     cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16);
     cpu->cfg.vlenb = 128 >> 3;
     cpu->cfg.elen = 64;
+    cpu->cfg.sdidlen = MMPT_SDIDLEN_MAX;
     cpu->cfg.cbom_blocksize = 64;
     cpu->cfg.cbop_blocksize = 64;
     cpu->cfg.cboz_blocksize = 64;
@@ -1939,6 +1940,48 @@ static const PropertyInfo prop_vlen = {
     .set = prop_vlen_set,
 };
 
+static void prop_sdidlen_set(Object *obj, Visitor *v, const char *name,
+                             void *opaque, Error **errp)
+{
+    RISCVCPU *cpu = RISCV_CPU(obj);
+    uint8_t value;
+
+    if (!visit_type_uint8(v, name, &value, errp)) {
+        return;
+    }
+
+    if (value > MMPT_SDIDLEN_MAX) {
+        error_setg(errp, "smmpt-sdidlen must be between 0 and %d",
+                   MMPT_SDIDLEN_MAX);
+        return;
+    }
+
+    if (value != cpu->cfg.sdidlen && riscv_cpu_is_vendor(obj)) {
+        cpu_set_prop_err(cpu, name, errp);
+        error_append_hint(errp, "Current '%s' val: %u\n",
+                          name, cpu->cfg.sdidlen);
+        return;
+    }
+
+    cpu_option_add_user_setting(cpu, name);
+    cpu->cfg.sdidlen = value;
+}
+
+static void prop_sdidlen_get(Object *obj, Visitor *v, const char *name,
+                             void *opaque, Error **errp)
+{
+    uint8_t value = RISCV_CPU(obj)->cfg.sdidlen;
+
+    visit_type_uint8(v, name, &value, errp);
+}
+
+static const PropertyInfo prop_sdidlen = {
+    .type = "uint8",
+    .description = "smmpt-sdidlen",
+    .get = prop_sdidlen_get,
+    .set = prop_sdidlen_set,
+};
+
 static void prop_elen_set(Object *obj, Visitor *v, const char *name,
                          void *opaque, Error **errp)
 {
@@ -2853,6 +2896,8 @@ static const Property riscv_cpu_properties[] = {
     {.name = "vlen", .info = &prop_vlen},
     {.name = "elen", .info = &prop_elen},
 
+    {.name = "smmpt-sdidlen", .info = &prop_sdidlen},
+
     {.name = "cbom_blocksize", .info = &prop_cbom_blksize},
     {.name = "cbop_blocksize", .info = &prop_cbop_blksize},
     {.name = "cboz_blocksize", .info = &prop_cboz_blksize},
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 4ed4843e3d..642edf3369 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -1171,6 +1171,9 @@ typedef enum CTRType {
 #define CSR_MMPT        0x382
 #define CSR_MSDCFG      0x74E
 
+/* Maximal number of implemented SDID bits (SDIDMAX) */
+#define MMPT_SDIDLEN_MAX    6
+
 /*
  * MMPT register layout for MXLEN=32:
  * MODE[31:30], 0[29:28], SDID[27:22], PPN[21:0]
diff --git a/target/riscv/cpu_cfg_fields.h.inc 
b/target/riscv/cpu_cfg_fields.h.inc
index 6b616388be..4a8c9b9e21 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -174,6 +174,7 @@ TYPED_FIELD(uint64_t, mimpid, 0)
 TYPED_FIELD(uint32_t, pmu_mask, 0)
 TYPED_FIELD(uint16_t, vlenb, 0)
 TYPED_FIELD(uint16_t, elen, 0)
+TYPED_FIELD(uint8_t,  sdidlen, 0)
 TYPED_FIELD(uint16_t, cbom_blocksize, 0)
 TYPED_FIELD(uint16_t, cbop_blocksize, 0)
 TYPED_FIELD(uint16_t, cboz_blocksize, 0)
diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
index 8ffe85caa9..8d38d7a972 100644
--- a/target/riscv/tcg/csr.c
+++ b/target/riscv/tcg/csr.c
@@ -5608,6 +5608,11 @@ static RISCVException write_mmpt(CPURISCVState *env, int 
csrno,
                                  target_ulong val, uintptr_t ra)
 {
     uint32_t mode_value = 0;
+    /*
+     * Only the least-significant SDIDLEN bits of the SDID field are
+     * writable; the remaining bits are WARL and read as zero.
+     */
+    uint64_t sdid_mask = MAKE_64BIT_MASK(0, riscv_cpu_cfg(env)->sdidlen);
     if (!riscv_cpu_cfg(env)->ext_smmpt) {
         goto set_remaining_fields_zero;
     }
@@ -5621,7 +5626,8 @@ static RISCVException write_mmpt(CPURISCVState *env, int 
csrno,
             /* Only write the legal value */
             env->mptmode = mode_value;
         }
-        env->sdid = (val & MMPT_SDID_MASK_32) >> MMPT_SDID_SHIFT_32;
+        env->sdid = ((val & MMPT_SDID_MASK_32) >> MMPT_SDID_SHIFT_32)
+                    & sdid_mask;
         env->mptppn = val & MMPT_PPN_MASK_32;
     } else if (riscv_cpu_xlen(env) == 64) {
         mode_value = (val & MMPT_MODE_MASK_64) >> MMPT_MODE_SHIFT_64;
@@ -5632,7 +5638,8 @@ static RISCVException write_mmpt(CPURISCVState *env, int 
csrno,
             mode_value += SMMPT43 - SMMPT34;
             env->mptmode = mode_value;
         }
-        env->sdid = (val & MMPT_SDID_MASK_64) >> MMPT_SDID_SHIFT_64;
+        env->sdid = (((uint64_t)val & MMPT_SDID_MASK_64) >> MMPT_SDID_SHIFT_64)
+                    & sdid_mask;
         env->mptppn = val & MMPT_PPN_MASK_64;
         /* Smmpt64: root table PPN bits 2:0 must be zero (32KiB alignment) */
         if (env->mptmode == SMMPT64) {
-- 
2.43.0


Reply via email to