hw/hexagon/hex-subsys.c | 32 +++++--- include/hw/hexagon/hexagon.h | 14 +++- target/hexagon/hexswi.c | 94 +++++++++++++++++++++++ tests/functional/hexagon/test_systests.py | 9 +++ 4 files changed, 137 insertions(+), 12 deletions(-)
Baremetal Hexagon programs use semihosting to enumerate host
directories via OPENDIR, READDIR, and CLOSEDIR calls. The list of
open directory handles are global to all CPUs, so that guest
index values map back to host DIR pointers across calls.
Also add functional tests for the new semihosting ops.
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
v1: https://lore.kernel.org/qemu-devel/9823f67f-bfc6-40e2-ba3e-cb02e53a4004@oss.qualcomm.com/
Diff from v1: defined the dir_list inside the new HexagonClusterState,
as suggested by Phil.
hw/hexagon/hex-subsys.c | 32 +++++---
include/hw/hexagon/hexagon.h | 14 +++-
target/hexagon/hexswi.c | 94 +++++++++++++++++++++++
tests/functional/hexagon/test_systests.py | 9 +++
4 files changed, 137 insertions(+), 12 deletions(-)
diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c
index 4e3a418340..f76f803dfb 100644
--- a/hw/hexagon/hex-subsys.c
+++ b/hw/hexagon/hex-subsys.c
@@ -98,14 +98,11 @@ static DeviceState *tlb_create(HexagonCommonMachineState *hms,
return tlb;
}
-static DeviceState *cluster_create(HexagonCommonMachineState *hms)
+static void cluster_create(HexagonCommonMachineState *hms)
{
- DeviceState *cluster = qdev_new(TYPE_CPU_CLUSTER);
-
- object_property_add_child(OBJECT(hms), "cluster", OBJECT(cluster));
- qdev_prop_set_uint32(cluster, "cluster-id", 0);
-
- return cluster;
+ object_initialize_child(OBJECT(hms), "cluster", &hms->cluster,
+ TYPE_HEXAGON_CLUSTER_STATE);
+ qdev_prop_set_uint32(DEVICE(&hms->cluster), "cluster-id", 0);
}
void hex_subsys_create(HexagonCommonMachineState *hms,
@@ -135,7 +132,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
&hms->vtcm);
}
- hms->cluster = cluster_create(hms);
+ cluster_create(hms);
hms->l2vic = l2vic_create(hms, m_cfg);
hms->qtimer = qtimer_create(hms, m_cfg);
hms->glob_regs = globalreg_create(hms, m_cfg, rev);
@@ -144,7 +141,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
{
- object_property_add_child(OBJECT(hms->cluster), "cpu[*]", OBJECT(cpu));
+ object_property_add_child(OBJECT(&hms->cluster), "cpu[*]", OBJECT(cpu));
object_property_set_link(OBJECT(cpu), "global-regs",
OBJECT(hms->glob_regs), &error_fatal);
object_property_set_link(OBJECT(cpu), "tlb", OBJECT(hms->tlb),
@@ -158,10 +155,10 @@ void hex_subsys_realize_cluster(HexagonCommonMachineState *hms)
/*
* The cluster must be realized after its CPUs have been parented into it
* (see hex_subsys_add_cpu()) but before any CPU is itself realized, since
- * qdev_realize_and_unref() on a CPU latches cluster_index into the TCG
+ * qdev_realize() on a CPU latches cluster_index into the TCG
* cflags at that point.
*/
- qdev_realize_and_unref(hms->cluster, NULL, &error_fatal);
+ qdev_realize(DEVICE(&hms->cluster), NULL, &error_fatal);
}
void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu,
@@ -173,3 +170,16 @@ void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu,
l2vic_connect_cpu(hms->l2vic, cpu);
}
}
+
+static const TypeInfo hexagon_cluster_type_info = {
+ .name = TYPE_HEXAGON_CLUSTER_STATE,
+ .parent = TYPE_CPU_CLUSTER,
+ .instance_size = sizeof(HexagonClusterState),
+};
+
+static void hexagon_cluster_register_types(void)
+{
+ type_register_static(&hexagon_cluster_type_info);
+}
+
+type_init(hexagon_cluster_register_types)
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 3d7b3cb12d..bdb95b1819 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -11,6 +11,7 @@
#include "system/memory.h"
#include "hw/core/boards.h"
+#include "hw/cpu/cluster.h"
struct hexagon_board_boot_info {
uint64_t ram_size;
@@ -148,6 +149,17 @@ struct hexagon_machine_config {
union hexagon_config_table cfgtable;
};
+#define TYPE_HEXAGON_CLUSTER_STATE "hexagon-cluster-state"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonClusterState, HEXAGON_CLUSTER_STATE)
+
+struct HexagonClusterState {
+ CPUClusterState parent_obj;
+
+ struct {
+ GList *dir_list;
+ } semihosting;
+};
+
#define TYPE_HEXAGON_COMMON_MACHINE "hexagon-common-machine"
OBJECT_DECLARE_SIMPLE_TYPE(HexagonCommonMachineState, HEXAGON_COMMON_MACHINE)
@@ -157,7 +169,7 @@ struct HexagonCommonMachineState {
MemoryRegion ram;
MemoryRegion cfgtable_rom;
MemoryRegion vtcm;
- DeviceState *cluster;
+ HexagonClusterState cluster;
DeviceState *l2vic;
DeviceState *qtimer;
DeviceState *glob_regs;
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index a50ab22554..f24ebe24c4 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -19,6 +19,7 @@
#include "hex_mmu.h"
#include "hexswi.h"
#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon.h"
#ifdef CONFIG_USER_ONLY
#error "This file is only used in system emulation"
@@ -30,6 +31,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) \
@@ -375,6 +379,13 @@ static void coredump(CPUHexagonState *env)
qemu_log_unlock(f);
}
+static GList **hex_semihosting_dir_list(CPUHexagonState *env)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ HexagonClusterState *cluster = HEXAGON_CLUSTER_STATE(OBJECT(cpu)->parent);
+ return &cluster->semihosting.dir_list;
+}
+
static void sim_handle_trap0(CPUHexagonState *env)
{
target_ulong what_swi, swi_info;
@@ -644,6 +655,89 @@ 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]);
+
+ if (buf[i - 1]) {
+ err = ENAMETOOLONG;
+ } else {
+ GList **dir_list = hex_semihosting_dir_list(env);
+ dir = opendir(buf);
+ if (dir != NULL) {
+ *dir_list = g_list_append(*dir_list, dir);
+ rc = g_list_index(*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;
+ GList **dir_list = hex_semihosting_dir_list(env);
+ DIR *dir = g_list_nth_data(*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 = env->gpr[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;
+ GList **dir_list = hex_semihosting_dir_list(env);
+
+ dir = g_list_nth_data(*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;
diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
index f36e015f50..c354fd20ca 100755
--- a/tests/functional/hexagon/test_systests.py
+++ b/tests/functional/hexagon/test_systests.py
@@ -7,6 +7,7 @@
import re
import time
import unittest
+from pathlib import Path
from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
@@ -90,5 +91,13 @@ def test_access(self):
def test_semihost(self):
self.run_console_pattern("semihost", "PASS", "-append", "arg1", "arg2")
+ def test_dirent(self):
+ testdir = Path(self.scratch_file("_testdir_dirent"))
+ testdir.mkdir()
+ files = [".", "..", "file1", "file2"]
+ for f in files:
+ testdir.joinpath(f).touch()
+ self.run_console_pattern("dirent", " ".join(files), "-append", str(testdir))
+
if __name__ == "__main__":
QemuSystemTest.main()
--
2.37.2
On 2/9/26 19:04, Matheus Tavares Bernardino wrote: > Baremetal Hexagon programs use semihosting to enumerate host > directories via OPENDIR, READDIR, and CLOSEDIR calls. The list of > open directory handles are global to all CPUs, so that guest > index values map back to host DIR pointers across calls. > > Also add functional tests for the new semihosting ops. > > Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com> > Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com> > Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> > --- > v1: https://lore.kernel.org/qemu-devel/9823f67f-bfc6-40e2-ba3e-cb02e53a4004@oss.qualcomm.com/ > > Diff from v1: defined the dir_list inside the new HexagonClusterState, > as suggested by Phil. Thank you Matheus! QOM/QDev: Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> > > hw/hexagon/hex-subsys.c | 32 +++++--- > include/hw/hexagon/hexagon.h | 14 +++- > target/hexagon/hexswi.c | 94 +++++++++++++++++++++++ > tests/functional/hexagon/test_systests.py | 9 +++ > 4 files changed, 137 insertions(+), 12 deletions(-)
© 2016 - 2026 Red Hat, Inc.