diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h index 027213cb..0bf42d16 100644 --- a/include/sbi/sbi_ecall.h +++ b/include/sbi/sbi_ecall.h @@ -20,6 +20,13 @@ 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; @@ -62,9 +69,8 @@ struct sbi_ecall_extension { * 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); diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index 58b9069d..2fb33e16 100644 --- a/include/sbi/sbi_platform.h +++ b/include/sbi/sbi_platform.h @@ -50,7 +50,7 @@ #include struct sbi_domain_memregion; -struct sbi_trap_info; +struct sbi_ecall_return; struct sbi_trap_regs; struct sbi_hart_features; @@ -137,9 +137,8 @@ struct sbi_platform_operations { 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 */ @@ -666,16 +665,12 @@ static inline bool sbi_platform_vendor_ext_check( 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; } diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c index 3eb4f0ad..631c5dd1 100644 --- a/lib/sbi/sbi_ecall.c +++ b/lib/sbi/sbi_ecall.c @@ -101,14 +101,12 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs) 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; @@ -116,10 +114,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs) 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)) { @@ -140,7 +135,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs) regs->mepc += 4; regs->a0 = ret; if (!is_0_1_spec) - regs->a1 = out_val; + regs->a1 = out.value; } return 0; diff --git a/lib/sbi/sbi_ecall_base.c b/lib/sbi/sbi_ecall_base.c index 74f05eb2..b7178ea8 100644 --- a/lib/sbi/sbi_ecall_base.c +++ b/lib/sbi/sbi_ecall_base.c @@ -33,37 +33,36 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val) } 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; diff --git a/lib/sbi/sbi_ecall_cppc.c b/lib/sbi/sbi_ecall_cppc.c index b54d54ec..c26bb401 100644 --- a/lib/sbi/sbi_ecall_cppc.c +++ b/lib/sbi/sbi_ecall_cppc.c @@ -12,9 +12,8 @@ #include 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; @@ -22,14 +21,14 @@ static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid, 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: @@ -38,7 +37,7 @@ static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid, case SBI_EXT_CPPC_PROBE: ret = sbi_cppc_probe(regs->a0); if (ret >= 0) { - *out_val = ret; + out->value = ret; ret = 0; } break; diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c index 18cd6c8b..49a7713f 100644 --- a/lib/sbi/sbi_ecall_dbcn.c +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -17,9 +17,8 @@ #include 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; @@ -49,9 +48,9 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid, 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: diff --git a/lib/sbi/sbi_ecall_hsm.c b/lib/sbi/sbi_ecall_hsm.c index 20705c39..93170b09 100644 --- a/lib/sbi/sbi_ecall_hsm.c +++ b/lib/sbi/sbi_ecall_hsm.c @@ -17,9 +17,8 @@ #include 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(); @@ -47,7 +46,7 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid, } if (ret >= 0) { - *out_val = ret; + out->value = ret; ret = 0; } diff --git a/lib/sbi/sbi_ecall_ipi.c b/lib/sbi/sbi_ecall_ipi.c index a40d6b8c..50ef41dc 100644 --- a/lib/sbi/sbi_ecall_ipi.c +++ b/lib/sbi/sbi_ecall_ipi.c @@ -15,9 +15,8 @@ #include 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; diff --git a/lib/sbi/sbi_ecall_legacy.c b/lib/sbi/sbi_ecall_legacy.c index 556f629b..48bd2274 100644 --- a/lib/sbi/sbi_ecall_legacy.c +++ b/lib/sbi/sbi_ecall_legacy.c @@ -43,13 +43,13 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask, } 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) { @@ -71,37 +71,58 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid, 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: diff --git a/lib/sbi/sbi_ecall_pmu.c b/lib/sbi/sbi_ecall_pmu.c index c5859110..40a63a62 100644 --- a/lib/sbi/sbi_ecall_pmu.c +++ b/lib/sbi/sbi_ecall_pmu.c @@ -18,9 +18,8 @@ #include 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; @@ -29,12 +28,12 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid, 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 @@ -45,21 +44,21 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid, 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: diff --git a/lib/sbi/sbi_ecall_rfence.c b/lib/sbi/sbi_ecall_rfence.c index 4b74d412..ded16c26 100644 --- a/lib/sbi/sbi_ecall_rfence.c +++ b/lib/sbi/sbi_ecall_rfence.c @@ -16,9 +16,8 @@ #include 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; diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c index dcd560d2..46cfaca4 100644 --- a/lib/sbi/sbi_ecall_srst.c +++ b/lib/sbi/sbi_ecall_srst.c @@ -15,9 +15,8 @@ #include 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)) || diff --git a/lib/sbi/sbi_ecall_susp.c b/lib/sbi/sbi_ecall_susp.c index 2bfd99ae..7b66bfcd 100644 --- a/lib/sbi/sbi_ecall_susp.c +++ b/lib/sbi/sbi_ecall_susp.c @@ -6,9 +6,8 @@ #include 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; @@ -16,7 +15,7 @@ static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid, ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2); if (ret >= 0) { - *out_val = ret; + out->value = ret; ret = 0; } diff --git a/lib/sbi/sbi_ecall_time.c b/lib/sbi/sbi_ecall_time.c index e79196f7..5a2316eb 100644 --- a/lib/sbi/sbi_ecall_time.c +++ b/lib/sbi/sbi_ecall_time.c @@ -15,9 +15,8 @@ #include 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; diff --git a/lib/sbi/sbi_ecall_vendor.c b/lib/sbi/sbi_ecall_vendor.c index 700f475f..ebebc586 100644 --- a/lib/sbi/sbi_ecall_vendor.c +++ b/lib/sbi/sbi_ecall_vendor.c @@ -23,13 +23,11 @@ static inline unsigned long sbi_ecall_vendor_id(void) } 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; diff --git a/platform/generic/andes/andes_sbi.c b/platform/generic/andes/andes_sbi.c index 3e89fb9c..267c6638 100644 --- a/platform/generic/andes/andes_sbi.c +++ b/platform/generic/andes/andes_sbi.c @@ -33,14 +33,13 @@ static bool andes45_apply_iocp_sw_workaround(void) } 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: diff --git a/platform/generic/include/andes/andes_sbi.h b/platform/generic/include/andes/andes_sbi.h index e5dc2507..1288af81 100644 --- a/platform/generic/include/andes/andes_sbi.h +++ b/platform/generic/include/andes/andes_sbi.h @@ -3,13 +3,13 @@ #ifndef _RISCV_ANDES_SBI_H #define _RISCV_ANDES_SBI_H +#include #include #include 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 */ diff --git a/platform/generic/include/platform_override.h b/platform/generic/include/platform_override.h index f2a4327e..b0585c21 100644 --- a/platform/generic/include/platform_override.h +++ b/platform/generic/include/platform_override.h @@ -10,6 +10,7 @@ #ifndef __PLATFORM_OVERRIDE_H__ #define __PLATFORM_OVERRIDE_H__ +#include #include #include #include @@ -30,9 +31,8 @@ struct platform_override { 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); }; diff --git a/platform/generic/platform.c b/platform/generic/platform.c index 85072275..bfd7d318 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -203,12 +203,10 @@ static bool generic_vendor_ext_check(void) } 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); }