target/hexagon: Add privilege check, use tag_ignore()
Add system event and cause code definitions needed for exception handling in sysemu mode. Add privilege checks that raise exceptions for guest/supervisor-only instructions executed without appropriate privilege. Expose hex_gen_exception_end_tb() via translate.h (previously the static gen_exception_end_tb) so that it can be called from the generated privileged-instruction TCG stubs. Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Jun 22, 2026 at 15:27 UTC
9831d3cab16819ce6d9c39cbd66db019b5fc4256
7 files changed
+127
-24
linux-user/hexagon/cpu_loop.c
+16
@@ -22,6 +22,7 @@
22
#include "qemu.h"
23
#include "user-internals.h"
24
#include "user/cpu_loop.h"
25
+#include "target/hexagon/internal.h"
26
#include "signal-common.h"
27
#include "internal.h"
28
@@ -60,6 +61,21 @@ void cpu_loop(CPUHexagonState *env)
61
env->gpr[0] = ret;
62
}
63
break;
64
+ case HEX_EVENT_PRECISE:
65
+ switch (env->cause_code) {
66
+ case HEX_CAUSE_PRIV_USER_NO_GINSN:
67
+ case HEX_CAUSE_PRIV_USER_NO_SINSN:
68
+ case HEX_CAUSE_INVALID_PACKET:
69
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
70
+ env->gpr[HEX_REG_PC]);
71
+ break;
72
+ default:
73
+ EXCP_DUMP(env, "\nqemu: unhandled CPU precise exception "
74
+ "cause code 0x%x - aborting\n",
75
+ env->cause_code);
76
+ exit(EXIT_FAILURE);
77
+ }
78
+ break;
79
case HEX_CAUSE_PC_NOT_ALIGNED:
80
force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
81
env->gpr[HEX_REG_R31]);
target/hexagon/cpu.c
+1
@@ -299,6 +299,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
299
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
300
/* Default NaN value: sign bit set, all frac bits set */
301
set_float_default_nan_pattern(0b11111111, &env->fp_status);
302
+ env->cause_code = HEX_EVENT_NONE;
303
}
304
305
static void hexagon_cpu_disas_set_info(const CPUState *cs,
target/hexagon/cpu.h
+10
@@ -45,6 +45,15 @@
45
46
#define MMU_USER_IDX 0
47
48
+#define HEXAGON_CPU_IRQ_0 0
49
+#define HEXAGON_CPU_IRQ_1 1
50
+#define HEXAGON_CPU_IRQ_2 2
51
+#define HEXAGON_CPU_IRQ_3 3
52
+#define HEXAGON_CPU_IRQ_4 4
53
+#define HEXAGON_CPU_IRQ_5 5
54
+#define HEXAGON_CPU_IRQ_6 6
55
+#define HEXAGON_CPU_IRQ_7 7
56
+
57
typedef struct {
58
target_ulong va;
59
uint32_t width;
@@ -77,6 +86,7 @@ typedef struct {
86
typedef struct CPUArchState {
87
target_ulong gpr[TOTAL_PER_THREAD_REGS];
88
target_ulong pred[NUM_PREGS];
89
+ uint32_t cause_code;
90
91
/* For comparing with LLDB on target - see adjust_stack_ptrs function */
92
target_ulong last_pc_dumped;
target/hexagon/cpu_bits.h
+66
-9
@@ -25,20 +25,77 @@
25
#define PCALIGN_MASK (PCALIGN - 1)
26
27
enum hex_event {
28
- HEX_EVENT_NONE = -1,
29
- HEX_EVENT_TRAP0 = 0x008,
28
+ HEX_EVENT_NONE = -1,
29
+ HEX_EVENT_RESET = 0x0,
30
+ HEX_EVENT_IMPRECISE = 0x1,
31
+ HEX_EVENT_PRECISE = 0x2,
32
+ HEX_EVENT_TLB_MISS_X = 0x4,
33
+ HEX_EVENT_TLB_MISS_RW = 0x6,
34
+ HEX_EVENT_TRAP0 = 0x8,
35
+ HEX_EVENT_TRAP1 = 0x9,
36
+ HEX_EVENT_FPTRAP = 0xb,
37
+ HEX_EVENT_DEBUG = 0xc,
38
+ HEX_EVENT_INT0 = 0x10,
39
+ HEX_EVENT_INT1 = 0x11,
40
+ HEX_EVENT_INT2 = 0x12,
41
+ HEX_EVENT_INT3 = 0x13,
42
+ HEX_EVENT_INT4 = 0x14,
43
+ HEX_EVENT_INT5 = 0x15,
44
+ HEX_EVENT_INT6 = 0x16,
45
+ HEX_EVENT_INT7 = 0x17,
46
+ HEX_EVENT_INT8 = 0x18,
47
+ HEX_EVENT_INT9 = 0x19,
48
+ HEX_EVENT_INTA = 0x1a,
49
+ HEX_EVENT_INTB = 0x1b,
50
+ HEX_EVENT_INTC = 0x1c,
51
+ HEX_EVENT_INTD = 0x1d,
52
+ HEX_EVENT_INTE = 0x1e,
53
+ HEX_EVENT_INTF = 0x1f,
54
};
55
56
enum hex_cause {
57
HEX_CAUSE_NONE = -1,
34
- HEX_CAUSE_TRAP0 = 0x172,
35
- HEX_CAUSE_FETCH_NO_UPAGE = 0x012,
36
- HEX_CAUSE_INVALID_PACKET = 0x015,
37
- HEX_CAUSE_INVALID_OPCODE = 0x015,
58
+ HEX_CAUSE_RESET = 0x000,
59
+ HEX_CAUSE_BIU_PRECISE = 0x001,
60
+ HEX_CAUSE_UNSUPPORTED_HVX_64B = 0x002, /* QEMU-specific */
61
+ HEX_CAUSE_DOUBLE_EXCEPT = 0x003,
62
+ HEX_CAUSE_TRAP0 = 0x008,
63
+ HEX_CAUSE_TRAP1 = 0x009,
64
+ HEX_CAUSE_FETCH_NO_XPAGE = 0x011,
65
+ HEX_CAUSE_FETCH_NO_UPAGE = 0x012,
66
+ HEX_CAUSE_INVALID_PACKET = 0x015,
67
+ HEX_CAUSE_INVALID_OPCODE = 0x015, /* alias: same cause as INVALID_PACKET */
68
+ HEX_CAUSE_NO_COPROC_ENABLE = 0x016,
69
+ HEX_CAUSE_NO_COPROC2_ENABLE = 0x018,
70
+ HEX_CAUSE_PRIV_USER_NO_GINSN = 0x01a,
71
+ HEX_CAUSE_PRIV_USER_NO_SINSN = 0x01b,
72
HEX_CAUSE_REG_WRITE_CONFLICT = 0x01d,
39
- HEX_CAUSE_PC_NOT_ALIGNED = 0x01e,
40
- HEX_CAUSE_PRIV_NO_UREAD = 0x024,
41
- HEX_CAUSE_PRIV_NO_UWRITE = 0x025,
73
+ HEX_CAUSE_PC_NOT_ALIGNED = 0x01e,
74
+ HEX_CAUSE_MISALIGNED_LOAD = 0x020,
75
+ HEX_CAUSE_MISALIGNED_STORE = 0x021,
76
+ HEX_CAUSE_PRIV_NO_READ = 0x022,
77
+ HEX_CAUSE_PRIV_NO_WRITE = 0x023,
78
+ HEX_CAUSE_PRIV_NO_UREAD = 0x024,
79
+ HEX_CAUSE_PRIV_NO_UWRITE = 0x025,
80
+ HEX_CAUSE_COPROC_LDST = 0x026,
81
+ HEX_CAUSE_STACK_LIMIT = 0x027,
82
+ HEX_CAUSE_VWCTRL_WINDOW_MISS = 0x029,
83
+ HEX_CAUSE_IMPRECISE_NMI = 0x043,
84
+ HEX_CAUSE_IMPRECISE_MULTI_TLB_MATCH = 0x044,
85
+ HEX_CAUSE_TLBMISSX_CAUSE_NORMAL = 0x060,
86
+ HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE = 0x061,
87
+ HEX_CAUSE_TLBMISSRW_CAUSE_READ = 0x070,
88
+ HEX_CAUSE_TLBMISSRW_CAUSE_WRITE = 0x071,
89
+ HEX_CAUSE_DEBUG_SINGLESTEP = 0x80,
90
+ HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT = 0x0bf,
91
+ HEX_CAUSE_INT0 = 0x0c0,
92
+ HEX_CAUSE_INT1 = 0x0c1,
93
+ HEX_CAUSE_INT2 = 0x0c2,
94
+ HEX_CAUSE_INT3 = 0x0c3,
95
+ HEX_CAUSE_INT4 = 0x0c4,
96
+ HEX_CAUSE_INT5 = 0x0c5,
97
+ HEX_CAUSE_INT6 = 0x0c6,
98
+ HEX_CAUSE_INT7 = 0x0c7,
99
};
100
101
#define PACKET_WORDS_MAX 4
target/hexagon/gen_tcg_funcs.py
+22
-13
@@ -21,7 +21,7 @@ import sys
21
import re
22
import string
23
import hex_common
24
-
24
+from textwrap import dedent
25
26
##
27
## Generate the TCG code to call the helper
@@ -49,6 +49,18 @@ def gen_tcg_func(f, tag, regs, imms):
49
50
f.write(" Insn *insn G_GNUC_UNUSED = ctx->insn;\n")
51
52
+ if "A_PRIV" in hex_common.attribdict[tag]:
53
+ f.write(dedent("""\
54
+#ifdef CONFIG_USER_ONLY
55
+ hex_gen_exception_end_tb(ctx, HEX_CAUSE_PRIV_USER_NO_SINSN);
56
+#else
57
+"""))
58
+ if "A_GUEST" in hex_common.attribdict[tag]:
59
+ f.write(dedent("""\
60
+#ifdef CONFIG_USER_ONLY
61
+ hex_gen_exception_end_tb(ctx, HEX_CAUSE_PRIV_USER_NO_GINSN);
62
+#else
63
+"""))
64
if hex_common.need_ea(tag):
65
f.write(" TCGv EA G_GNUC_UNUSED = tcg_temp_new();\n")
66
@@ -100,6 +112,11 @@ def gen_tcg_func(f, tag, regs, imms):
112
if reg.is_written():
113
reg.gen_write(f, tag)
114
115
+ if (
116
+ "A_PRIV" in hex_common.attribdict[tag]
117
+ or "A_GUEST" in hex_common.attribdict[tag]
118
+ ):
119
+ f.write("#endif /* CONFIG_USER_ONLY */\n")
120
f.write("}\n\n")
121
122
@@ -124,18 +141,10 @@ def main():
141
f.write('#include "idef-generated-emitter.h.inc"\n\n')
142
143
for tag in hex_common.tags:
127
- ## Skip the priv instructions
128
- if "A_PRIV" in hex_common.attribdict[tag]:
129
- continue
130
- ## Skip the guest instructions
131
- if "A_GUEST" in hex_common.attribdict[tag]:
132
- continue
133
- ## Skip the diag instructions
134
- if tag == "Y6_diag":
135
- continue
136
- if tag == "Y6_diag0":
137
- continue
138
- if tag == "Y6_diag1":
144
+ if hex_common.tag_ignore(tag):
145
+ f.write(f"static void generate_{tag}"
146
+ f"(DisasContext *ctx)\n")
147
+ f.write("{\n}\n\n")
148
continue
149
150
gen_def_tcg_func(f, tag, tagregs, tagimms)
target/hexagon/translate.c
+10
-2
@@ -65,6 +65,10 @@ TCGv hex_vstore_addr[VSTORES_MAX];
65
TCGv hex_vstore_size[VSTORES_MAX];
66
TCGv hex_vstore_pending[VSTORES_MAX];
67
68
+#ifndef CONFIG_USER_ONLY
69
+TCGv_i32 hex_cause_code;
70
+#endif
71
+
72
static const char * const hexagon_prednames[] = {
73
"p0", "p1", "p2", "p3"
74
};
@@ -187,7 +191,7 @@ static void gen_end_tb(DisasContext *ctx)
191
ctx->base.is_jmp = DISAS_NORETURN;
192
}
193
190
-static void gen_exception_end_tb(DisasContext *ctx, int excp)
194
+void hex_gen_exception_end_tb(DisasContext *ctx, int excp)
195
{
196
gen_exec_counters(ctx);
197
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC);
@@ -580,7 +584,7 @@ static void gen_insn(DisasContext *ctx)
584
ctx->insn->generate(ctx);
585
mark_store_width(ctx);
586
} else {
583
- gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_OPCODE);
587
+ hex_gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_OPCODE);
588
}
589
}
590
@@ -1138,4 +1142,8 @@ void hexagon_translate_init(void)
1142
offsetof(CPUHexagonState, vstore_pending[i]),
1143
vstore_pending_names[i]);
1144
}
1145
+#ifndef CONFIG_USER_ONLY
1146
+ hex_cause_code = tcg_global_mem_new(tcg_env,
1147
+ offsetof(CPUHexagonState, cause_code), "cause_code");
1148
+#endif
1149
}
target/hexagon/translate.h
+2
@@ -283,6 +283,8 @@ extern TCGv hex_vstore_addr[VSTORES_MAX];
283
extern TCGv hex_vstore_size[VSTORES_MAX];
284
extern TCGv hex_vstore_pending[VSTORES_MAX];
285
286
+void hex_gen_exception_end_tb(DisasContext *ctx, int excp);
287
+
288
void process_store(DisasContext *ctx, int slot_num);
289
290
FIELD(PROBE_PKT_SCALAR_STORE_S0, MMU_IDX, 0, 2)