struct sbi_trap_regs;
struct sbi_trap_info;
+struct sbi_ecall_return {
+ /* Return flag to skip register update */
+ bool skip_regs_update;
+ /* Return value */
+ unsigned long value;
+};
+
struct sbi_ecall_extension {
/* head is used by the extension list */
struct sbi_dlist head;
* never invoked with an invalid or unavailable extension ID.
*/
int (* handle)(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap);
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out);
};
u16 sbi_ecall_version_major(void);
#include <sbi/sbi_version.h>
struct sbi_domain_memregion;
-struct sbi_trap_info;
+struct sbi_ecall_return;
struct sbi_trap_regs;
struct sbi_hart_features;
bool (*vendor_ext_check)(void);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_value,
- struct sbi_trap_info *out_trap);
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out);
};
/** Platform default per-HART stack size for exception/interrupt handling */
static inline int sbi_platform_vendor_ext_provider(
const struct sbi_platform *plat,
long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_value,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
- if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
+ if (plat && sbi_platform_ops(plat)->vendor_ext_provider)
return sbi_platform_ops(plat)->vendor_ext_provider(funcid,
- regs,
- out_value,
- out_trap);
- }
+ regs, out);
return SBI_ENOTSUPP;
}
struct sbi_ecall_extension *ext;
unsigned long extension_id = regs->a7;
unsigned long func_id = regs->a6;
- struct sbi_trap_info trap = {0};
- unsigned long out_val = 0;
+ struct sbi_ecall_return out = {0};
bool is_0_1_spec = 0;
ext = sbi_ecall_find_extension(extension_id);
if (ext && ext->handle) {
- ret = ext->handle(extension_id, func_id,
- regs, &out_val, &trap);
+ ret = ext->handle(extension_id, func_id, regs, &out);
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN)
is_0_1_spec = 1;
ret = SBI_ENOTSUPP;
}
- if (ret == SBI_ETRAP) {
- trap.epc = regs->mepc;
- sbi_trap_redirect(regs, &trap);
- } else {
+ if (!out.skip_regs_update) {
if (ret < SBI_LAST_ERR ||
(extension_id != SBI_EXT_0_1_CONSOLE_GETCHAR &&
SBI_SUCCESS < ret)) {
regs->mepc += 4;
regs->a0 = ret;
if (!is_0_1_spec)
- regs->a1 = out_val;
+ regs->a1 = out.value;
}
return 0;
}
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
switch (funcid) {
case SBI_EXT_BASE_GET_SPEC_VERSION:
- *out_val = (SBI_ECALL_VERSION_MAJOR <<
- SBI_SPEC_VERSION_MAJOR_OFFSET) &
- (SBI_SPEC_VERSION_MAJOR_MASK <<
- SBI_SPEC_VERSION_MAJOR_OFFSET);
- *out_val = *out_val | SBI_ECALL_VERSION_MINOR;
+ out->value = (SBI_ECALL_VERSION_MAJOR <<
+ SBI_SPEC_VERSION_MAJOR_OFFSET) &
+ (SBI_SPEC_VERSION_MAJOR_MASK <<
+ SBI_SPEC_VERSION_MAJOR_OFFSET);
+ out->value = out->value | SBI_ECALL_VERSION_MINOR;
break;
case SBI_EXT_BASE_GET_IMP_ID:
- *out_val = sbi_ecall_get_impid();
+ out->value = sbi_ecall_get_impid();
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
- *out_val = OPENSBI_VERSION;
+ out->value = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
- *out_val = csr_read(CSR_MVENDORID);
+ out->value = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
- *out_val = csr_read(CSR_MARCHID);
+ out->value = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
- *out_val = csr_read(CSR_MIMPID);
+ out->value = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
- ret = sbi_ecall_base_probe(regs->a0, out_val);
+ ret = sbi_ecall_base_probe(regs->a0, &out->value);
break;
default:
ret = SBI_ENOTSUPP;
#include <sbi/sbi_cppc.h>
static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
uint64_t temp;
switch (funcid) {
case SBI_EXT_CPPC_READ:
ret = sbi_cppc_read(regs->a0, &temp);
- *out_val = temp;
+ out->value = temp;
break;
case SBI_EXT_CPPC_READ_HI:
#if __riscv_xlen == 32
ret = sbi_cppc_read(regs->a0, &temp);
- *out_val = temp >> 32;
+ out->value = temp >> 32;
#else
- *out_val = 0;
+ out->value = 0;
#endif
break;
case SBI_EXT_CPPC_WRITE:
case SBI_EXT_CPPC_PROBE:
ret = sbi_cppc_probe(regs->a0);
if (ret >= 0) {
- *out_val = ret;
+ out->value = ret;
ret = 0;
}
break;
#include <sbi/sbi_hart.h>
static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
MSTATUS_MPP_SHIFT;
return SBI_ERR_INVALID_PARAM;
sbi_hart_map_saddr(regs->a1, regs->a0);
if (funcid == SBI_EXT_DBCN_CONSOLE_WRITE)
- *out_val = sbi_nputs((const char *)regs->a1, regs->a0);
+ out->value = sbi_nputs((const char *)regs->a1, regs->a0);
else
- *out_val = sbi_ngets((char *)regs->a1, regs->a0);
+ out->value = sbi_ngets((char *)regs->a1, regs->a0);
sbi_hart_unmap_saddr();
return 0;
case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE:
#include <sbi/riscv_asm.h>
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
}
if (ret >= 0) {
- *out_val = ret;
+ out->value = ret;
ret = 0;
}
#include <sbi/sbi_ipi.h>
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
}
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = current_hartid();
+ struct sbi_trap_info trap = {0};
ulong hmask = 0;
switch (extid) {
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
- &hmask, out_trap);
- if (ret != SBI_ETRAP)
+ &hmask, &trap);
+ if (ret != SBI_ETRAP) {
ret = sbi_ipi_send_smode(hmask, 0);
+ } else {
+ ret = 0;
+ trap.epc = regs->mepc;
+ sbi_trap_redirect(regs, &trap);
+ out->skip_regs_update = true;
+ }
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
- &hmask, out_trap);
+ &hmask, &trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_TLB_FENCE_I, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
+ } else {
+ ret = 0;
+ trap.epc = regs->mepc;
+ sbi_trap_redirect(regs, &trap);
+ out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
- &hmask, out_trap);
+ &hmask, &trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
SBI_TLB_SFENCE_VMA, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
+ } else {
+ ret = 0;
+ trap.epc = regs->mepc;
+ sbi_trap_redirect(regs, &trap);
+ out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
- &hmask, out_trap);
+ &hmask, &trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
regs->a2, regs->a3, 0,
SBI_TLB_SFENCE_VMA_ASID,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
+ } else {
+ ret = 0;
+ trap.epc = regs->mepc;
+ sbi_trap_redirect(regs, &trap);
+ out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_SHUTDOWN:
#include <sbi/riscv_asm.h>
static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
uint64_t temp;
case SBI_EXT_PMU_NUM_COUNTERS:
ret = sbi_pmu_num_ctr();
if (ret >= 0) {
- *out_val = ret;
+ out->value = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_GET_INFO:
- ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
+ ret = sbi_pmu_ctr_get_info(regs->a0, &out->value);
break;
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
#if __riscv_xlen == 32
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
regs->a3, temp);
if (ret >= 0) {
- *out_val = ret;
+ out->value = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_FW_READ:
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
- *out_val = temp;
+ out->value = temp;
break;
case SBI_EXT_PMU_COUNTER_FW_READ_HI:
#if __riscv_xlen == 32
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
- *out_val = temp >> 32;
+ out->value = temp >> 32;
#else
- *out_val = 0;
+ out->value = 0;
#endif
break;
case SBI_EXT_PMU_COUNTER_START:
#include <sbi/sbi_tlb.h>
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
unsigned long vmid;
#include <sbi/sbi_system.h>
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
if (funcid == SBI_EXT_SRST_RESET) {
if ((((u32)-1U) <= ((u64)regs->a0)) ||
#include <sbi/sbi_system.h>
static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = SBI_ENOTSUPP;
ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2);
if (ret >= 0) {
- *out_val = ret;
+ out->value = ret;
ret = 0;
}
#include <sbi/sbi_timer.h>
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
int ret = 0;
}
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_val,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
- funcid, regs,
- out_val, out_trap);
+ funcid, regs, out);
}
struct sbi_ecall_extension ecall_vendor;
}
int andes_sbi_vendor_ext_provider(long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_value,
- struct sbi_trap_info *out_trap,
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out,
const struct fdt_match *match)
{
switch (funcid) {
case SBI_EXT_ANDES_IOCP_SW_WORKAROUND:
- *out_value = andes45_apply_iocp_sw_workaround();
+ out->value = andes45_apply_iocp_sw_workaround();
break;
default:
#ifndef _RISCV_ANDES_SBI_H
#define _RISCV_ANDES_SBI_H
+#include <sbi/sbi_ecall.h>
#include <sbi/sbi_trap.h>
#include <sbi_utils/fdt/fdt_helper.h>
int andes_sbi_vendor_ext_provider(long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_value,
- struct sbi_trap_info *out_trap,
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out,
const struct fdt_match *match);
#endif /* _RISCV_ANDES_SBI_H */
#ifndef __PLATFORM_OVERRIDE_H__
#define __PLATFORM_OVERRIDE_H__
+#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_types.h>
#include <sbi/sbi_trap.h>
int (*pmu_init)(const struct fdt_match *match);
void (*fw_init)(void *fdt, const struct fdt_match *match);
int (*vendor_ext_provider)(long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_value,
- struct sbi_trap_info *out_trap,
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out,
const struct fdt_match *match);
};
}
static int generic_vendor_ext_provider(long funcid,
- const struct sbi_trap_regs *regs,
- unsigned long *out_value,
- struct sbi_trap_info *out_trap)
+ struct sbi_trap_regs *regs,
+ struct sbi_ecall_return *out)
{
- return generic_plat->vendor_ext_provider(funcid, regs,
- out_value, out_trap,
+ return generic_plat->vendor_ext_provider(funcid, regs, out,
generic_plat_match);
}