Skip to content

Commit

Permalink
Merge branch 'for-next/semihosting' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
saschahauer committed Jun 14, 2024
2 parents 6ffdcf2 + 1d2df6d commit 95ad7e0
Show file tree
Hide file tree
Showing 18 changed files with 227 additions and 88 deletions.
2 changes: 1 addition & 1 deletion arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ config ARM_UNWIND

config ARM_SEMIHOSTING
bool "enable ARM semihosting support"
depends on !CPU_V8
select SEMIHOSTING
help
This option enables ARM semihosting support in barebox. ARM
semihosting is a communication discipline that allows code
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/cpu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ obj-pbl-y += setupc_$(S64_32).o cache_$(S64_32).o

obj-$(CONFIG_ARM_PSCI_CLIENT) += psci-client.o

obj-$(CONFIG_ARM_SEMIHOSTING) += semihosting-trap_$(S64_32).o

#
# Any variants can be called as start-armxyz.S
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* SPDX-FileCopyrightText: 2015 Zodiac Inflight Innovations */

/*
* semihosting-trap.S -- Assembly code needed to make a semihosting call
* semihosting-trap_32.S -- Assembly code needed to make a semihosting call
*
* Author: Andrey Smirnov <[email protected]>
*/
Expand Down
10 changes: 10 additions & 0 deletions arch/arm/cpu/semihosting-trap_64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#include <linux/linkage.h>
#include <asm/unified.h>

.section .text.semihosting_trap
ENTRY(semihosting_trap)
hlt #0xf000
ret
ENDPROC(semihosting_trap)
4 changes: 4 additions & 0 deletions arch/arm/include/asm/debug_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
#include <mach/layerscape/debug_ll.h>
#endif

#ifdef CONFIG_DEBUG_SEMIHOSTING
#include <debug_ll/semihosting.h>
#endif

#ifdef CONFIG_DEBUG_QEMU_ARM64_VIRT
#define DEBUG_LL_UART_ADDR 0x9000000
#include <debug_ll/pl011.h>
Expand Down
47 changes: 33 additions & 14 deletions arch/arm/include/asm/semihosting.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,38 @@
#ifndef __ASM_ARM_SEMIHOSTING_H
#define __ASM_ARM_SEMIHOSTING_H

int semihosting_open(const char *fname, int flags);
int semihosting_close(int fd);
int semihosting_writec(char c);
int semihosting_write0(const char *str);
ssize_t semihosting_write(int fd, const void *buf, size_t count);
ssize_t semihosting_read(int fd, void *buf, size_t count);
int semihosting_readc(void);
int semihosting_isatty(int fd);
int semihosting_seek(int fd, loff_t pos);
int semihosting_flen(int fd);
int semihosting_remove(const char *fname);
int semihosting_rename(const char *fname1, const char *fname2);
int semihosting_errno(void);
int semihosting_system(const char *command);
#include <asm-generic/semihosting.h>
#include <asm/unified.h>

static inline void semihosting_putc(void *unused, int c)
{
/* We may not be relocated yet here, so we push
* to stack and take address of that
*/
#ifdef CONFIG_CPU_64
asm volatile (
"stp %0, xzr, [sp, #-16]!\n"
"mov x1, sp\n"
"mov x0, #0x03\n"
"hlt #0xf000\n"
"add sp, sp, #16\n"
: /* No outputs */
: "r" ((long)c)
: "x0", "x1", "x2", "x3", "x12", "memory"
);
#else
asm volatile (
"push {%0}\n"
"mov r1, sp\n"
"mov r0, #0x03\n"
ARM( "bkpt #0x123456\n")
THUMB( "bkpt #0xAB\n")
"pop {%0}\n"
: /* No outputs */
: "r" (c)
: "r0", "r1", "r2", "r3", "r12", "memory"
);
#endif
}

#endif
1 change: 0 additions & 1 deletion arch/arm/lib32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ pbl-y += runtime-offset.o
obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memcpy.o
obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memset.o
obj-$(CONFIG_ARM_UNWIND) += unwind.o
obj-$(CONFIG_ARM_SEMIHOSTING) += semihosting-trap.o semihosting.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_ARM_MODULE_PLTS) += module-plts.o
extra-y += barebox.lds
Expand Down
13 changes: 13 additions & 0 deletions common/Kconfig.debug_ll
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,19 @@ config DEBUG_QEMU_ARM64_VIRT
bool "QEMU ARM64 Virt PL011 console"
depends on ARCH_ARM64_VIRT

config DEBUG_SEMIHOSTING
bool "Semihosting console"
depends on SEMIHOSTING
help
Semihosting enables code to use the I/O facilities on a
host debugger/emulator through a simple supervisor call.
The host debugger or emulator must have semihosting enabled
for the supervisor call to be trapped, otherwise barebox
will crash.

Say Y here if you want low-level debugging support
using semihosting writec.

endchoice

config DEBUG_LL_NS16550
Expand Down
4 changes: 4 additions & 0 deletions drivers/firmware/Kconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "Firmware Drivers"

config SEMIHOSTING
bool
select HAS_DEBUG_LL

config FIRMWARE_ALTERA_SERIAL
bool "Altera SPI programming"
depends on OFDEVICE
Expand Down
1 change: 1 addition & 0 deletions drivers/firmware/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SEMIHOSTING) += semihosting.o
obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o socfpga_sdr.o
obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
Expand Down
99 changes: 55 additions & 44 deletions arch/arm/lib32/semihosting.c → drivers/firmware/semihosting.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@ enum {
SEMIHOSTING_SYS_SYSTEM = 0x12,
};

uint32_t semihosting_trap(uint32_t sysnum, void *addr);
long semihosting_trap(ulong sysnum, void *addr);

static uint32_t semihosting_flags_to_mode(int flags)
static long semihosting_call(ulong sysnum, void *addr)
{
long ret = semihosting_trap(sysnum, addr);
return ret >= 0 ? ret : -semihosting_errno();
}

static ulong semihosting_flags_to_mode(int flags)
{
static const int semihosting_open_modeflags[12] = {
O_RDONLY,
Expand Down Expand Up @@ -72,148 +78,153 @@ static uint32_t semihosting_flags_to_mode(int flags)
int semihosting_open(const char *fname, int flags)
{
struct __packed {
uint32_t fname;
uint32_t mode;
uint32_t len;
ulong fname;
ulong mode;
ulong len;
} open = {
.fname = (uint32_t)fname,
.fname = virt_to_phys(fname),
.len = strlen(fname),
.mode = semihosting_flags_to_mode(flags),
};

return semihosting_trap(SEMIHOSTING_SYS_OPEN, &open);
return semihosting_call(SEMIHOSTING_SYS_OPEN, &open);
}
EXPORT_SYMBOL(semihosting_open);

int semihosting_close(int fd)
{
return semihosting_trap(SEMIHOSTING_SYS_CLOSE, &fd);
return semihosting_call(SEMIHOSTING_SYS_CLOSE, &fd);
}
EXPORT_SYMBOL(semihosting_close);

int semihosting_writec(char c)
void semihosting_writec(char c)
{
return semihosting_trap(SEMIHOSTING_SYS_WRITEC, &c);
(void)semihosting_trap(SEMIHOSTING_SYS_WRITEC, &c);
}
EXPORT_SYMBOL(semihosting_writec);

int semihosting_write0(const char *str)
void semihosting_write0(const char *str)
{
return semihosting_trap(SEMIHOSTING_SYS_WRITE0, (void *)str);
(void)semihosting_trap(SEMIHOSTING_SYS_WRITE0, (void *)str);
}
EXPORT_SYMBOL(semihosting_write0);

struct __packed semihosting_file_io {
uint32_t fd;
uint32_t memp;
uint32_t len;
ulong fd;
ulong memp;
ulong len;
};

ssize_t semihosting_write(int fd, const void *buf, size_t count)
{
ssize_t ret;
struct semihosting_file_io write = {
.fd = fd,
.memp = (uint32_t)buf,
.memp = virt_to_phys(buf),
.len = count,
};

return semihosting_trap(SEMIHOSTING_SYS_WRITE, &write);
ret = semihosting_call(SEMIHOSTING_SYS_WRITE, &write);

return ret >= 0 ? count - ret : ret;
}
EXPORT_SYMBOL(semihosting_write);

ssize_t semihosting_read(int fd, void *buf, size_t count)
{
ssize_t ret;
struct semihosting_file_io read = {
.fd = fd,
.memp = (uint32_t)buf,
.memp = virt_to_phys(buf),
.len = count,
};

return semihosting_trap(SEMIHOSTING_SYS_READ, &read);
ret = semihosting_call(SEMIHOSTING_SYS_READ, &read);

return ret >= 0 ? count - ret : ret;
}
EXPORT_SYMBOL(semihosting_read);

int semihosting_readc(void)
{
return semihosting_trap(SEMIHOSTING_SYS_READC, NULL);
return semihosting_call(SEMIHOSTING_SYS_READC, NULL);
}
EXPORT_SYMBOL(semihosting_readc);

int semihosting_isatty(int fd)
{
return semihosting_trap(SEMIHOSTING_SYS_ISATTY, &fd);
return semihosting_call(SEMIHOSTING_SYS_ISATTY, &fd);
}
EXPORT_SYMBOL(semihosting_isatty);

int semihosting_seek(int fd, loff_t pos)
off_t semihosting_seek(int fd, off_t pos)
{
struct __packed {
uint32_t fd;
uint32_t pos;
ulong fd;
ulong pos;
} seek = {
.fd = fd,
.pos = pos,
};

return semihosting_trap(SEMIHOSTING_SYS_SEEK, &seek);
return semihosting_call(SEMIHOSTING_SYS_SEEK, &seek);
}
EXPORT_SYMBOL(semihosting_seek);

int semihosting_flen(int fd)
off_t semihosting_flen(int fd)
{
return semihosting_trap(SEMIHOSTING_SYS_FLEN, &fd);
return semihosting_call(SEMIHOSTING_SYS_FLEN, &fd);
}
EXPORT_SYMBOL(semihosting_flen);

int semihosting_remove(const char *fname)
{
struct __packed {
uint32_t fname;
uint32_t fname_length;
ulong fname;
ulong fname_length;
} remove = {
.fname = (uint32_t)fname,
.fname = virt_to_phys(fname),
.fname_length = strlen(fname),
};

return semihosting_trap(SEMIHOSTING_SYS_REMOVE, &remove);
return semihosting_call(SEMIHOSTING_SYS_REMOVE, &remove);
}
EXPORT_SYMBOL(semihosting_remove);

int semihosting_rename(const char *fname1, const char *fname2)
{
struct __packed {
uint32_t fname1;
uint32_t fname1_length;
uint32_t fname2;
uint32_t fname2_length;
ulong fname1;
ulong fname1_length;
ulong fname2;
ulong fname2_length;
} rename = {
.fname1 = (uint32_t)fname1,
.fname1 = virt_to_phys(fname1),
.fname1_length = strlen(fname1),
.fname2 = (uint32_t)fname2,
.fname2 = virt_to_phys(fname2),
.fname2_length = strlen(fname2),
};

return semihosting_trap(SEMIHOSTING_SYS_RENAME, &rename);
return semihosting_call(SEMIHOSTING_SYS_RENAME, &rename);
}
EXPORT_SYMBOL(semihosting_rename);

int semihosting_errno(void)
{
return semihosting_trap(SEMIHOSTING_SYS_ERRNO, NULL);
return semihosting_call(SEMIHOSTING_SYS_ERRNO, NULL);
}
EXPORT_SYMBOL(semihosting_errno);


int semihosting_system(const char *command)
{
struct __packed {
uint32_t cmd;
uint32_t cmd_len;
ulong cmd;
ulong cmd_len;
} system = {
.cmd = (uint32_t)command,
.cmd = virt_to_phys(command),
.cmd_len = strlen(command),
};

return semihosting_trap(SEMIHOSTING_SYS_SYSTEM, &system);
return semihosting_call(SEMIHOSTING_SYS_SYSTEM, &system);
}
EXPORT_SYMBOL(semihosting_system);
8 changes: 8 additions & 0 deletions drivers/serial/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,12 @@ config SERIAL_SBI
Select this option if you are building barebox for a RISCV platform
that implements a serial over SBI.

config SERIAL_SEMIHOSTING
bool "Semihosting console"
depends on SEMIHOSTING
help
Select this option if you want barebox to be able to output to
the semihosting console implemented by a debugger or emulator.
This console can not be read from.

endmenu
1 change: 1 addition & 0 deletions drivers/serial/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_SERIAL_SIFIVE) += serial_sifive.o
obj-$(CONFIG_SERIAL_SBI) += serial_sbi.o
obj-$(CONFIG_SOC_LITEX) += serial_litex.o
obj-$(CONFIG_SERIAL_SEMIHOSTING) += serial_semihosting.o
Loading

0 comments on commit 95ad7e0

Please sign in to comment.