lib: sbi: Add support for Supervisor Software Events extension

This extension [1] allows to deliver events from SBI to supervisor via
a software mechanism. This extension defines events (either local or
global) which are signaled by the SBI on specific signal sources (IRQ,
exceptions, etc) and are injected to be executed in supervisor mode.

[1] https://lists.riscv.org/g/tech-prs/message/798

Signed-off-by: Clément Léger <cleger@rivosinc.com>
Reviewed-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
Clément Léger 2024-03-21 16:57:16 +01:00 committed by Anup Patel
parent 76d7e9b8ee
commit c8cdf01d8f
7 changed files with 1322 additions and 1 deletions

View File

@ -33,6 +33,7 @@
#define SBI_EXT_SUSP 0x53555350 #define SBI_EXT_SUSP 0x53555350
#define SBI_EXT_CPPC 0x43505043 #define SBI_EXT_CPPC 0x43505043
#define SBI_EXT_DBTR 0x44425452 #define SBI_EXT_DBTR 0x44425452
#define SBI_EXT_SSE 0x535345
/* SBI function IDs for BASE extension*/ /* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@ -304,6 +305,80 @@ enum sbi_cppc_reg_id {
SBI_CPPC_NON_ACPI_LAST = SBI_CPPC_TRANSITION_LATENCY, SBI_CPPC_NON_ACPI_LAST = SBI_CPPC_TRANSITION_LATENCY,
}; };
/* SBI Function IDs for SSE extension */
#define SBI_EXT_SSE_READ_ATTR 0x00000000
#define SBI_EXT_SSE_WRITE_ATTR 0x00000001
#define SBI_EXT_SSE_REGISTER 0x00000002
#define SBI_EXT_SSE_UNREGISTER 0x00000003
#define SBI_EXT_SSE_ENABLE 0x00000004
#define SBI_EXT_SSE_DISABLE 0x00000005
#define SBI_EXT_SSE_COMPLETE 0x00000006
#define SBI_EXT_SSE_INJECT 0x00000007
/* SBI SSE Event Attributes. */
enum sbi_sse_attr_id {
SBI_SSE_ATTR_STATUS = 0x00000000,
SBI_SSE_ATTR_PRIO = 0x00000001,
SBI_SSE_ATTR_CONFIG = 0x00000002,
SBI_SSE_ATTR_PREFERRED_HART = 0x00000003,
SBI_SSE_ATTR_ENTRY_PC = 0x00000004,
SBI_SSE_ATTR_ENTRY_ARG = 0x00000005,
SBI_SSE_ATTR_INTERRUPTED_SEPC = 0x00000006,
SBI_SSE_ATTR_INTERRUPTED_FLAGS = 0x00000007,
SBI_SSE_ATTR_INTERRUPTED_A6 = 0x00000008,
SBI_SSE_ATTR_INTERRUPTED_A7 = 0x00000009,
SBI_SSE_ATTR_MAX = 0x0000000A
};
#define SBI_SSE_ATTR_STATUS_STATE_OFFSET 0
#define SBI_SSE_ATTR_STATUS_STATE_MASK 0x3
#define SBI_SSE_ATTR_STATUS_PENDING_OFFSET 2
#define SBI_SSE_ATTR_STATUS_INJECT_OFFSET 3
#define SBI_SSE_ATTR_CONFIG_ONESHOT (1 << 0)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPP BIT(0)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPIE BIT(1)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPV BIT(2)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPVP BIT(3)
enum sbi_sse_state {
SBI_SSE_STATE_UNUSED = 0,
SBI_SSE_STATE_REGISTERED = 1,
SBI_SSE_STATE_ENABLED = 2,
SBI_SSE_STATE_RUNNING = 3,
};
/* SBI SSE Event IDs. */
#define SBI_SSE_EVENT_LOCAL_RAS 0x00000000
#define SBI_SSE_EVENT_LOCAL_PLAT_0_START 0x00004000
#define SBI_SSE_EVENT_LOCAL_PLAT_0_END 0x00007fff
#define SBI_SSE_EVENT_GLOBAL_RAS 0x00008000
#define SBI_SSE_EVENT_GLOBAL_PLAT_0_START 0x00004000
#define SBI_SSE_EVENT_GLOBAL_PLAT_0_END 0x00007fff
#define SBI_SSE_EVENT_LOCAL_PMU 0x00010000
#define SBI_SSE_EVENT_LOCAL_PLAT_1_START 0x00014000
#define SBI_SSE_EVENT_LOCAL_PLAT_1_END 0x00017fff
#define SBI_SSE_EVENT_GLOBAL_PLAT_1_START 0x0001c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_1_END 0x0001ffff
#define SBI_SSE_EVENT_LOCAL_PLAT_2_START 0x00024000
#define SBI_SSE_EVENT_LOCAL_PLAT_2_END 0x00027fff
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_START 0x0002c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_END 0x0002ffff
#define SBI_SSE_EVENT_LOCAL_SOFTWARE 0xffff0000
#define SBI_SSE_EVENT_LOCAL_PLAT_3_START 0xffff4000
#define SBI_SSE_EVENT_LOCAL_PLAT_3_END 0xffff7fff
#define SBI_SSE_EVENT_GLOBAL_SOFTWARE 0xffff8000
#define SBI_SSE_EVENT_GLOBAL_PLAT_3_START 0xffffc000
#define SBI_SSE_EVENT_GLOBAL_PLAT_3_END 0xffffffff
#define SBI_SSE_EVENT_GLOBAL_BIT (1 << 15)
#define SBI_SSE_EVENT_PLATFORM_BIT (1 << 14)
/* SBI base specification related macros */ /* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24 #define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
@ -324,8 +399,10 @@ enum sbi_cppc_reg_id {
#define SBI_ERR_ALREADY_STARTED -7 #define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8 #define SBI_ERR_ALREADY_STOPPED -8
#define SBI_ERR_NO_SHMEM -9 #define SBI_ERR_NO_SHMEM -9
#define SBI_ERR_INVALID_STATE -10
#define SBI_ERR_BAD_RANGE -11
#define SBI_LAST_ERR SBI_ERR_NO_SHMEM #define SBI_LAST_ERR SBI_ERR_BAD_RANGE
/* clang-format on */ /* clang-format on */

View File

@ -24,6 +24,8 @@
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED #define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED #define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
#define SBI_ENO_SHMEM SBI_ERR_NO_SHMEM #define SBI_ENO_SHMEM SBI_ERR_NO_SHMEM
#define SBI_EINVALID_STATE SBI_ERR_INVALID_STATE
#define SBI_EBAD_RANGE SBI_ERR_BAD_RANGE
#define SBI_ENODEV -1000 #define SBI_ENODEV -1000
#define SBI_ENOSYS -1001 #define SBI_ENOSYS -1001

93
include/sbi/sbi_sse.h Normal file
View File

@ -0,0 +1,93 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Rivos Systems.
*/
#ifndef __SBI_SSE_H__
#define __SBI_SSE_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#include <sbi/riscv_locks.h>
struct sbi_scratch;
struct sbi_trap_regs;
struct sbi_ecall_return;
#define EXC_MODE_PP_SHIFT 0
#define EXC_MODE_PP BIT(EXC_MODE_PP_SHIFT)
#define EXC_MODE_PV_SHIFT 1
#define EXC_MODE_PV BIT(EXC_MODE_PV_SHIFT)
#define EXC_MODE_SSTATUS_SPIE_SHIFT 2
#define EXC_MODE_SSTATUS_SPIE BIT(EXC_MODE_SSTATUS_SPIE_SHIFT)
struct sbi_sse_cb_ops {
/**
* Called when hart_id is changed on the event.
*/
void (*set_hartid_cb)(uint32_t event_id, unsigned long hart_id);
/**
* Called when the SBI_EXT_SSE_COMPLETE is invoked on the event.
*/
void (*complete_cb)(uint32_t event_id);
/**
* Called when the SBI_EXT_SSE_REGISTER is invoked on the event.
*/
void (*register_cb)(uint32_t event_id);
/**
* Called when the SBI_EXT_SSE_UNREGISTER is invoked on the event.
*/
void (*unregister_cb)(uint32_t event_id);
/**
* Called when the SBI_EXT_SSE_ENABLE is invoked on the event.
*/
void (*enable_cb)(uint32_t event_id);
/**
* Called when the SBI_EXT_SSE_DISABLE is invoked on the event.
*/
void (*disable_cb)(uint32_t event_id);
};
/* Set the callback operations for an event
* @param event_id Event identifier (SBI_SSE_EVENT_*)
* @param cb_ops Callback operations
* @return 0 on success, error otherwise
*/
int sbi_sse_set_cb_ops(uint32_t event_id, const struct sbi_sse_cb_ops *cb_ops);
/* Inject an event to the current hard
* @param event_id Event identifier (SBI_SSE_EVENT_*)
* @param regs Registers that were used on SBI entry
* @return 0 on success, error otherwise
*/
int sbi_sse_inject_event(uint32_t event_id);
void sbi_sse_process_pending_events(struct sbi_trap_regs *regs);
int sbi_sse_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_sse_exit(struct sbi_scratch *scratch);
/* Interface called from sbi_ecall_sse.c */
int sbi_sse_register(uint32_t event_id, unsigned long handler_entry_pc,
unsigned long handler_entry_arg);
int sbi_sse_unregister(uint32_t event_id);
int sbi_sse_enable(uint32_t event_id);
int sbi_sse_disable(uint32_t event_id);
int sbi_sse_complete(struct sbi_trap_regs *regs, struct sbi_ecall_return *out);
int sbi_sse_inject_from_ecall(uint32_t event_id, unsigned long hart_id,
struct sbi_ecall_return *out);
int sbi_sse_read_attrs(uint32_t event_id, uint32_t base_attr_id,
uint32_t attr_count, unsigned long output_phys_lo,
unsigned long output_phys_hi);
int sbi_sse_write_attrs(uint32_t event_id, uint32_t base_attr_id,
uint32_t attr_count, unsigned long input_phys_lo,
unsigned long input_phys_hi);
#endif

View File

@ -75,6 +75,7 @@ libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_pmu.o libsbi-objs-y += sbi_pmu.o
libsbi-objs-y += sbi_dbtr.o libsbi-objs-y += sbi_dbtr.o
libsbi-objs-y += sbi_scratch.o libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_sse.o
libsbi-objs-y += sbi_string.o libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_system.o libsbi-objs-y += sbi_system.o
libsbi-objs-y += sbi_timer.o libsbi-objs-y += sbi_timer.o

View File

@ -24,6 +24,7 @@
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h> #include <sbi/sbi_pmu.h>
#include <sbi/sbi_dbtr.h> #include <sbi/sbi_dbtr.h>
#include <sbi/sbi_sse.h>
#include <sbi/sbi_system.h> #include <sbi/sbi_system.h>
#include <sbi/sbi_string.h> #include <sbi/sbi_string.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
@ -319,6 +320,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
rc = sbi_sse_init(scratch, true);
if (rc) {
sbi_printf("%s: sse init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
rc = sbi_pmu_init(scratch, true); rc = sbi_pmu_init(scratch, true);
if (rc) { if (rc) {
sbi_printf("%s: pmu init failed (error %d)\n", sbi_printf("%s: pmu init failed (error %d)\n",
@ -445,6 +452,10 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
rc = sbi_sse_init(scratch, false);
if (rc)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, false); rc = sbi_pmu_init(scratch, false);
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
@ -653,6 +664,8 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
sbi_platform_early_exit(plat); sbi_platform_early_exit(plat);
sbi_sse_exit(scratch);
sbi_pmu_exit(scratch); sbi_pmu_exit(scratch);
sbi_timer_exit(scratch); sbi_timer_exit(scratch);

1130
lib/sbi/sbi_sse.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#include <sbi/sbi_trap_ldst.h> #include <sbi/sbi_trap_ldst.h>
#include <sbi/sbi_pmu.h> #include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_sse.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
@ -337,6 +338,10 @@ struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx)
trap_done: trap_done:
if (rc) if (rc)
sbi_trap_error(msg, rc, tcntx); sbi_trap_error(msg, rc, tcntx);
if (((regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT) != PRV_M)
sbi_sse_process_pending_events(regs);
sbi_trap_set_context(scratch, tcntx->prev_context); sbi_trap_set_context(scratch, tcntx->prev_context);
return tcntx; return tcntx;
} }