This patch introduces the core implementation for the Memory Protection Table
(MPT) walk, which is the central mechanism of the SMMPT extension.
A new file, `riscv_smmpt.c`, is added to encapsulate the MPT logic. It
implements the `smmpt_lookup()` function, which performs a multi-level
page table-like walk starting from the physical address specified in the
`mptppn` CSR field. This walk determines the access permissions (read,
write, execute) for a given physical address.
The implementation supports various SMMPT modes (SMMPT34, SMMPT43, etc.) and
correctly handles leaf and non-leaf entries, including reserved bit
checks. Helper functions for parsing MPT entries and converting access
permissions are also included in the new `riscv_smmpt.h` header.
Co-authored-by: Huang Tao <[email protected]>
Co-authored-by: TANG Tiancheng <[email protected]>
Signed-off-by: LIU Zhiwei <[email protected]>
Reviewed-by: Daniel Henrique Barboza <[email protected]>
---
target/riscv/cpu_helper.c | 5 +-
target/riscv/meson.build | 1 +
target/riscv/pmp.h | 3 +
target/riscv/riscv_smmpt.c | 274 +++++++++++++++++++++++++++++++++++++
target/riscv/riscv_smmpt.h | 15 ++
5 files changed, 295 insertions(+), 3 deletions(-)
create mode 100644 target/riscv/riscv_smmpt.c
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index dd6c861a90..e3361fadae 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1089,9 +1089,8 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong
newpriv, bool virt_en)
* @access_type: The type of MMU access
* @mode: Indicates current privilege level.
*/
-static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
- int size, MMUAccessType access_type,
- int mode)
+int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
+ int size, MMUAccessType access_type, int mode)
{
pmp_priv_t pmp_priv;
bool pmp_has_privs;
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 3842c7c1a8..bd1c2e8fad 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -34,6 +34,7 @@ riscv_system_ss = ss.source_set()
riscv_system_ss.add(files(
'arch_dump.c',
'pmp.c',
+ 'riscv_smmpt.c',
'debug.c',
'monitor.c',
'machine.c',
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index 467fb6b4b1..1ed574227c 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -86,6 +86,9 @@ 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);
void pmp_unlock_entries(CPURISCVState *env);
+int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
+ int size, MMUAccessType access_type,
+ int mode);
#define MSECCFG_MML_ISSET(env) get_field(env->mseccfg, MSECCFG_MML)
#define MSECCFG_MMWP_ISSET(env) get_field(env->mseccfg, MSECCFG_MMWP)
diff --git a/target/riscv/riscv_smmpt.c b/target/riscv/riscv_smmpt.c
new file mode 100644
index 0000000000..b7b47c5ae1
--- /dev/null
+++ b/target/riscv/riscv_smmpt.c
@@ -0,0 +1,274 @@
+/*
+ * QEMU RISC-V Smmpt (Memory Protection Table)
+ *
+ * Copyright (c) 2024 Alibaba Group. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "riscv_smmpt.h"
+#include "pmp.h"
+#include "system/memory.h"
+
+typedef uint64_t load_entry_fn(AddressSpace *, hwaddr,
+ MemTxAttrs, MemTxResult *);
+
+static uint64_t load_entry_32(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs, MemTxResult *result)
+{
+ return address_space_ldl(as, addr, attrs, result);
+}
+
+static uint64_t load_entry_64(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs, MemTxResult *result)
+{
+ return address_space_ldq(as, addr, attrs, result);
+}
+
+typedef union {
+ uint64_t raw;
+ struct {
+ uint32_t v:1;
+ uint32_t l:1;
+ uint32_t rsv1:5;
+ uint32_t perms:24;
+ uint32_t n:1;
+ } leaf32;
+ struct {
+ uint32_t v:1;
+ uint32_t l:1;
+ uint32_t rsv1:8;
+ uint32_t ppn:22;
+ } nonleaf32;
+ struct {
+ uint64_t v:1;
+ uint64_t l:1;
+ uint64_t rsv1:8;
+ uint64_t perms:48;
+ uint64_t rsv2:5;
+ uint64_t n:1;
+ } leaf64;
+ struct {
+ uint64_t v:1;
+ uint64_t l:1;
+ uint64_t rsv1:8;
+ uint64_t ppn:52;
+ uint64_t rsv2:1;
+ uint64_t n:1;
+ } nonleaf64;
+} mpte_union_t;