@samitouri / QOSamiQemu / commits / 9831d3cab1

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)