Files
opensbi/lib/sbi/sbi_hart_protection.c
T
Anup Patel 2636a9c2a8 lib: sbi: Extend hart protection abstraction to allow ID configuration
There are various ID configuration ISA extensions such as RISC-V Worlds,
Supervisor domain ID, QoS ID, etc which need to be re-configured upon
domain context switch on a hart. Extend hart protection abstraction to
support both memory protection and ID configuration ISA extensions.

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
Reviewed-by: Rahul Pathak <rahul.pathak@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260727042504.1743250-5-anup.patel@oss.qualcomm.com
Signed-off-by: Anup Patel <anup@brainfault.org>
2026-08-02 15:17:12 +05:30

190 lines
4.1 KiB
C

/*
* 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_memory_protection_best(void)
{
struct sbi_hart_protection *pos;
sbi_list_for_each_entry(pos, &hart_protection_list, head) {
if (pos->type == SBI_HART_PROTECTION_TYPE_MEMORY)
return pos;
}
return NULL;
}
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;
if (hprot->type >= SBI_HART_PROTECTION_TYPE_MAX)
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;
}
void sbi_hart_protection_unregister(struct sbi_hart_protection *hprot)
{
if (!hprot)
return;
sbi_list_del(&hprot->head);
}
static int __hart_protection_configure(struct sbi_scratch *scratch,
struct sbi_hart_protection *hprot,
struct sbi_domain *dom)
{
if (!hprot)
return 0;
if (!hprot->configure)
return SBI_ENOSYS;
return hprot->configure(scratch, dom);
}
static void __hart_protection_unconfigure(struct sbi_scratch *scratch,
struct sbi_hart_protection *hprot,
struct sbi_domain *dom)
{
if (!hprot || !hprot->unconfigure)
return;
hprot->unconfigure(scratch, dom);
}
int sbi_hart_protection_configure(struct sbi_scratch *scratch,
struct sbi_domain *dom)
{
bool do_configure, memory_protect_done = false;
struct sbi_hart_protection *hprot;
int ret;
sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
do_configure = false;
switch (hprot->type) {
case SBI_HART_PROTECTION_TYPE_MEMORY:
do_configure = !memory_protect_done;
memory_protect_done = true;
break;
case SBI_HART_PROTECTION_TYPE_ID:
do_configure = true;
break;
default:
break;
}
if (!do_configure)
continue;
ret = __hart_protection_configure(scratch, hprot, dom);
if (ret)
return ret;
}
return 0;
}
void sbi_hart_protection_unconfigure(struct sbi_scratch *scratch,
struct sbi_domain *dom)
{
bool do_unconfigure, memory_protect_done = false;
struct sbi_hart_protection *hprot;
sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
do_unconfigure = false;
switch (hprot->type) {
case SBI_HART_PROTECTION_TYPE_MEMORY:
do_unconfigure = !memory_protect_done;
memory_protect_done = true;
break;
case SBI_HART_PROTECTION_TYPE_ID:
do_unconfigure = true;
break;
default:
break;
}
if (!do_unconfigure)
continue;
__hart_protection_unconfigure(scratch, hprot, dom);
}
}
int sbi_hart_protection_reconfigure(struct sbi_scratch *scratch,
struct sbi_domain *current_dom,
struct sbi_domain *next_dom)
{
bool do_reconfigure, memory_protect_done = false;
struct sbi_hart_protection *hprot;
int ret;
sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
do_reconfigure = false;
switch (hprot->type) {
case SBI_HART_PROTECTION_TYPE_MEMORY:
do_reconfigure = !memory_protect_done;
memory_protect_done = true;
break;
case SBI_HART_PROTECTION_TYPE_ID:
do_reconfigure = true;
break;
default:
break;
}
if (!do_reconfigure)
continue;
__hart_protection_unconfigure(scratch, hprot, current_dom);
ret = __hart_protection_configure(scratch, hprot, next_dom);
if (ret)
return ret;
}
return 0;
}
int sbi_hart_protection_map_range(unsigned long base, unsigned long size)
{
struct sbi_hart_protection *hprot = sbi_hart_memory_protection_best();
if (!hprot || !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_memory_protection_best();
if (!hprot || !hprot->unmap_range)
return 0;
return hprot->unmap_range(sbi_scratch_thishart_ptr(), base, size);
}