diff options
author | Tom Rini <trini@konsulko.com> | 2022-12-08 08:28:14 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-12-08 08:28:14 -0500 |
commit | 90609198223e9a3e4cf63e4225d3f9a3118171c9 (patch) | |
tree | eb5d1aedd895f082736a27d81f59a74281a87026 | |
parent | 341ba8d94b1c2f98766ad27b4a5b79ecafd2ba47 (diff) | |
parent | 57b9900cd59ad492f74390515901788459f1e8aa (diff) | |
download | u-boot-90609198223e9a3e4cf63e4225d3f9a3118171c9.zip u-boot-90609198223e9a3e4cf63e4225d3f9a3118171c9.tar.gz u-boot-90609198223e9a3e4cf63e4225d3f9a3118171c9.tar.bz2 |
Merge https://source.denx.de/u-boot/custodians/u-boot-riscv
- Kautuk's semihosting patch:
move semihosting library from arm directory to common place and add
RISC-V support
- Zong's Kconfig patch:
use "imply" instead of "select" to allow user to decide if
SPL_SEPARATE_BSS should be selected
-rw-r--r-- | arch/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/Kconfig | 46 | ||||
-rw-r--r-- | arch/arm/lib/semihosting.c | 181 | ||||
-rw-r--r-- | arch/riscv/include/asm/spl.h | 1 | ||||
-rw-r--r-- | arch/riscv/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/riscv/lib/interrupts.c | 25 | ||||
-rw-r--r-- | arch/riscv/lib/semihosting.c | 24 | ||||
-rw-r--r-- | common/spl/Kconfig | 2 | ||||
-rw-r--r-- | include/semihosting.h | 11 | ||||
-rw-r--r-- | lib/Kconfig | 47 | ||||
-rw-r--r-- | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/semihosting.c | 186 |
12 files changed, 301 insertions, 228 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index ae39716..102956d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -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 diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3f68d09..cac4fa0 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 939c0f7..7b7669b 100644 --- a/arch/arm/lib/semihosting.c +++ b/arch/arm/lib/semihosting.c @@ -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); -} diff --git a/arch/riscv/include/asm/spl.h b/arch/riscv/include/asm/spl.h index e8a94fc..2898a77 100644 --- a/arch/riscv/include/asm/spl.h +++ b/arch/riscv/include/asm/spl.h @@ -25,6 +25,7 @@ enum { BOOT_DEVICE_DFU, BOOT_DEVICE_XIP, BOOT_DEVICE_BOOTROM, + BOOT_DEVICE_SMH, BOOT_DEVICE_NONE }; diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index d6a8ae9..e5a81ba 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -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 diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c index 100be2e..e966afa 100644 --- a/arch/riscv/lib/interrupts.c +++ b/arch/riscv/lib/interrupts.c @@ -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 index 0000000..d6593b0 --- /dev/null +++ b/arch/riscv/lib/semihosting.c @@ -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; +} diff --git a/common/spl/Kconfig b/common/spl/Kconfig index fef01bd..6c4848f 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -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/include/semihosting.h b/include/semihosting.h index f1f7346..4e844cb 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 6abe1d0..3c5a4ab 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -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 diff --git a/lib/Makefile b/lib/Makefile index f2cfd1e..d77b33e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -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 index 0000000..831774e --- /dev/null +++ b/lib/semihosting.c @@ -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); +} |