]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
lib: Add common semihosting library
authorKautuk Consul <kconsul@ventanamicro.com>
Wed, 7 Dec 2022 11:42:34 +0000 (17:12 +0530)
committerLeo Yu-Chi Liang <ycliang@andestech.com>
Thu, 8 Dec 2022 07:15:22 +0000 (15:15 +0800)
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@ventanamicro.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
arch/arm/Kconfig
arch/arm/lib/semihosting.c
include/semihosting.h
lib/Kconfig
lib/Makefile
lib/semihosting.c [new file with mode: 0644]

index 3f68d0988b7f6af150699d17739f56e266daaf2a..cac4fa09fd32c3af29d126dfeaf1c9e9bbb9d522 100644 (file)
@@ -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
index 939c0f75132b26dffa31abce4d9d181b51f6f461..7b7669bed0657f8472cc34a5408843de5ffce3eb 100644 (file)
@@ -5,20 +5,6 @@
  */
 
 #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
 
 /*
  * Macro to force the compiler to *populate* memory (for an array or struct)
@@ -39,7 +25,7 @@
 /*
  * Call the handler
  */
-static long smh_trap(unsigned int sysnum, void *addr)
+long smh_trap(unsigned int sysnum, void *addr)
 {
        register long result asm("r0");
        register void *_addr asm("r1") = addr;
@@ -59,168 +45,3 @@ static long smh_trap(unsigned int sysnum, void *addr)
 
        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);
-}
index f1f73464e4f92993cf9c267fbfcc2f82f2b3373e..4e844cbad87bb1ae6bb365f87f3e7a8aeea445f4 100644 (file)
 #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
index 6abe1d0a863badc503961bb24a6977f2df4d8a23..b8833e018371dd3af833608c0b15cb619e114496 100644 (file)
@@ -71,6 +71,53 @@ config HAVE_PRIVATE_LIBGCC
 config LIB_UUID
        bool
 
+config SEMIHOSTING
+       bool "Support semihosting"
+       depends on ARM
+       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 && ARM
+       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
index f2cfd1e428920573ea1cd8171f26fe94f0b6eaec..d77b33e7f482f813aca78b222b0f86f1cd2f1fd8 100644 (file)
@@ -146,6 +146,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 (file)
index 0000000..831774e
--- /dev/null
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Sean Anderson <sean.anderson@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);
+}