@samitouri / QOSamiQemu / commits / a6c834a160

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 */