hw/hexagon: Add globalreg model
Some of the system registers are shared among all threads in the core. This object contains the representation and interface to the system registers. Reviewed-by: Sid Manning <sid.manning@oss.qualcomm.com> Acked-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Jun 22, 2026 at 15:28 UTC
a6c834a1600b78cfc06ccf91782b2f980f449b4e
2 files changed
+298
hw/hexagon/hexagon_globalreg.c
new
+243
@@ -0,0 +1,243 @@
1
+/*
2
+ * Hexagon Global Registers
3
+ *
4
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5
+ * SPDX-License-Identifier: GPL-2.0-or-later
6
+ */
7
+
8
+#include "qemu/osdep.h"
9
+#include "hw/hexagon/hexagon.h"
10
+#include "hw/hexagon/hexagon_globalreg.h"
11
+#include "hw/core/qdev-properties.h"
12
+#include "hw/core/sysbus.h"
13
+#include "hw/core/resettable.h"
14
+#include "migration/vmstate.h"
15
+#include "qom/object.h"
16
+#include "target/hexagon/cpu.h"
17
+#include "target/hexagon/hex_regs.h"
18
+#include "qemu/log.h"
19
+#include "qapi/error.h"
20
+
21
+#define IMMUTABLE (~0)
22
+#define INVALID_REG_VAL 0xdeadbeef
23
+
24
+/* Global system register mutability masks */
25
+static const uint32_t global_sreg_immut_masks[NUM_SREGS] = {
26
+ [HEX_SREG_EVB] = 0x000000ff,
27
+ [HEX_SREG_MODECTL] = IMMUTABLE,
28
+ [HEX_SREG_SYSCFG] = 0x80001c00,
29
+ [HEX_SREG_IPENDAD] = IMMUTABLE,
30
+ [HEX_SREG_VID] = 0xfc00fc00,
31
+ [HEX_SREG_VID1] = 0xfc00fc00,
32
+ [HEX_SREG_BESTWAIT] = 0xfffffe00,
33
+ [HEX_SREG_IAHL] = 0x00000000,
34
+ [HEX_SREG_SCHEDCFG] = 0xfffffee0,
35
+ [HEX_SREG_CFGBASE] = IMMUTABLE,
36
+ [HEX_SREG_DIAG] = 0x00000000,
37
+ [HEX_SREG_REV] = IMMUTABLE,
38
+ [HEX_SREG_ISDBST] = IMMUTABLE,
39
+ [HEX_SREG_ISDBCFG0] = 0xe0000000,
40
+ [HEX_SREG_BRKPTPC0] = 0x00000003,
41
+ [HEX_SREG_BRKPTCFG0] = 0xfc007000,
42
+ [HEX_SREG_BRKPTPC1] = 0x00000003,
43
+ [HEX_SREG_BRKPTCFG1] = 0xfc007000,
44
+ [HEX_SREG_ISDBMBXIN] = IMMUTABLE,
45
+ [HEX_SREG_ISDBMBXOUT] = 0x00000000,
46
+ [HEX_SREG_ISDBEN] = 0xfffffffe,
47
+ [HEX_SREG_TIMERLO] = IMMUTABLE,
48
+ [HEX_SREG_TIMERHI] = IMMUTABLE,
49
+};
50
+
51
+static void hexagon_globalreg_init(Object *obj)
52
+{
53
+ HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
54
+
55
+ memset(s->regs, 0, sizeof(s->regs));
56
+}
57
+
58
+static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val,
59
+ uint32_t reg_mask)
60
+{
61
+ if (reg_mask) {
62
+ return (new_val & ~reg_mask) | (cur_val & reg_mask);
63
+ }
64
+ return new_val;
65
+}
66
+
67
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
68
+ uint32_t htid)
69
+{
70
+ uint32_t value;
71
+
72
+ if (!s) {
73
+ return 0;
74
+ }
75
+ g_assert(reg < NUM_SREGS);
76
+ g_assert(reg >= HEX_SREG_GLB_START);
77
+
78
+ value = s->regs[reg];
79
+
80
+ return value;
81
+}
82
+
83
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
84
+ uint32_t value, uint32_t htid)
85
+{
86
+ if (!s) {
87
+ return;
88
+ }
89
+ g_assert(reg < NUM_SREGS);
90
+ g_assert(reg >= HEX_SREG_GLB_START);
91
+ s->regs[reg] = value;
92
+}
93
+
94
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
95
+ uint32_t value)
96
+{
97
+ uint32_t reg_mask;
98
+
99
+ if (!s) {
100
+ return value;
101
+ }
102
+ g_assert(reg < NUM_SREGS);
103
+ g_assert(reg >= HEX_SREG_GLB_START);
104
+ reg_mask = global_sreg_immut_masks[reg];
105
+ return reg_mask == IMMUTABLE ?
106
+ s->regs[reg] :
107
+ apply_write_mask(value, s->regs[reg], reg_mask);
108
+}
109
+
110
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
111
+ uint32_t value)
112
+{
113
+ if (!s) {
114
+ return;
115
+ }
116
+ s->regs[reg] = hexagon_globalreg_masked_value(s, reg, value);
117
+}
118
+
119
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s)
120
+{
121
+ g_assert(s);
122
+ return s->g_pcycle_base;
123
+}
124
+
125
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
126
+ uint64_t value)
127
+{
128
+ g_assert(s);
129
+ s->g_pcycle_base = value;
130
+}
131
+
132
+static void do_hexagon_globalreg_reset(HexagonGlobalRegState *s)
133
+{
134
+ uint32_t isdben_val = 0;
135
+
136
+ g_assert(s);
137
+ memset(s->regs, 0, sizeof(s->regs));
138
+
139
+ s->g_pcycle_base = 0;
140
+
141
+ s->regs[HEX_SREG_EVB] = s->boot_evb;
142
+ s->regs[HEX_SREG_CFGBASE] = HEXAGON_CFG_ADDR_BASE(s->config_table_addr);
143
+ s->regs[HEX_SREG_REV] = s->dsp_rev;
144
+
145
+ if (s->isdben_etm_enable) {
146
+ isdben_val |= (1 << 0); /* ETM enable bit */
147
+ }
148
+ if (s->isdben_dfd_enable) {
149
+ isdben_val |= (1 << 1); /* DFD enable bit */
150
+ }
151
+ if (s->isdben_trusted) {
152
+ isdben_val |= (1 << 2); /* Trusted bit */
153
+ }
154
+ if (s->isdben_secure) {
155
+ isdben_val |= (1 << 3); /* Secure bit */
156
+ }
157
+ s->regs[HEX_SREG_ISDBEN] = isdben_val;
158
+ s->regs[HEX_SREG_MODECTL] = 0x1;
159
+
160
+ /*
161
+ * These register indices are placeholders in these arrays
162
+ * and their actual values are synthesized from state elsewhere.
163
+ * We can initialize these with invalid values so that if we
164
+ * mistakenly generate reads, they will look obviously wrong.
165
+ */
166
+ s->regs[HEX_SREG_PCYCLELO] = INVALID_REG_VAL;
167
+ s->regs[HEX_SREG_PCYCLEHI] = INVALID_REG_VAL;
168
+ s->regs[HEX_SREG_TIMERLO] = INVALID_REG_VAL;
169
+ s->regs[HEX_SREG_TIMERHI] = INVALID_REG_VAL;
170
+ s->regs[HEX_SREG_PMUCNT0] = INVALID_REG_VAL;
171
+ s->regs[HEX_SREG_PMUCNT1] = INVALID_REG_VAL;
172
+ s->regs[HEX_SREG_PMUCNT2] = INVALID_REG_VAL;
173
+ s->regs[HEX_SREG_PMUCNT3] = INVALID_REG_VAL;
174
+ s->regs[HEX_SREG_PMUCNT4] = INVALID_REG_VAL;
175
+ s->regs[HEX_SREG_PMUCNT5] = INVALID_REG_VAL;
176
+ s->regs[HEX_SREG_PMUCNT6] = INVALID_REG_VAL;
177
+ s->regs[HEX_SREG_PMUCNT7] = INVALID_REG_VAL;
178
+}
179
+
180
+static void hexagon_globalreg_reset_hold(Object *obj, ResetType type)
181
+{
182
+ HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
183
+ do_hexagon_globalreg_reset(s);
184
+}
185
+
186
+static const VMStateDescription vmstate_hexagon_globalreg = {
187
+ .name = "hexagon_globalreg",
188
+ .version_id = 1,
189
+ .minimum_version_id = 1,
190
+ .fields = (const VMStateField[]){
191
+ VMSTATE_UINT32_ARRAY(regs, HexagonGlobalRegState, NUM_SREGS),
192
+ VMSTATE_UINT64(g_pcycle_base, HexagonGlobalRegState),
193
+ VMSTATE_UINT32(boot_evb, HexagonGlobalRegState),
194
+ VMSTATE_UINT64(config_table_addr, HexagonGlobalRegState),
195
+ VMSTATE_UINT32(dsp_rev, HexagonGlobalRegState),
196
+ VMSTATE_BOOL(isdben_etm_enable, HexagonGlobalRegState),
197
+ VMSTATE_BOOL(isdben_dfd_enable, HexagonGlobalRegState),
198
+ VMSTATE_BOOL(isdben_trusted, HexagonGlobalRegState),
199
+ VMSTATE_BOOL(isdben_secure, HexagonGlobalRegState),
200
+ VMSTATE_END_OF_LIST()
201
+ }
202
+};
203
+
204
+static const Property hexagon_globalreg_properties[] = {
205
+ DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
206
+ DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
207
+ config_table_addr, 0xffffffffULL),
208
+ DEFINE_PROP_UINT32("dsp-rev", HexagonGlobalRegState, dsp_rev, 0),
209
+ DEFINE_PROP_BOOL("isdben-etm-enable", HexagonGlobalRegState,
210
+ isdben_etm_enable, false),
211
+ DEFINE_PROP_BOOL("isdben-dfd-enable", HexagonGlobalRegState,
212
+ isdben_dfd_enable, false),
213
+ DEFINE_PROP_BOOL("isdben-trusted", HexagonGlobalRegState,
214
+ isdben_trusted, false),
215
+ DEFINE_PROP_BOOL("isdben-secure", HexagonGlobalRegState,
216
+ isdben_secure, false),
217
+};
218
+
219
+static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data)
220
+{
221
+ DeviceClass *dc = DEVICE_CLASS(klass);
222
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
223
+
224
+ rc->phases.hold = hexagon_globalreg_reset_hold;
225
+ dc->vmsd = &vmstate_hexagon_globalreg;
226
+ dc->user_creatable = false;
227
+ device_class_set_props(dc, hexagon_globalreg_properties);
228
+}
229
+
230
+static const TypeInfo hexagon_globalreg_info = {
231
+ .name = TYPE_HEXAGON_GLOBALREG,
232
+ .parent = TYPE_SYS_BUS_DEVICE,
233
+ .instance_size = sizeof(HexagonGlobalRegState),
234
+ .instance_init = hexagon_globalreg_init,
235
+ .class_init = hexagon_globalreg_class_init,
236
+};
237
+
238
+static void hexagon_globalreg_register_types(void)
239
+{
240
+ type_register_static(&hexagon_globalreg_info);
241
+}
242
+
243
+type_init(hexagon_globalreg_register_types)
include/hw/hexagon/hexagon_globalreg.h
new
+55
@@ -0,0 +1,55 @@
1
+/*
2
+ * Hexagon Global Registers QOM Object
3
+ *
4
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5
+ * SPDX-License-Identifier: GPL-2.0-or-later
6
+ */
7
+
8
+#ifndef HEXAGON_GLOBALREG_H
9
+#define HEXAGON_GLOBALREG_H
10
+
11
+#include "hw/core/qdev.h"
12
+#include "hw/core/sysbus.h"
13
+#include "qom/object.h"
14
+#include "target/hexagon/cpu.h"
15
+
16
+#define TYPE_HEXAGON_GLOBALREG "hexagon-globalreg"
17
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonGlobalRegState, HEXAGON_GLOBALREG)
18
+
19
+struct HexagonGlobalRegState {
20
+ SysBusDevice parent_obj;
21
+
22
+ /* Array of system registers */
23
+ uint32_t regs[NUM_SREGS];
24
+
25
+ /* Global performance cycle counter base */
26
+ uint64_t g_pcycle_base;
27
+
28
+ /* Properties for global register reset values */
29
+ uint32_t boot_evb; /* Boot Exception Vector Base (HEX_SREG_EVB) */
30
+ uint64_t config_table_addr; /* Configuration table base */
31
+ uint32_t dsp_rev; /* DSP revision register (HEX_SREG_REV) */
32
+
33
+ /* ISDB properties */
34
+ bool isdben_etm_enable; /* ISDB ETM enable bit */
35
+ bool isdben_dfd_enable; /* ISDB DFD enable bit */
36
+ bool isdben_trusted; /* ISDB trusted mode bit */
37
+ bool isdben_secure; /* ISDB secure mode bit */
38
+};
39
+
40
+/* Public interface functions */
41
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
42
+ uint32_t htid);
43
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
44
+ uint32_t value, uint32_t htid);
45
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
46
+ uint32_t value);
47
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
48
+ uint32_t value);
49
+
50
+/* Global performance cycle counter access */
51
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s);
52
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
53
+ uint64_t value);
54
+
55
+#endif /* HEXAGON_GLOBALREG_H */