Some of the system registers are shared among all threads
in the core. This object contains the representation and
interface to the system registers.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/hexagon_globalreg.h | 56 ++++++
hw/hexagon/hexagon_globalreg.c | 240 +++++++++++++++++++++++++
2 files changed, 296 insertions(+)
create mode 100644 include/hw/hexagon/hexagon_globalreg.h
create mode 100644 hw/hexagon/hexagon_globalreg.c
diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/hexagon_globalreg.h
new file mode 100644
index 00000000000..c9e72f30b0a
--- /dev/null
+++ b/include/hw/hexagon/hexagon_globalreg.h
@@ -0,0 +1,56 @@
+/*
+ * Hexagon Global Registers QOM Object
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_GLOBALREG_H
+#define HEXAGON_GLOBALREG_H
+
+#include "hw/core/qdev.h"
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+#include "target/hexagon/cpu.h"
+
+#define TYPE_HEXAGON_GLOBALREG "hexagon-globalreg"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonGlobalRegState, HEXAGON_GLOBALREG)
+
+struct HexagonGlobalRegState {
+ SysBusDevice parent_obj;
+
+ /* Array of system registers */
+ uint32_t regs[NUM_SREGS];
+
+ /* Global performance cycle counter base */
+ uint64_t g_pcycle_base;
+
+ /* Properties for global register reset values */
+ uint32_t boot_evb; /* Boot Exception Vector Base (HEX_SREG_EVB) */
+ uint64_t config_table_addr; /* Configuration table base */
+ uint32_t dsp_rev; /* DSP revision register (HEX_SREG_REV) */
+
+ /* ISDB properties */
+ bool isdben_etm_enable; /* ISDB ETM enable bit */
+ bool isdben_dfd_enable; /* ISDB DFD enable bit */
+ bool isdben_trusted; /* ISDB trusted mode bit */
+ bool isdben_secure; /* ISDB secure mode bit */
+};
+
+/* Public interface functions */
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t htid);
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value, uint32_t htid);
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value);
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value);
+void hexagon_globalreg_reset(HexagonGlobalRegState *s);
+
+/* Global performance cycle counter access */
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s);
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
+ uint64_t value);
+
+#endif /* HEXAGON_GLOBALREG_H */
diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
new file mode 100644
index 00000000000..5187b91dcae
--- /dev/null
+++ b/hw/hexagon/hexagon_globalreg.c
@@ -0,0 +1,240 @@
+/*
+ * Hexagon Global Registers
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/sysbus.h"
+#include "hw/core/resettable.h"
+#include "migration/vmstate.h"
+#include "qom/object.h"
+#include "target/hexagon/cpu.h"
+#include "target/hexagon/hex_regs.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+
+#define IMMUTABLE (~0)
+#define INVALID_REG_VAL 0xdeadbeef
+
+/* Global system register mutability masks */
+static const uint32_t global_sreg_immut_masks[NUM_SREGS] = {
+ [HEX_SREG_EVB] = 0x000000ff,
+ [HEX_SREG_MODECTL] = IMMUTABLE,
+ [HEX_SREG_SYSCFG] = 0x80001c00,
+ [HEX_SREG_IPENDAD] = IMMUTABLE,
+ [HEX_SREG_VID] = 0xfc00fc00,
+ [HEX_SREG_VID1] = 0xfc00fc00,
+ [HEX_SREG_BESTWAIT] = 0xfffffe00,
+ [HEX_SREG_IAHL] = 0x00000000,
+ [HEX_SREG_SCHEDCFG] = 0xfffffee0,
+ [HEX_SREG_CFGBASE] = IMMUTABLE,
+ [HEX_SREG_DIAG] = 0x00000000,
+ [HEX_SREG_REV] = IMMUTABLE,
+ [HEX_SREG_ISDBST] = IMMUTABLE,
+ [HEX_SREG_ISDBCFG0] = 0xe0000000,
+ [HEX_SREG_BRKPTPC0] = 0x00000003,
+ [HEX_SREG_BRKPTCFG0] = 0xfc007000,
+ [HEX_SREG_BRKPTPC1] = 0x00000003,
+ [HEX_SREG_BRKPTCFG1] = 0xfc007000,
+ [HEX_SREG_ISDBMBXIN] = IMMUTABLE,
+ [HEX_SREG_ISDBMBXOUT] = 0x00000000,
+ [HEX_SREG_ISDBEN] = 0xfffffffe,
+ [HEX_SREG_TIMERLO] = IMMUTABLE,
+ [HEX_SREG_TIMERHI] = IMMUTABLE,
+};
+
+static void hexagon_globalreg_init(Object *obj)
+{
+ HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
+
+ memset(s->regs, 0, sizeof(uint32_t) * NUM_SREGS);
+}
+
+static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val,
+ uint32_t reg_mask)
+{
+ if (reg_mask) {
+ return (new_val & ~reg_mask) | (cur_val & reg_mask);
+ }
+ return new_val;
+}
+
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t htid)
+{
+ g_assert(reg < NUM_SREGS);
+ g_assert(reg >= HEX_SREG_GLB_START);
+ g_assert(s);
+
+ uint32_t value = s->regs[reg];
+
+ return value;
+}
+
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value, uint32_t htid)
+{
+ g_assert(s);
+ g_assert(reg < NUM_SREGS);
+ g_assert(reg >= HEX_SREG_GLB_START);
+ s->regs[reg] = value;
+}
+
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value)
+{
+ g_assert(s);
+ g_assert(reg < NUM_SREGS);
+ g_assert(reg >= HEX_SREG_GLB_START);
+ const uint32_t reg_mask = global_sreg_immut_masks[reg];
+ return reg_mask == IMMUTABLE ?
+ s->regs[reg] :
+ apply_write_mask(value, s->regs[reg], reg_mask);
+}
+
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
+ uint32_t value)
+{
+ g_assert(s);
+ s->regs[reg] = hexagon_globalreg_masked_value(s, reg, value);
+}
+
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s)
+{
+ g_assert(s);
+ return s->g_pcycle_base;
+}
+
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
+ uint64_t value)
+{
+ g_assert(s);
+ s->g_pcycle_base = value;
+}
+
+static void do_hexagon_globalreg_reset(HexagonGlobalRegState *s)
+{
+ g_assert(s);
+ memset(s->regs, 0, sizeof(uint32_t) * NUM_SREGS);
+
+ s->g_pcycle_base = 0;
+
+ s->regs[HEX_SREG_EVB] = s->boot_evb;
+ s->regs[HEX_SREG_CFGBASE] = HEXAGON_CFG_ADDR_BASE(s->config_table_addr);
+ s->regs[HEX_SREG_REV] = s->dsp_rev;
+
+ uint32_t isdben_val = 0;
+ if (s->isdben_etm_enable) {
+ isdben_val |= (1 << 0); /* ETM enable bit */
+ }
+ if (s->isdben_dfd_enable) {
+ isdben_val |= (1 << 1); /* DFD enable bit */
+ }
+ if (s->isdben_trusted) {
+ isdben_val |= (1 << 2); /* Trusted bit */
+ }
+ if (s->isdben_secure) {
+ isdben_val |= (1 << 3); /* Secure bit */
+ }
+ s->regs[HEX_SREG_ISDBEN] = isdben_val;
+ s->regs[HEX_SREG_MODECTL] = 0x1;
+
+ /*
+ * These register indices are placeholders in these arrays
+ * and their actual values are synthesized from state elsewhere.
+ * We can initialize these with invalid values so that if we
+ * mistakenly generate reads, they will look obviously wrong.
+ */
+ s->regs[HEX_SREG_PCYCLELO] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PCYCLEHI] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_TIMERLO] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_TIMERHI] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT0] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT1] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT2] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT3] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT4] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT5] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT6] = INVALID_REG_VAL;
+ s->regs[HEX_SREG_PMUCNT7] = INVALID_REG_VAL;
+}
+
+static void hexagon_globalreg_realize(DeviceState *dev, Error **errp)
+{
+}
+
+void hexagon_globalreg_reset(HexagonGlobalRegState *s)
+{
+ do_hexagon_globalreg_reset(s);
+}
+
+static void hexagon_globalreg_reset_hold(Object *obj, ResetType type)
+{
+ HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
+ do_hexagon_globalreg_reset(s);
+}
+
+static const VMStateDescription vmstate_hexagon_globalreg = {
+ .name = "hexagon_globalreg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]){
+ VMSTATE_UINT32_ARRAY(regs, HexagonGlobalRegState, NUM_SREGS),
+ VMSTATE_UINT64(g_pcycle_base, HexagonGlobalRegState),
+ VMSTATE_UINT32(boot_evb, HexagonGlobalRegState),
+ VMSTATE_UINT64(config_table_addr, HexagonGlobalRegState),
+ VMSTATE_UINT32(dsp_rev, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_etm_enable, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_dfd_enable, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_trusted, HexagonGlobalRegState),
+ VMSTATE_BOOL(isdben_secure, HexagonGlobalRegState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property hexagon_globalreg_properties[] = {
+ DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
+ DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
+ config_table_addr, 0xffffffffULL),
+ DEFINE_PROP_UINT32("dsp-rev", HexagonGlobalRegState, dsp_rev, 0),
+ DEFINE_PROP_BOOL("isdben-etm-enable", HexagonGlobalRegState,
+ isdben_etm_enable, false),
+ DEFINE_PROP_BOOL("isdben-dfd-enable", HexagonGlobalRegState,
+ isdben_dfd_enable, false),
+ DEFINE_PROP_BOOL("isdben-trusted", HexagonGlobalRegState,
+ isdben_trusted, false),
+ DEFINE_PROP_BOOL("isdben-secure", HexagonGlobalRegState,
+ isdben_secure, false),
+};
+
+static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = hexagon_globalreg_realize;
+ rc->phases.hold = hexagon_globalreg_reset_hold;
+ dc->vmsd = &vmstate_hexagon_globalreg;
+ dc->user_creatable = false;
+ device_class_set_props(dc, hexagon_globalreg_properties);
+}
+
+static const TypeInfo hexagon_globalreg_info = {
+ .name = TYPE_HEXAGON_GLOBALREG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HexagonGlobalRegState),
+ .instance_init = hexagon_globalreg_init,
+ .class_init = hexagon_globalreg_class_init,
+};
+
+static void hexagon_globalreg_register_types(void)
+{
+ type_register_static(&hexagon_globalreg_info);
+}
+
+type_init(hexagon_globalreg_register_types)
--
2.34.1
On Tue, Mar 10, 2026 at 10:20 PM Brian Cain <brian.cain@oss.qualcomm.com>
wrote:
> Some of the system registers are shared among all threads
> in the core. This object contains the representation and
> interface to the system registers.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/hw/hexagon/hexagon_globalreg.h | 56 ++++++
> hw/hexagon/hexagon_globalreg.c | 240 +++++++++++++++++++++++++
> 2 files changed, 296 insertions(+)
> create mode 100644 include/hw/hexagon/hexagon_globalreg.h
> create mode 100644 hw/hexagon/hexagon_globalreg.c
>
> diff --git a/include/hw/hexagon/hexagon_globalreg.h
> b/include/hw/hexagon/hexagon_globalreg.h
> new file mode 100644
> index 00000000000..c9e72f30b0a
> --- /dev/null
> +++ b/include/hw/hexagon/hexagon_globalreg.h
> @@ -0,0 +1,56 @@
> +/*
> + * Hexagon Global Registers QOM Object
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef HEXAGON_GLOBALREG_H
> +#define HEXAGON_GLOBALREG_H
> +
> +#include "hw/core/qdev.h"
> +#include "hw/core/sysbus.h"
> +#include "qom/object.h"
> +#include "target/hexagon/cpu.h"
> +
> +#define TYPE_HEXAGON_GLOBALREG "hexagon-globalreg"
> +OBJECT_DECLARE_SIMPLE_TYPE(HexagonGlobalRegState, HEXAGON_GLOBALREG)
> +
> +struct HexagonGlobalRegState {
> + SysBusDevice parent_obj;
> +
> + /* Array of system registers */
> + uint32_t regs[NUM_SREGS];
> +
> + /* Global performance cycle counter base */
> + uint64_t g_pcycle_base;
> +
> + /* Properties for global register reset values */
> + uint32_t boot_evb; /* Boot Exception Vector Base
> (HEX_SREG_EVB) */
> + uint64_t config_table_addr; /* Configuration table base */
> + uint32_t dsp_rev; /* DSP revision register (HEX_SREG_REV) */
> +
> + /* ISDB properties */
> + bool isdben_etm_enable; /* ISDB ETM enable bit */
> + bool isdben_dfd_enable; /* ISDB DFD enable bit */
> + bool isdben_trusted; /* ISDB trusted mode bit */
> + bool isdben_secure; /* ISDB secure mode bit */
>
Should the TLB entries go in here also?
> +};
> +
> +/* Public interface functions */
> +uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
> + uint32_t htid);
>
Why is htid needed?
> +void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
> + uint32_t value, uint32_t htid);
>
Ditto
> +uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s,
> uint32_t reg,
> + uint32_t value);
> +void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t
> reg,
> + uint32_t value);
> +void hexagon_globalreg_reset(HexagonGlobalRegState *s);
> +
> +/* Global performance cycle counter access */
> +uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s);
> +void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
> + uint64_t value);
> +
> +#endif /* HEXAGON_GLOBALREG_H */
> diff --git a/hw/hexagon/hexagon_globalreg.c
> b/hw/hexagon/hexagon_globalreg.c
> new file mode 100644
> index 00000000000..5187b91dcae
> --- /dev/null
> +++ b/hw/hexagon/hexagon_globalreg.c
> @@ -0,0 +1,240 @@
> +static void hexagon_globalreg_init(Object *obj)
> +{
> + HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
> +
> + memset(s->regs, 0, sizeof(uint32_t) * NUM_SREGS);
>
Should we memset the whole thing?
> +}
>
>
© 2016 - 2026 Red Hat, Inc.