qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/8]  RISC-V: Add support for ePMP v0.9.1
@ 2021-04-02 12:47 Alistair Francis
  2021-04-02 12:47 ` [PATCH v1 1/8] target/riscv: Fix the PMP is locked check when using TOR Alistair Francis
                   ` (7 more replies)
  0 siblings, 8 replies; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:47 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

This series adds support for ePMP v0.9.1 to the QEMU RISC-V target.

This is based on previous patches, but has been rebased on the latest
master and updated for the latest spec.

The spec is avaliable at: https://docs.google.com/document/d/1Mh_aiHYxemL0umN3GTTw8vsbmzHZ_nxZXgjgOUzbvc8

This was tested by running Tock on the OpenTitan board.

This is based on the original work by
 Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
 Hou Weiying <weiying_hou@outlook.com>
 Myriad-Dreamin <camiyoru@gmail.com>

Alistair Francis (4):
  target/riscv: Fix the PMP is locked check when using TOR
  target/riscv: Add the ePMP feature
  target/riscv/pmp: Remove outdated comment
  target/riscv: Add ePMP support for the Ibex CPU

Hou Weiying (4):
  target/riscv: Define ePMP mseccfg
  target/riscv: Add ePMP CSR access functions
  target/riscv: Implementation of enhanced PMP (ePMP)
  target/riscv: Add a config option for ePMP

 target/riscv/cpu.h        |   3 +
 target/riscv/cpu_bits.h   |   3 +
 target/riscv/pmp.h        |  14 +++
 target/riscv/cpu.c        |  11 ++
 target/riscv/csr.c        |  22 ++++
 target/riscv/pmp.c        | 228 +++++++++++++++++++++++++++++++++-----
 target/riscv/trace-events |   3 +
 7 files changed, 258 insertions(+), 26 deletions(-)

-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 1/8] target/riscv: Fix the PMP is locked check when using TOR
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
@ 2021-04-02 12:47 ` Alistair Francis
  2021-04-08  9:25   ` Bin Meng
  2021-04-02 12:47 ` [PATCH v1 2/8] target/riscv: Define ePMP mseccfg Alistair Francis
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:47 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

The RISC-V spec says:
    if PMP entry i is locked and pmpicfg.A is set to TOR, writes to
    pmpaddri-1 are ignored.

The current QEMU code ignores accesses to pmpaddri-1 and pmpcfgi-1 which
is incorrect.

Update the pmp_is_locked() function to not check the suppording fields
and instaed enforce the lock functionality in the pmpaddr write operation.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/pmp.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index cff020122a..6141d0f8f9 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -59,16 +59,6 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
         return 0;
     }
 
-    /* In TOR mode, need to check the lock bit of the next pmp
-     * (if there is a next)
-     */
-    const uint8_t a_field =
-        pmp_get_a_field(env->pmp_state.pmp[pmp_index + 1].cfg_reg);
-    if ((env->pmp_state.pmp[pmp_index + 1u].cfg_reg & PMP_LOCK) &&
-         (PMP_AMATCH_TOR == a_field)) {
-        return 1;
-    }
-
     return 0;
 }
 
@@ -380,7 +370,22 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
     target_ulong val)
 {
     trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
+
     if (addr_index < MAX_RISCV_PMPS) {
+        /* In TOR mode, need to check the lock bit of the next pmp
+         * (if there is a next).
+         */
+        if (addr_index + 1 < MAX_RISCV_PMPS) {
+            uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
+
+            if (pmp_cfg & PMP_LOCK &&
+                PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg)) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "ignoring pmpaddr write - pmpcfg + 1 locked\n");
+                return;
+            }
+        }
+
         if (!pmp_is_locked(env, addr_index)) {
             env->pmp_state.pmp[addr_index].addr_reg = val;
             pmp_update_rule(env, addr_index);
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 2/8] target/riscv: Define ePMP mseccfg
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
  2021-04-02 12:47 ` [PATCH v1 1/8] target/riscv: Fix the PMP is locked check when using TOR Alistair Francis
@ 2021-04-02 12:47 ` Alistair Francis
  2021-04-07 14:24   ` Bin Meng
  2021-04-02 12:47 ` [PATCH v1 3/8] target/riscv: Add the ePMP feature Alistair Francis
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:47 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

From: Hou Weiying <weiying_hou@outlook.com>

Use address  0x390 and 0x391 for the ePMP CSRs.

Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-Id: <SG2PR02MB2634D85E5DF0C2BB540AE1BB93450@SG2PR02MB2634.apcprd02.prod.outlook.com>
[ Changes by AF:
 - Tidy up commit message
]
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_bits.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index caf4599207..32e1ee92dc 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -232,6 +232,9 @@
 #define CSR_MTINST          0x34a
 #define CSR_MTVAL2          0x34b
 
+/* Enhanced PMP */
+#define CSR_MSECCFG         0x390
+#define CSR_MSECCFGH        0x391
 /* Physical Memory Protection */
 #define CSR_PMPCFG0         0x3a0
 #define CSR_PMPCFG1         0x3a1
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 3/8] target/riscv: Add the ePMP feature
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
  2021-04-02 12:47 ` [PATCH v1 1/8] target/riscv: Fix the PMP is locked check when using TOR Alistair Francis
  2021-04-02 12:47 ` [PATCH v1 2/8] target/riscv: Define ePMP mseccfg Alistair Francis
@ 2021-04-02 12:47 ` Alistair Francis
  2021-04-07 14:24   ` Bin Meng
  2021-04-02 12:47 ` [PATCH v1 4/8] target/riscv: Add ePMP CSR access functions Alistair Francis
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:47 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0a33d387ba..8dcb4a4bb2 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -80,6 +80,7 @@
 enum {
     RISCV_FEATURE_MMU,
     RISCV_FEATURE_PMP,
+    RISCV_FEATURE_EPMP,
     RISCV_FEATURE_MISA
 };
 
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 4/8] target/riscv: Add ePMP CSR access functions
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
                   ` (2 preceding siblings ...)
  2021-04-02 12:47 ` [PATCH v1 3/8] target/riscv: Add the ePMP feature Alistair Francis
@ 2021-04-02 12:47 ` Alistair Francis
  2021-04-08 12:57   ` Bin Meng
  2021-04-02 12:48 ` [PATCH v1 5/8] target/riscv: Implementation of enhanced PMP (ePMP) Alistair Francis
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:47 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

From: Hou Weiying <weiying_hou@outlook.com>

Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
Message-Id: <SG2PR02MB26348FDC30678B3177B5CF3893450@SG2PR02MB2634.apcprd02.prod.outlook.com>
[ Changes by AF:
 - Rebase on master
 - Fix build errors
 - Fix some style issues
]
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |  1 +
 target/riscv/pmp.h        | 14 ++++++++++++++
 target/riscv/csr.c        | 22 ++++++++++++++++++++++
 target/riscv/pmp.c        | 34 ++++++++++++++++++++++++++++++++++
 target/riscv/trace-events |  3 +++
 5 files changed, 74 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 8dcb4a4bb2..d1198c0d0d 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -231,6 +231,7 @@ struct CPURISCVState {
 
     /* physical memory protection */
     pmp_table_t pmp_state;
+    target_ulong mseccfg;
 
     /* machine specific rdtime callback */
     uint64_t (*rdtime_fn)(uint32_t);
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index b82a30f0d5..a9a0b363a7 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -36,6 +36,12 @@ typedef enum {
     PMP_AMATCH_NAPOT /* Naturally aligned power-of-two region */
 } pmp_am_t;
 
+typedef enum {
+    MSECCFG_MML  = 1 << 0,
+    MSECCFG_MMWP = 1 << 1,
+    MSECCFG_RLB  = 1 << 2
+} mseccfg_field_t;
+
 typedef struct {
     target_ulong addr_reg;
     uint8_t  cfg_reg;
@@ -55,6 +61,10 @@ typedef struct {
 void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
     target_ulong val);
 target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index);
+
+void mseccfg_csr_write(CPURISCVState *env, target_ulong val);
+target_ulong mseccfg_csr_read(CPURISCVState *env);
+
 void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
     target_ulong val);
 target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
@@ -68,4 +78,8 @@ void pmp_update_rule_nums(CPURISCVState *env);
 uint32_t pmp_get_num_rules(CPURISCVState *env);
 int pmp_priv_to_page_prot(pmp_priv_t pmp_priv);
 
+#define MSECCFG_MML_ISSET(env) get_field(env->mseccfg, MSECCFG_MML)
+#define MSECCFG_MMWP_ISSET(env) get_field(env->mseccfg, MSECCFG_MMWP)
+#define MSECCFG_RLB_ISSET(env) get_field(env->mseccfg, MSECCFG_RLB)
+
 #endif
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index d2585395bf..78b7fb8040 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -184,6 +184,15 @@ static int hmode32(CPURISCVState *env, int csrno)
 
 }
 
+static int epmp(CPURISCVState *env, int csrno)
+{
+    if (env->priv == PRV_M && riscv_feature(env, RISCV_FEATURE_EPMP)) {
+        return 0;
+    }
+
+    return -RISCV_EXCP_ILLEGAL_INST;
+}
+
 static int pmp(CPURISCVState *env, int csrno)
 {
     return -!riscv_feature(env, RISCV_FEATURE_PMP);
@@ -1239,6 +1248,18 @@ static int write_mtinst(CPURISCVState *env, int csrno, target_ulong val)
 }
 
 /* Physical Memory Protection */
+static int read_mseccfg(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = mseccfg_csr_read(env);
+    return 0;
+}
+
+static int write_mseccfg(CPURISCVState *env, int csrno, target_ulong val)
+{
+    mseccfg_csr_write(env, val);
+    return 0;
+}
+
 static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val)
 {
     *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
@@ -1473,6 +1494,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
 
     /* Physical Memory Protection */
+    [CSR_MSECCFG]    = { "mseccfg",  epmp, read_mseccfg, write_mseccfg },
     [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
     [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
     [CSR_PMPCFG2]    = { "pmpcfg2",   pmp, read_pmpcfg,  write_pmpcfg  },
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 6141d0f8f9..1d071b044b 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -418,6 +418,40 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
     return val;
 }
 
+/*
+ * Handle a write to a mseccfg CSR
+ */
+void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
+{
+    int i;
+
+    trace_mseccfg_csr_write(env->mhartid, val);
+
+    /* RLB cannot be enabled if it's already 0 and if any regions are locked */
+    if (!MSECCFG_RLB_ISSET(env)) {
+        for (i = 0; i < MAX_RISCV_PMPS; i++) {
+            if (pmp_is_locked(env, i)) {
+                val &= ~MSECCFG_RLB;
+                break;
+            }
+        }
+    }
+
+    /* Sticky bits */
+    val |= (env->mseccfg & (MSECCFG_MMWP | MSECCFG_MML));
+
+    env->mseccfg = val;
+}
+
+/*
+ * Handle a read from a mseccfg CSR
+ */
+target_ulong mseccfg_csr_read(CPURISCVState *env)
+{
+    trace_mseccfg_csr_read(env->mhartid, env->mseccfg);
+    return env->mseccfg;
+}
+
 /*
  * Calculate the TLB size if the start address or the end address of
  * PMP entry is presented in thie TLB page.
diff --git a/target/riscv/trace-events b/target/riscv/trace-events
index b7e371ee97..49ec4d3b7d 100644
--- a/target/riscv/trace-events
+++ b/target/riscv/trace-events
@@ -6,3 +6,6 @@ pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRI
 pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64
 pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64
 pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64
+
+mseccfg_csr_read(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": read mseccfg, val: 0x%" PRIx64
+mseccfg_csr_write(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": write mseccfg, val: 0x%" PRIx64
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 5/8] target/riscv: Implementation of enhanced PMP (ePMP)
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
                   ` (3 preceding siblings ...)
  2021-04-02 12:47 ` [PATCH v1 4/8] target/riscv: Add ePMP CSR access functions Alistair Francis
@ 2021-04-02 12:48 ` Alistair Francis
  2021-04-09  4:24   ` Bin Meng
  2021-04-02 12:48 ` [PATCH v1 6/8] target/riscv: Add a config option for ePMP Alistair Francis
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:48 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

From: Hou Weiying <weiying_hou@outlook.com>

This commit adds support for ePMP v0.9.1.

The ePMP spec can be found in:
https://docs.google.com/document/d/1Mh_aiHYxemL0umN3GTTw8vsbmzHZ_nxZXgjgOUzbvc8

Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
Message-Id: <SG2PR02MB263462CCDBCBBAD36983C2CD93450@SG2PR02MB2634.apcprd02.prod.outlook.com>
[ Changes by AF:
 - Rebase on master
 - Update to latest spec
 - Use a switch case to handle ePMP MML permissions
 - Fix a few bugs
]
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/pmp.c | 165 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 153 insertions(+), 12 deletions(-)

diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 1d071b044b..3794c808e8 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -90,11 +90,42 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
 static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
 {
     if (pmp_index < MAX_RISCV_PMPS) {
-        if (!pmp_is_locked(env, pmp_index)) {
-            env->pmp_state.pmp[pmp_index].cfg_reg = val;
-            pmp_update_rule(env, pmp_index);
+        bool locked = true;
+
+        if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
+            /* mseccfg.RLB is set */
+            if (MSECCFG_RLB_ISSET(env)) {
+                locked = false;
+            }
+
+            /* mseccfg.MML is not set */
+            if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
+                locked = false;
+            }
+
+            /* mseccfg.MML is set */
+            if (MSECCFG_MML_ISSET(env)) {
+                /* not adding execute bit */
+                if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
+                    locked = false;
+                }
+                 /* shared region and not adding X bit*/
+                if ((val & PMP_LOCK) != PMP_LOCK &&
+                    (val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
+                    locked = false;
+                }
+            }
         } else {
+            if (!pmp_is_locked(env, pmp_index)) {
+                locked = false;
+            }
+        }
+
+        if (locked) {
             qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
+        } else {
+            env->pmp_state.pmp[pmp_index].cfg_reg = val;
+            pmp_update_rule(env, pmp_index);
         }
     } else {
         qemu_log_mask(LOG_GUEST_ERROR,
@@ -217,6 +248,33 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
 {
     bool ret;
 
+    if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
+        if (MSECCFG_MMWP_ISSET(env)) {
+            /*
+             * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set
+             * so we default to deny all, even for M mode.
+             */
+            *allowed_privs = 0;
+            return false;
+        } else if (MSECCFG_MML_ISSET(env)) {
+            /*
+             * The Machine Mode Lockdown (mseccfg.MML) bit is set
+             * so we can only execute code in M mode with an applicable
+             * rule.
+             * Other modes are disabled.
+             */
+            if (mode == PRV_M && !(privs & PMP_EXEC)) {
+                ret = true;
+                *allowed_privs = PMP_READ | PMP_WRITE;
+            } else {
+                ret = false;
+                *allowed_privs = 0;
+            }
+
+            return ret;
+        }
+    }
+
     if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) {
         /*
          * Privileged spec v1.10 states if HW doesn't implement any PMP entry
@@ -294,13 +352,94 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
             pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
 
         /*
-         * If the PMP entry is not off and the address is in range, do the priv
-         * check
+         * Convert the PMP permissions to match the truth table in the
+         * ePMP spec.
          */
+        const uint8_t epmp_operation =
+            ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
+            ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
+            (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
+            ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
+
         if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
-            *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
-            if ((mode != PRV_M) || pmp_is_locked(env, i)) {
-                *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
+            /*
+             * If the PMP entry is not off and the address is in range,
+             * do the priv check
+             */
+            if (!MSECCFG_MML_ISSET(env)) {
+                /*
+                 * If mseccfg.MML Bit is not set, do pmp priv check
+                 * This will always apply to regular PMP.
+                 */
+                *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+                if ((mode != PRV_M) || pmp_is_locked(env, i)) {
+                    *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
+                }
+            } else {
+                /*
+                 * If mseccfg.MML Bit set, do the enhanced pmp priv check
+                 */
+                if (mode == PRV_M) {
+                    switch (epmp_operation) {
+                    case 0:
+                    case 1:
+                    case 4:
+                    case 5:
+                    case 6:
+                    case 7:
+                    case 8:
+                        *allowed_privs = 0;
+                        break;
+                    case 2:
+                    case 3:
+                    case 14:
+                        *allowed_privs = PMP_READ | PMP_WRITE;
+                        break;
+                    case 9:
+                    case 10:
+                        *allowed_privs = PMP_EXEC;
+                        break;
+                    case 11:
+                    case 13:
+                        *allowed_privs = PMP_READ | PMP_EXEC;
+                        break;
+                    case 12:
+                    case 15:
+                        *allowed_privs = PMP_READ;
+                        break;
+                    }
+                } else {
+                    switch (epmp_operation) {
+                    case 0:
+                    case 8:
+                    case 9:
+                    case 12:
+                    case 13:
+                    case 14:
+                        *allowed_privs = 0;
+                        break;
+                    case 1:
+                    case 10:
+                    case 11:
+                        *allowed_privs = PMP_EXEC;
+                        break;
+                    case 2:
+                    case 4:
+                    case 15:
+                        *allowed_privs = PMP_READ;
+                        break;
+                    case 3:
+                    case 6:
+                        *allowed_privs = PMP_READ | PMP_WRITE;
+                        break;
+                    case 5:
+                        *allowed_privs = PMP_READ | PMP_EXEC;
+                        break;
+                    case 7:
+                        *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+                        break;
+                    }
+                }
             }
 
             ret = ((privs & *allowed_privs) == privs);
@@ -328,10 +467,12 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
 
     trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
 
-    if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "ignoring pmpcfg write - incorrect address\n");
-        return;
+    if (!riscv_feature(env, RISCV_FEATURE_EPMP) || !MSECCFG_RLB_ISSET(env)) {
+        if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "ignoring pmpcfg write - incorrect address\n");
+            return;
+        }
     }
 
     for (i = 0; i < sizeof(target_ulong); i++) {
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 6/8] target/riscv: Add a config option for ePMP
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
                   ` (4 preceding siblings ...)
  2021-04-02 12:48 ` [PATCH v1 5/8] target/riscv: Implementation of enhanced PMP (ePMP) Alistair Francis
@ 2021-04-02 12:48 ` Alistair Francis
  2021-04-07 14:28   ` Bin Meng
  2021-04-02 12:48 ` [PATCH v1 7/8] target/riscv/pmp: Remove outdated comment Alistair Francis
  2021-04-02 12:48 ` [PATCH v1 8/8] target/riscv: Add ePMP support for the Ibex CPU Alistair Francis
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:48 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

From: Hou Weiying <weiying_hou@outlook.com>

Add a config option to enable experimental support for ePMP. This
is disabled by default and can be enabled with 'x-epmp=true'.

Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
Message-Id: <SG2PR02MB263458D195A60A57C05EBE9993450@SG2PR02MB2634.apcprd02.prod.outlook.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h |  1 +
 target/riscv/cpu.c | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index d1198c0d0d..22df0d8206 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -305,6 +305,7 @@ struct RISCVCPU {
         uint16_t elen;
         bool mmu;
         bool pmp;
+        bool epmp;
         uint64_t resetvec;
     } cfg;
 };
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7d6ed80f6b..d665681f90 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -412,6 +412,14 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 
     if (cpu->cfg.pmp) {
         set_feature(env, RISCV_FEATURE_PMP);
+
+        /*
+         * Enhanced PMP should only be available
+         * on harts with PMP support
+         */
+        if (cpu->cfg.epmp) {
+            set_feature(env, RISCV_FEATURE_EPMP);
+        }
     }
 
     set_resetvec(env, cpu->cfg.resetvec);
@@ -554,6 +562,8 @@ static Property riscv_cpu_properties[] = {
     DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
     DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
     DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
+    DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
+
     DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
     DEFINE_PROP_END_OF_LIST(),
 };
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 7/8] target/riscv/pmp: Remove outdated comment
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
                   ` (5 preceding siblings ...)
  2021-04-02 12:48 ` [PATCH v1 6/8] target/riscv: Add a config option for ePMP Alistair Francis
@ 2021-04-02 12:48 ` Alistair Francis
  2021-04-07 14:28   ` Bin Meng
  2021-04-02 12:48 ` [PATCH v1 8/8] target/riscv: Add ePMP support for the Ibex CPU Alistair Francis
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:48 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/pmp.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 3794c808e8..07e4c407ab 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -19,10 +19,6 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-/*
- * PMP (Physical Memory Protection) is as-of-yet unused and needs testing.
- */
-
 #include "qemu/osdep.h"
 #include "qemu/log.h"
 #include "qapi/error.h"
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v1 8/8] target/riscv: Add ePMP support for the Ibex CPU
  2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
                   ` (6 preceding siblings ...)
  2021-04-02 12:48 ` [PATCH v1 7/8] target/riscv/pmp: Remove outdated comment Alistair Francis
@ 2021-04-02 12:48 ` Alistair Francis
  2021-04-07 14:28   ` Bin Meng
  7 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2021-04-02 12:48 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: weiying_hou, Ethan.Lee.QNL, alistair.francis, alistair23, palmer,
	bmeng.cn, camiyoru

The physical Ibex CPU has ePMP support and it's enabled for the
OpenTitan machine so let's enable ePMP support for the Ibex CPU in QEMU.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index d665681f90..244066a6fc 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -202,6 +202,7 @@ static void rv32_ibex_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+    qdev_prop_set_bit(DEVICE(obj), "x-epmp", true);
 }
 
 static void rv32_imafcu_nommu_cpu_init(Object *obj)
-- 
2.31.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 2/8] target/riscv: Define ePMP mseccfg
  2021-04-02 12:47 ` [PATCH v1 2/8] target/riscv: Define ePMP mseccfg Alistair Francis
@ 2021-04-07 14:24   ` Bin Meng
  0 siblings, 0 replies; 18+ messages in thread
From: Bin Meng @ 2021-04-07 14:24 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:49 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> From: Hou Weiying <weiying_hou@outlook.com>
>
> Use address  0x390 and 0x391 for the ePMP CSRs.

nits: remove one space before 0x390

>
> Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
> Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
> Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
> Message-Id: <SG2PR02MB2634D85E5DF0C2BB540AE1BB93450@SG2PR02MB2634.apcprd02.prod.outlook.com>
> [ Changes by AF:
>  - Tidy up commit message
> ]
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_bits.h | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index caf4599207..32e1ee92dc 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -232,6 +232,9 @@
>  #define CSR_MTINST          0x34a
>  #define CSR_MTVAL2          0x34b
>
> +/* Enhanced PMP */

nits: Enhanced Physical Memory Protection ?

> +#define CSR_MSECCFG         0x390
> +#define CSR_MSECCFGH        0x391
>  /* Physical Memory Protection */
>  #define CSR_PMPCFG0         0x3a0
>  #define CSR_PMPCFG1         0x3a1

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

Regards,
Bin


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 3/8] target/riscv: Add the ePMP feature
  2021-04-02 12:47 ` [PATCH v1 3/8] target/riscv: Add the ePMP feature Alistair Francis
@ 2021-04-07 14:24   ` Bin Meng
  0 siblings, 0 replies; 18+ messages in thread
From: Bin Meng @ 2021-04-07 14:24 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:50 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>

nits: I guess mentioning the ePMP spec URL in the commit message might
be helpful

> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0a33d387ba..8dcb4a4bb2 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -80,6 +80,7 @@
>  enum {
>      RISCV_FEATURE_MMU,
>      RISCV_FEATURE_PMP,
> +    RISCV_FEATURE_EPMP,
>      RISCV_FEATURE_MISA
>  };

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 6/8] target/riscv: Add a config option for ePMP
  2021-04-02 12:48 ` [PATCH v1 6/8] target/riscv: Add a config option for ePMP Alistair Francis
@ 2021-04-07 14:28   ` Bin Meng
  0 siblings, 0 replies; 18+ messages in thread
From: Bin Meng @ 2021-04-07 14:28 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:50 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> From: Hou Weiying <weiying_hou@outlook.com>
>
> Add a config option to enable experimental support for ePMP. This
> is disabled by default and can be enabled with 'x-epmp=true'.
>
> Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
> Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
> Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
> Message-Id: <SG2PR02MB263458D195A60A57C05EBE9993450@SG2PR02MB2634.apcprd02.prod.outlook.com>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h |  1 +
>  target/riscv/cpu.c | 10 ++++++++++
>  2 files changed, 11 insertions(+)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 7/8] target/riscv/pmp: Remove outdated comment
  2021-04-02 12:48 ` [PATCH v1 7/8] target/riscv/pmp: Remove outdated comment Alistair Francis
@ 2021-04-07 14:28   ` Bin Meng
  0 siblings, 0 replies; 18+ messages in thread
From: Bin Meng @ 2021-04-07 14:28 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:50 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/pmp.c | 4 ----
>  1 file changed, 4 deletions(-)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 8/8] target/riscv: Add ePMP support for the Ibex CPU
  2021-04-02 12:48 ` [PATCH v1 8/8] target/riscv: Add ePMP support for the Ibex CPU Alistair Francis
@ 2021-04-07 14:28   ` Bin Meng
  0 siblings, 0 replies; 18+ messages in thread
From: Bin Meng @ 2021-04-07 14:28 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:50 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> The physical Ibex CPU has ePMP support and it's enabled for the
> OpenTitan machine so let's enable ePMP support for the Ibex CPU in QEMU.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c | 1 +
>  1 file changed, 1 insertion(+)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 1/8] target/riscv: Fix the PMP is locked check when using TOR
  2021-04-02 12:47 ` [PATCH v1 1/8] target/riscv: Fix the PMP is locked check when using TOR Alistair Francis
@ 2021-04-08  9:25   ` Bin Meng
  0 siblings, 0 replies; 18+ messages in thread
From: Bin Meng @ 2021-04-08  9:25 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:49 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> The RISC-V spec says:
>     if PMP entry i is locked and pmpicfg.A is set to TOR, writes to
>     pmpaddri-1 are ignored.
>
> The current QEMU code ignores accesses to pmpaddri-1 and pmpcfgi-1 which
> is incorrect.
>
> Update the pmp_is_locked() function to not check the suppording fields

typo: supported?

> and instaed enforce the lock functionality in the pmpaddr write operation.

typo: instead

>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/pmp.c | 25 +++++++++++++++----------
>  1 file changed, 15 insertions(+), 10 deletions(-)
>
> diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
> index cff020122a..6141d0f8f9 100644
> --- a/target/riscv/pmp.c
> +++ b/target/riscv/pmp.c
> @@ -59,16 +59,6 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
>          return 0;
>      }
>
> -    /* In TOR mode, need to check the lock bit of the next pmp
> -     * (if there is a next)
> -     */
> -    const uint8_t a_field =
> -        pmp_get_a_field(env->pmp_state.pmp[pmp_index + 1].cfg_reg);
> -    if ((env->pmp_state.pmp[pmp_index + 1u].cfg_reg & PMP_LOCK) &&
> -         (PMP_AMATCH_TOR == a_field)) {
> -        return 1;
> -    }
> -
>      return 0;
>  }
>
> @@ -380,7 +370,22 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
>      target_ulong val)
>  {
>      trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
> +
>      if (addr_index < MAX_RISCV_PMPS) {
> +        /* In TOR mode, need to check the lock bit of the next pmp

nits: should use correct multi-line comment block format

> +         * (if there is a next).
> +         */
> +        if (addr_index + 1 < MAX_RISCV_PMPS) {
> +            uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
> +
> +            if (pmp_cfg & PMP_LOCK &&
> +                PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg)) {
> +                qemu_log_mask(LOG_GUEST_ERROR,
> +                              "ignoring pmpaddr write - pmpcfg + 1 locked\n");
> +                return;
> +            }
> +        }
> +
>          if (!pmp_is_locked(env, addr_index)) {
>              env->pmp_state.pmp[addr_index].addr_reg = val;
>              pmp_update_rule(env, addr_index);
> --

Otherwise,
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 4/8] target/riscv: Add ePMP CSR access functions
  2021-04-02 12:47 ` [PATCH v1 4/8] target/riscv: Add ePMP CSR access functions Alistair Francis
@ 2021-04-08 12:57   ` Bin Meng
  0 siblings, 0 replies; 18+ messages in thread
From: Bin Meng @ 2021-04-08 12:57 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:50 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> From: Hou Weiying <weiying_hou@outlook.com>
>
> Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
> Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
> Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
> Message-Id: <SG2PR02MB26348FDC30678B3177B5CF3893450@SG2PR02MB2634.apcprd02.prod.outlook.com>
> [ Changes by AF:
>  - Rebase on master
>  - Fix build errors
>  - Fix some style issues
> ]
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h        |  1 +
>  target/riscv/pmp.h        | 14 ++++++++++++++
>  target/riscv/csr.c        | 22 ++++++++++++++++++++++
>  target/riscv/pmp.c        | 34 ++++++++++++++++++++++++++++++++++
>  target/riscv/trace-events |  3 +++
>  5 files changed, 74 insertions(+)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 5/8] target/riscv: Implementation of enhanced PMP (ePMP)
  2021-04-02 12:48 ` [PATCH v1 5/8] target/riscv: Implementation of enhanced PMP (ePMP) Alistair Francis
@ 2021-04-09  4:24   ` Bin Meng
  2021-04-11 23:03     ` Alistair Francis
  0 siblings, 1 reply; 18+ messages in thread
From: Bin Meng @ 2021-04-09  4:24 UTC (permalink / raw)
  To: Alistair Francis
  Cc: weiying_hou, open list:RISC-V, Ethan.Lee.QNL,
	qemu-devel@nongnu.org Developers, Palmer Dabbelt,
	Alistair Francis, camiyoru

On Fri, Apr 2, 2021 at 8:50 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> From: Hou Weiying <weiying_hou@outlook.com>
>
> This commit adds support for ePMP v0.9.1.
>
> The ePMP spec can be found in:
> https://docs.google.com/document/d/1Mh_aiHYxemL0umN3GTTw8vsbmzHZ_nxZXgjgOUzbvc8
>
> Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
> Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
> Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
> Message-Id: <SG2PR02MB263462CCDBCBBAD36983C2CD93450@SG2PR02MB2634.apcprd02.prod.outlook.com>
> [ Changes by AF:
>  - Rebase on master
>  - Update to latest spec
>  - Use a switch case to handle ePMP MML permissions
>  - Fix a few bugs
> ]
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/pmp.c | 165 +++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 153 insertions(+), 12 deletions(-)
>
> diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
> index 1d071b044b..3794c808e8 100644
> --- a/target/riscv/pmp.c
> +++ b/target/riscv/pmp.c
> @@ -90,11 +90,42 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
>  static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
>  {
>      if (pmp_index < MAX_RISCV_PMPS) {
> -        if (!pmp_is_locked(env, pmp_index)) {
> -            env->pmp_state.pmp[pmp_index].cfg_reg = val;
> -            pmp_update_rule(env, pmp_index);
> +        bool locked = true;
> +
> +        if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
> +            /* mseccfg.RLB is set */
> +            if (MSECCFG_RLB_ISSET(env)) {
> +                locked = false;
> +            }
> +
> +            /* mseccfg.MML is not set */
> +            if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
> +                locked = false;
> +            }
> +
> +            /* mseccfg.MML is set */
> +            if (MSECCFG_MML_ISSET(env)) {
> +                /* not adding execute bit */
> +                if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
> +                    locked = false;
> +                }
> +                 /* shared region and not adding X bit*/

nits: /* is not aligned, and a space is needed before */

> +                if ((val & PMP_LOCK) != PMP_LOCK &&
> +                    (val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
> +                    locked = false;
> +                }
> +            }
>          } else {
> +            if (!pmp_is_locked(env, pmp_index)) {
> +                locked = false;
> +            }
> +        }
> +
> +        if (locked) {
>              qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
> +        } else {
> +            env->pmp_state.pmp[pmp_index].cfg_reg = val;
> +            pmp_update_rule(env, pmp_index);
>          }
>      } else {
>          qemu_log_mask(LOG_GUEST_ERROR,
> @@ -217,6 +248,33 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
>  {
>      bool ret;
>
> +    if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
> +        if (MSECCFG_MMWP_ISSET(env)) {
> +            /*
> +             * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set
> +             * so we default to deny all, even for M mode.

nits: M-mode

> +             */
> +            *allowed_privs = 0;
> +            return false;
> +        } else if (MSECCFG_MML_ISSET(env)) {
> +            /*
> +             * The Machine Mode Lockdown (mseccfg.MML) bit is set
> +             * so we can only execute code in M mode with an applicable

nits: M-mode

> +             * rule.
> +             * Other modes are disabled.

nits: this line can be put in the same line of "rule."

> +             */
> +            if (mode == PRV_M && !(privs & PMP_EXEC)) {
> +                ret = true;
> +                *allowed_privs = PMP_READ | PMP_WRITE;
> +            } else {
> +                ret = false;
> +                *allowed_privs = 0;
> +            }
> +
> +            return ret;
> +        }

If I understand the spec correctly, I think we are missing a branch to
handle MML unset case, in which RWX is allowed in M-mode.

> +    }
> +
>      if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) {
>          /*
>           * Privileged spec v1.10 states if HW doesn't implement any PMP entry
> @@ -294,13 +352,94 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
>              pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
>
>          /*
> -         * If the PMP entry is not off and the address is in range, do the priv
> -         * check
> +         * Convert the PMP permissions to match the truth table in the
> +         * ePMP spec.
>           */
> +        const uint8_t epmp_operation =
> +            ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
> +            ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
> +            (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
> +            ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
> +
>          if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
> -            *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
> -            if ((mode != PRV_M) || pmp_is_locked(env, i)) {
> -                *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
> +            /*
> +             * If the PMP entry is not off and the address is in range,
> +             * do the priv check
> +             */
> +            if (!MSECCFG_MML_ISSET(env)) {
> +                /*
> +                 * If mseccfg.MML Bit is not set, do pmp priv check
> +                 * This will always apply to regular PMP.
> +                 */
> +                *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
> +                if ((mode != PRV_M) || pmp_is_locked(env, i)) {
> +                    *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
> +                }
> +            } else {
> +                /*
> +                 * If mseccfg.MML Bit set, do the enhanced pmp priv check
> +                 */
> +                if (mode == PRV_M) {
> +                    switch (epmp_operation) {
> +                    case 0:
> +                    case 1:
> +                    case 4:
> +                    case 5:
> +                    case 6:
> +                    case 7:
> +                    case 8:
> +                        *allowed_privs = 0;
> +                        break;
> +                    case 2:
> +                    case 3:
> +                    case 14:
> +                        *allowed_privs = PMP_READ | PMP_WRITE;
> +                        break;
> +                    case 9:
> +                    case 10:
> +                        *allowed_privs = PMP_EXEC;
> +                        break;
> +                    case 11:
> +                    case 13:
> +                        *allowed_privs = PMP_READ | PMP_EXEC;
> +                        break;
> +                    case 12:
> +                    case 15:
> +                        *allowed_privs = PMP_READ;
> +                        break;
> +                    }
> +                } else {
> +                    switch (epmp_operation) {
> +                    case 0:
> +                    case 8:
> +                    case 9:
> +                    case 12:
> +                    case 13:
> +                    case 14:
> +                        *allowed_privs = 0;
> +                        break;
> +                    case 1:
> +                    case 10:
> +                    case 11:
> +                        *allowed_privs = PMP_EXEC;
> +                        break;
> +                    case 2:
> +                    case 4:
> +                    case 15:
> +                        *allowed_privs = PMP_READ;
> +                        break;
> +                    case 3:
> +                    case 6:
> +                        *allowed_privs = PMP_READ | PMP_WRITE;
> +                        break;
> +                    case 5:
> +                        *allowed_privs = PMP_READ | PMP_EXEC;
> +                        break;
> +                    case 7:
> +                        *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
> +                        break;
> +                    }
> +                }
>              }
>
>              ret = ((privs & *allowed_privs) == privs);
> @@ -328,10 +467,12 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
>
>      trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
>
> -    if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
> -        qemu_log_mask(LOG_GUEST_ERROR,
> -                      "ignoring pmpcfg write - incorrect address\n");
> -        return;
> +    if (!riscv_feature(env, RISCV_FEATURE_EPMP) || !MSECCFG_RLB_ISSET(env)) {
> +        if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "ignoring pmpcfg write - incorrect address\n");

If ePMP RLB is off, this log message is inaccurate and misleading.

> +            return;
> +        }
>      }
>
>      for (i = 0; i < sizeof(target_ulong); i++) {
> --

Regards,
Bin


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v1 5/8] target/riscv: Implementation of enhanced PMP (ePMP)
  2021-04-09  4:24   ` Bin Meng
@ 2021-04-11 23:03     ` Alistair Francis
  0 siblings, 0 replies; 18+ messages in thread
From: Alistair Francis @ 2021-04-11 23:03 UTC (permalink / raw)
  To: Bin Meng
  Cc: Hou Weiying, open list:RISC-V, qemu-devel@nongnu.org Developers,
	Hongzheng-Li, Palmer Dabbelt, Alistair Francis, Myriad-Dreamin

On Fri, Apr 9, 2021 at 2:24 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Fri, Apr 2, 2021 at 8:50 PM Alistair Francis
> <alistair.francis@wdc.com> wrote:
> >
> > From: Hou Weiying <weiying_hou@outlook.com>
> >
> > This commit adds support for ePMP v0.9.1.
> >
> > The ePMP spec can be found in:
> > https://docs.google.com/document/d/1Mh_aiHYxemL0umN3GTTw8vsbmzHZ_nxZXgjgOUzbvc8
> >
> > Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
> > Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
> > Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
> > Message-Id: <SG2PR02MB263462CCDBCBBAD36983C2CD93450@SG2PR02MB2634.apcprd02.prod.outlook.com>
> > [ Changes by AF:
> >  - Rebase on master
> >  - Update to latest spec
> >  - Use a switch case to handle ePMP MML permissions
> >  - Fix a few bugs
> > ]
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  target/riscv/pmp.c | 165 +++++++++++++++++++++++++++++++++++++++++----
> >  1 file changed, 153 insertions(+), 12 deletions(-)
> >
> > diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
> > index 1d071b044b..3794c808e8 100644
> > --- a/target/riscv/pmp.c
> > +++ b/target/riscv/pmp.c
> > @@ -90,11 +90,42 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
> >  static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
> >  {
> >      if (pmp_index < MAX_RISCV_PMPS) {
> > -        if (!pmp_is_locked(env, pmp_index)) {
> > -            env->pmp_state.pmp[pmp_index].cfg_reg = val;
> > -            pmp_update_rule(env, pmp_index);
> > +        bool locked = true;
> > +
> > +        if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
> > +            /* mseccfg.RLB is set */
> > +            if (MSECCFG_RLB_ISSET(env)) {
> > +                locked = false;
> > +            }
> > +
> > +            /* mseccfg.MML is not set */
> > +            if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
> > +                locked = false;
> > +            }
> > +
> > +            /* mseccfg.MML is set */
> > +            if (MSECCFG_MML_ISSET(env)) {
> > +                /* not adding execute bit */
> > +                if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
> > +                    locked = false;
> > +                }
> > +                 /* shared region and not adding X bit*/
>
> nits: /* is not aligned, and a space is needed before */
>
> > +                if ((val & PMP_LOCK) != PMP_LOCK &&
> > +                    (val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
> > +                    locked = false;
> > +                }
> > +            }
> >          } else {
> > +            if (!pmp_is_locked(env, pmp_index)) {
> > +                locked = false;
> > +            }
> > +        }
> > +
> > +        if (locked) {
> >              qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
> > +        } else {
> > +            env->pmp_state.pmp[pmp_index].cfg_reg = val;
> > +            pmp_update_rule(env, pmp_index);
> >          }
> >      } else {
> >          qemu_log_mask(LOG_GUEST_ERROR,
> > @@ -217,6 +248,33 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
> >  {
> >      bool ret;
> >
> > +    if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
> > +        if (MSECCFG_MMWP_ISSET(env)) {
> > +            /*
> > +             * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set
> > +             * so we default to deny all, even for M mode.
>
> nits: M-mode
>
> > +             */
> > +            *allowed_privs = 0;
> > +            return false;
> > +        } else if (MSECCFG_MML_ISSET(env)) {
> > +            /*
> > +             * The Machine Mode Lockdown (mseccfg.MML) bit is set
> > +             * so we can only execute code in M mode with an applicable
>
> nits: M-mode
>
> > +             * rule.
> > +             * Other modes are disabled.
>
> nits: this line can be put in the same line of "rule."
>
> > +             */
> > +            if (mode == PRV_M && !(privs & PMP_EXEC)) {
> > +                ret = true;
> > +                *allowed_privs = PMP_READ | PMP_WRITE;
> > +            } else {
> > +                ret = false;
> > +                *allowed_privs = 0;
> > +            }
> > +
> > +            return ret;
> > +        }
>
> If I understand the spec correctly, I think we are missing a branch to
> handle MML unset case, in which RWX is allowed in M-mode.

Yep, so if MML and MMWP aren't set then we just fall back to the
standard PMP checks which are below. So M-mode accesses will be
allowed and other privs won't be.

>
> > +    }
> > +
> >      if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) {
> >          /*
> >           * Privileged spec v1.10 states if HW doesn't implement any PMP entry
> > @@ -294,13 +352,94 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
> >              pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
> >
> >          /*
> > -         * If the PMP entry is not off and the address is in range, do the priv
> > -         * check
> > +         * Convert the PMP permissions to match the truth table in the
> > +         * ePMP spec.
> >           */
> > +        const uint8_t epmp_operation =
> > +            ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
> > +            ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
> > +            (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
> > +            ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
> > +
> >          if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
> > -            *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
> > -            if ((mode != PRV_M) || pmp_is_locked(env, i)) {
> > -                *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
> > +            /*
> > +             * If the PMP entry is not off and the address is in range,
> > +             * do the priv check
> > +             */
> > +            if (!MSECCFG_MML_ISSET(env)) {
> > +                /*
> > +                 * If mseccfg.MML Bit is not set, do pmp priv check
> > +                 * This will always apply to regular PMP.
> > +                 */
> > +                *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
> > +                if ((mode != PRV_M) || pmp_is_locked(env, i)) {
> > +                    *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
> > +                }
> > +            } else {
> > +                /*
> > +                 * If mseccfg.MML Bit set, do the enhanced pmp priv check
> > +                 */
> > +                if (mode == PRV_M) {
> > +                    switch (epmp_operation) {
> > +                    case 0:
> > +                    case 1:
> > +                    case 4:
> > +                    case 5:
> > +                    case 6:
> > +                    case 7:
> > +                    case 8:
> > +                        *allowed_privs = 0;
> > +                        break;
> > +                    case 2:
> > +                    case 3:
> > +                    case 14:
> > +                        *allowed_privs = PMP_READ | PMP_WRITE;
> > +                        break;
> > +                    case 9:
> > +                    case 10:
> > +                        *allowed_privs = PMP_EXEC;
> > +                        break;
> > +                    case 11:
> > +                    case 13:
> > +                        *allowed_privs = PMP_READ | PMP_EXEC;
> > +                        break;
> > +                    case 12:
> > +                    case 15:
> > +                        *allowed_privs = PMP_READ;
> > +                        break;
> > +                    }
> > +                } else {
> > +                    switch (epmp_operation) {
> > +                    case 0:
> > +                    case 8:
> > +                    case 9:
> > +                    case 12:
> > +                    case 13:
> > +                    case 14:
> > +                        *allowed_privs = 0;
> > +                        break;
> > +                    case 1:
> > +                    case 10:
> > +                    case 11:
> > +                        *allowed_privs = PMP_EXEC;
> > +                        break;
> > +                    case 2:
> > +                    case 4:
> > +                    case 15:
> > +                        *allowed_privs = PMP_READ;
> > +                        break;
> > +                    case 3:
> > +                    case 6:
> > +                        *allowed_privs = PMP_READ | PMP_WRITE;
> > +                        break;
> > +                    case 5:
> > +                        *allowed_privs = PMP_READ | PMP_EXEC;
> > +                        break;
> > +                    case 7:
> > +                        *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
> > +                        break;
> > +                    }
> > +                }
> >              }
> >
> >              ret = ((privs & *allowed_privs) == privs);
> > @@ -328,10 +467,12 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
> >
> >      trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
> >
> > -    if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
> > -        qemu_log_mask(LOG_GUEST_ERROR,
> > -                      "ignoring pmpcfg write - incorrect address\n");
> > -        return;
> > +    if (!riscv_feature(env, RISCV_FEATURE_EPMP) || !MSECCFG_RLB_ISSET(env)) {
> > +        if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
> > +            qemu_log_mask(LOG_GUEST_ERROR,
> > +                          "ignoring pmpcfg write - incorrect address\n");
>
> If ePMP RLB is off, this log message is inaccurate and misleading.

Thanks, I have fixed this and all the other comments.

Alistair

>
> > +            return;
> > +        }
> >      }
> >
> >      for (i = 0; i < sizeof(target_ulong); i++) {
> > --
>
> Regards,
> Bin


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2021-04-11 23:05 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-02 12:47 [PATCH v1 0/8] RISC-V: Add support for ePMP v0.9.1 Alistair Francis
2021-04-02 12:47 ` [PATCH v1 1/8] target/riscv: Fix the PMP is locked check when using TOR Alistair Francis
2021-04-08  9:25   ` Bin Meng
2021-04-02 12:47 ` [PATCH v1 2/8] target/riscv: Define ePMP mseccfg Alistair Francis
2021-04-07 14:24   ` Bin Meng
2021-04-02 12:47 ` [PATCH v1 3/8] target/riscv: Add the ePMP feature Alistair Francis
2021-04-07 14:24   ` Bin Meng
2021-04-02 12:47 ` [PATCH v1 4/8] target/riscv: Add ePMP CSR access functions Alistair Francis
2021-04-08 12:57   ` Bin Meng
2021-04-02 12:48 ` [PATCH v1 5/8] target/riscv: Implementation of enhanced PMP (ePMP) Alistair Francis
2021-04-09  4:24   ` Bin Meng
2021-04-11 23:03     ` Alistair Francis
2021-04-02 12:48 ` [PATCH v1 6/8] target/riscv: Add a config option for ePMP Alistair Francis
2021-04-07 14:28   ` Bin Meng
2021-04-02 12:48 ` [PATCH v1 7/8] target/riscv/pmp: Remove outdated comment Alistair Francis
2021-04-07 14:28   ` Bin Meng
2021-04-02 12:48 ` [PATCH v1 8/8] target/riscv: Add ePMP support for the Ibex CPU Alistair Francis
2021-04-07 14:28   ` Bin Meng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).