[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