Message ID | 20220912105253.2342504-2-kconsul@ventanamicro.com |
---|---|
State | Accepted |
Headers | show |
Series | [v3] lib: utils/serial: add semihosting support | expand |
On Mon, Sep 12, 2022 at 4:28 PM Kautuk Consul <kconsul@ventanamicro.com> wrote: > > We add RISC-V semihosting based serial console for JTAG based early > debugging. > > The RISC-V semihosting specification is available at: > https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc > > Signed-off-by: Anup Patel <apatel@ventanamicro.com> > Signed-off-by: Kautuk Consul <kconsul@ventanamicro.com> Looks good to me. Reviewed-by: Anup Patel <anup@brainfault.org> Applied this patch to the riscv/opensbi repo. Thanks, Anup > --- > include/sbi_utils/serial/semihosting.h | 47 +++++++ > lib/utils/serial/Kconfig | 4 + > lib/utils/serial/objects.mk | 1 + > lib/utils/serial/semihosting.c | 177 +++++++++++++++++++++++++ > platform/generic/configs/defconfig | 1 + > platform/generic/platform.c | 11 +- > 6 files changed, 240 insertions(+), 1 deletion(-) > create mode 100644 include/sbi_utils/serial/semihosting.h > create mode 100644 lib/utils/serial/semihosting.c > > diff --git a/include/sbi_utils/serial/semihosting.h b/include/sbi_utils/serial/semihosting.h > new file mode 100644 > index 0000000..8cc4a86 > --- /dev/null > +++ b/include/sbi_utils/serial/semihosting.h > @@ -0,0 +1,47 @@ > +/* > + * SPDX-License-Identifier: BSD-2-Clause > + * > + * Copyright (c) 2022 Ventana Micro Systems Inc. > + * > + * Authors: > + * Anup Patel <apatel@ventanamicro.com> > + * Kautuk Consul <kconsul@ventanamicro.com> > + */ > + > +#ifndef __SERIAL_SEMIHOSTING_H__ > +#define __SERIAL_SEMIHOSTING_H__ > + > +#include <sbi/sbi_types.h> > + > +/** > + * enum semihosting_open_mode - Numeric file modes for use with semihosting_open() > + * MODE_READ: 'r' > + * MODE_BINARY: 'b' > + * MODE_PLUS: '+' > + * MODE_WRITE: 'w' > + * MODE_APPEND: 'a' > + * > + * These modes represent the mode string used by fopen(3) in a form which can > + * be passed to semihosting_open(). These do NOT correspond directly to %O_RDONLY, > + * %O_CREAT, etc; see fopen(3) for details. In particular, @MODE_PLUS > + * effectively results in adding %O_RDWR, and @MODE_WRITE will add %O_TRUNC. > + * For compatibility, @MODE_BINARY should be added when opening non-text files > + * (such as images). > + */ > +enum semihosting_open_mode { > + MODE_READ = 0x0, > + MODE_BINARY = 0x1, > + MODE_PLUS = 0x2, > + MODE_WRITE = 0x4, > + MODE_APPEND = 0x8, > +}; > + > +#ifdef CONFIG_SERIAL_SEMIHOSTING > +int semihosting_init(void); > +int semihosting_enabled(void); > +#else > +static inline int semihosting_init(void) { return SBI_ENODEV; } > +static inline int semihosting_enabled(void) { return 0; } > +#endif > + > +#endif > diff --git a/lib/utils/serial/Kconfig b/lib/utils/serial/Kconfig > index 6e425f2..da549a7 100644 > --- a/lib/utils/serial/Kconfig > +++ b/lib/utils/serial/Kconfig > @@ -79,4 +79,8 @@ config SERIAL_XILINX_UARTLITE > bool "Xilinx UART Lite support" > default n > > +config SERIAL_SEMIHOSTING > + bool "Semihosting support" > + default n > + > endmenu > diff --git a/lib/utils/serial/objects.mk b/lib/utils/serial/objects.mk > index efb1d9e..98f3f9a 100644 > --- a/lib/utils/serial/objects.mk > +++ b/lib/utils/serial/objects.mk > @@ -41,3 +41,4 @@ libsbiutils-objs-$(CONFIG_SERIAL_SIFIVE) += serial/sifive-uart.o > libsbiutils-objs-$(CONFIG_SERIAL_LITEX) += serial/litex-uart.o > libsbiutils-objs-$(CONFIG_SERIAL_UART8250) += serial/uart8250.o > libsbiutils-objs-$(CONFIG_SERIAL_XILINX_UARTLITE) += serial/xlnx-uartlite.o > +libsbiutils-objs-$(CONFIG_SERIAL_SEMIHOSTING) += serial/semihosting.o > diff --git a/lib/utils/serial/semihosting.c b/lib/utils/serial/semihosting.c > new file mode 100644 > index 0000000..7298049 > --- /dev/null > +++ b/lib/utils/serial/semihosting.c > @@ -0,0 +1,177 @@ > +/* > + * SPDX-License-Identifier: BSD-2-Clause > + * > + * Copyright (c) 2022 Ventana Micro Systems Inc. > + * > + * Authors: > + * Anup Patel <apatel@ventanamicro.com> > + * Kautuk Consul <kconsul@ventanamicro.com> > + */ > + > +#include <sbi/sbi_console.h> > +#include <sbi/sbi_string.h> > +#include <sbi/sbi_error.h> > +#include <sbi_utils/serial/semihosting.h> > + > +#define SYSOPEN 0x01 > +#define SYSWRITEC 0x03 > +#define SYSREAD 0x06 > +#define SYSREADC 0x07 > +#define SYSERRNO 0x13 > + > +static long semihosting_trap(int sysnum, void *addr) > +{ > + register int ret asm ("a0") = sysnum; > + register void *param0 asm ("a1") = addr; > + > + asm volatile ( > + "\t.option push\n" > + "\t.option norvc\n" > + "\tj 1f\n" > + "\t.align 4\n" > + "\t1: slli zero, zero, 0x1f\n" > + "\tebreak\n" > + "\tsrai zero, zero, 7\n" > + "\t.option pop\n" > + : "+r" (ret) : "r" (param0) : "memory"); > + > + return ret; > +} > + > +static bool _semihosting_enabled = true; > +static bool try_semihosting = true; > + > +bool semihosting_enabled(void) > +{ > + register int ret asm ("a0") = SYSERRNO; > + register void *param0 asm ("a1") = NULL; > + unsigned long tmp = 0; > + > + if (!try_semihosting) > + return _semihosting_enabled; > + > + asm volatile ( > + "\t.option push\n" > + "\t.option norvc\n" > + > + "\tj _semihost_test_vector_next\n" > + "\t.align 4\n" > + "\t_semihost_test_vector:\n" > + "\t\tcsrr %[en], mepc\n" > + "\t\taddi %[en], %[en], 4\n" > + "\t\tcsrw mepc, %[en]\n" > + "\t\tadd %[en], zero, zero\n" > + "\t\tmret\n" > + "\t_semihost_test_vector_next:\n" > + > + "\tla %[tmp], _semihost_test_vector\n" > + "\tcsrrw %[tmp], mtvec, %[tmp]\n" > + "\tj 1f\n" > + "\t.align 4\n" > + "\t1: slli zero, zero, 0x1f\n" > + "\tebreak\n" > + "\tsrai zero, zero, 7\n" > + "\tcsrw mtvec, %[tmp]\n" > + > + "\t.option pop\n" > + : [tmp] "+r" (tmp), [en] "+r" (_semihosting_enabled), > + [ret] "+r" (ret) > + : "r" (param0) : "memory"); > + > + try_semihosting = false; > + return _semihosting_enabled; > +} > + > +static int semihosting_errno(void) > +{ > + long ret = semihosting_trap(SYSERRNO, NULL); > + > + if (ret > 0) > + return -ret; > + return SBI_EIO; > +} > + > +static int semihosting_infd = SBI_ENODEV; > + > +static long semihosting_open(const char *fname, enum semihosting_open_mode mode) > +{ > + long fd; > + struct semihosting_open_s { > + const char *fname; > + unsigned long mode; > + size_t len; > + } open; > + > + open.fname = fname; > + open.len = sbi_strlen(fname); > + open.mode = mode; > + > + /* Open the file on the host */ > + fd = semihosting_trap(SYSOPEN, &open); > + if (fd == -1) > + return semihosting_errno(); > + return fd; > +} > + > +/** > + * struct semihosting_rdwr_s - Arguments for read and write > + * @fd: A file descriptor returned from semihosting_open() > + * @memp: Pointer to a buffer of memory of at least @len bytes > + * @len: The number of bytes to read or write > + */ > +struct semihosting_rdwr_s { > + long fd; > + void *memp; > + size_t len; > +}; > + > +static long semihosting_read(long fd, void *memp, size_t len) > +{ > + long ret; > + struct semihosting_rdwr_s read; > + > + read.fd = fd; > + read.memp = memp; > + read.len = len; > + > + ret = semihosting_trap(SYSREAD, &read); > + if (ret < 0) > + return semihosting_errno(); > + return len - ret; > +} > + > +/* clang-format on */ > + > +static void semihosting_putc(char ch) > +{ > + semihosting_trap(SYSWRITEC, &ch); > +} > + > +static int semihosting_getc(void) > +{ > + char ch = 0; > + int ret; > + > + if (semihosting_infd < 0) { > + ch = semihosting_trap(SYSREADC, NULL); > + ret = ch > -1 ? ch : -1; > + } else > + ret = semihosting_read(semihosting_infd, &ch, 1) > 0 ? ch : -1; > + > + return ret; > +} > + > +static struct sbi_console_device semihosting_console = { > + .name = "semihosting", > + .console_putc = semihosting_putc, > + .console_getc = semihosting_getc > +}; > + > +int semihosting_init(void) > +{ > + semihosting_infd = semihosting_open(":tt", MODE_READ); > + > + sbi_console_set_device(&semihosting_console); > + > + return 0; > +} > diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig > index e324173..c95b7fa 100644 > --- a/platform/generic/configs/defconfig > +++ b/platform/generic/configs/defconfig > @@ -28,3 +28,4 @@ CONFIG_FDT_SERIAL_UART8250=y > CONFIG_FDT_SERIAL_XILINX_UARTLITE=y > CONFIG_FDT_TIMER=y > CONFIG_FDT_TIMER_MTIMER=y > +CONFIG_SERIAL_SEMIHOSTING=y > diff --git a/platform/generic/platform.c b/platform/generic/platform.c > index cc3620f..bf51aba 100644 > --- a/platform/generic/platform.c > +++ b/platform/generic/platform.c > @@ -23,6 +23,7 @@ > #include <sbi_utils/timer/fdt_timer.h> > #include <sbi_utils/ipi/fdt_ipi.h> > #include <sbi_utils/reset/fdt_reset.h> > +#include <sbi_utils/serial/semihosting.h> > > /* List of platform override modules generated at compile time */ > extern const struct platform_override *platform_override_modules[]; > @@ -242,6 +243,14 @@ static uint64_t generic_pmu_xlate_to_mhpmevent(uint32_t event_idx, > return evt_val; > } > > +static int generic_console_init(void) > +{ > + if (semihosting_enabled()) > + return semihosting_init(); > + else > + return fdt_serial_init(); > +} > + > const struct sbi_platform_operations platform_ops = { > .nascent_init = generic_nascent_init, > .early_init = generic_early_init, > @@ -249,7 +258,7 @@ const struct sbi_platform_operations platform_ops = { > .early_exit = generic_early_exit, > .final_exit = generic_final_exit, > .domains_init = generic_domains_init, > - .console_init = fdt_serial_init, > + .console_init = generic_console_init, > .irqchip_init = fdt_irqchip_init, > .irqchip_exit = fdt_irqchip_exit, > .ipi_init = fdt_ipi_init, > -- > 2.34.1 > > > -- > opensbi mailing list > opensbi@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/opensbi
On Tue, Sep 13, 2022 at 9:12 PM Anup Patel <anup@brainfault.org> wrote: > > On Mon, Sep 12, 2022 at 4:28 PM Kautuk Consul <kconsul@ventanamicro.com> wrote: > > > > We add RISC-V semihosting based serial console for JTAG based early > > debugging. > > > > The RISC-V semihosting specification is available at: > > https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc > > > > Signed-off-by: Anup Patel <apatel@ventanamicro.com> > > Signed-off-by: Kautuk Consul <kconsul@ventanamicro.com> > > Looks good to me. > > Reviewed-by: Anup Patel <anup@brainfault.org> Thanks, Anup. This is the first time I have submitted an opensbi patch so I deeply appreciate it! > > Applied this patch to the riscv/opensbi repo. > > Thanks, > Anup > > > --- > > include/sbi_utils/serial/semihosting.h | 47 +++++++ > > lib/utils/serial/Kconfig | 4 + > > lib/utils/serial/objects.mk | 1 + > > lib/utils/serial/semihosting.c | 177 +++++++++++++++++++++++++ > > platform/generic/configs/defconfig | 1 + > > platform/generic/platform.c | 11 +- > > 6 files changed, 240 insertions(+), 1 deletion(-) > > create mode 100644 include/sbi_utils/serial/semihosting.h > > create mode 100644 lib/utils/serial/semihosting.c > > > > diff --git a/include/sbi_utils/serial/semihosting.h b/include/sbi_utils/serial/semihosting.h > > new file mode 100644 > > index 0000000..8cc4a86 > > --- /dev/null > > +++ b/include/sbi_utils/serial/semihosting.h > > @@ -0,0 +1,47 @@ > > +/* > > + * SPDX-License-Identifier: BSD-2-Clause > > + * > > + * Copyright (c) 2022 Ventana Micro Systems Inc. > > + * > > + * Authors: > > + * Anup Patel <apatel@ventanamicro.com> > > + * Kautuk Consul <kconsul@ventanamicro.com> > > + */ > > + > > +#ifndef __SERIAL_SEMIHOSTING_H__ > > +#define __SERIAL_SEMIHOSTING_H__ > > + > > +#include <sbi/sbi_types.h> > > + > > +/** > > + * enum semihosting_open_mode - Numeric file modes for use with semihosting_open() > > + * MODE_READ: 'r' > > + * MODE_BINARY: 'b' > > + * MODE_PLUS: '+' > > + * MODE_WRITE: 'w' > > + * MODE_APPEND: 'a' > > + * > > + * These modes represent the mode string used by fopen(3) in a form which can > > + * be passed to semihosting_open(). These do NOT correspond directly to %O_RDONLY, > > + * %O_CREAT, etc; see fopen(3) for details. In particular, @MODE_PLUS > > + * effectively results in adding %O_RDWR, and @MODE_WRITE will add %O_TRUNC. > > + * For compatibility, @MODE_BINARY should be added when opening non-text files > > + * (such as images). > > + */ > > +enum semihosting_open_mode { > > + MODE_READ = 0x0, > > + MODE_BINARY = 0x1, > > + MODE_PLUS = 0x2, > > + MODE_WRITE = 0x4, > > + MODE_APPEND = 0x8, > > +}; > > + > > +#ifdef CONFIG_SERIAL_SEMIHOSTING > > +int semihosting_init(void); > > +int semihosting_enabled(void); > > +#else > > +static inline int semihosting_init(void) { return SBI_ENODEV; } > > +static inline int semihosting_enabled(void) { return 0; } > > +#endif > > + > > +#endif > > diff --git a/lib/utils/serial/Kconfig b/lib/utils/serial/Kconfig > > index 6e425f2..da549a7 100644 > > --- a/lib/utils/serial/Kconfig > > +++ b/lib/utils/serial/Kconfig > > @@ -79,4 +79,8 @@ config SERIAL_XILINX_UARTLITE > > bool "Xilinx UART Lite support" > > default n > > > > +config SERIAL_SEMIHOSTING > > + bool "Semihosting support" > > + default n > > + > > endmenu > > diff --git a/lib/utils/serial/objects.mk b/lib/utils/serial/objects.mk > > index efb1d9e..98f3f9a 100644 > > --- a/lib/utils/serial/objects.mk > > +++ b/lib/utils/serial/objects.mk > > @@ -41,3 +41,4 @@ libsbiutils-objs-$(CONFIG_SERIAL_SIFIVE) += serial/sifive-uart.o > > libsbiutils-objs-$(CONFIG_SERIAL_LITEX) += serial/litex-uart.o > > libsbiutils-objs-$(CONFIG_SERIAL_UART8250) += serial/uart8250.o > > libsbiutils-objs-$(CONFIG_SERIAL_XILINX_UARTLITE) += serial/xlnx-uartlite.o > > +libsbiutils-objs-$(CONFIG_SERIAL_SEMIHOSTING) += serial/semihosting.o > > diff --git a/lib/utils/serial/semihosting.c b/lib/utils/serial/semihosting.c > > new file mode 100644 > > index 0000000..7298049 > > --- /dev/null > > +++ b/lib/utils/serial/semihosting.c > > @@ -0,0 +1,177 @@ > > +/* > > + * SPDX-License-Identifier: BSD-2-Clause > > + * > > + * Copyright (c) 2022 Ventana Micro Systems Inc. > > + * > > + * Authors: > > + * Anup Patel <apatel@ventanamicro.com> > > + * Kautuk Consul <kconsul@ventanamicro.com> > > + */ > > + > > +#include <sbi/sbi_console.h> > > +#include <sbi/sbi_string.h> > > +#include <sbi/sbi_error.h> > > +#include <sbi_utils/serial/semihosting.h> > > + > > +#define SYSOPEN 0x01 > > +#define SYSWRITEC 0x03 > > +#define SYSREAD 0x06 > > +#define SYSREADC 0x07 > > +#define SYSERRNO 0x13 > > + > > +static long semihosting_trap(int sysnum, void *addr) > > +{ > > + register int ret asm ("a0") = sysnum; > > + register void *param0 asm ("a1") = addr; > > + > > + asm volatile ( > > + "\t.option push\n" > > + "\t.option norvc\n" > > + "\tj 1f\n" > > + "\t.align 4\n" > > + "\t1: slli zero, zero, 0x1f\n" > > + "\tebreak\n" > > + "\tsrai zero, zero, 7\n" > > + "\t.option pop\n" > > + : "+r" (ret) : "r" (param0) : "memory"); > > + > > + return ret; > > +} > > + > > +static bool _semihosting_enabled = true; > > +static bool try_semihosting = true; > > + > > +bool semihosting_enabled(void) > > +{ > > + register int ret asm ("a0") = SYSERRNO; > > + register void *param0 asm ("a1") = NULL; > > + unsigned long tmp = 0; > > + > > + if (!try_semihosting) > > + return _semihosting_enabled; > > + > > + asm volatile ( > > + "\t.option push\n" > > + "\t.option norvc\n" > > + > > + "\tj _semihost_test_vector_next\n" > > + "\t.align 4\n" > > + "\t_semihost_test_vector:\n" > > + "\t\tcsrr %[en], mepc\n" > > + "\t\taddi %[en], %[en], 4\n" > > + "\t\tcsrw mepc, %[en]\n" > > + "\t\tadd %[en], zero, zero\n" > > + "\t\tmret\n" > > + "\t_semihost_test_vector_next:\n" > > + > > + "\tla %[tmp], _semihost_test_vector\n" > > + "\tcsrrw %[tmp], mtvec, %[tmp]\n" > > + "\tj 1f\n" > > + "\t.align 4\n" > > + "\t1: slli zero, zero, 0x1f\n" > > + "\tebreak\n" > > + "\tsrai zero, zero, 7\n" > > + "\tcsrw mtvec, %[tmp]\n" > > + > > + "\t.option pop\n" > > + : [tmp] "+r" (tmp), [en] "+r" (_semihosting_enabled), > > + [ret] "+r" (ret) > > + : "r" (param0) : "memory"); > > + > > + try_semihosting = false; > > + return _semihosting_enabled; > > +} > > + > > +static int semihosting_errno(void) > > +{ > > + long ret = semihosting_trap(SYSERRNO, NULL); > > + > > + if (ret > 0) > > + return -ret; > > + return SBI_EIO; > > +} > > + > > +static int semihosting_infd = SBI_ENODEV; > > + > > +static long semihosting_open(const char *fname, enum semihosting_open_mode mode) > > +{ > > + long fd; > > + struct semihosting_open_s { > > + const char *fname; > > + unsigned long mode; > > + size_t len; > > + } open; > > + > > + open.fname = fname; > > + open.len = sbi_strlen(fname); > > + open.mode = mode; > > + > > + /* Open the file on the host */ > > + fd = semihosting_trap(SYSOPEN, &open); > > + if (fd == -1) > > + return semihosting_errno(); > > + return fd; > > +} > > + > > +/** > > + * struct semihosting_rdwr_s - Arguments for read and write > > + * @fd: A file descriptor returned from semihosting_open() > > + * @memp: Pointer to a buffer of memory of at least @len bytes > > + * @len: The number of bytes to read or write > > + */ > > +struct semihosting_rdwr_s { > > + long fd; > > + void *memp; > > + size_t len; > > +}; > > + > > +static long semihosting_read(long fd, void *memp, size_t len) > > +{ > > + long ret; > > + struct semihosting_rdwr_s read; > > + > > + read.fd = fd; > > + read.memp = memp; > > + read.len = len; > > + > > + ret = semihosting_trap(SYSREAD, &read); > > + if (ret < 0) > > + return semihosting_errno(); > > + return len - ret; > > +} > > + > > +/* clang-format on */ > > + > > +static void semihosting_putc(char ch) > > +{ > > + semihosting_trap(SYSWRITEC, &ch); > > +} > > + > > +static int semihosting_getc(void) > > +{ > > + char ch = 0; > > + int ret; > > + > > + if (semihosting_infd < 0) { > > + ch = semihosting_trap(SYSREADC, NULL); > > + ret = ch > -1 ? ch : -1; > > + } else > > + ret = semihosting_read(semihosting_infd, &ch, 1) > 0 ? ch : -1; > > + > > + return ret; > > +} > > + > > +static struct sbi_console_device semihosting_console = { > > + .name = "semihosting", > > + .console_putc = semihosting_putc, > > + .console_getc = semihosting_getc > > +}; > > + > > +int semihosting_init(void) > > +{ > > + semihosting_infd = semihosting_open(":tt", MODE_READ); > > + > > + sbi_console_set_device(&semihosting_console); > > + > > + return 0; > > +} > > diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig > > index e324173..c95b7fa 100644 > > --- a/platform/generic/configs/defconfig > > +++ b/platform/generic/configs/defconfig > > @@ -28,3 +28,4 @@ CONFIG_FDT_SERIAL_UART8250=y > > CONFIG_FDT_SERIAL_XILINX_UARTLITE=y > > CONFIG_FDT_TIMER=y > > CONFIG_FDT_TIMER_MTIMER=y > > +CONFIG_SERIAL_SEMIHOSTING=y > > diff --git a/platform/generic/platform.c b/platform/generic/platform.c > > index cc3620f..bf51aba 100644 > > --- a/platform/generic/platform.c > > +++ b/platform/generic/platform.c > > @@ -23,6 +23,7 @@ > > #include <sbi_utils/timer/fdt_timer.h> > > #include <sbi_utils/ipi/fdt_ipi.h> > > #include <sbi_utils/reset/fdt_reset.h> > > +#include <sbi_utils/serial/semihosting.h> > > > > /* List of platform override modules generated at compile time */ > > extern const struct platform_override *platform_override_modules[]; > > @@ -242,6 +243,14 @@ static uint64_t generic_pmu_xlate_to_mhpmevent(uint32_t event_idx, > > return evt_val; > > } > > > > +static int generic_console_init(void) > > +{ > > + if (semihosting_enabled()) > > + return semihosting_init(); > > + else > > + return fdt_serial_init(); > > +} > > + > > const struct sbi_platform_operations platform_ops = { > > .nascent_init = generic_nascent_init, > > .early_init = generic_early_init, > > @@ -249,7 +258,7 @@ const struct sbi_platform_operations platform_ops = { > > .early_exit = generic_early_exit, > > .final_exit = generic_final_exit, > > .domains_init = generic_domains_init, > > - .console_init = fdt_serial_init, > > + .console_init = generic_console_init, > > .irqchip_init = fdt_irqchip_init, > > .irqchip_exit = fdt_irqchip_exit, > > .ipi_init = fdt_ipi_init, > > -- > > 2.34.1 > > > > > > -- > > opensbi mailing list > > opensbi@lists.infradead.org > > http://lists.infradead.org/mailman/listinfo/opensbi
diff --git a/include/sbi_utils/serial/semihosting.h b/include/sbi_utils/serial/semihosting.h new file mode 100644 index 0000000..8cc4a86 --- /dev/null +++ b/include/sbi_utils/serial/semihosting.h @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel <apatel@ventanamicro.com> + * Kautuk Consul <kconsul@ventanamicro.com> + */ + +#ifndef __SERIAL_SEMIHOSTING_H__ +#define __SERIAL_SEMIHOSTING_H__ + +#include <sbi/sbi_types.h> + +/** + * enum semihosting_open_mode - Numeric file modes for use with semihosting_open() + * MODE_READ: 'r' + * MODE_BINARY: 'b' + * MODE_PLUS: '+' + * MODE_WRITE: 'w' + * MODE_APPEND: 'a' + * + * These modes represent the mode string used by fopen(3) in a form which can + * be passed to semihosting_open(). These do NOT correspond directly to %O_RDONLY, + * %O_CREAT, etc; see fopen(3) for details. In particular, @MODE_PLUS + * effectively results in adding %O_RDWR, and @MODE_WRITE will add %O_TRUNC. + * For compatibility, @MODE_BINARY should be added when opening non-text files + * (such as images). + */ +enum semihosting_open_mode { + MODE_READ = 0x0, + MODE_BINARY = 0x1, + MODE_PLUS = 0x2, + MODE_WRITE = 0x4, + MODE_APPEND = 0x8, +}; + +#ifdef CONFIG_SERIAL_SEMIHOSTING +int semihosting_init(void); +int semihosting_enabled(void); +#else +static inline int semihosting_init(void) { return SBI_ENODEV; } +static inline int semihosting_enabled(void) { return 0; } +#endif + +#endif diff --git a/lib/utils/serial/Kconfig b/lib/utils/serial/Kconfig index 6e425f2..da549a7 100644 --- a/lib/utils/serial/Kconfig +++ b/lib/utils/serial/Kconfig @@ -79,4 +79,8 @@ config SERIAL_XILINX_UARTLITE bool "Xilinx UART Lite support" default n +config SERIAL_SEMIHOSTING + bool "Semihosting support" + default n + endmenu diff --git a/lib/utils/serial/objects.mk b/lib/utils/serial/objects.mk index efb1d9e..98f3f9a 100644 --- a/lib/utils/serial/objects.mk +++ b/lib/utils/serial/objects.mk @@ -41,3 +41,4 @@ libsbiutils-objs-$(CONFIG_SERIAL_SIFIVE) += serial/sifive-uart.o libsbiutils-objs-$(CONFIG_SERIAL_LITEX) += serial/litex-uart.o libsbiutils-objs-$(CONFIG_SERIAL_UART8250) += serial/uart8250.o libsbiutils-objs-$(CONFIG_SERIAL_XILINX_UARTLITE) += serial/xlnx-uartlite.o +libsbiutils-objs-$(CONFIG_SERIAL_SEMIHOSTING) += serial/semihosting.o diff --git a/lib/utils/serial/semihosting.c b/lib/utils/serial/semihosting.c new file mode 100644 index 0000000..7298049 --- /dev/null +++ b/lib/utils/serial/semihosting.c @@ -0,0 +1,177 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel <apatel@ventanamicro.com> + * Kautuk Consul <kconsul@ventanamicro.com> + */ + +#include <sbi/sbi_console.h> +#include <sbi/sbi_string.h> +#include <sbi/sbi_error.h> +#include <sbi_utils/serial/semihosting.h> + +#define SYSOPEN 0x01 +#define SYSWRITEC 0x03 +#define SYSREAD 0x06 +#define SYSREADC 0x07 +#define SYSERRNO 0x13 + +static long semihosting_trap(int sysnum, void *addr) +{ + register int ret asm ("a0") = sysnum; + register void *param0 asm ("a1") = addr; + + asm volatile ( + "\t.option push\n" + "\t.option norvc\n" + "\tj 1f\n" + "\t.align 4\n" + "\t1: slli zero, zero, 0x1f\n" + "\tebreak\n" + "\tsrai zero, zero, 7\n" + "\t.option pop\n" + : "+r" (ret) : "r" (param0) : "memory"); + + return ret; +} + +static bool _semihosting_enabled = true; +static bool try_semihosting = true; + +bool semihosting_enabled(void) +{ + register int ret asm ("a0") = SYSERRNO; + register void *param0 asm ("a1") = NULL; + unsigned long tmp = 0; + + if (!try_semihosting) + return _semihosting_enabled; + + asm volatile ( + "\t.option push\n" + "\t.option norvc\n" + + "\tj _semihost_test_vector_next\n" + "\t.align 4\n" + "\t_semihost_test_vector:\n" + "\t\tcsrr %[en], mepc\n" + "\t\taddi %[en], %[en], 4\n" + "\t\tcsrw mepc, %[en]\n" + "\t\tadd %[en], zero, zero\n" + "\t\tmret\n" + "\t_semihost_test_vector_next:\n" + + "\tla %[tmp], _semihost_test_vector\n" + "\tcsrrw %[tmp], mtvec, %[tmp]\n" + "\tj 1f\n" + "\t.align 4\n" + "\t1: slli zero, zero, 0x1f\n" + "\tebreak\n" + "\tsrai zero, zero, 7\n" + "\tcsrw mtvec, %[tmp]\n" + + "\t.option pop\n" + : [tmp] "+r" (tmp), [en] "+r" (_semihosting_enabled), + [ret] "+r" (ret) + : "r" (param0) : "memory"); + + try_semihosting = false; + return _semihosting_enabled; +} + +static int semihosting_errno(void) +{ + long ret = semihosting_trap(SYSERRNO, NULL); + + if (ret > 0) + return -ret; + return SBI_EIO; +} + +static int semihosting_infd = SBI_ENODEV; + +static long semihosting_open(const char *fname, enum semihosting_open_mode mode) +{ + long fd; + struct semihosting_open_s { + const char *fname; + unsigned long mode; + size_t len; + } open; + + open.fname = fname; + open.len = sbi_strlen(fname); + open.mode = mode; + + /* Open the file on the host */ + fd = semihosting_trap(SYSOPEN, &open); + if (fd == -1) + return semihosting_errno(); + return fd; +} + +/** + * struct semihosting_rdwr_s - Arguments for read and write + * @fd: A file descriptor returned from semihosting_open() + * @memp: Pointer to a buffer of memory of at least @len bytes + * @len: The number of bytes to read or write + */ +struct semihosting_rdwr_s { + long fd; + void *memp; + size_t len; +}; + +static long semihosting_read(long fd, void *memp, size_t len) +{ + long ret; + struct semihosting_rdwr_s read; + + read.fd = fd; + read.memp = memp; + read.len = len; + + ret = semihosting_trap(SYSREAD, &read); + if (ret < 0) + return semihosting_errno(); + return len - ret; +} + +/* clang-format on */ + +static void semihosting_putc(char ch) +{ + semihosting_trap(SYSWRITEC, &ch); +} + +static int semihosting_getc(void) +{ + char ch = 0; + int ret; + + if (semihosting_infd < 0) { + ch = semihosting_trap(SYSREADC, NULL); + ret = ch > -1 ? ch : -1; + } else + ret = semihosting_read(semihosting_infd, &ch, 1) > 0 ? ch : -1; + + return ret; +} + +static struct sbi_console_device semihosting_console = { + .name = "semihosting", + .console_putc = semihosting_putc, + .console_getc = semihosting_getc +}; + +int semihosting_init(void) +{ + semihosting_infd = semihosting_open(":tt", MODE_READ); + + sbi_console_set_device(&semihosting_console); + + return 0; +} diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index e324173..c95b7fa 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -28,3 +28,4 @@ CONFIG_FDT_SERIAL_UART8250=y CONFIG_FDT_SERIAL_XILINX_UARTLITE=y CONFIG_FDT_TIMER=y CONFIG_FDT_TIMER_MTIMER=y +CONFIG_SERIAL_SEMIHOSTING=y diff --git a/platform/generic/platform.c b/platform/generic/platform.c index cc3620f..bf51aba 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -23,6 +23,7 @@ #include <sbi_utils/timer/fdt_timer.h> #include <sbi_utils/ipi/fdt_ipi.h> #include <sbi_utils/reset/fdt_reset.h> +#include <sbi_utils/serial/semihosting.h> /* List of platform override modules generated at compile time */ extern const struct platform_override *platform_override_modules[]; @@ -242,6 +243,14 @@ static uint64_t generic_pmu_xlate_to_mhpmevent(uint32_t event_idx, return evt_val; } +static int generic_console_init(void) +{ + if (semihosting_enabled()) + return semihosting_init(); + else + return fdt_serial_init(); +} + const struct sbi_platform_operations platform_ops = { .nascent_init = generic_nascent_init, .early_init = generic_early_init, @@ -249,7 +258,7 @@ const struct sbi_platform_operations platform_ops = { .early_exit = generic_early_exit, .final_exit = generic_final_exit, .domains_init = generic_domains_init, - .console_init = fdt_serial_init, + .console_init = generic_console_init, .irqchip_init = fdt_irqchip_init, .irqchip_exit = fdt_irqchip_exit, .ipi_init = fdt_ipi_init,