summaryrefslogtreecommitdiffstats
path: root/arch/arm/lib
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2015-10-28 11:34:36 -0700
committerSascha Hauer <s.hauer@pengutronix.de>2015-10-30 08:06:03 +0100
commit48d61510290ea3380e4987d38e512d2d8304849a (patch)
treeaa606c7c7a204b6686f0f24830ece7f2b614a793 /arch/arm/lib
parent611e86d58154752fd1fd0051b6e5dec325329dbe (diff)
downloadbarebox-48d61510290ea3380e4987d38e512d2d8304849a.tar.gz
barebox-48d61510290ea3380e4987d38e512d2d8304849a.tar.xz
ARM: Add support for semihosting
Add semihosting API implementation and implement a filesystem driver to access debugging host filesystem using it. Tested on Freescale SabreSD board (i.MX6Q) using OpenOCD Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/lib')
-rw-r--r--arch/arm/lib/Makefile1
-rw-r--r--arch/arm/lib/semihosting-trap.S28
-rw-r--r--arch/arm/lib/semihosting.c227
3 files changed, 256 insertions, 0 deletions
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index a32879537c..e1c6f5bfd3 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -20,6 +20,7 @@ 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
extra-y += barebox.lds
diff --git a/arch/arm/lib/semihosting-trap.S b/arch/arm/lib/semihosting-trap.S
new file mode 100644
index 0000000000..9e40ebfe21
--- /dev/null
+++ b/arch/arm/lib/semihosting-trap.S
@@ -0,0 +1,28 @@
+/*
+ * semihosting-trap.S -- Assembly code needed to make a semihosting call
+ *
+ * Copyright (c) 2015 Zodiac Inflight Innovations
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/unified.h>
+
+.section .text.semihosting_trap
+ENTRY(semihosting_trap)
+ @ In supervisor mode SVC would clobber LR
+ push {lr}
+ ARM( svc #0x123456 )
+ THUMB( svc #0xAB )
+ pop {pc}
+ENDPROC(semihosting_trap)
diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c
new file mode 100644
index 0000000000..a7351961dc
--- /dev/null
+++ b/arch/arm/lib/semihosting.c
@@ -0,0 +1,227 @@
+/*
+ * semihosting.c -- ARM Semihoting API implementation
+ *
+ * Copyright (c) 2015 Zodiac Inflight Innovations
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * based on a smiliar code from U-Boot
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+
+enum {
+ SEMIHOSTING_SYS_OPEN = 0x01,
+ SEMIHOSTING_SYS_CLOSE = 0x02,
+ SEMIHOSTING_SYS_WRITEC = 0x03,
+ SEMIHOSTING_SYS_WRITE0 = 0x04,
+ SEMIHOSTING_SYS_WRITE = 0x05,
+ SEMIHOSTING_SYS_READ = 0x06,
+ SEMIHOSTING_SYS_READC = 0x07,
+ /* SYS_ISERROR is not implemented */
+ SEMIHOSTING_SYS_ISATTY = 0x09,
+ SEMIHOSTING_SYS_SEEK = 0x0a,
+ SEMIHOSTING_SYS_FLEN = 0x0c,
+ SEMIHOSTING_SYS_REMOVE = 0x0e,
+ SEMIHOSTING_SYS_RENAME = 0x0f,
+ SEMIHOSTING_SYS_TIME = 0x11,
+ SEMIHOSTING_SYS_ERRNO = 0x13,
+ /* SYS_GET_CMDLINE is not implemented */
+ /* SYS_HEAPINFO is not implemented */
+ /* angel_SWIreason_ReportException is not implemented */
+ SEMIHOSTING_SYS_SYSTEM = 0x12,
+};
+
+uint32_t semihosting_trap(uint32_t sysnum, void *addr);
+
+static uint32_t semihosting_flags_to_mode(int flags)
+{
+ static const int semihosting_open_modeflags[12] = {
+ O_RDONLY,
+ O_RDONLY | O_BINARY,
+ O_RDWR,
+ O_RDWR | O_BINARY,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ O_RDWR | O_CREAT | O_TRUNC,
+ O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+ O_WRONLY | O_CREAT | O_APPEND,
+ O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
+ O_RDWR | O_CREAT | O_APPEND,
+ O_RDWR | O_CREAT | O_APPEND | O_BINARY
+ };
+
+ int i;
+ for (i = 0; i < ARRAY_SIZE(semihosting_open_modeflags); i++) {
+ if (semihosting_open_modeflags[i] == flags)
+ return i;
+ }
+
+ return 0;
+}
+
+int semihosting_open(const char *fname, int flags)
+{
+ struct __packed {
+ uint32_t fname;
+ uint32_t mode;
+ uint32_t len;
+ } open = {
+ .fname = (uint32_t)fname,
+ .len = strlen(fname),
+ .mode = semihosting_flags_to_mode(flags),
+ };
+
+ return semihosting_trap(SEMIHOSTING_SYS_OPEN, &open);
+}
+EXPORT_SYMBOL(semihosting_open);
+
+int semihosting_close(int fd)
+{
+ return semihosting_trap(SEMIHOSTING_SYS_CLOSE, &fd);
+}
+EXPORT_SYMBOL(semihosting_close);
+
+int semihosting_writec(char c)
+{
+ return semihosting_trap(SEMIHOSTING_SYS_WRITEC, &c);
+}
+EXPORT_SYMBOL(semihosting_writec);
+
+int semihosting_write0(const char *str)
+{
+ return 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;
+};
+
+ssize_t semihosting_write(int fd, const void *buf, size_t count)
+{
+ struct semihosting_file_io write = {
+ .fd = fd,
+ .memp = (uint32_t)buf,
+ .len = count,
+ };
+
+ return semihosting_trap(SEMIHOSTING_SYS_WRITE, &write);
+}
+EXPORT_SYMBOL(semihosting_write);
+
+ssize_t semihosting_read(int fd, void *buf, size_t count)
+{
+ struct semihosting_file_io read = {
+ .fd = fd,
+ .memp = (uint32_t)buf,
+ .len = count,
+ };
+
+ return semihosting_trap(SEMIHOSTING_SYS_READ, &read);
+}
+EXPORT_SYMBOL(semihosting_read);
+
+int semihosting_readc(void)
+{
+ return semihosting_trap(SEMIHOSTING_SYS_READC, NULL);
+}
+EXPORT_SYMBOL(semihosting_readc);
+
+int semihosting_isatty(int fd)
+{
+ return semihosting_trap(SEMIHOSTING_SYS_ISATTY, &fd);
+}
+EXPORT_SYMBOL(semihosting_isatty);
+
+int semihosting_seek(int fd, off_t pos)
+{
+ struct __packed {
+ uint32_t fd;
+ uint32_t pos;
+ } seek = {
+ .fd = fd,
+ .pos = pos,
+ };
+
+ return semihosting_trap(SEMIHOSTING_SYS_SEEK, &seek);
+}
+EXPORT_SYMBOL(semihosting_seek);
+
+int semihosting_flen(int fd)
+{
+ return semihosting_trap(SEMIHOSTING_SYS_FLEN, &fd);
+}
+EXPORT_SYMBOL(semihosting_flen);
+
+int semihosting_remove(const char *fname)
+{
+ struct __packed {
+ uint32_t fname;
+ uint32_t fname_length;
+ } remove = {
+ .fname = (uint32_t)fname,
+ .fname_length = strlen(fname),
+ };
+
+ return semihosting_trap(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;
+ } rename = {
+ .fname1 = (uint32_t)fname1,
+ .fname1_length = strlen(fname1),
+ .fname2 = (uint32_t)fname2,
+ .fname2_length = strlen(fname2),
+ };
+
+ return semihosting_trap(SEMIHOSTING_SYS_RENAME, &rename);
+}
+EXPORT_SYMBOL(semihosting_rename);
+
+int semihosting_errno(void)
+{
+ return semihosting_trap(SEMIHOSTING_SYS_ERRNO, NULL);
+}
+EXPORT_SYMBOL(semihosting_errno);
+
+
+int semihosting_system(const char *command)
+{
+ struct __packed {
+ uint32_t cmd;
+ uint32_t cmd_len;
+ } system = {
+ .cmd = (uint32_t)command,
+ .cmd_len = strlen(command),
+ };
+
+ return semihosting_trap(SEMIHOSTING_SYS_SYSTEM, &system);
+}
+EXPORT_SYMBOL(semihosting_system);