diff options
author | Anup Patel <anup.patel@wdc.com> | 2020-01-16 11:38:49 +0530 |
---|---|---|
committer | Anup Patel <anup@brainfault.org> | 2020-01-22 12:13:34 +0530 |
commit | 37923c4a66180b2f7881d959cd631038e81dbfec (patch) | |
tree | 02b37146d8e63222ae2a7187405b2eb2bdb58c95 /lib/sbi/sbi_ecall.c | |
parent | 0a411bf717d20a212949af443b275fab9469992f (diff) |
lib: Add dynamic registration of SBI extensions
This patch extends our SBI ecall implementation to allow
dynamic registration of various SBI extensions. Using this
dynamic registration we can break-up SBI ecall implementation
into multiple files and even register experimental/custom
SBI extensions from platform code.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Diffstat (limited to 'lib/sbi/sbi_ecall.c')
-rw-r--r-- | lib/sbi/sbi_ecall.c | 240 |
1 files changed, 174 insertions, 66 deletions
diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c index 8d136cc..1c49d79 100644 --- a/lib/sbi/sbi_ecall.c +++ b/lib/sbi/sbi_ecall.c @@ -52,49 +52,29 @@ static int sbi_load_hart_mask_unpriv(struct sbi_scratch *scratch, ulong *pmask, return 0; } -int sbi_check_extension(struct sbi_scratch *scratch, unsigned long extid, - unsigned long *out_val) +static int sbi_ecall_base_probe(struct sbi_scratch *scratch, + unsigned long extid, + unsigned long *out_val) { - /** - * Each extension apart from base & 0.1, will be implemented as - * platform specific feature. Thus, extension probing can be achieved - * by checking the feature bits of the platform. We can create a map - * between extension ID & feature and use a generic function to check - * or just use a switch case for every new extension support added - * TODO: Implement it. - */ - - if ((extid >= SBI_EXT_0_1_SET_TIMER && extid <= SBI_EXT_0_1_SHUTDOWN) || - (extid == SBI_EXT_BASE) || - (extid == SBI_EXT_TIME) || - (extid == SBI_EXT_IPI) || - (extid == SBI_EXT_RFENCE)) { - *out_val = 1; - } else if (extid >= SBI_EXT_VENDOR_START && - extid <= SBI_EXT_VENDOR_END) { - *out_val = sbi_platform_vendor_ext_check( - sbi_platform_ptr(scratch), - extid); - } else + struct sbi_ecall_extension *ext; + + ext = sbi_ecall_find_extension(extid); + if (!ext) { *out_val = 0; + return 0; + } - return 0; -} + if (ext->probe) + return ext->probe(scratch, extid, out_val); -int sbi_ecall_vendor_ext_handler(struct sbi_scratch *scratch, - unsigned long extid, unsigned long funcid, - unsigned long *args, unsigned long *out_val, - struct sbi_trap_info *out_trap) -{ - return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch), - extid, funcid, args, - out_val, out_trap); + *out_val = 1; + return 0; } -int sbi_ecall_base_handler(struct sbi_scratch *scratch, - unsigned long extid, unsigned long funcid, - unsigned long *args, unsigned long *out_val, - struct sbi_trap_info *out_trap) +static int sbi_ecall_base_handler(struct sbi_scratch *scratch, + unsigned long extid, unsigned long funcid, + unsigned long *args, unsigned long *out_val, + struct sbi_trap_info *out_trap) { int ret = 0; @@ -122,7 +102,7 @@ int sbi_ecall_base_handler(struct sbi_scratch *scratch, *out_val = csr_read(CSR_MIMPID); break; case SBI_EXT_BASE_PROBE_EXT: - ret = sbi_check_extension(scratch, args[0], out_val); + ret = sbi_ecall_base_probe(scratch, args[0], out_val); break; default: ret = SBI_ENOTSUPP; @@ -131,8 +111,16 @@ int sbi_ecall_base_handler(struct sbi_scratch *scratch, return ret; } -int sbi_ecall_time_handler(struct sbi_scratch *scratch, unsigned long funcid, - unsigned long *args) +static struct sbi_ecall_extension ecall_base = { + .extid_start = SBI_EXT_BASE, + .extid_end = SBI_EXT_BASE, + .handle = sbi_ecall_base_handler, +}; + +static int sbi_ecall_time_handler(struct sbi_scratch *scratch, + unsigned long extid, unsigned long funcid, + unsigned long *args, unsigned long *out_val, + struct sbi_trap_info *out_trap) { int ret = 0; @@ -149,8 +137,16 @@ int sbi_ecall_time_handler(struct sbi_scratch *scratch, unsigned long funcid, return ret; } -int sbi_ecall_ipi_handler(struct sbi_scratch *scratch, unsigned long funcid, - unsigned long *args, unsigned long *tval) +static struct sbi_ecall_extension ecall_time = { + .extid_start = SBI_EXT_TIME, + .extid_end = SBI_EXT_TIME, + .handle = sbi_ecall_time_handler, +}; + +static int sbi_ecall_ipi_handler(struct sbi_scratch *scratch, + unsigned long extid, unsigned long funcid, + unsigned long *args, unsigned long *out_val, + struct sbi_trap_info *out_trap) { int ret = 0; @@ -162,8 +158,16 @@ int sbi_ecall_ipi_handler(struct sbi_scratch *scratch, unsigned long funcid, return ret; } -int sbi_ecall_rfence_handler(struct sbi_scratch *scratch, unsigned long funcid, - unsigned long *args, unsigned long *tval) +static struct sbi_ecall_extension ecall_ipi = { + .extid_start = SBI_EXT_IPI, + .extid_end = SBI_EXT_IPI, + .handle = sbi_ecall_ipi_handler, +}; + +static int sbi_ecall_rfence_handler(struct sbi_scratch *scratch, + unsigned long extid, unsigned long funcid, + unsigned long *args, unsigned long *out_val, + struct sbi_trap_info *out_trap) { int ret = 0; struct sbi_tlb_info tlb_info; @@ -235,8 +239,16 @@ int sbi_ecall_rfence_handler(struct sbi_scratch *scratch, unsigned long funcid, return ret; } -int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, unsigned long extid, - unsigned long *args, struct sbi_trap_info *out_trap) +static struct sbi_ecall_extension ecall_rfence = { + .extid_start = SBI_EXT_RFENCE, + .extid_end = SBI_EXT_RFENCE, + .handle = sbi_ecall_rfence_handler, +}; + +static int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, + unsigned long extid, unsigned long funcid, + unsigned long *args, unsigned long *out_val, + struct sbi_trap_info *out_trap) { int ret = 0; struct sbi_tlb_info tlb_info; @@ -308,10 +320,92 @@ int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, unsigned long extid, return ret; } +static struct sbi_ecall_extension ecall_0_1 = { + .extid_start = SBI_EXT_0_1_SET_TIMER, + .extid_end = SBI_EXT_0_1_SHUTDOWN, + .handle = sbi_ecall_0_1_handler, +}; + +static int sbi_ecall_vendor_probe(struct sbi_scratch *scratch, + unsigned long extid, + unsigned long *out_val) +{ + *out_val = sbi_platform_vendor_ext_check(sbi_platform_ptr(scratch), + extid); + return 0; +} + +static int sbi_ecall_vendor_handler(struct sbi_scratch *scratch, + unsigned long extid, unsigned long funcid, + unsigned long *args, unsigned long *out_val, + struct sbi_trap_info *out_trap) +{ + return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch), + extid, funcid, args, + out_val, out_trap); +} + +static struct sbi_ecall_extension ecall_vendor = { + .extid_start = SBI_EXT_VENDOR_START, + .extid_end = SBI_EXT_VENDOR_END, + .probe = sbi_ecall_vendor_probe, + .handle = sbi_ecall_vendor_handler, +}; + +static SBI_LIST_HEAD(ecall_exts_list); + +struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid) +{ + struct sbi_ecall_extension *t, *ret = NULL; + + sbi_list_for_each_entry(t, &ecall_exts_list, head) { + if (t->extid_start <= extid && extid <= t->extid_end) { + ret = t; + break; + } + } + + return ret; +} + +int sbi_ecall_register_extension(struct sbi_ecall_extension *ext) +{ + if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle) + return SBI_EINVAL; + if (sbi_ecall_find_extension(ext->extid_start) || + sbi_ecall_find_extension(ext->extid_end)) + return SBI_EINVAL; + + SBI_INIT_LIST_HEAD(&ext->head); + sbi_list_add_tail(&ext->head, &ecall_exts_list); + + return 0; +} + +void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext) +{ + bool found = FALSE; + struct sbi_ecall_extension *t; + + if (!ext) + return; + + sbi_list_for_each_entry(t, &ecall_exts_list, head) { + if (t == ext) { + found = TRUE; + break; + } + } + + if (found) + sbi_list_del_init(&ext->head); +} + int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs, struct sbi_scratch *scratch) { int ret = 0; + struct sbi_ecall_extension *ext; unsigned long extension_id = regs->a7; unsigned long func_id = regs->a6; struct sbi_trap_info trap = {0}; @@ -326,26 +420,13 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs, args[4] = regs->a4; args[5] = regs->a5; - if (extension_id >= SBI_EXT_0_1_SET_TIMER && - extension_id <= SBI_EXT_0_1_SHUTDOWN) { - ret = sbi_ecall_0_1_handler(scratch, extension_id, - args, &trap); - is_0_1_spec = 1; - } else if (extension_id == SBI_EXT_BASE) - ret = sbi_ecall_base_handler(scratch, extension_id, func_id, - args, &out_val, &trap); - else if (extension_id == SBI_EXT_TIME) - ret = sbi_ecall_time_handler(scratch, func_id, args); - else if (extension_id == SBI_EXT_IPI) - ret = sbi_ecall_ipi_handler(scratch, func_id, args, &out_val); - else if (extension_id == SBI_EXT_RFENCE) - ret = sbi_ecall_rfence_handler(scratch, func_id, - args, &out_val); - else if (extension_id >= SBI_EXT_VENDOR_START && - extension_id <= SBI_EXT_VENDOR_END) { - ret = sbi_ecall_vendor_ext_handler(scratch, extension_id, - func_id, args, &out_val, - &trap); + ext = sbi_ecall_find_extension(extension_id); + if (ext && ext->handle) { + ret = ext->handle(scratch, extension_id, func_id, + args, &out_val, &trap); + if (extension_id >= SBI_EXT_0_1_SET_TIMER && + extension_id <= SBI_EXT_0_1_SHUTDOWN) + is_0_1_spec = 1; } else { ret = SBI_ENOTSUPP; } @@ -369,3 +450,30 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs, return 0; } + +int sbi_ecall_init(void) +{ + int ret; + + /* The order of below registrations is performance optimized */ + ret = sbi_ecall_register_extension(&ecall_time); + if (ret) + return ret; + ret = sbi_ecall_register_extension(&ecall_rfence); + if (ret) + return ret; + ret = sbi_ecall_register_extension(&ecall_ipi); + if (ret) + return ret; + ret = sbi_ecall_register_extension(&ecall_base); + if (ret) + return ret; + ret = sbi_ecall_register_extension(&ecall_0_1); + if (ret) + return ret; + ret = sbi_ecall_register_extension(&ecall_vendor); + if (ret) + return ret; + + return 0; +} |