[4/4,sim/riscv] Add semi-hosting support

Message ID CWXP265MB5321BB1FBF7F40AE191D72E18CD6A@CWXP265MB5321.GBRP265.PROD.OUTLOOK.COM
State New
Headers
Series [1/4,sim/riscv] Add basic semi-hosting support |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gdb_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gdb_check--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 fail Patch failed to apply

Commit Message

Jaydeep Patil Oct. 17, 2023, 5:53 a.m. UTC
  Added support for all semi-hosting calls.
Enable prints in gdb.arch/riscv-insn-simulation.c.
---
.../gdb.arch/riscv-insn-simulation.c          |   2 -
.../gdb.arch/riscv-insn-simulation.exp        |   2 +-
sim/riscv/riscv-sim.h                         |  21 +
sim/riscv/sim-main.c                          | 419 ++++++++++++++++++
4 files changed, 441 insertions(+), 3 deletions(-)

/* Some utils don't like having a NULL environ.  */
--
2.25.1
  

Patch

diff --git a/gdb/testsuite/gdb.arch/riscv-insn-simulation.c b/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
index 5764d879b6d..5fc47f43411 100644
--- a/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
+++ b/gdb/testsuite/gdb.arch/riscv-insn-simulation.c
@@ -35,8 +35,6 @@ 
#define SKIP_c_fsdsp
#endif

-#define DISABLE_PRINTS
-
#if defined (DISABLE_PRINTS)
#define print(...) ;
#else
diff --git a/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp b/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
index 99eb7f3df01..f48e716351c 100644
--- a/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
+++ b/gdb/testsuite/gdb.arch/riscv-insn-simulation.exp
@@ -32,4 +32,4 @@  if { ![runto_main] } {
     return -1
}

-gdb_test "continue" ".*Inferior.*process.*exited normally.*"
+gdb_test "continue" ".*All.*tests pass.*Inferior.*process.*exited normally.*"
diff --git a/sim/riscv/riscv-sim.h b/sim/riscv/riscv-sim.h
index e147b2641f2..014c912fc65 100644
--- a/sim/riscv/riscv-sim.h
+++ b/sim/riscv/riscv-sim.h
@@ -78,8 +78,29 @@  extern void initialize_env (SIM_DESC, const char * const *argv,
#define ApplicationExit 0x20026

#define SYS_OPEN 0x01
+#define SYS_CLOSE 0x02
+#define SYS_WRITEC 0x03
+#define SYS_WRITE0 0x04
+#define SYS_WRITE 0x05
+#define SYS_READ 0x06
+#define SYS_READC 0x07
+#define SYS_ISERROR 0x08
+#define SYS_ISTTY 0x09
+#define SYS_SEEK 0x0A
+#define SYS_FLEN 0x0C
+#define SYS_TMPNAM 0x0D
+#define SYS_REMOVE 0x0E
+#define SYS_RENAME 0x0F
+#define SYS_CLOCK 0x10
+#define SYS_TIME 0x11
+#define SYS_SYSTEM 0x12
+#define SYS_ERRNO 0x13
#define SYS_GET_CMDLINE 0x15
+#define SYS_HEAPINFO 0x16
#define SYS_EXIT 0x18
+#define SYS_EXIT_EXTENDED 0x20
+#define SYS_ELAPSED 0x30
+#define SYS_TICKFREQ 0x31

#define GDB_O_RDONLY 0x000
#define GDB_O_WRONLY 0x001
diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c
index 7d6a743753c..89dfffb4689 100644
--- a/sim/riscv/sim-main.c
+++ b/sim/riscv/sim-main.c
@@ -26,7 +26,11 @@ 

#include <inttypes.h>
#include <time.h>
+#include <sys/stat.h>
+#include <sys/unistd.h>
+#include <sys/fcntl.h>

+#include "bfd.h"
#include "sim-main.h"
#include "sim-signal.h"
#include "sim-syscall.h"
@@ -66,6 +70,8 @@  static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
       } \
   } while (0)

+static clock_t clock_start = 0;
+
static INLINE void
store_rd (SIM_CPU *cpu, int rd, unsigned_word val)
{
@@ -153,6 +159,21 @@  get_core_data (SIM_CPU *cpu, unsigned_word addr, unsigned_word index)
   return param;
}

+static void
+set_core_data (SIM_CPU *cpu, unsigned_word addr, unsigned_word index,
+                     uintptr_t value)
+{
+  int xlen = RISCV_XLEN (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  if (xlen == 64)
+    sim_core_write_unaligned_8 (cpu, riscv_cpu->pc, read_map,
+                                                              addr + (index * 8), value);
+  else
+    sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, read_map,
+                                                              addr + (index * 4), (uint32_t) value);
+}
+
static void
set_core_string (SIM_CPU *cpu, unsigned_word core_addr, char *host_buf,
                                int len)
@@ -183,6 +204,160 @@  get_core_string_with_len (SIM_CPU *cpu, unsigned_word addr,
   return str;
}

+static char *
+get_core_string (SIM_CPU *cpu, unsigned_word addr, int *slen)
+{
+  int len = 0;
+  char * str;
+  const int chunk_size = 128;     /* allocate buffer in chunks.  */
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  str = (char *) malloc (chunk_size);
+
+  while (1)
+    {
+      uint8_t ch = sim_core_read_unaligned_1 (cpu, riscv_cpu->pc, read_map,
+                                                                                    addr + len);
+      str[len] = ch;
+      if (ch == 0)
+              break;
+      len++;
+      if ((len % chunk_size) == 0)
+              str = (char *) realloc (str, len + chunk_size);
+    }
+
+  *slen = len;
+  return str;
+}
+
+static uintptr_t
+get_symbol_value (SIM_CPU *cpu, const char *symname)
+{
+  struct bfd *abfd = STATE_PROG_BFD (CPU_STATE (cpu));
+  static asymbol **symbol_table = NULL;
+  static long number_of_symbols = 0;
+
+  if (symbol_table == NULL)
+    {
+      long storage_needed;
+      storage_needed = bfd_get_symtab_upper_bound (abfd);
+      if (storage_needed <= 0)
+              return 0;
+      symbol_table = (asymbol **) malloc (storage_needed);
+      if (symbol_table == NULL)
+              return 0;
+      number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+      if (number_of_symbols <= 0)
+              return 0;
+    }
+
+  for (long i = 0; i < number_of_symbols; i++)
+    {
+      asymbol *sym = symbol_table[i];
+      if (!strcmp (sym->name, symname))
+              return bfd_asymbol_value (sym);
+    }
+
+  return 0;
+}
+
+static void
+semihosting_flen (SIM_CPU *cpu)
+{
+  int fd;
+  struct stat sb;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+
+  if (fd > STDERR_FILENO)
+    {
+      fstat (fd, &sb);
+      riscv_cpu->a0 = sb.st_size;
+    }
+  else
+    riscv_cpu->a0 = 0;
+}
+
+static void
+semihosting_write (SIM_CPU *cpu)
+{
+  int i, fd;
+  uintptr_t buf;
+  uintptr_t count;
+  char *str;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  buf = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  count = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);
+
+  if (count <= 0)
+    {
+      riscv_cpu->a0 = -1;
+      return;
+    }
+
+  str = get_core_string_with_len (cpu, buf, count);
+  riscv_cpu->a0 = sim_io_write (CPU_STATE (cpu), fd, str, count);
+  free (str);
+}
+
+static void
+semihosting_writec (SIM_CPU *cpu)
+{
+  char ch;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  ch = (char) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = sim_io_write_stdout (CPU_STATE (cpu), &ch, 1);
+}
+
+static void
+semihosting_write0 (SIM_CPU *cpu)
+{
+  int len;
+  char *str;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  str = get_core_string (cpu, riscv_cpu->a1, &len);
+  riscv_cpu->a0 = sim_io_write_stdout (CPU_STATE (cpu), str, len);
+}
+
+static void
+semihosting_read (SIM_CPU *cpu)
+{
+  int i, fd, read_len;
+  uintptr_t dst_buf;
+  uintptr_t count;
+  char *host_buf;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  dst_buf = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  count = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);
+
+  if (count <= 0)
+    {
+      riscv_cpu->a0 = 0;
+      return;
+    }
+
+  host_buf = (char *) malloc (count);
+  read_len = sim_io_read (CPU_STATE (cpu), fd, host_buf, count);
+  if (read_len > 0)
+    set_core_string (cpu, dst_buf, host_buf, read_len);
+  riscv_cpu->a0 = read_len;
+  free (host_buf);
+}
+
+static void
+semihosting_readc (SIM_CPU *cpu)
+{
+  char ch;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  sim_io_read_stdin (CPU_STATE (cpu), &ch, 1);
+  riscv_cpu->a0 = ch;
+}
+
static void
semihosting_open (SIM_CPU *cpu)
{
@@ -208,6 +383,26 @@  semihosting_open (SIM_CPU *cpu)
   free (name);
}

+static void
+semihosting_close (SIM_CPU *cpu)
+{
+  int fd;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = sim_io_close (CPU_STATE (cpu), fd);
+}
+
+static void
+semihosting_seek (SIM_CPU *cpu)
+{
+  int fd;
+  uintptr_t pos;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  pos = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  riscv_cpu->a0 = sim_io_lseek (CPU_STATE (cpu), fd, pos, 0);
+}
+
static void
semihosting_exit (SIM_CPU *cpu)
{
@@ -229,6 +424,137 @@  semihosting_exit (SIM_CPU *cpu)
   sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_exited, exit_code);
}

+static void
+semihosting_exit_extended (SIM_CPU *cpu)
+{
+  int ret;
+  uintptr_t app_code, exit_status;
+  SIM_DESC sd = CPU_STATE (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  app_code = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  exit_status = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  if (app_code == ApplicationExit)
+    ret = exit_status;
+  else
+    ret = 1;
+  riscv_cpu->a0 = ret;
+  sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_exited, ret);
+}
+
+static void
+semihosting_iserror (SIM_CPU *cpu)
+{
+  intptr_t status;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  status = (intptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = (status < 0);
+}
+
+static void
+semihosting_istty (SIM_CPU *cpu)
+{
+  int fd;
+  SIM_DESC sd = CPU_STATE (cpu);
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  fd = (int) get_core_data (cpu, riscv_cpu->a1, 0);
+  riscv_cpu->a0 = sim_io_isatty (sd, fd);
+}
+
+static void
+semihosting_tmpnam (SIM_CPU *cpu)
+{
+  uintptr_t t_pname;
+  int len, id, maxpath;
+  char *pname;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  t_pname = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  id = (int) get_core_data (cpu, riscv_cpu->a1, 1);
+  maxpath = (int) get_core_data (cpu, riscv_cpu->a1, 2);
+
+  pname = tmpnam (NULL);
+
+  if (pname == NULL)
+    {
+      riscv_cpu->a0 = 0;
+      return;
+    }
+
+  len = strlen (pname);
+  if (maxpath > len)
+    {
+      riscv_cpu->a0 = 0;
+      return;
+    }
+
+  set_core_string (cpu, t_pname, pname, len + 1);
+  riscv_cpu->a0 = t_pname;
+}
+
+static void
+semihosting_remove (SIM_CPU *cpu)
+{
+  uintptr_t t_pname;
+  int len;
+  char *pname;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  t_pname = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  len = (int) get_core_data (cpu, riscv_cpu->a1, 1);
+  pname = get_core_string_with_len (cpu, t_pname, len);
+  riscv_cpu->a0 = sim_io_unlink (CPU_STATE (cpu), pname);
+  free (pname);
+}
+
+static void
+semihosting_rename (SIM_CPU *cpu)
+{
+  uintptr_t old_name_addr, new_name_addr;
+  uintptr_t old_len, new_len;
+  char *old_host_name, *new_host_name;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  old_name_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  old_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  new_name_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 2);
+  new_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 3);
+  old_host_name = get_core_string_with_len (cpu, old_name_addr, old_len);
+  new_host_name = get_core_string_with_len (cpu, new_name_addr, new_len);
+  riscv_cpu->a0 = sim_io_rename (CPU_STATE (cpu), old_host_name,
+                                                              new_host_name);
+  free (old_host_name);
+  free (new_host_name);
+}
+
+static void
+semihosting_system (SIM_CPU *cpu)
+{
+  uintptr_t cmd_addr;
+  uintptr_t cmd_len;
+  char *cmd_host;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  cmd_addr = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 0);
+  cmd_len = (uintptr_t) get_core_data (cpu, riscv_cpu->a1, 1);
+  cmd_host = get_core_string_with_len (cpu, cmd_addr, cmd_len);
+  riscv_cpu->a0 = sim_io_system (CPU_STATE (cpu), cmd_host);
+  free (cmd_host);
+}
+
+static void
+semihosting_elapsed (SIM_CPU *cpu)
+{
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+  clock_t elapsed = clock () - clock_start;
+  if (RISCV_XLEN (cpu) == 32)
+    {
+      sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, write_map,
+              riscv_cpu->a1, (uint32_t) elapsed);
+      sim_core_write_unaligned_4 (cpu, riscv_cpu->pc, write_map,
+              riscv_cpu->a1 + 4, (uint32_t) (elapsed >> 32));
+    }
+  else
+    sim_core_write_unaligned_8 (cpu, riscv_cpu->pc, write_map, riscv_cpu->a1,
+                                                              elapsed);
+}
+
static void
semihosting_get_cmdline (SIM_CPU *cpu)
{
@@ -263,6 +589,35 @@  semihosting_get_cmdline (SIM_CPU *cpu)
   riscv_cpu->a0 = 0;         // no error
}

+static void
+semihosting_heapinfo (SIM_CPU *cpu)
+{
+  static uintptr_t heap_base = 0, heap_limit = 0,
+              stack_base = 0, stack_limit = 0, stack_size = 0;
+  static bool have_heap = false, have_stack = false;
+  struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu);
+
+  if (have_heap == false)
+    {
+      heap_base = get_symbol_value (cpu, "__heap_start");
+      heap_limit = get_symbol_value (cpu, "__heap_end");
+      have_heap = true;
+    }
+
+  if (have_stack == false)
+    {
+      stack_base = get_symbol_value (cpu, "__stack");
+      stack_size = get_symbol_value (cpu, "__stack_size");
+      stack_limit = stack_base + stack_size;
+      have_stack = true;
+    }
+
+  set_core_data (cpu, riscv_cpu->a1, 0, heap_base);
+  set_core_data (cpu, riscv_cpu->a1, 1, heap_limit);
+  set_core_data (cpu, riscv_cpu->a1, 2, stack_base);
+  set_core_data (cpu, riscv_cpu->a1, 3, stack_limit);
+}
+
static int
do_semihosting (SIM_CPU *cpu)
{
@@ -272,12 +627,75 @@  do_semihosting (SIM_CPU *cpu)
     case SYS_OPEN:
       semihosting_open (cpu);
       break;
+    case SYS_CLOSE:
+      semihosting_close (cpu);
+      break;
+    case SYS_WRITEC:
+      semihosting_writec (cpu);
+      break;
+    case SYS_WRITE0:
+      semihosting_write0 (cpu);
+      break;
+    case SYS_WRITE:
+      semihosting_write (cpu);
+      break;
+    case SYS_READ:
+      semihosting_read (cpu);
+      break;
+    case SYS_READC:
+      semihosting_readc (cpu);
+      break;
+    case SYS_ISERROR:
+      semihosting_iserror (cpu);
+      break;
+    case SYS_ISTTY:
+      semihosting_istty (cpu);
+      break;
+    case SYS_SEEK:
+      semihosting_seek (cpu);
+      break;
+    case SYS_FLEN:
+      semihosting_flen (cpu);
+      break;
+    case SYS_TMPNAM:
+      semihosting_tmpnam (cpu);
+      break;
+    case SYS_REMOVE:
+      semihosting_remove (cpu);
+      break;
+    case SYS_RENAME:
+      semihosting_rename (cpu);
+      break;
+    case SYS_CLOCK:
+      riscv_cpu->a0 = (clock () / (CLOCKS_PER_SEC / 100));
+      break;
+    case SYS_TIME:
+      riscv_cpu->a0 = sim_io_time (CPU_STATE (cpu));
+      break;
+    case SYS_SYSTEM:
+      semihosting_system (cpu);
+      break;
+    case SYS_ERRNO:
+      riscv_cpu->a0 = sim_io_get_errno (CPU_STATE (cpu));
+      break;
     case SYS_GET_CMDLINE:
       semihosting_get_cmdline (cpu);
       break;
+    case SYS_HEAPINFO:
+      semihosting_heapinfo (cpu);
+      break;
     case SYS_EXIT:
       semihosting_exit (cpu);
       break;
+    case SYS_EXIT_EXTENDED:
+      semihosting_exit_extended (cpu);
+      break;
+    case SYS_ELAPSED:
+      semihosting_elapsed (cpu);
+      break;
+    case SYS_TICKFREQ:
+      riscv_cpu->a0 = 1000000000;
+      break;
     default:
       return -1;     // semi-hosting call not supported
     }
@@ -1702,6 +2120,7 @@  initialize_cpu (SIM_DESC sd, SIM_CPU *cpu, int mhartid)

   riscv_cpu->csr.mimpid = 0x8000;
   riscv_cpu->csr.mhartid = mhartid;
+  clock_start = clock ();
}