This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 5a9b2920e872cda1edfadfb5982a65522cf40337
Author: Masayuki Ishikawa <[email protected]>
AuthorDate: Mon May 2 18:00:26 2022 +0900

    arch: risc-v: Add support for semihosting and hostfs
    
    Summary:
    - This commit adds support for semihosting and hostfs
    
    Impact:
    - None
    
    Testing:
    - Tested with nsh and nsh64 (defconfig will be updated later)
    
    Signed-off-by: Masayuki Ishikawa <[email protected]>
---
 arch/risc-v/Kconfig                     |  19 ++
 arch/risc-v/include/syscall.h           |   2 +
 arch/risc-v/src/common/riscv_hostfs.c   | 359 ++++++++++++++++++++++++++++++++
 arch/risc-v/src/common/riscv_semihost.S |  40 ++++
 arch/risc-v/src/qemu-rv/Make.defs       |   5 +
 5 files changed, 425 insertions(+)

diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig
index 8c4e0d516d..43d28a9787 100644
--- a/arch/risc-v/Kconfig
+++ b/arch/risc-v/Kconfig
@@ -276,6 +276,25 @@ config RISCV_TOOLCHAIN_GNU_RVG
 
 endchoice
 
+config RISCV_SEMIHOSTING_HOSTFS
+       bool "Semihosting HostFS"
+       depends on FS_HOSTFS
+       ---help---
+               Mount HostFS through semihosting.
+
+               This doesn't support some directory operations like readdir 
because
+               of the limitations of semihosting mechanism.
+
+if RISCV_SEMIHOSTING_HOSTFS
+
+config RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE
+       bool "Cache coherence in semihosting hostfs"
+       depends on ARCH_DCACHE
+       ---help---
+               Flush & Invalidte cache before & after bkpt instruction.
+
+endif
+
 source "arch/risc-v/src/opensbi/Kconfig"
 
 if ARCH_CHIP_FE310
diff --git a/arch/risc-v/include/syscall.h b/arch/risc-v/include/syscall.h
index 9991111acb..ccb751fb07 100644
--- a/arch/risc-v/include/syscall.h
+++ b/arch/risc-v/include/syscall.h
@@ -150,6 +150,8 @@ extern "C"
 #define EXTERN extern
 #endif
 
+long smh_call(unsigned int nbr, void *parm);
+
 #if defined(CONFIG_ARCH_USE_S_MODE) && defined(__KERNEL__)
 uintptr_t sys_call0(unsigned int nbr);
 uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1);
diff --git a/arch/risc-v/src/common/riscv_hostfs.c 
b/arch/risc-v/src/common/riscv_hostfs.c
new file mode 100644
index 0000000000..d5786e22a2
--- /dev/null
+++ b/arch/risc-v/src/common/riscv_hostfs.c
@@ -0,0 +1,359 @@
+/****************************************************************************
+ * arch/risc-v/src/common/riscv_hostfs.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/cache.h>
+#include <nuttx/fs/hostfs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <syscall.h>
+#include <unistd.h>
+
+/****************************************************************************
+ * 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, size_t size)
+{
+#ifdef CONFIG_RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE
+  up_clean_dcache(parm, parm + size);
+#endif
+
+  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, sizeof(long));
+}
+
+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),
+  };
+
+#ifdef CONFIG_RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE
+  up_clean_dcache(pathname, pathname + open.len + 1);
+#endif
+
+  return host_call(HOST_OPEN, &open, sizeof(open));
+}
+
+int host_close(int fd_)
+{
+  long fd = fd_;
+  return host_call(HOST_CLOSE, &fd, sizeof(long));
+}
+
+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;
+
+#ifdef CONFIG_RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE
+  up_invalidate_dcache(buf, buf + count);
+#endif
+
+  ret = host_call(HOST_READ, &read, sizeof(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;
+
+#ifdef CONFIG_RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE
+  up_clean_dcache(buf, buf + count);
+#endif
+
+  ret = host_call(HOST_WRITE, &write, sizeof(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, sizeof(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_fchstat(int fd, const struct stat *buf, int flags)
+{
+  return -ENOSYS;
+}
+
+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),
+  };
+
+#ifdef CONFIG_RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE
+  up_clean_dcache(pathname, pathname +
+                  remove.pathname_len + 1);
+#endif
+
+  return host_call(HOST_REMOVE, &remove, sizeof(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),
+  };
+
+#ifdef CONFIG_RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE
+  up_clean_dcache(oldpath, oldpath + rename.oldpath_len + 1);
+  up_clean_dcache(newpath, newpath + rename.newpath_len + 1);
+#endif
+
+  return host_call(HOST_RENAME, &rename, sizeof(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;
+}
+
+int host_chstat(const char *path, const struct stat *buf, int flags)
+{
+  return -ENOSYS;
+}
diff --git a/arch/risc-v/src/common/riscv_semihost.S 
b/arch/risc-v/src/common/riscv_semihost.S
new file mode 100644
index 0000000000..0bd9db2f81
--- /dev/null
+++ b/arch/risc-v/src/common/riscv_semihost.S
@@ -0,0 +1,40 @@
+/****************************************************************************
+ * arch/risc-v/src/common/riscv_semihost.S
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: smh_call
+ *
+ * Description:
+ *   Semihosting call with call number and one parameter
+ *
+ ****************************************************************************/
+
+  .option norvc
+  .text
+  .balign 16
+  .global smh_call
+  .type smh_call @function
+
+smh_call:
+
+  slli zero, zero, 0x1f
+  ebreak
+  srai zero, zero, 0x7
+  ret
diff --git a/arch/risc-v/src/qemu-rv/Make.defs 
b/arch/risc-v/src/qemu-rv/Make.defs
index a222285990..74fc60a903 100644
--- a/arch/risc-v/src/qemu-rv/Make.defs
+++ b/arch/risc-v/src/qemu-rv/Make.defs
@@ -68,6 +68,11 @@ ifeq ($(CONFIG_ARCH_RV_ISA_A),y)
 CMN_ASRCS += riscv_testset.S
 endif
 
+ifeq ($(CONFIG_RISCV_SEMIHOSTING_HOSTFS),y)
+CMN_ASRCS += riscv_semihost.S
+CMN_CSRCS += riscv_hostfs.c
+endif
+
 # Specify our C code within this directory to be included
 CHIP_CSRCS  = qemu_rv_start.c qemu_rv_irq_dispatch.c qemu_rv_irq.c
 CHIP_CSRCS += qemu_rv_timerisr.c

Reply via email to