master
c 169 lines 4.29 KB
Raw
1 /*
2 * Test detection of multiple writes to the same register.
3 *
4 * Ported from the system test (tests/tcg/hexagon/system/multiple_writes.c).
5 * In linux-user mode, duplicate GPR writes are detected at translate time
6 * and raise SIGILL when at least one conflicting write is unconditional.
7 * Purely predicated duplicate writes (e.g., complementary if/if-not) are
8 * legal and are not flagged statically.
9 *
10 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
14 #include <assert.h>
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 static void *resume_pc;
22
23 static void handle_sigill(int sig, siginfo_t *info, void *puc)
24 {
25 ucontext_t *uc = (ucontext_t *)puc;
26
27 if (sig != SIGILL) {
28 _exit(EXIT_FAILURE);
29 }
30
31 uc->uc_mcontext.r0 = SIGILL;
32 uc->uc_mcontext.pc = (unsigned long)resume_pc;
33 }
34
35 /*
36 * Unconditional pair write overlapping a single write:
37 * { r1:0 = add(r3:2, r3:2); r1 = add(r0, r1) }
38 * R1 is written by both instructions. This is invalid and must raise SIGILL.
39 */
40 static int test_static_pair_overlap(void)
41 {
42 int sig;
43
44 asm volatile(
45 "r0 = #0\n"
46 "r1 = ##1f\n"
47 "memw(%1) = r1\n"
48 ".word 0xd30242e0\n" /* r1:0 = add(r3:2, r3:2), parse=01 */
49 ".word 0xf300c101\n" /* r1 = add(r0, r1), parse=11 (end) */
50 "1:\n"
51 "%0 = r0\n"
52 : "=r"(sig)
53 : "r"(&resume_pc)
54 : "r0", "r1", "memory");
55
56 return sig;
57 }
58
59 /*
60 * Two predicated writes under complementary predicates:
61 * { if (p0) r0 = r2; if (!p0) r0 = r3 }
62 * This is architecturally valid: only one write executes at runtime.
63 * Must NOT raise SIGILL; the result should reflect the executed branch.
64 */
65 static int test_legal_predicated(void)
66 {
67 int result;
68
69 asm volatile(
70 "r0 = #0\n"
71 "r1 = ##1f\n"
72 "memw(%1) = r1\n"
73 "r2 = #7\n"
74 "r3 = #13\n"
75 "p0 = cmp.eq(r2, r2)\n"
76 "{\n"
77 " if (p0) r0 = r2\n"
78 " if (!p0) r0 = r3\n"
79 "}\n"
80 "1:\n"
81 "%0 = r0\n"
82 : "=r"(result)
83 : "r"(&resume_pc)
84 : "r0", "r1", "r2", "r3", "p0", "memory");
85
86 return result;
87 }
88
89 /*
90 * Mixed: unconditional + predicated writes to the same register:
91 * { if (p0) r1 = add(r0, #0); if (!p0) r1 = add(r0, #0);
92 * r1 = add(r0, #0) }
93 * The unconditional write always conflicts with the predicated writes.
94 * Must raise SIGILL.
95 */
96 static int test_mixed_writes(void)
97 {
98 int sig;
99
100 asm volatile(
101 "r0 = #0\n"
102 "r1 = ##1f\n"
103 "memw(%1) = r1\n"
104 "p0 = cmp.eq(r0, r0)\n"
105 ".word 0x7e204021\n" /* if (p0) r1 = add(r0, #0), parse=01 */
106 ".word 0x7ea04021\n" /* if (!p0) r1 = add(r0, #0), parse=01 */
107 ".word 0x7800c021\n" /* r1 = add(r0, #0), parse=11 (end) */
108 "1:\n"
109 "%0 = r0\n"
110 : "=r"(sig)
111 : "r"(&resume_pc)
112 : "r0", "r1", "p0", "memory");
113
114 return sig;
115 }
116
117 /*
118 * Zero encoding (issue #2696):
119 * The encoding 0x00000000 decodes as a duplex with parse bits
120 * [15:14] = 0b00:
121 * slot1: SL1_loadri_io R0 = memw(R0+#0x0)
122 * slot0: SL1_loadri_io R0 = memw(R0+#0x0)
123 *
124 * Both sub-instructions write R0 unconditionally, which is an invalid
125 * packet. This tests what happens when we jump to zeroed memory.
126 * Must raise SIGILL.
127 */
128 static int test_zero(void)
129 {
130 int sig;
131
132 asm volatile(
133 "r0 = #0\n"
134 "r1 = ##1f\n"
135 "memw(%1) = r1\n"
136 ".word 0x00000000\n"
137 "1:\n"
138 "%0 = r0\n"
139 : "=r"(sig)
140 : "r"(&resume_pc)
141 : "r0", "r1", "memory");
142
143 return sig;
144 }
145
146 int main()
147 {
148 struct sigaction act;
149
150 memset(&act, 0, sizeof(act));
151 act.sa_sigaction = handle_sigill;
152 act.sa_flags = SA_SIGINFO;
153 assert(sigaction(SIGILL, &act, NULL) == 0);
154
155 /* Legal: complementary predicated writes must not raise SIGILL */
156 assert(test_legal_predicated() == 7);
157
158 /* Illegal: unconditional pair + single overlap must raise SIGILL */
159 assert(test_static_pair_overlap() == SIGILL);
160
161 /* Illegal: unconditional + predicated writes to same reg must SIGILL */
162 assert(test_mixed_writes() == SIGILL);
163
164 /* Illegal: zero encoding = duplex with duplicate dest R0 */
165 assert(test_zero() == SIGILL);
166
167 puts("PASS");
168 return EXIT_SUCCESS;
169 }