Previously, the PMP granularity in qemu always used a minimum
granularity of 4 bytes, this patch add pmp-granularity to allow
platforms to configure the value.
A new CPU parameter pmp-granularity has been introduced to the QEMU
command line. For example:
-cpu rv64, g=true, c=true, pmp=true, pmp-granularity=1024
If no specific value is provided, the default value is 4 bytes.
Signed-off-by: Jay Chang <jay.chang@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Jim Shu <jim.shu@sifive.com>
---
target/riscv/cpu.c | 39 +++++++++++++++++++++++++++++++
target/riscv/cpu.h | 1 +
target/riscv/cpu_cfg_fields.h.inc | 1 +
3 files changed, 41 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a877018ab0..73d4280d7c 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1121,6 +1121,7 @@ static void riscv_cpu_init(Object *obj)
cpu->cfg.cbop_blocksize = 64;
cpu->cfg.cboz_blocksize = 64;
cpu->cfg.pmp_regions = 16;
+ cpu->cfg.pmp_granularity = MIN_RISCV_PMP_GRANULARITY;
cpu->env.vext_ver = VEXT_VERSION_1_00_0;
cpu->cfg.max_satp_mode = -1;
@@ -1606,6 +1607,43 @@ static const PropertyInfo prop_num_pmp_regions = {
.set = prop_num_pmp_regions_set,
};
+static void prop_pmp_granularity_set(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ RISCVCPU *cpu = RISCV_CPU(obj);
+ uint32_t value;
+
+ visit_type_uint32(v, name, &value, errp);
+
+ if ((value < MIN_RISCV_PMP_GRANULARITY) && (value & (value - 1))) {
+ error_setg(errp, "PMP granularity must be a power of 2 and at least %d",
+ MIN_RISCV_PMP_GRANULARITY);
+ return;
+ }
+
+ if (cpu->cfg.pmp_granularity != value && riscv_cpu_is_vendor(obj)) {
+ cpu_set_prop_err(cpu, name, errp);
+ return;
+ }
+
+ cpu_option_add_user_setting(name, value);
+ cpu->cfg.pmp_granularity = value;
+}
+
+static void prop_pmp_granularity_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint32_t value = RISCV_CPU(obj)->cfg.pmp_granularity;
+
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static const PropertyInfo prop_pmp_granularity = {
+ .description = "pmp-granularity",
+ .get = prop_pmp_granularity_get,
+ .set = prop_pmp_granularity_set,
+};
+
static int priv_spec_from_str(const char *priv_spec_str)
{
int priv_version = -1;
@@ -2606,6 +2644,7 @@ static const Property riscv_cpu_properties[] = {
{.name = "mmu", .info = &prop_mmu},
{.name = "pmp", .info = &prop_pmp},
{.name = "num-pmp-regions", .info = &prop_num_pmp_regions},
+ {.name = "pmp-granularity", .info = &prop_pmp_granularity},
{.name = "priv_spec", .info = &prop_priv_spec},
{.name = "vext_spec", .info = &prop_vext_spec},
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 2c2266415e..04711f93a2 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -176,6 +176,7 @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];
#define MAX_RISCV_PMPS (64)
#define OLD_MAX_RISCV_PMPS (16)
+#define MIN_RISCV_PMP_GRANULARITY 4
#if !defined(CONFIG_USER_ONLY)
#include "pmp.h"
diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
index e2d116f0df..a154ecdc79 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -166,6 +166,7 @@ TYPED_FIELD(uint16_t, cbom_blocksize, 0)
TYPED_FIELD(uint16_t, cbop_blocksize, 0)
TYPED_FIELD(uint16_t, cboz_blocksize, 0)
TYPED_FIELD(uint8_t, pmp_regions, 0)
+TYPED_FIELD(uint32_t, pmp_granularity, 0)
TYPED_FIELD(int8_t, max_satp_mode, -1)
--
2.48.1
On Tue, Oct 14, 2025 at 6:24 PM Jay Chang <jay.chang@sifive.com> wrote:
>
> Previously, the PMP granularity in qemu always used a minimum
> granularity of 4 bytes, this patch add pmp-granularity to allow
> platforms to configure the value.
>
> A new CPU parameter pmp-granularity has been introduced to the QEMU
> command line. For example:
>
> -cpu rv64, g=true, c=true, pmp=true, pmp-granularity=1024
>
> If no specific value is provided, the default value is 4 bytes.
>
> Signed-off-by: Jay Chang <jay.chang@sifive.com>
> Reviewed-by: Frank Chang <frank.chang@sifive.com>
> Reviewed-by: Jim Shu <jim.shu@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> target/riscv/cpu.c | 39 +++++++++++++++++++++++++++++++
> target/riscv/cpu.h | 1 +
> target/riscv/cpu_cfg_fields.h.inc | 1 +
> 3 files changed, 41 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index a877018ab0..73d4280d7c 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -1121,6 +1121,7 @@ static void riscv_cpu_init(Object *obj)
> cpu->cfg.cbop_blocksize = 64;
> cpu->cfg.cboz_blocksize = 64;
> cpu->cfg.pmp_regions = 16;
> + cpu->cfg.pmp_granularity = MIN_RISCV_PMP_GRANULARITY;
> cpu->env.vext_ver = VEXT_VERSION_1_00_0;
> cpu->cfg.max_satp_mode = -1;
>
> @@ -1606,6 +1607,43 @@ static const PropertyInfo prop_num_pmp_regions = {
> .set = prop_num_pmp_regions_set,
> };
>
> +static void prop_pmp_granularity_set(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + RISCVCPU *cpu = RISCV_CPU(obj);
> + uint32_t value;
> +
> + visit_type_uint32(v, name, &value, errp);
> +
> + if ((value < MIN_RISCV_PMP_GRANULARITY) && (value & (value - 1))) {
> + error_setg(errp, "PMP granularity must be a power of 2 and at least %d",
> + MIN_RISCV_PMP_GRANULARITY);
> + return;
> + }
> +
> + if (cpu->cfg.pmp_granularity != value && riscv_cpu_is_vendor(obj)) {
> + cpu_set_prop_err(cpu, name, errp);
> + return;
> + }
> +
> + cpu_option_add_user_setting(name, value);
> + cpu->cfg.pmp_granularity = value;
> +}
> +
> +static void prop_pmp_granularity_get(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + uint32_t value = RISCV_CPU(obj)->cfg.pmp_granularity;
> +
> + visit_type_uint32(v, name, &value, errp);
> +}
> +
> +static const PropertyInfo prop_pmp_granularity = {
> + .description = "pmp-granularity",
> + .get = prop_pmp_granularity_get,
> + .set = prop_pmp_granularity_set,
> +};
> +
> static int priv_spec_from_str(const char *priv_spec_str)
> {
> int priv_version = -1;
> @@ -2606,6 +2644,7 @@ static const Property riscv_cpu_properties[] = {
> {.name = "mmu", .info = &prop_mmu},
> {.name = "pmp", .info = &prop_pmp},
> {.name = "num-pmp-regions", .info = &prop_num_pmp_regions},
> + {.name = "pmp-granularity", .info = &prop_pmp_granularity},
>
> {.name = "priv_spec", .info = &prop_priv_spec},
> {.name = "vext_spec", .info = &prop_vext_spec},
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 2c2266415e..04711f93a2 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -176,6 +176,7 @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];
>
> #define MAX_RISCV_PMPS (64)
> #define OLD_MAX_RISCV_PMPS (16)
> +#define MIN_RISCV_PMP_GRANULARITY 4
>
> #if !defined(CONFIG_USER_ONLY)
> #include "pmp.h"
> diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
> index e2d116f0df..a154ecdc79 100644
> --- a/target/riscv/cpu_cfg_fields.h.inc
> +++ b/target/riscv/cpu_cfg_fields.h.inc
> @@ -166,6 +166,7 @@ TYPED_FIELD(uint16_t, cbom_blocksize, 0)
> TYPED_FIELD(uint16_t, cbop_blocksize, 0)
> TYPED_FIELD(uint16_t, cboz_blocksize, 0)
> TYPED_FIELD(uint8_t, pmp_regions, 0)
> +TYPED_FIELD(uint32_t, pmp_granularity, 0)
>
> TYPED_FIELD(int8_t, max_satp_mode, -1)
>
> --
> 2.48.1
>
>
© 2016 - 2025 Red Hat, Inc.