[PATCH 2/5] lib: sbi: Introduce hart protection abstraction
Samuel Holland
samuel.holland at sifive.com
Sun Dec 7 03:10:50 PST 2025
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.
> +
> +#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?
> +}
> +
> +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.
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.
I'm guessing you plan to use an entirely separate set of APIs for system-level
protection schemes like WorldGuard and IOPMP?
Regards,
Samuel
> +
> +void sbi_hart_protection_unconfigure(struct sbi_scratch *scratch)
> +{
> + struct sbi_hart_protection *hprot = sbi_hart_protection_best();
> +
> + if (!hprot || !hprot->unconfigure)
> + return;
> +
> + hprot->unconfigure(scratch);
> +}
> +
> +int sbi_hart_protection_map_range(unsigned long base, unsigned long size)
> +{
> + struct sbi_hart_protection *hprot = sbi_hart_protection_best();
> +
> + if (!hprot)
> + return SBI_EINVAL;
> + if (!hprot->map_range)
> + return 0;
> +
> + return hprot->map_range(sbi_scratch_thishart_ptr(), base, size);
> +}
> +
> +int sbi_hart_protection_unmap_range(unsigned long base, unsigned long size)
> +{
> + struct sbi_hart_protection *hprot = sbi_hart_protection_best();
> +
> + if (!hprot)
> + return SBI_EINVAL;
> + if (!hprot->unmap_range)
> + return 0;
> +
> + return hprot->unmap_range(sbi_scratch_thishart_ptr(), base, size);
> +}
> diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> index 663b486b..b161d1c1 100644
> --- a/lib/sbi/sbi_init.c
> +++ b/lib/sbi/sbi_init.c
> @@ -18,6 +18,7 @@
> #include <sbi/sbi_fwft.h>
> #include <sbi/sbi_hart.h>
> #include <sbi/sbi_hartmask.h>
> +#include <sbi/sbi_hart_protection.h>
> #include <sbi/sbi_heap.h>
> #include <sbi/sbi_hsm.h>
> #include <sbi/sbi_ipi.h>
> @@ -74,6 +75,7 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
> const struct sbi_hsm_device *hdev;
> const struct sbi_ipi_device *idev;
> const struct sbi_timer_device *tdev;
> + const struct sbi_hart_protection *hprot;
> const struct sbi_console_device *cdev;
> const struct sbi_system_reset_device *srdev;
> const struct sbi_system_suspend_device *susp_dev;
> @@ -90,6 +92,9 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
> sbi_printf("Platform Features : %s\n", str);
> sbi_printf("Platform HART Count : %u\n",
> sbi_platform_hart_count(plat));
> + hprot = sbi_hart_protection_best();
> + sbi_printf("Platform HART Protection : %s\n",
> + (hprot) ? hprot->name : "---");
> idev = sbi_ipi_get_device();
> sbi_printf("Platform IPI Device : %s\n",
> (idev) ? idev->name : "---");
More information about the opensbi
mailing list