Merge tag 'u-boot-stm32-20221207' of https://source.denx.de/u-boot/custodians/u-boot-stm
authorTom Rini <trini@konsulko.com>
Thu, 8 Dec 2022 16:25:08 +0000 (11:25 -0500)
committerTom Rini <trini@konsulko.com>
Thu, 8 Dec 2022 16:25:08 +0000 (11:25 -0500)
- Drop MMCI interrupt-names in STM32H743, STM32MP15 and STM322MP13 DT

DHSOM:
  - Enable assorted ST specific commands
  - Add version variable
  - Add boot counter
STM32MP13:
  - Add sdmmc cd-gpios for STM32MP135F-DK
  - Add clock & reset support
STM32 ADC:
  - Split channel init into several routines
  - Add support of generic channels binding

24 files changed:
arch/Kconfig
arch/arm/Kconfig
arch/arm/dts/sama7g5-pinfunc.h
arch/arm/lib/semihosting.c
arch/riscv/include/asm/spl.h
arch/riscv/lib/Makefile
arch/riscv/lib/interrupts.c
arch/riscv/lib/semihosting.c [new file with mode: 0644]
arch/sandbox/cpu/sdl.c
arch/sandbox/include/asm/test.h
cmd/sound.c
common/spl/Kconfig
doc/usage/cmd/sound.rst [new file with mode: 0644]
doc/usage/index.rst
drivers/sound/sandbox.c
drivers/sound/sound.c
drivers/usb/gadget/f_dfu.c
drivers/usb/gadget/rndis.c
include/dfu.h
include/semihosting.h
lib/Kconfig
lib/Makefile
lib/semihosting.c [new file with mode: 0644]
test/dm/sound.c

index ae39716..102956d 100644 (file)
@@ -111,7 +111,7 @@ config RISCV
        select SUPPORT_OF_CONTROL
        select OF_CONTROL
        select DM
-       select SPL_SEPARATE_BSS if SPL
+       imply SPL_SEPARATE_BSS if SPL
        imply DM_SERIAL
        imply DM_ETH
        imply DM_EVENT
index 3f68d09..cac4fa0 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 b77185f..a17707b 100644 (file)
 #define PIN_PD8__GPIO                  PINMUX_PIN(PIN_PD8, 0, 0)
 #define PIN_PD8__SDMMC2_DAT3           PINMUX_PIN(PIN_PD8, 1, 1)
 #define PIN_PD8__I2SMCC0_DIN0          PINMUX_PIN(PIN_PD8, 3, 1)
-#define PIN_PD8__A11_NANDCLE           PINMUX_PIN(PIN_PD8, 4, 2)
+#define PIN_PD8__A22_NANDCLE           PINMUX_PIN(PIN_PD8, 4, 2)
 #define PIN_PD8__TIOA2                 PINMUX_PIN(PIN_PD8, 5, 2)
 #define PIN_PD8__FLEXCOM11_IO0         PINMUX_PIN(PIN_PD8, 6, 5)
 #define PIN_PD9                                105
index 939c0f7..7b7669b 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 e8a94fc..2898a77 100644 (file)
@@ -25,6 +25,7 @@ enum {
        BOOT_DEVICE_DFU,
        BOOT_DEVICE_XIP,
        BOOT_DEVICE_BOOTROM,
+       BOOT_DEVICE_SMH,
        BOOT_DEVICE_NONE
 };
 
index d6a8ae9..e5a81ba 100644 (file)
@@ -42,3 +42,5 @@ extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC)
 obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMSET) += memset.o
 obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMMOVE) += memmove.o
 obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o
+
+obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += semihosting.o
index 100be2e..e966afa 100644 (file)
@@ -9,6 +9,7 @@
  * Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
  */
 
+#include <linux/compat.h>
 #include <common.h>
 #include <efi_loader.h>
 #include <hang.h>
@@ -17,6 +18,7 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/encoding.h>
+#include <semihosting.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -149,6 +151,29 @@ ulong handle_trap(ulong cause, ulong epc, ulong tval, struct pt_regs *regs)
        /* An UEFI application may have changed gd. Restore U-Boot's gd. */
        efi_restore_gd();
 
+       if (cause == CAUSE_BREAKPOINT &&
+           CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)) {
+               ulong pre_addr = epc - 4, post_addr = epc + 4;
+
+               /* Check for prior and post addresses to be in same page. */
+               if ((pre_addr & ~(PAGE_SIZE - 1)) ==
+                       (post_addr & ~(PAGE_SIZE - 1))) {
+                       u32 pre = *(u32 *)pre_addr;
+                       u32 post = *(u32 *)post_addr;
+
+                       /* Check for semihosting, i.e.:
+                        * slli    zero,zero,0x1f
+                        * ebreak
+                        * srai    zero,zero,0x7
+                        */
+                       if (pre == 0x01f01013 && post == 0x40705013) {
+                               disable_semihosting();
+                               epc += 4;
+                               return epc;
+                       }
+               }
+       }
+
        is_irq = (cause & MCAUSE_INT);
        irq = (cause & ~MCAUSE_INT);
 
diff --git a/arch/riscv/lib/semihosting.c b/arch/riscv/lib/semihosting.c
new file mode 100644 (file)
index 0000000..d6593b0
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Ventana Micro Systems Inc.
+ */
+
+#include <common.h>
+
+long smh_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;
+}
index f4ca36b..2c570ed 100644 (file)
@@ -441,7 +441,6 @@ void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
 {
        struct buf_info *buf;
        int avail;
-       bool have_data = false;
        int i;
 
        for (i = 0; i < 2; i++) {
@@ -453,10 +452,9 @@ void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
                }
                if (avail > len)
                        avail = len;
-               have_data = true;
 
-               SDL_MixAudio(stream, buf->data + buf->pos, avail,
-                            SDL_MIX_MAXVOLUME);
+               memcpy(stream, buf->data + buf->pos, avail);
+               stream += avail;
                buf->pos += avail;
                len -= avail;
 
@@ -466,7 +464,8 @@ void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
                else
                        break;
        }
-       sdl.stopping = !have_data;
+       memset(stream, 0, len);
+       sdl.stopping = !!len;
 }
 
 int sandbox_sdl_sound_init(int rate, int channels)
@@ -484,7 +483,7 @@ int sandbox_sdl_sound_init(int rate, int channels)
        wanted.freq = rate;
        wanted.format = AUDIO_S16;
        wanted.channels = channels;
-       wanted.samples = 1024;  /* Good low-latency value for callback */
+       wanted.samples = 960;  /* Good low-latency value for callback */
        wanted.callback = sandbox_sdl_fill_audio;
        wanted.userdata = NULL;
 
index 0406085..568738c 100644 (file)
@@ -189,6 +189,16 @@ int sandbox_get_setup_called(struct udevice *dev);
 int sandbox_get_sound_active(struct udevice *dev);
 
 /**
+ * sandbox_get_sound_count() - Read back the count of the sound data so far
+ *
+ * This data is provided to the sandbox driver by the sound play() method.
+ *
+ * @dev: Device to check
+ * Return: count of audio data
+ */
+int sandbox_get_sound_count(struct udevice *dev);
+
+/**
  * sandbox_get_sound_sum() - Read back the sum of the sound data so far
  *
  * This data is provided to the sandbox driver by the sound play() method.
index f82f2aa..20ac3f7 100644 (file)
@@ -86,5 +86,5 @@ U_BOOT_CMD(
        sound, 4, 1, do_sound,
        "sound sub-system",
        "init - initialise the sound driver\n"
-       "sound play [len] [freq] - play a sound for len ms at freq hz\n"
+       "sound play [len [freq]] - play a sound for len ms at freq Hz\n"
 );
index fef01bd..6c4848f 100644 (file)
@@ -691,7 +691,7 @@ config SPL_FS_FAT
 
 config SPL_FS_LOAD_PAYLOAD_NAME
        string "File to load for U-Boot from the filesystem"
-       depends on SPL_FS_EXT4 || SPL_FS_FAT || SPL_FS_SQUASHFS
+       depends on SPL_FS_EXT4 || SPL_FS_FAT || SPL_FS_SQUASHFS || SPL_SEMIHOSTING
        default "tispl.bin" if SYS_K3_SPL_ATF
        default "u-boot.itb" if SPL_LOAD_FIT
        default "u-boot.img"
diff --git a/doc/usage/cmd/sound.rst b/doc/usage/cmd/sound.rst
new file mode 100644 (file)
index 0000000..d3fac24
--- /dev/null
@@ -0,0 +1,41 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright 2022, Heinrich Schuchardt <xypron.glpk@gmx.de>
+
+sound command
+=============
+
+Synopsis
+--------
+
+::
+
+    sound init
+    sound play [len [freq]]
+
+Description
+-----------
+
+The *sound* command is used to play a beep sound.
+
+sound init
+    initializes the sound driver.
+
+sound play
+    plays a square wave sound. It does not depend on previously calling
+    *sound init*.
+
+len
+    duration of the sound in ms, defaults to 1000 ms
+
+freq
+    frequency of the sound in Hz, defaults to 400 Hz
+
+Configuration
+-------------
+
+The sound command is enabled by CONFIG_CMD_SOUND=y.
+
+Return value
+------------
+
+The return value $? is 0 (true) if the command succeeds, 1 (false) otherwise.
index 0bc8288..bbd40a6 100644 (file)
@@ -73,6 +73,7 @@ Shell commands
    cmd/scp03
    cmd/setexpr
    cmd/size
+   cmd/sound
    cmd/temperature
    cmd/tftpput
    cmd/true
index 4a2c87a..c6cbd81 100644 (file)
@@ -29,6 +29,7 @@ struct sandbox_i2s_priv {
 struct sandbox_sound_priv {
        int setup_called;       /* Incremented when setup() method is called */
        bool active;            /* TX data is being sent */
+       int count;              /* Use to count the provided audio data */
        int sum;                /* Use to sum the provided audio data */
        bool allow_beep;        /* true to allow the start_beep() interface */
        int frequency_hz;       /* Beep frequency if active, else 0 */
@@ -68,6 +69,13 @@ int sandbox_get_sound_active(struct udevice *dev)
        return priv->active;
 }
 
+int sandbox_get_sound_count(struct udevice *dev)
+{
+       struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+       return priv->count;
+}
+
 int sandbox_get_sound_sum(struct udevice *dev)
 {
        struct sandbox_sound_priv *priv = dev_get_priv(dev);
@@ -168,6 +176,7 @@ static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size)
 
        for (i = 0; i < data_size; i++)
                priv->sum += ((uint8_t *)data)[i];
+       priv->count += data_size;
 
        return i2s_tx_data(uc_priv->i2s, data, data_size);
 }
index 041dfdc..c0fc50c 100644 (file)
@@ -15,7 +15,10 @@ void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
        const int period = freq ? sample_rate / freq : 0;
        const int half = period / 2;
 
-       assert(freq);
+       if (!half) {
+               memset(data, 0, size);
+               return;
+       }
 
        /* Make sure we don't overflow our buffer */
        if (size % 2)
index 33ef62f..44877df 100644 (file)
@@ -325,7 +325,7 @@ static int state_dfu_idle(struct f_dfu *f_dfu,
 
        switch (ctrl->bRequest) {
        case USB_REQ_DFU_DNLOAD:
-               if (ctrl->bRequestType == USB_DIR_OUT) {
+               if (!(ctrl->bRequestType & USB_DIR_IN)) {
                        if (len == 0) {
                                f_dfu->dfu_state = DFU_STATE_dfuERROR;
                                value = RET_STALL;
@@ -337,7 +337,7 @@ static int state_dfu_idle(struct f_dfu *f_dfu,
                }
                break;
        case USB_REQ_DFU_UPLOAD:
-               if (ctrl->bRequestType == USB_DIR_IN) {
+               if (ctrl->bRequestType & USB_DIR_IN) {
                        f_dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
                        f_dfu->blk_seq_num = 0;
                        value = handle_upload(req, len);
@@ -436,7 +436,7 @@ static int state_dfu_dnload_idle(struct f_dfu *f_dfu,
 
        switch (ctrl->bRequest) {
        case USB_REQ_DFU_DNLOAD:
-               if (ctrl->bRequestType == USB_DIR_OUT) {
+               if (!(ctrl->bRequestType & USB_DIR_IN)) {
                        f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
                        f_dfu->blk_seq_num = w_value;
                        value = handle_dnload(gadget, len);
@@ -527,7 +527,7 @@ static int state_dfu_upload_idle(struct f_dfu *f_dfu,
 
        switch (ctrl->bRequest) {
        case USB_REQ_DFU_UPLOAD:
-               if (ctrl->bRequestType == USB_DIR_IN) {
+               if (ctrl->bRequestType & USB_DIR_IN) {
                        /* state transition if less data then requested */
                        f_dfu->blk_seq_num = w_value;
                        value = handle_upload(req, len);
index 13c327e..3948f2c 100644 (file)
@@ -855,14 +855,17 @@ static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
        rndis_set_cmplt_type    *resp;
        rndis_resp_t            *r;
 
+       BufLength = get_unaligned_le32(&buf->InformationBufferLength);
+       BufOffset = get_unaligned_le32(&buf->InformationBufferOffset);
+       if ((BufOffset > RNDIS_MAX_TOTAL_SIZE - 8) ||
+           (BufLength > RNDIS_MAX_TOTAL_SIZE - 8 - BufOffset))
+               return -EINVAL;
+
        r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_set_cmplt_type *) r->buf;
 
-       BufLength = get_unaligned_le32(&buf->InformationBufferLength);
-       BufOffset = get_unaligned_le32(&buf->InformationBufferOffset);
-
 #ifdef VERBOSE
        debug("%s: Length: %d\n", __func__, BufLength);
        debug("%s: Offset: %d\n", __func__, BufOffset);
index dcb9cd9..0792222 100644 (file)
@@ -495,7 +495,7 @@ static inline int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr,
 }
 #endif
 
-#ifdef CONFIG_DFU_VIRT
+#if CONFIG_IS_ENABLED(DFU_VIRT)
 int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr,
                         char **argv, int argc);
 int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset,
index f1f7346..4e844cb 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 6abe1d0..3c5a4ab 100644 (file)
@@ -71,6 +71,53 @@ config HAVE_PRIVATE_LIBGCC
 config LIB_UUID
        bool
 
+config SEMIHOSTING
+       bool "Support semihosting"
+       depends on ARM || RISCV
+       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 || RISCV)
+       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 || RISCV)
+       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 || RISCV)
+       select ARMV8_SPL_EXCEPTION_VECTORS if 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 PRINTF
        bool
        default y
index f2cfd1e..d77b33e 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);
+}
index b73f6ab..15d545a 100644 (file)
@@ -26,8 +26,19 @@ static int dm_test_sound(struct unit_test_state *uts)
        ut_asserteq(0, sandbox_get_setup_called(dev));
 
        ut_assertok(sound_beep(dev, 1, 100));
+       ut_asserteq(48, sandbox_get_sound_count(dev));
        ut_asserteq(4560, sandbox_get_sound_sum(dev));
        ut_assertok(sound_beep(dev, 1, 100));
+       ut_asserteq(96, sandbox_get_sound_count(dev));
+       ut_asserteq(9120, sandbox_get_sound_sum(dev));
+       ut_assertok(sound_beep(dev, 1, -100));
+       ut_asserteq(144, sandbox_get_sound_count(dev));
+       ut_asserteq(9120, sandbox_get_sound_sum(dev));
+       ut_assertok(sound_beep(dev, 1, 0));
+       ut_asserteq(192, sandbox_get_sound_count(dev));
+       ut_asserteq(9120, sandbox_get_sound_sum(dev));
+       ut_assertok(sound_beep(dev, 1, INT_MAX));
+       ut_asserteq(240, sandbox_get_sound_count(dev));
        ut_asserteq(9120, sandbox_get_sound_sum(dev));
        ut_asserteq(false, sandbox_get_sound_active(dev));