diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cb8e8632e7d..8ffe84c7782 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -737,6 +737,18 @@ config DEBUG_MEMFAULT output is sometimes helpful when debugging difficult mem fault problems, but may be more than you typically want to see. +config ARM_SEMIHOSTING_SYSLOG + bool "Semihosting SYSLOG support" + select ARCH_SYSLOG + ---help--- + Enable hooks to support semihosting syslog output. + +config ARM_SEMIHOSTING_HOSTFS + bool "Semihosting HostFS" + depends on FS_HOSTFS + ---help--- + Mount HostFS through semihosting. + if ARCH_CORTEXM0 source arch/arm/src/armv6-m/Kconfig endif diff --git a/arch/arm/include/arm/syscall.h b/arch/arm/include/arm/syscall.h index 18aa53f84e2..5b011dbe38e 100644 --- a/arch/arm/include/arm/syscall.h +++ b/arch/arm/include/arm/syscall.h @@ -218,6 +218,28 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, return reg0; } +/* semihosting(SMH) call with call number and one parameter */ + +static inline long smh_call(unsigned int nbr, void *parm) +{ + register long reg0 __asm__("r0") = (long)(nbr); + register long reg1 __asm__("r1") = (long)(parm); + + __asm__ __volatile__ + ( +#if defined(__thumb__) || defined(__thumb2__) + "svc #0xab" +#else + "svc #0x123456" +#endif + : "=r"(reg0) + : "r"(reg0), "r"(reg1) + : "memory" + ); + + return reg0; +} + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/arch/arm/include/armv6-m/syscall.h b/arch/arm/include/armv6-m/syscall.h index de7c2a754b8..d16ab9da6eb 100644 --- a/arch/arm/include/armv6-m/syscall.h +++ b/arch/arm/include/armv6-m/syscall.h @@ -241,6 +241,24 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, return reg0; } +/* semihosting(SMH) call with call number and one parameter */ + +static inline long smh_call(unsigned int nbr, void *parm) +{ + register long reg0 __asm__("r0") = (long)(nbr); + register long reg1 __asm__("r1") = (long)(parm); + + __asm__ __volatile__ + ( + "bkpt #0xab" + : "=r"(reg0) + : "r"(reg0), "r"(reg1) + : "memory" + ); + + return reg0; +} + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/arch/arm/include/armv7-a/syscall.h b/arch/arm/include/armv7-a/syscall.h index 9b86d064659..5682fc4a4f9 100644 --- a/arch/arm/include/armv7-a/syscall.h +++ b/arch/arm/include/armv7-a/syscall.h @@ -218,6 +218,28 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, return reg0; } +/* semihosting(SMH) call with call number and one parameter */ + +static inline long smh_call(unsigned int nbr, void *parm) +{ + register long reg0 __asm__("r0") = (long)(nbr); + register long reg1 __asm__("r1") = (long)(parm); + + __asm__ __volatile__ + ( +#if defined(__thumb__) || defined(__thumb2__) + "svc #0xab" +#else + "svc #0x123456" +#endif + : "=r"(reg0) + : "r"(reg0), "r"(reg1) + : "memory" + ); + + return reg0; +} + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/arch/arm/include/armv7-m/syscall.h b/arch/arm/include/armv7-m/syscall.h index dfef3ec3910..09981fc4ea5 100644 --- a/arch/arm/include/armv7-m/syscall.h +++ b/arch/arm/include/armv7-m/syscall.h @@ -241,6 +241,24 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, return reg0; } +/* semihosting(SMH) call with call number and one parameter */ + +static inline long smh_call(unsigned int nbr, void *parm) +{ + register long reg0 __asm__("r0") = (long)(nbr); + register long reg1 __asm__("r1") = (long)(parm); + + __asm__ __volatile__ + ( + "bkpt #0xab" + : "=r"(reg0) + : "r"(reg0), "r"(reg1) + : "memory" + ); + + return reg0; +} + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/arch/arm/include/armv7-r/syscall.h b/arch/arm/include/armv7-r/syscall.h index 2c0cb7ca37d..ba9378ce823 100644 --- a/arch/arm/include/armv7-r/syscall.h +++ b/arch/arm/include/armv7-r/syscall.h @@ -218,6 +218,28 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, return reg0; } +/* semihosting(SMH) call with call number and one parameter */ + +static inline long smh_call(unsigned int nbr, void *parm) +{ + register long reg0 __asm__("r0") = (long)(nbr); + register long reg1 __asm__("r1") = (long)(parm); + + __asm__ __volatile__ + ( +#if defined(__thumb__) || defined(__thumb2__) + "svc #0xab" +#else + "svc #0x123456" +#endif + : "=r"(reg0) + : "r"(reg0), "r"(reg1) + : "memory" + ); + + return reg0; +} + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/arch/arm/src/common/up_hostfs.c b/arch/arm/src/common/up_hostfs.c new file mode 100644 index 00000000000..35d4ab4e11f --- /dev/null +++ b/arch/arm/src/common/up_hostfs.c @@ -0,0 +1,332 @@ +/**************************************************************************** + * arch/arm/src/common/up_hostfs.c + * + * Copyright (C) 2018 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARM_SEMIHOSTING_HOSTFS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define HOST_OPEN 0x01 +#define HOST_CLOSE 0x02 +#define HOST_WRITE 0x05 +#define HOST_READ 0x06 +#define HOST_SEEK 0x0a +#define HOST_FLEN 0x0c +#define HOST_REMOVE 0x0e +#define HOST_RENAME 0x0f +#define HOST_ERROR 0x13 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static long host_call(unsigned int nbr, void *parm) +{ + long ret = smh_call(nbr, parm); + if (ret < 0) + { + long err = smh_call(HOST_ERROR, NULL); + if (err > 0) + { + ret = -err; + } + } + + return ret; +} + +static ssize_t host_flen(long fd) +{ + return host_call(HOST_FLEN, &fd); +} + +static int host_flags_to_mode(int flags) +{ + static const int modeflags[] = + { + 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, + 0, + }; + + int i; + for (i = 0; modeflags[i] != 0; i++) + { + if (modeflags[i] == flags) + { + return i; + } + } + + return -EINVAL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int host_open(const char *pathname, int flags, int mode) +{ + struct + { + const char *pathname; + long mode; + size_t len; + } open = + { + .pathname = pathname, + .mode = host_flags_to_mode(flags), + .len = strlen(pathname), + }; + + return host_call(HOST_OPEN, &open); +} + +int host_close(int fd_) +{ + long fd = fd_; + return host_call(HOST_CLOSE, &fd); +} + +ssize_t host_read(int fd, void *buf, size_t count) +{ + struct + { + long fd; + void *buf; + size_t count; + } read = + { + .fd = fd, + .buf = buf, + .count = count, + }; + ssize_t ret = host_call(HOST_READ, &read); + return ret < 0 ? ret : count - ret; +} + +ssize_t host_write(int fd, const void *buf, size_t count) +{ + struct + { + long fd; + const void *buf; + size_t count; + } write = + { + .fd = fd, + .buf = buf, + .count = count, + }; + ssize_t ret = host_call(HOST_WRITE, &write); + return ret < 0 ? ret : count - ret; +} + +off_t host_lseek(int fd, off_t offset, int whence) +{ + off_t ret = -ENOSYS; + + if (whence == SEEK_END) + { + ret = host_flen(fd); + if (ret >= 0) + { + offset += ret; + whence = SEEK_SET; + } + } + + if (whence == SEEK_SET) + { + struct + { + long fd; + size_t pos; + } seek = + { + .fd = fd, + .pos = offset, + }; + ret = host_call(HOST_SEEK, &seek); + if (ret >= 0) + { + ret = offset; + } + } + + return ret; +} + +int host_ioctl(int fd, int request, unsigned long arg) +{ + return -ENOSYS; +} + +void host_sync(int fd) +{ +} + +int host_dup(int fd) +{ + return -ENOSYS; +} + +int host_fstat(int fd, struct stat *buf) +{ + memset(buf, 0, sizeof(*buf)); + buf->st_mode = S_IFREG | 0777; + buf->st_size = host_flen(fd); + return buf->st_size < 0 ? buf->st_size : 0; +} + +int host_ftruncate(int fd, off_t length) +{ + return -ENOSYS; +} + +void *host_opendir(const char *name) +{ + return NULL; +} + +int host_readdir(void *dirp, struct dirent *entry) +{ + return -ENOSYS; +} + +void host_rewinddir(void *dirp) +{ +} + +int host_closedir(void *dirp) +{ + return -ENOSYS; +} + +int host_statfs(const char *path, struct statfs *buf) +{ + return 0; +} + +int host_unlink(const char *pathname) +{ + struct + { + const char *pathname; + size_t pathname_len; + } remove = + { + .pathname = pathname, + .pathname_len = strlen(pathname), + }; + + return host_call(HOST_REMOVE, &remove); +} + +int host_mkdir(const char *pathname, mode_t mode) +{ + return -ENOSYS; +} + +int host_rmdir(const char *pathname) +{ + return host_unlink(pathname); +} + +int host_rename(const char *oldpath, const char *newpath) +{ + struct + { + const char *oldpath; + size_t oldpath_len; + const char *newpath; + size_t newpath_len; + } rename = + { + .oldpath = oldpath, + .oldpath_len = strlen(oldpath), + .newpath = newpath, + .newpath_len = strlen(newpath), + }; + + return host_call(HOST_RENAME, &rename); +} + +int host_stat(const char *path, struct stat *buf) +{ + int ret = host_open(path, O_RDONLY, 0); + if (ret >= 0) + { + int fd = ret; + ret = host_fstat(fd, buf); + host_close(fd); + } + + if (ret < 0) + { + /* Since semihosting doesn't support directory yet, */ + ret = 0; /* we have to assume it's a directory here. */ + memset(buf, 0, sizeof(*buf)); + buf->st_mode = S_IFDIR | 0777; + } + + return ret; +} + +#endif diff --git a/arch/arm/src/common/up_semi_syslog.c b/arch/arm/src/common/up_semi_syslog.c new file mode 100644 index 00000000000..dc66003439c --- /dev/null +++ b/arch/arm/src/common/up_semi_syslog.c @@ -0,0 +1,83 @@ +/**************************************************************************** + * arch/arm/src/common/up_semi_syslog.c + * + * Copyright (C) 2018 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +#include "up_internal.h" + +#ifdef CONFIG_ARM_SEMIHOSTING_SYSLOG + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SEMI_SYSLOG_WRITEC 0x03 +#define SEMI_SYSLOG_WRITE0 0x04 +#define SEMI_SYSLOG_READC 0x07 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_putc + ****************************************************************************/ + +int up_putc(int ch) +{ + smh_call(SEMI_SYSLOG_WRITEC, &ch); + return ch; +} + +/**************************************************************************** + * Name: up_puts + * + * Description: + * Output a string on the console + * + ****************************************************************************/ + +void up_puts(FAR const char *str) +{ + smh_call(SEMI_SYSLOG_WRITE0, (char *)str); +} +#endif