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
