From: Matheus Tavares Bernardino <[email protected]>

Baremetal Hexagon programs use semihosting to enumerate host
directories via OPENDIR, READDIR, and CLOSEDIR calls.  Track
open directory handles per-CPU in a GList so that guest
index values map back to host DIR pointers across calls.

Signed-off-by: Matheus Tavares Bernardino <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 target/hexagon/cpu.h     |  1 +
 hw/hexagon/hexagon_dsp.c |  5 +++
 hw/hexagon/virt.c        |  5 +++
 target/hexagon/hexswi.c  | 79 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 90 insertions(+)

diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 7694fd91fa8..536843584f4 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -144,6 +144,7 @@ typedef struct CPUArchState {
     uint32_t tlb_lock_count;
     uint32_t k0_lock_count;
     uint64_t t_cycle_count;
+    GList **g_dir_list;
 #endif
     uint32_t next_PC;
     target_ulong new_value_usr;
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index 315733cded3..be47daa0d82 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -147,6 +147,7 @@ static void hexagon_common_init(MachineState *machine, 
Rev_t rev,
 
     for (int i = 0; i < machine->smp.cpus; i++) {
         HexagonCPU *cpu = HEXAGON_CPU(object_new(machine->cpu_type));
+        CPUHexagonState *env = &cpu->env;
         qemu_register_reset(do_cpu_reset, cpu);
 
         /*
@@ -156,6 +157,10 @@ static void hexagon_common_init(MachineState *machine, 
Rev_t rev,
         qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
         if (i == 0) {
             hexagon_init_bootstrap(dms, cpu);
+            env->g_dir_list = g_malloc0(sizeof(GList *));
+        } else {
+            CPUHexagonState *env0 = cpu_env(qemu_get_cpu(0));
+            env->g_dir_list = env0->g_dir_list;
         }
         object_property_set_link(OBJECT(cpu), "global-regs",
                                  OBJECT(glob_regs_dev), &error_fatal);
diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c
index a3638998b87..62100c08277 100644
--- a/hw/hexagon/virt.c
+++ b/hw/hexagon/virt.c
@@ -283,10 +283,12 @@ static void virt_init(MachineState *ms)
     cpu0 = NULL;
     for (int i = 0; i < ms->smp.cpus; i++) {
         HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
+        CPUHexagonState *env = &cpu->env;
         qemu_register_reset(do_cpu_reset, cpu);
 
         if (i == 0) {
             cpu0 = DEVICE(cpu);
+            env->g_dir_list = g_malloc0(sizeof(GList *));
             if (ms->kernel_filename) {
                 uint64_t entry = load_kernel(vms);
                 qdev_prop_set_uint32(cpu0, "exec-start-addr", entry);
@@ -294,6 +296,9 @@ static void virt_init(MachineState *ms)
                 uint64_t entry = load_bios(vms);
                 qdev_prop_set_uint32(cpu0, "exec-start-addr", entry);
             }
+        } else {
+            CPUHexagonState *env0 = cpu_env(qemu_get_cpu(0));
+            env->g_dir_list = env0->g_dir_list;
         }
         qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
         qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 7efd33d3533..edadb40bed6 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -30,6 +30,9 @@
 #include "semihosting/guestfd.h"
 #include "system/runstate.h"
 
+/* We start from 1 as 0 is used to signal an error from opendir() */
+static const int DIR_INDEX_OFFSET = 1;
+
 /* non-arm-compatible semihosting calls */
 #define HEXAGON_SPECIFIC_SWI_FLAGS \
     DEF_SWI_FLAG(OPEN,             0x01) \
@@ -566,6 +569,82 @@ static void sim_handle_trap0(CPUHexagonState *env)
     }
     break;
 
+    case HEX_SYS_OPENDIR:
+    {
+        DIR *dir;
+        char buf[BUFSIZ];
+        int rc = 0, err = 0;
+        int i = 0;
+
+        do {
+            hexagon_read_memory(env, swi_info + i, 1, &buf[i], retaddr);
+            i++;
+        } while ((i < BUFSIZ) && buf[i - 1]);
+
+        dir = opendir(buf);
+        if (dir != NULL) {
+            *env->g_dir_list = g_list_append(*env->g_dir_list, dir);
+            rc = g_list_index(*env->g_dir_list, dir) + DIR_INDEX_OFFSET;
+        } else {
+            err = errno;
+        }
+        common_semi_cb(cs, rc, rc != 0 ? 0 : err);
+        break;
+    }
+
+    case HEX_SYS_READDIR:
+    {
+        struct dirent *host_dir_entry = NULL;
+        int dir_index = swi_info - DIR_INDEX_OFFSET;
+        DIR *dir = g_list_nth_data(*env->g_dir_list, dir_index);
+        uint32_t rc = 0, err = 0;
+
+        if (dir) {
+            errno = 0;
+            host_dir_entry = readdir(dir);
+            if (host_dir_entry == NULL) {
+                err = errno;
+            }
+        } else {
+            err = EBADF;
+        }
+
+        if (host_dir_entry) {
+            uint32_t guest_dir_entry = arch_get_thread_reg(env, HEX_REG_R02);
+            hexagon_write_memory(env, guest_dir_entry, 4, 
host_dir_entry->d_ino,
+                                 retaddr);
+            for (int i = 0; i < sizeof(host_dir_entry->d_name); i++) {
+                hexagon_write_memory(env, guest_dir_entry + 4 + i, 1,
+                                     host_dir_entry->d_name[i], retaddr);
+                if (!host_dir_entry->d_name[i]) {
+                    break;
+                }
+            }
+            rc = guest_dir_entry;
+        }
+        common_semi_cb(cs, rc, err);
+        break;
+    }
+
+    case HEX_SYS_CLOSEDIR:
+    {
+        DIR *dir;
+        int ret = -1, err = 0;
+        int dir_index = swi_info - DIR_INDEX_OFFSET;
+
+        dir = g_list_nth_data(*env->g_dir_list, dir_index);
+        if (dir != NULL) {
+            ret = closedir(dir);
+            if (ret != 0) {
+                err = errno;
+            }
+        } else {
+            err = EBADF;
+        }
+        common_semi_cb(cs, ret, ret == 0 ? 0 : err);
+        break;
+    }
+
     case HEX_SYS_COREDUMP:
         coredump(env);
         break;
-- 
2.37.2


Reply via email to