[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