[PATCH v2 20/20] platform: generic: mips eyeq7h: prohibit accessing memory beyond DRAM
Anup Patel
anup at brainfault.org
Sun Feb 22 08:03:00 PST 2026
On Sun, Jan 18, 2026 at 5:08 PM Vladimir Kondratiev
<vladimir.kondratiev at mobileye.com> wrote:
>
> SBI code arranges domain PMP regions in a way that last entry is
> all-inclusive "0..~0 RWX" and the rest of entries are not programmed.
> This causes 2 problems for the eyeq7h.
>
> 1) Remaining entries from the boot loader.
> When PMP is actually programmed on the later stage, only defined entries
> get programmed. Therefore, if boot code configured some entries beyond
> what is set in domain configuration, it will be untouched. Ex: boot code
> sets entries 14 and 15, leaving others unconfigured. To prevent such
> left over PMP entries, domain should configure all possible PMP regions.
Better disable unused PMP entries in generic code itself. Basically,
sbi_hart_oldpmp_configure() and sbi_hart_smepmp_configure()
can disable unused PMP entries at the end just before calling
sbi_hart_pmp_fence().
>
> 2) speculative prefetches
> CPU can issue speculative prefetches to non-existent addresses. If this
> access goes to the system NOC, it is mis-interpreted as an access
> violation and error is reported, forcing system reset.
>
> To prevent such a speculative transaction to leave a CPU cluster,
> block it using PMP, by restricting memory region to physically present
> memory.
The unused PMP entries are typically used when we have
multiple domains on a platform (e.g. non-secure domain and
secure domain). Consuming unused PMP entries to block
speculative transactions leaves no PMP entries for system-level
partitioning using domains.
I assume MIPS does not want to support OpenSBI domain
on their platforms ??
Regards,
Anup
>
> How is it done:
>
> - on early init, add an all-permissive entry matching DRAM.
>
> - on final init, find the last last PMP entry configured by generic code,
> update its flags to inaccessible MMIO memory. MMIO serves to set up
> PMA attributes to uncached non-prefetchable. Then duplicate this entry
> for the rest of the PMP table
>
> Resulting memory regions:
>
> Domain0 Region00 : 0x0000000800100000-0x000000080013ffff M: (F,R,X) S/U: ()
> Domain0 Region01 : 0x0000000800100000-0x00000008001fffff M: (F,R,W) S/U: ()
> Domain0 Region02 : 0x0000000048700000-0x000000004870ffff M: (I,R,W) S/U: ()
> Domain0 Region03 : 0x0000000067480000-0x000000006748ffff M: (I,R,W) S/U: ()
> Domain0 Region04 : 0x0000000067500000-0x000000006750ffff M: (I,R,W) S/U: ()
> Domain0 Region05 : 0x0000000048740000-0x000000004875ffff M: (I,R,W) S/U: ()
> Domain0 Region06 : 0x00000000674c0000-0x00000000674dffff M: (I,R,W) S/U: ()
> Domain0 Region07 : 0x0000000067540000-0x000000006755ffff M: (I,R,W) S/U: ()
> Domain0 Region08 : 0x0000000000000000-0x000000007fffffff M: (I,R,W) S/U: (R,W)
> Domain0 Region09 : 0x0000000800000000-0x00000008ffffffff M: () S/U: (R,W,X)
> Domain0 Region10 : 0x0000001000000000-0x0000001fffffffff M: (I) S/U: (R,W)
> Domain0 Region11 : 0x0000000000000000-0xffffffffffffffff M: (I) S/U: ()
> Domain0 Region12 : 0x0000000000000000-0xffffffffffffffff M: (I) S/U: ()
> Domain0 Region13 : 0x0000000000000000-0xffffffffffffffff M: (I) S/U: ()
> Domain0 Region14 : 0x0000000000000000-0xffffffffffffffff M: (I) S/U: ()
> Domain0 Region15 : 0x0000000000000000-0xffffffffffffffff M: (I) S/U: ()
>
> Here Region09 covers DRAM, regions 11..15 set to non-accessible
> uncached no-prefetch for thw whole address range
>
> Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev at mobileye.com>
> ---
> platform/generic/mips/eyeq7h.c | 56 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 55 insertions(+), 1 deletion(-)
>
> diff --git a/platform/generic/mips/eyeq7h.c b/platform/generic/mips/eyeq7h.c
> index 2fb498c1b8f47a5a16d74a2c78fd9dff6dda156c..9341c8beaca25c8c62e19efbdd4a59c726814261 100644
> --- a/platform/generic/mips/eyeq7h.c
> +++ b/platform/generic/mips/eyeq7h.c
> @@ -14,6 +14,7 @@
> #include <sbi/sbi_timer.h>
> #include <sbi/sbi_hart_pmp.h>
> #include <sbi/riscv_io.h>
> +#include <libfdt.h>
> #include <sbi_utils/fdt/fdt_helper.h>
> #include <sbi_utils/fdt/fdt_fixup.h>
> #include <mips/p8700.h>
> @@ -121,6 +122,31 @@ static struct sbi_domain_memregion *find_last_memregion(const struct sbi_domain
> return --reg;
> }
>
> +static int fixup_dram_region(const struct sbi_domain *dom,
> + struct sbi_domain_memregion *reg)
> +{
> + const void *fdt = fdt_get_address();
> + int node;
> + int ret;
> + uint64_t mem_addr, mem_size;
> + static const char mem_str[] = "memory";
> +
> + if (!reg || !fdt)
> + return SBI_EINVAL;
> +
> + /* Find the memory range */
> + node = fdt_node_offset_by_prop_value(fdt, -1, "device_type",
> + mem_str, sizeof(mem_str));
> + ret = fdt_get_node_addr_size(fdt, node, 0, &mem_addr, &mem_size);
> + if (ret)
> + return ret;
> + reg->flags = SBI_DOMAIN_MEMREGION_MMIO; // disable cache & prefetch
> + return sbi_domain_root_add_memrange(mem_addr, mem_size, mem_size,
> + (SBI_DOMAIN_MEMREGION_SU_READABLE |
> + SBI_DOMAIN_MEMREGION_SU_WRITABLE |
> + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE));
> +}
> +
> static void fdt_disable_by_compat(void *fdt, const char *compatible)
> {
> int node = 0;
> @@ -203,10 +229,29 @@ static struct fdt_general_fixup eyeq7h_cache_fixup = {
>
> static int eyeq7h_final_init(bool cold_boot)
> {
> + struct sbi_scratch *scratch;
> + const struct sbi_domain *dom;
> + struct sbi_domain_memregion *last_reg;
> + int pmp_count;
> +
> if (!cold_boot)
> return 0;
>
> sbi_hsm_set_device(&eyeq7h_hsm);
> + scratch = sbi_scratch_thishart_ptr();
> + pmp_count = sbi_hart_pmp_count(scratch);
> +
> + /*
> + * clear the rest of regions that may be set by the boot code
> + * SBI code don't let to disable PMP region, so configure it to
> + * all-denied and no-cache no-prefetch
> + */
> + dom = sbi_domain_thishart_ptr();
> + last_reg = find_last_memregion(dom);
> + last_reg->flags = SBI_DOMAIN_MEMREGION_MMIO; // disable cache & prefetch
> + for (struct sbi_domain_memregion *reg = last_reg + 1; reg < &dom->regions[pmp_count]; reg++) {
> + *reg = *last_reg;
> + }
> fdt_register_general_fixup(&eyeq7h_acc_clusters_fixup);
> fdt_register_general_fixup(&eyeq7h_cache_fixup);
>
> @@ -263,6 +308,8 @@ static void eyeq7h_init_clusters(void)
>
> static int eyeq7h_early_init(bool cold_boot)
> {
> + const struct sbi_domain *dom;
> + struct sbi_domain_memregion *reg;
> int rc;
> unsigned long cm_base;
>
> @@ -308,7 +355,14 @@ static int eyeq7h_early_init(bool cold_boot)
> SBI_DOMAIN_MEMREGION_SU_READABLE |
> SBI_DOMAIN_MEMREGION_SU_WRITABLE);
>
> - return 0;
> + /*
> + * sbi_domain_init adds last "all-inclusive" memory region
> + * 0 .. ~0 RWX
> + * Find this region (it is the last one) and update size according to DRAM
> + */
> + dom = sbi_domain_thishart_ptr();
> + reg = find_last_memregion(dom);
> + return fixup_dram_region(dom, reg);
> }
>
> static int eyeq7h_nascent_init(void)
>
> --
> 2.43.0
>
More information about the opensbi
mailing list