[PATCH 2/5] lib: sbi: Introduce hart protection abstraction

Anup Patel anup at brainfault.org
Sun Dec 7 07:58:36 PST 2025


On Sun, Dec 7, 2025 at 4:40 PM Samuel Holland <samuel.holland at sifive.com> wrote:
>
> Hi Anup,
>
> On 2025-11-26 8:18 AM, Anup Patel wrote:
> > Currently, PMP and ePMP are the only hart protection mechanisms
> > available in OpenSBI but new protection mechanisms (such as Smmpt)
> > will be added in the near future.
> >
> > To allow multiple hart protection mechanisms, introduce hart
> > protection abstraction and related APIs.
> >
> > Signed-off-by: Anup Patel <apatel at ventanamicro.com>
> > ---
> >  include/sbi/sbi_hart_protection.h |  88 ++++++++++++++++++++++++
> >  lib/sbi/objects.mk                |   1 +
> >  lib/sbi/sbi_hart_protection.c     | 110 ++++++++++++++++++++++++++++++
> >  lib/sbi/sbi_init.c                |   5 ++
> >  4 files changed, 204 insertions(+)
> >  create mode 100644 include/sbi/sbi_hart_protection.h
> >  create mode 100644 lib/sbi/sbi_hart_protection.c
> >
> > diff --git a/include/sbi/sbi_hart_protection.h b/include/sbi/sbi_hart_protection.h
> > new file mode 100644
> > index 00000000..c9e452db
> > --- /dev/null
> > +++ b/include/sbi/sbi_hart_protection.h
> > @@ -0,0 +1,88 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 Ventana Micro Systems Inc.
> > + */
> > +
> > +#ifndef __SBI_HART_PROTECTION_H__
> > +#define __SBI_HART_PROTECTION_H__
> > +
> > +#include <sbi/sbi_types.h>
> > +#include <sbi/sbi_list.h>
> > +
> > +struct sbi_scratch;
> > +
> > +/** Representation of hart protection mechanism */
> > +struct sbi_hart_protection {
> > +     /** List head */
> > +     struct sbi_dlist head;
> > +
> > +     /** Name of the hart protection mechanism */
> > +     char name[32];
> > +
> > +     /** Ratings of the hart protection mechanism (higher is better) */
> > +     unsigned long rating;
> > +
> > +     /** Configure protection for current HART (Mandatory) */
> > +     int (*configure)(struct sbi_scratch *scratch);
> > +
> > +     /** Unconfigure protection for current HART (Mandatory) */
> > +     void (*unconfigure)(struct sbi_scratch *scratch);
> > +
> > +     /** Create temporary mapping to access address range on current HART (Optional) */
> > +     int (*map_range)(struct sbi_scratch *scratch,
> > +                      unsigned long base, unsigned long size);
> > +
> > +     /** Destroy temporary mapping on current HART (Optional) */
> > +     int (*unmap_range)(struct sbi_scratch *scratch,
> > +                        unsigned long base, unsigned long size);
> > +};
> > +
> > +/**
> > + * Get the best hart protection mechanism
> > + *
> > + * @return pointer to best hart protection mechanism
> > + */
> > +struct sbi_hart_protection *sbi_hart_protection_best(void);
> > +
> > +/**
> > + * Register a hart protection mechanism
> > + *
> > + * @return 0 on success and negative error code on failure
> > + */
> > +int sbi_hart_protection_register(struct sbi_hart_protection *hprot);
> > +
> > +/**
> > + * Unregister a hart protection mechanism
> > + *
> > + * @return 0 on success and negative error code on failure
> > + */
> > +int sbi_hart_protection_unregister(struct sbi_hart_protection *hprot);
> > +
> > +/**
> > + * Configure protection for current HART
> > + *
> > + * @return 0 on success and negative error code on failure
> > + */
> > +int sbi_hart_protection_configure(struct sbi_scratch *scratch);
> > +
> > +/**
> > + * Unconfigure protection for current HART
> > + */
> > +void sbi_hart_protection_unconfigure(struct sbi_scratch *scratch);
> > +
> > +/**
> > + * Create temporary mapping to access address range on current HART
> > + *
> > + * @return 0 on success and negative error code on failure
> > + */
> > +int sbi_hart_protection_map_range(unsigned long base, unsigned long size);
> > +
> > +/**
> > + * Destroy temporary mapping to access address range on current HART
> > + *
> > + * @return 0 on success and negative error code on failure
> > + */
> > +int sbi_hart_protection_unmap_range(unsigned long base, unsigned long size);
>
> These functions should document (or take a parameter for) the permissions of the
> temporary mapping. "saddr" sort of documents that for the existing functions.

Sure, I will add parameter documentation.

>
> > +
> > +#endif /* __SBI_HART_PROTECTION_H__ */
> > diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
> > index 8abe1e8e..51588cd1 100644
> > --- a/lib/sbi/objects.mk
> > +++ b/lib/sbi/objects.mk
> > @@ -75,6 +75,7 @@ libsbi-objs-y += sbi_emulate_csr.o
> >  libsbi-objs-y += sbi_fifo.o
> >  libsbi-objs-y += sbi_fwft.o
> >  libsbi-objs-y += sbi_hart.o
> > +libsbi-objs-y += sbi_hart_protection.o
> >  libsbi-objs-y += sbi_heap.o
> >  libsbi-objs-y += sbi_math.o
> >  libsbi-objs-y += sbi_hfence.o
> > diff --git a/lib/sbi/sbi_hart_protection.c b/lib/sbi/sbi_hart_protection.c
> > new file mode 100644
> > index 00000000..831072ad
> > --- /dev/null
> > +++ b/lib/sbi/sbi_hart_protection.c
> > @@ -0,0 +1,110 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 Ventana Micro Systems Inc.
> > + */
> > +
> > +#include <sbi/sbi_error.h>
> > +#include <sbi/sbi_hart_protection.h>
> > +#include <sbi/sbi_scratch.h>
> > +
> > +static SBI_LIST_HEAD(hart_protection_list);
> > +
> > +struct sbi_hart_protection *sbi_hart_protection_best(void)
> > +{
> > +     if (sbi_list_empty(&hart_protection_list))
> > +             return NULL;
> > +
> > +     return sbi_list_first_entry(&hart_protection_list, struct sbi_hart_protection, head);
> > +}
> > +
> > +int sbi_hart_protection_register(struct sbi_hart_protection *hprot)
> > +{
> > +     struct sbi_hart_protection *pos = NULL;
> > +     bool found_pos = false;
> > +
> > +     if (!hprot)
> > +             return SBI_EINVAL;
> > +
> > +     sbi_list_for_each_entry(pos, &hart_protection_list, head) {
> > +             if (hprot->rating > pos->rating) {
> > +                     found_pos = true;
> > +                     break;
> > +             }
> > +     }
> > +
> > +     if (found_pos)
> > +             sbi_list_add_tail(&hprot->head, &pos->head);
> > +     else
> > +             sbi_list_add_tail(&hprot->head, &hart_protection_list);
> > +
> > +     return 0;
> > +}
> > +
> > +int sbi_hart_protection_unregister(struct sbi_hart_protection *hprot)
> > +{
> > +     struct sbi_hart_protection *pos = NULL;
> > +     bool found_pos = false;
> > +
> > +     if (!hprot)
> > +             return SBI_EINVAL;
> > +
> > +     sbi_list_for_each_entry(pos, &hart_protection_list, head) {
> > +             if (hprot == pos) {
> > +                     found_pos = true;
> > +                     break;
> > +             }
> > +     }
> > +
> > +     if (!found_pos)
> > +             return SBI_ENOENT;
> > +
> > +     sbi_list_del(&hprot->head);
> > +     return 0;
>
> I don't think this function is needed. ISA extensions aren't going to disappear
> at runtime. Also, what would you expect to happen if the active hart protection
> mechanism is unregistered?

I have added this so that if there is any failure in the function registering
hart protection mechanism then the function can unregister the hart
protection.

>
> > +}
> > +
> > +int sbi_hart_protection_configure(struct sbi_scratch *scratch)
> > +{
> > +     struct sbi_hart_protection *hprot = sbi_hart_protection_best();
> > +
> > +     if (!hprot)
> > +             return SBI_EINVAL;
> > +     if (!hprot->configure)
> > +             return SBI_ENOSYS;
> > +
> > +     return hprot->configure(scratch);
> > +}
>
> If you only ever use the "best" backend, there is no need to maintain a list,
> just a single pointer.

I agree that since we are only using the "best" backend, using list seems
redundant. I have kept list to know all the available hart protection
mechanism plus there is very little overhead since the list is sorted
based on rating.

>
> But then that seems too simplistic. We'll probably want to use (e)PMP and Smmpt
> together, to avoid splitting huge MPT pages to make M-mode carveouts. So we
> would want to loop through all registered protection schemes.

Thinking about this more. It is better to register a composite hart protection
for (e)PMP+Smmpt instead of hart protection abstraction calling multiple
configure/unconfigure and map/unmap_range because this allows Smmpt
code to decide when to use (e)PMP for a domain memregion and when
to use Smmpt for a domain memregion. The (e)PMP+Smmpt and platform
specific hart protection can always share the PMP programing functions
with (e)PMP hart protection.

>
> I'm guessing you plan to use an entirely separate set of APIs for system-level
> protection schemes like WorldGuard and IOPMP?
>

Yes, that's correct we will have separate system protection abstraction for
WorldGuard and IOPMP. The OpenSBI domain framework will use system
protection abstraction differently compared to how it uses hart protection
abstraction.

Regards,
Anup



More information about the opensbi mailing list