[RFC PATCH v2 2/5] mpt: Add Smsdid and Smmpt supervisor domain core

Rahul Pathak rahul.pathak at oss.qualcomm.com
Sat Aug 22 05:18:42 PDT 2026


On Fri, Aug 14, 2026 at 11:58 PM Pawandeep Oza
<pawandeep.oza at oss.qualcomm.com> wrote:
>
> On Mon, Jul 27, 2026 at 6:56 AM Rahul Pathak
> <rahul.pathak at oss.qualcomm.com> wrote:
> >
> > Introduce the supervisord omain memory-protection (Smmpt) table
> Oza: typo: "supervisord omain"

Rahul: Sure, will update

> > management core. This adds the mode agnostic core layer and the
> > per mode table walkers/builder.
> >
> > Add defines for the mmpt CSR encoding, MPTE bit layout, permission flags,
> > structures, fence helpers and the public interfaces.
> >
> > It implements the RV64 supported modes (Smmpt43/52/64) and
> > the RV32 mode (Smmpt34), its MPT table support.
> >
> > Also implements mpt core which integrates Smmpt with SBI domains and
> > other core layers.
> >
> > Signed-off-by: Rahul Pathak <rahul.pathak at oss.qualcomm.com>
> > ---
> >  include/sbi/sbi_mpt.h  | 334 ++++++++++++++
> >  lib/sbi/objects.mk     |   2 +
> >  lib/sbi/sbi_mpt.c      | 926 ++++++++++++++++++++++++++++++++++++++
> >  lib/sbi/sbi_mpt_mode.c | 997 +++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 2259 insertions(+)
> >  create mode 100644 include/sbi/sbi_mpt.h
> >  create mode 100644 lib/sbi/sbi_mpt.c
> >  create mode 100644 lib/sbi/sbi_mpt_mode.c
> >
> > +       return xwr;
> > +}
> > +
> > +/*
> > + * sbi_mpt_domain_create(): Create a Supervisor Domain
> Oza: "Create a Supervisor Domain" ?  You probably meant "Create an mpt domain" !

Rahul: Yes, will change

>
> > + */
> > +int sbi_mpt_domain_create(const struct sbi_mpt_domain_config *cfg,
> > +                          u32 *out_sdid)
> > +{
> > +       int rc;
> > +       u32 sdid, i;
> > +       unsigned long root_pa;
> > +       struct sbi_mpt_mode *sch;
> > +       struct sbi_mpt_domain *dom;
> > +       const struct sbi_domain_memregion *mr;
> > +       struct sbi_mpt_ctrl *ctrl = &mpt_ctrl;
> > +       u8 base_xwr = SBI_MPT_PERM_NONE;
> > +
> > +       if (!ctrl->ready)
> > +               return SBI_ENODEV;
> > +
> > +       if (cfg->sbi_dom && cfg->nregions) {
> > +               sbi_printf("sbi_mpt: sbi_dom and explicit regions are mutually exclusive\n");
> > +               return SBI_EINVAL;
> > +       }
> > +
> > +       /*
> > +        * sdid_bitmap empty means every available SDID is
> > +        * currently in use and no domain can be created.
> > +        */
> > +       if (bitmap_empty(ctrl->sdid_bitmap, ctrl->max_domains))
> > +               return SBI_ENOMEM;
> > +
> > +       sch = ctrl->mode;
> > +
> > +       root_pa = sbi_mpt_pool_alloc(sch->root_table_size(),
> > +                                    sch->root_table_align());
> > +       if (!root_pa) {
        rv64_write_mpte(grp_base + i * RV64_MPTE_SIZE, leaf);
> > +}
> > +
> > +/*
> > + * MPT table best-level selection
> > + *
> > + * Returns the highest level at which the range [pa, pa+size] can be
> > + * covered by a single leaf MPTE. Level 0 is always valid because thats
> > + * the last resort.
> > + */
> > +static u32 rv64_best_level(unsigned long pa, unsigned long size,
> > +                          u32 top_level)
> > +{
> > +       u32 lvl;
> > +       unsigned long range;
> Oza: need to validate ?? or trust top_level her ?
> if (!top_level) return 0;

Rahul: This if condition will be redundant since below for
loop will not enter if top_level == 0

> > +
> > +       for (lvl = top_level; lvl >= 1; lvl--) {
> > +               range = rv64_mpte_range(lvl);
> > +
> > +               if (size >= range && (pa & (range - 1)) == 0)
> > +                       return lvl;
> > +       }
> > +       return 0;
> > +}
> > +
> > +/*
> > + * Generic N-level walk with lazy table allocation
> > + */
> > +static unsigned long rv64_split_leaf(unsigned long parent_ep)
> > +{
> > +       u64 parent = rv64_read_mpte(parent_ep);
> > +       unsigned long sub;
> > +       u32 j, pg, sh;
> > +       u8 xwr;
> > +       u64 child;
> > +
> > +       sub = sbi_mpt_pool_alloc(RV64_TABLE_SIZE, SBI_MPT_PAGE_SIZE);
> > +       if (!sub)
> > +               return 0;
> > +
> > +       for (j = 0; j < RV64_INNER_ENTRIES; j++) {
> > +               sh = sbi_mpte_xwr_shift(j >> 5);
> Oza: can we define 5 ?

Rahul: Sure, will define a macro for it

> > +               xwr = (((unsigned long)parent >> sh) & SBI_MPTE_XWR_MASK);
> > +               child = SBI_MPTE_V | SBI_MPTE_L; /* N=0 uniform leaf */
> > +
> > +               for (pg = 0; pg < RV64_PAGES_PER_MPTE; pg++)
> > +                       child = sbi_mpte_leaf_set_xwr(child, pg, xwr);
> > +
> > +               rv64_write_mpte(sub + j * RV64_MPTE_SIZE, child);
> > +       }
> > +
> > +       /* parent leaf -> non-leaf pointer to MPT sub table. */
> > +       rv64_write_mpte(parent_ep, sbi_mpte_nonleaf(sub));
> > +
> > +       return sub;
> > +}
> > +
> > +/*
> > + * Walk a MPT table and return MPTE PA and its suitable level
> > + */
> > +static unsigned long rv64_walk_alloc(struct sbi_mpt_domain *dom,
> > +                                    unsigned long pa,
> > +                                    unsigned long size,
> > +                                    u32 *out_level,
> > +                                    u32 top_level)
> > +{
> > +       u32 lvl, idx;
> > +       u64 mpte;
> > +       unsigned long ep, sub, new_pa;
> > +       const struct sbi_mpt_mode *sch = dom->mode;
> > +       unsigned long table_pa = dom->root_pa;
> > +       u32 best_lvl = rv64_best_level(pa, size, top_level);
> > +
> > +
> > +       for (lvl = top_level; lvl >= 1; lvl--) {
> > +               idx = rv64_table_idx(pa, lvl, sch);
> > +               ep = rv64_mpte_pa(table_pa, idx);
> > +               mpte = rv64_read_mpte(ep);
> > +
> > +               if (mpte & SBI_MPTE_L) {
> > +                       if (lvl > best_lvl) {
> > +                               sub = rv64_split_leaf(ep);
> > +                               if (!sub)
> > +                                       return 0;
> > +
> > +                               table_pa = sub;
> Oza: do you need to decrement lvl here since you are splitting ?  e.g. lvl--

Rahul: below continue make sure that lvl is decremented in next pass of for loop
Do you mean I have to decrement lvl again here though due to below continue,
it will be decremented twice?

>
> > +                               continue;
> > +                       }
> > +
> > +                       *out_level = lvl;
> > +                       return ep;
> > +               }
> > +
> > +               if (!(mpte & SBI_MPTE_V)) {
> > +                       if (lvl <= best_lvl) {
> > +                               *out_level = lvl;
> > +                               return ep;
> > +                       }
> > +                       /* Allocate inner table (always 4KiB, all levels, all modes) */
> > +                       new_pa = sbi_mpt_pool_alloc(RV64_TABLE_SIZE,
> > +                                                   SBI_MPT_PAGE_SIZE);
> > +                       if (!new_pa)
> > +                               return 0;
> > +
> > +                       rv64_write_mpte(ep, (u64)sbi_mpte_nonleaf(new_pa));
> > +                       table_pa = new_pa;
> > +               }
> > +               else {
> > +                       table_pa = rv64_next_table_pa(mpte);
> > +               }
> > +       }
> > +
> > +       *out_level = 0;
> > +
> > +       return rv64_mpte_pa(table_pa, rv64_table_idx(pa, 0, sch));
> > +}
> > +



More information about the opensbi mailing list