[PATCH v4 1/3] lib: Add common semihosting library
Kautuk Consul
kconsul at ventanamicro.com
Fri Sep 23 06:39:30 CEST 2022
Hi Sean,
On Thu, Sep 22, 2022 at 10:30 PM Sean Anderson <sean.anderson at seco.com> wrote:
>
>
>
> On 9/19/22 7:49 AM, Kautuk Consul wrote:
> > We factor out the arch-independent parts of the ARM semihosting
> > implementation as a common library so that it can be shared
> > with RISC-V.
> >
> > Signed-off-by: Kautuk Consul <kconsul at ventanamicro.com>
> > ---
> > arch/arm/Kconfig | 46 ---------
> > arch/arm/lib/semihosting.c | 181 +-----------------------------------
> > include/semihosting.h | 11 +++
> > lib/Kconfig | 46 +++++++++
> > lib/Makefile | 2 +
> > lib/semihosting.c | 186 +++++++++++++++++++++++++++++++++++++
> > 6 files changed, 246 insertions(+), 226 deletions(-)
> > create mode 100644 lib/semihosting.c
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 82cd456f51..ee6a9fadd9 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -413,52 +413,6 @@ config ARM_SMCCC
> > This should be enabled if U-Boot needs to communicate with system
> > firmware (for example, PSCI) according to SMCCC.
> >
> > -config SEMIHOSTING
> > - bool "Support ARM semihosting"
> > - help
> > - Semihosting is a method for a target to communicate with a host
> > - debugger. It uses special instructions which the debugger will trap
> > - on and interpret. This allows U-Boot to read/write files, print to
> > - the console, and execute arbitrary commands on the host system.
> > -
> > - Enabling this option will add support for reading and writing files
> > - on the host system. If you don't have a debugger attached then trying
> > - to do this will likely cause U-Boot to hang. Say 'n' if you are unsure.
> > -
> > -config SEMIHOSTING_FALLBACK
> > - bool "Recover gracefully when semihosting fails"
> > - depends on SEMIHOSTING && ARM64
> > - default y
> > - help
> > - Normally, if U-Boot makes a semihosting call and no debugger is
> > - attached, then it will panic due to a synchronous abort
> > - exception. This config adds an exception handler which will allow
> > - U-Boot to recover. Say 'y' if unsure.
> > -
> > -config SPL_SEMIHOSTING
> > - bool "Support ARM semihosting in SPL"
> > - depends on SPL
> > - help
> > - Semihosting is a method for a target to communicate with a host
> > - debugger. It uses special instructions which the debugger will trap
> > - on and interpret. This allows U-Boot to read/write files, print to
> > - the console, and execute arbitrary commands on the host system.
> > -
> > - Enabling this option will add support for reading and writing files
> > - on the host system. If you don't have a debugger attached then trying
> > - to do this will likely cause U-Boot to hang. Say 'n' if you are unsure.
> > -
> > -config SPL_SEMIHOSTING_FALLBACK
> > - bool "Recover gracefully when semihosting fails in SPL"
> > - depends on SPL_SEMIHOSTING && ARM64
> > - select ARMV8_SPL_EXCEPTION_VECTORS
> > - default y
> > - help
> > - Normally, if U-Boot makes a semihosting call and no debugger is
> > - attached, then it will panic due to a synchronous abort
> > - exception. This config adds an exception handler which will allow
> > - U-Boot to recover. Say 'y' if unsure.
> > -
> > config SYS_THUMB_BUILD
> > bool "Build U-Boot using the Thumb instruction set"
> > depends on !ARM64
> > diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c
> > index 01d652a6b8..11e7b85ee6 100644
> > --- a/arch/arm/lib/semihosting.c
> > +++ b/arch/arm/lib/semihosting.c
> > @@ -10,25 +10,11 @@
> > * available in silicon now, fastmodel usage makes less sense for them.
> > */
> > #include <common.h>
> > -#include <log.h>
> > -#include <semihosting.h>
> > -
> > -#define SYSOPEN 0x01
> > -#define SYSCLOSE 0x02
> > -#define SYSWRITEC 0x03
> > -#define SYSWRITE0 0x04
> > -#define SYSWRITE 0x05
> > -#define SYSREAD 0x06
> > -#define SYSREADC 0x07
> > -#define SYSISERROR 0x08
> > -#define SYSSEEK 0x0A
> > -#define SYSFLEN 0x0C
> > -#define SYSERRNO 0x13
> >
> > /*
> > * Call the handler
> > */
> > -static noinline long smh_trap(unsigned int sysnum, void *addr)
> > +long smh_trap(unsigned int sysnum, void *addr)
> > {
> > register long result asm("r0");
> > #if defined(CONFIG_ARM64)
> > @@ -41,168 +27,3 @@ static noinline long smh_trap(unsigned int sysnum, void *addr)
> > #endif
> > return result;
> > }
> > -
> > -#if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
> > -static bool _semihosting_enabled = true;
> > -static bool try_semihosting = true;
> > -
> > -bool semihosting_enabled(void)
> > -{
> > - if (try_semihosting) {
> > - smh_trap(SYSERRNO, NULL);
> > - try_semihosting = false;
> > - }
> > -
> > - return _semihosting_enabled;
> > -}
> > -
> > -void disable_semihosting(void)
> > -{
> > - _semihosting_enabled = false;
> > -}
> > -#endif
> > -
> > -/**
> > - * smh_errno() - Read the host's errno
> > - *
> > - * This gets the value of the host's errno and negates it. The host's errno may
> > - * or may not be set, so only call this function if a previous semihosting call
> > - * has failed.
> > - *
> > - * Return: a negative error value
> > - */
> > -static int smh_errno(void)
> > -{
> > - long ret = smh_trap(SYSERRNO, NULL);
> > -
> > - if (ret > 0 && ret < INT_MAX)
> > - return -ret;
> > - return -EIO;
> > -}
> > -
> > -long smh_open(const char *fname, enum smh_open_mode mode)
> > -{
> > - long fd;
> > - struct smh_open_s {
> > - const char *fname;
> > - unsigned long mode;
> > - size_t len;
> > - } open;
> > -
> > - debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
> > -
> > - open.fname = fname;
> > - open.len = strlen(fname);
> > - open.mode = mode;
> > -
> > - /* Open the file on the host */
> > - fd = smh_trap(SYSOPEN, &open);
> > - if (fd == -1)
> > - return smh_errno();
> > - return fd;
> > -}
> > -
> > -/**
> > - * struct smg_rdwr_s - Arguments for read and write
> > - * @fd: A file descriptor returned from smh_open()
> > - * @memp: Pointer to a buffer of memory of at least @len bytes
> > - * @len: The number of bytes to read or write
> > - */
> > -struct smh_rdwr_s {
> > - long fd;
> > - void *memp;
> > - size_t len;
> > -};
> > -
> > -long smh_read(long fd, void *memp, size_t len)
> > -{
> > - long ret;
> > - struct smh_rdwr_s read;
> > -
> > - debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
> > -
> > - read.fd = fd;
> > - read.memp = memp;
> > - read.len = len;
> > -
> > - ret = smh_trap(SYSREAD, &read);
> > - if (ret < 0)
> > - return smh_errno();
> > - return len - ret;
> > -}
> > -
> > -long smh_write(long fd, const void *memp, size_t len, ulong *written)
> > -{
> > - long ret;
> > - struct smh_rdwr_s write;
> > -
> > - debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
> > -
> > - write.fd = fd;
> > - write.memp = (void *)memp;
> > - write.len = len;
> > -
> > - ret = smh_trap(SYSWRITE, &write);
> > - *written = len - ret;
> > - if (ret)
> > - return smh_errno();
> > - return 0;
> > -}
> > -
> > -long smh_close(long fd)
> > -{
> > - long ret;
> > -
> > - debug("%s: fd %ld\n", __func__, fd);
> > -
> > - ret = smh_trap(SYSCLOSE, &fd);
> > - if (ret == -1)
> > - return smh_errno();
> > - return 0;
> > -}
> > -
> > -long smh_flen(long fd)
> > -{
> > - long ret;
> > -
> > - debug("%s: fd %ld\n", __func__, fd);
> > -
> > - ret = smh_trap(SYSFLEN, &fd);
> > - if (ret == -1)
> > - return smh_errno();
> > - return ret;
> > -}
> > -
> > -long smh_seek(long fd, long pos)
> > -{
> > - long ret;
> > - struct smh_seek_s {
> > - long fd;
> > - long pos;
> > - } seek;
> > -
> > - debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
> > -
> > - seek.fd = fd;
> > - seek.pos = pos;
> > -
> > - ret = smh_trap(SYSSEEK, &seek);
> > - if (ret)
> > - return smh_errno();
> > - return 0;
> > -}
> > -
> > -int smh_getc(void)
> > -{
> > - return smh_trap(SYSREADC, NULL);
> > -}
> > -
> > -void smh_putc(char ch)
> > -{
> > - smh_trap(SYSWRITEC, &ch);
> > -}
> > -
> > -void smh_puts(const char *s)
> > -{
> > - smh_trap(SYSWRITE0, (char *)s);
> > -}
> > diff --git a/include/semihosting.h b/include/semihosting.h
> > index f1f73464e4..4e844cbad8 100644
> > --- a/include/semihosting.h
> > +++ b/include/semihosting.h
> > @@ -17,6 +17,17 @@
> > #define SMH_T32_SVC 0xDFAB
> > #define SMH_T32_HLT 0xBABC
> >
> > +/**
> > + * smh_trap() - ARCH-specific semihosting call.
> > + *
> > + * Semihosting library/driver can use this function to do the
> > + * actual semihosting calls.
> > + *
> > + * Return: Error code defined by semihosting spec.
> > + */
> > +
> > +long smh_trap(unsigned int sysnum, void *addr);
> > +
> > #if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
> > /**
> > * semihosting_enabled() - Determine whether semihosting is supported
> > diff --git a/lib/Kconfig b/lib/Kconfig
> > index 6121c80dc8..97920e7552 100644
> > --- a/lib/Kconfig
> > +++ b/lib/Kconfig
> > @@ -71,6 +71,52 @@ config HAVE_PRIVATE_LIBGCC
> > config LIB_UUID
> > bool
> >
> > +config SEMIHOSTING
> > + bool "Support semihosting"
>
> Should probably depend on ARM (and in the next patch RISCV).
I did think of this. The fallback part appears to be arch-dependent.
But can we make the main SEMIHOSTING options as arch-independent
as that was the way they were before ?
>
> > + help
> > + Semihosting is a method for a target to communicate with a host
> > + debugger. It uses special instructions which the debugger will trap
> > + on and interpret. This allows U-Boot to read/write files, print to
> > + the console, and execute arbitrary commands on the host system.
> > +
> > + Enabling this option will add support for reading and writing files
> > + on the host system. If you don't have a debugger attached then trying
> > + to do this will likely cause U-Boot to hang. Say 'n' if you are unsure.
> > +
> > +config SEMIHOSTING_FALLBACK
> > + bool "Recover gracefully when semihosting fails"
> > + depends on SEMIHOSTING && ARM64
> > + default y
> > + help
> > + Normally, if U-Boot makes a semihosting call and no debugger is
> > + attached, then it will panic due to a synchronous abort
> > + exception. This config adds an exception handler which will allow
> > + U-Boot to recover. Say 'y' if unsure.
> > +
> > +config SPL_SEMIHOSTING
> > + bool "Support semihosting in SPL"
> > + depends on SPL
>
> ditto
>
> > + help
> > + Semihosting is a method for a target to communicate with a host
> > + debugger. It uses special instructions which the debugger will trap
> > + on and interpret. This allows U-Boot to read/write files, print to
> > + the console, and execute arbitrary commands on the host system.
> > +
> > + Enabling this option will add support for reading and writing files
> > + on the host system. If you don't have a debugger attached then trying
> > + to do this will likely cause U-Boot to hang. Say 'n' if you are unsure.
> > +
> > +config SPL_SEMIHOSTING_FALLBACK
> > + bool "Recover gracefully when semihosting fails in SPL"
> > + depends on SPL_SEMIHOSTING && ARM64
> > + select ARMV8_SPL_EXCEPTION_VECTORS
> > + default y
> > + help
> > + Normally, if U-Boot makes a semihosting call and no debugger is
> > + attached, then it will panic due to a synchronous abort
> > + exception. This config adds an exception handler which will allow
> > + U-Boot to recover. Say 'y' if unsure.
> > +
> > config PRINTF
> > bool
> > default y
> > diff --git a/lib/Makefile b/lib/Makefile
> > index e3deb15287..134c4319cd 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -145,6 +145,8 @@ obj-y += date.o
> > obj-y += rtc-lib.o
> > obj-$(CONFIG_LIB_ELF) += elf.o
> >
> > +obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += semihosting.o
> > +
> > #
> > # Build a fast OID lookup registry from include/linux/oid_registry.h
> > #
> > diff --git a/lib/semihosting.c b/lib/semihosting.c
> > new file mode 100644
> > index 0000000000..831774e356
> > --- /dev/null
> > +++ b/lib/semihosting.c
> > @@ -0,0 +1,186 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2022 Sean Anderson <sean.anderson at seco.com>
> > + * Copyright 2014 Broadcom Corporation
> > + */
> > +
> > +#include <common.h>
> > +#include <log.h>
> > +#include <semihosting.h>
> > +
> > +#define SYSOPEN 0x01
> > +#define SYSCLOSE 0x02
> > +#define SYSWRITEC 0x03
> > +#define SYSWRITE0 0x04
> > +#define SYSWRITE 0x05
> > +#define SYSREAD 0x06
> > +#define SYSREADC 0x07
> > +#define SYSISERROR 0x08
> > +#define SYSSEEK 0x0A
> > +#define SYSFLEN 0x0C
> > +#define SYSERRNO 0x13
> > +
> > +#if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
> > +static bool _semihosting_enabled = true;
> > +static bool try_semihosting = true;
> > +
> > +bool semihosting_enabled(void)
> > +{
> > + if (try_semihosting) {
> > + smh_trap(SYSERRNO, NULL);
> > + try_semihosting = false;
> > + }
> > +
> > + return _semihosting_enabled;
> > +}
> > +
> > +void disable_semihosting(void)
> > +{
> > + _semihosting_enabled = false;
> > +}
> > +#endif
> > +
> > +/**
> > + * smh_errno() - Read the host's errno
> > + *
> > + * This gets the value of the host's errno and negates it. The host's errno may
> > + * or may not be set, so only call this function if a previous semihosting call
> > + * has failed.
> > + *
> > + * Return: a negative error value
> > + */
> > +static int smh_errno(void)
> > +{
> > + long ret = smh_trap(SYSERRNO, NULL);
> > +
> > + if (ret > 0 && ret < INT_MAX)
> > + return -ret;
> > + return -EIO;
> > +}
> > +
> > +long smh_open(const char *fname, enum smh_open_mode mode)
> > +{
> > + long fd;
> > + struct smh_open_s {
> > + const char *fname;
> > + unsigned long mode;
> > + size_t len;
> > + } open;
> > +
> > + debug("%s: file \'%s\', mode \'%u\'\n", __func__, fname, mode);
> > +
> > + open.fname = fname;
> > + open.len = strlen(fname);
> > + open.mode = mode;
> > +
> > + /* Open the file on the host */
> > + fd = smh_trap(SYSOPEN, &open);
> > + if (fd == -1)
> > + return smh_errno();
> > + return fd;
> > +}
> > +
> > +/**
> > + * struct smg_rdwr_s - Arguments for read and write
> > + * @fd: A file descriptor returned from smh_open()
> > + * @memp: Pointer to a buffer of memory of at least @len bytes
> > + * @len: The number of bytes to read or write
> > + */
> > +struct smh_rdwr_s {
> > + long fd;
> > + void *memp;
> > + size_t len;
> > +};
> > +
> > +long smh_read(long fd, void *memp, size_t len)
> > +{
> > + long ret;
> > + struct smh_rdwr_s read;
> > +
> > + debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
> > +
> > + read.fd = fd;
> > + read.memp = memp;
> > + read.len = len;
> > +
> > + ret = smh_trap(SYSREAD, &read);
> > + if (ret < 0)
> > + return smh_errno();
> > + return len - ret;
> > +}
> > +
> > +long smh_write(long fd, const void *memp, size_t len, ulong *written)
> > +{
> > + long ret;
> > + struct smh_rdwr_s write;
> > +
> > + debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
> > +
> > + write.fd = fd;
> > + write.memp = (void *)memp;
> > + write.len = len;
> > +
> > + ret = smh_trap(SYSWRITE, &write);
> > + *written = len - ret;
> > + if (ret)
> > + return smh_errno();
> > + return 0;
> > +}
> > +
> > +long smh_close(long fd)
> > +{
> > + long ret;
> > +
> > + debug("%s: fd %ld\n", __func__, fd);
> > +
> > + ret = smh_trap(SYSCLOSE, &fd);
> > + if (ret == -1)
> > + return smh_errno();
> > + return 0;
> > +}
> > +
> > +long smh_flen(long fd)
> > +{
> > + long ret;
> > +
> > + debug("%s: fd %ld\n", __func__, fd);
> > +
> > + ret = smh_trap(SYSFLEN, &fd);
> > + if (ret == -1)
> > + return smh_errno();
> > + return ret;
> > +}
> > +
> > +long smh_seek(long fd, long pos)
> > +{
> > + long ret;
> > + struct smh_seek_s {
> > + long fd;
> > + long pos;
> > + } seek;
> > +
> > + debug("%s: fd %ld pos %ld\n", __func__, fd, pos);
> > +
> > + seek.fd = fd;
> > + seek.pos = pos;
> > +
> > + ret = smh_trap(SYSSEEK, &seek);
> > + if (ret)
> > + return smh_errno();
> > + return 0;
> > +}
> > +
> > +int smh_getc(void)
> > +{
> > + return smh_trap(SYSREADC, NULL);
> > +}
> > +
> > +void smh_putc(char ch)
> > +{
> > + smh_trap(SYSWRITEC, &ch);
> > +}
> > +
> > +void smh_puts(const char *s)
> > +{
> > + smh_trap(SYSWRITE0, (char *)s);
> > +}
> >
>
> Other than that,
>
> Reviewed-by: Sean Anderson <sean.anderson at seco.com>
More information about the U-Boot
mailing list