lib: utils/serial: add semihosting support
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> Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
parent
49372f2691
commit
7f09fba86e
|
@ -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
|
|
@ -79,4 +79,8 @@ config SERIAL_XILINX_UARTLITE
|
|||
bool "Xilinx UART Lite support"
|
||||
default n
|
||||
|
||||
config SERIAL_SEMIHOSTING
|
||||
bool "Semihosting support"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* 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 (
|
||||
" .align 4\n"
|
||||
" .option push\n"
|
||||
" .option norvc\n"
|
||||
|
||||
" slli zero, zero, 0x1f\n"
|
||||
" ebreak\n"
|
||||
" srai zero, zero, 7\n"
|
||||
|
||||
" .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 (
|
||||
" .align 4\n"
|
||||
" .option push\n"
|
||||
" .option norvc\n"
|
||||
|
||||
" j _semihost_test_vector_next\n"
|
||||
" .align 4\n"
|
||||
"_semihost_test_vector:\n"
|
||||
" csrr %[en], mepc\n"
|
||||
" addi %[en], %[en], 4\n"
|
||||
" csrw mepc, %[en]\n"
|
||||
" add %[en], zero, zero\n"
|
||||
" mret\n"
|
||||
"_semihost_test_vector_next:\n"
|
||||
|
||||
" la %[tmp], _semihost_test_vector\n"
|
||||
" csrrw %[tmp], mtvec, %[tmp]\n"
|
||||
" .align 4\n"
|
||||
" slli zero, zero, 0x1f\n"
|
||||
" ebreak\n"
|
||||
" srai zero, zero, 7\n"
|
||||
" csrw mtvec, %[tmp]\n"
|
||||
|
||||
" .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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue