- 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
This commit is contained in:
Tom Rini 2022-12-08 08:28:14 -05:00
commit 9060919822
12 changed files with 301 additions and 228 deletions

View 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

View 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

View 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);
}

View file

@ -25,6 +25,7 @@ enum {
BOOT_DEVICE_DFU,
BOOT_DEVICE_XIP,
BOOT_DEVICE_BOOTROM,
BOOT_DEVICE_SMH,
BOOT_DEVICE_NONE
};

View 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

View 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);

View file

@ -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;
}

View 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"

View file

@ -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

View 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

View 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
#

186
lib/semihosting.c Normal file
View file

@ -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);
}