1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright IBM Corp. 2023
4 *
5 * Test EXECUTE (RELATIVE LONG).
6 * These instructions execute a target instruction. The target instruction is formed
7 * by reading an instruction from memory and optionally modifying some of its bits.
8 * The execution of the target instruction is the same as if it was executed
9 * normally as part of the instruction sequence, except for the instruction
10 * address and the instruction-length code.
11 */
12
13 #include <libcflat.h>
14
15 /*
16 * Accesses to the operand of execute-type instructions are instruction fetches.
17 * Minimum alignment is two, since the relative offset is specified by number of halfwords.
18 */
19 asm ( ".pushsection .text.exrl_targets,\"x\"\n"
20 " .balign 2\n"
21 " .popsection\n"
22 );
23
24 /*
25 * BRANCH AND SAVE, register register variant.
26 * Saves the next instruction address (address from PSW + length of instruction)
27 * to the first register. No branch is taken in this test, because 0 is
28 * specified as target.
29 * BASR does *not* perform a relative address calculation with an intermediate.
30 */
test_basr(void)31 static void test_basr(void)
32 {
33 uint64_t ret_addr, after_ex;
34
35 report_prefix_push("BASR");
36 asm volatile ( ".pushsection .text.exrl_targets\n"
37 "0: basr %[ret_addr],0\n"
38 " .popsection\n"
39
40 " larl %[after_ex],1f\n"
41 " exrl 0,0b\n"
42 "1:\n"
43 : [ret_addr] "=d" (ret_addr),
44 [after_ex] "=d" (after_ex)
45 );
46
47 report(ret_addr == after_ex, "return address after EX");
48 report_prefix_pop();
49 }
50
51 /*
52 * BRANCH RELATIVE AND SAVE.
53 * According to PoP (Branch-Address Generation), the address calculated relative
54 * to the instruction address is relative to BRAS when it is the target of an
55 * execute-type instruction, not relative to the execute-type instruction.
56 */
test_bras(void)57 static void test_bras(void)
58 {
59 uint64_t after_target, ret_addr, after_ex, branch_addr;
60
61 report_prefix_push("BRAS");
62 asm volatile ( ".pushsection .text.exrl_targets\n"
63 "0: bras %[ret_addr],1f\n"
64 " nopr %%r7\n"
65 "1: larl %[branch_addr],0\n"
66 " j 4f\n"
67 " .popsection\n"
68
69 " larl %[after_target],1b\n"
70 " larl %[after_ex],3f\n"
71 "2: exrl 0,0b\n"
72 /*
73 * In case the address calculation is correct, we jump by the relative offset 1b-0b from 0b to 1b.
74 * In case the address calculation is relative to the exrl (i.e. a test failure),
75 * put a valid instruction at the same relative offset from the exrl, so the test continues in a
76 * controlled manner.
77 */
78 "3: larl %[branch_addr],0\n"
79 "4:\n"
80
81 /*
82 * Clang 15 doesn't like the if below, guard it s.t. we still have the assertion
83 * when compiling with GCC.
84 *
85 * s390x/ex.c:81:4: error: expected absolute expression
86 * " .if (1b - 0b) != (3b - 2b)\n"
87 */
88 #ifndef __clang__
89 " .if (1b - 0b) != (3b - 2b)\n"
90 " .error \"right and wrong target must have same offset\"\n"
91 " .endif\n"
92 #endif
93 : [after_target] "=d" (after_target),
94 [ret_addr] "=d" (ret_addr),
95 [after_ex] "=d" (after_ex),
96 [branch_addr] "=d" (branch_addr)
97 );
98
99 report(after_target == branch_addr, "address calculated relative to BRAS");
100 report(ret_addr == after_ex, "return address after EX");
101 report_prefix_pop();
102 }
103
104 /*
105 * LOAD ADDRESS RELATIVE LONG.
106 * If it is the target of an execute-type instruction, the address is relative
107 * to the LARL.
108 */
test_larl(void)109 static void test_larl(void)
110 {
111 uint64_t target, addr;
112
113 report_prefix_push("LARL");
114 asm volatile ( ".pushsection .text.exrl_targets\n"
115 "0: larl %[addr],0\n"
116 " .popsection\n"
117
118 " larl %[target],0b\n"
119 " exrl 0,0b\n"
120 : [target] "=d" (target),
121 [addr] "=d" (addr)
122 );
123
124 report(target == addr, "address calculated relative to LARL");
125 report_prefix_pop();
126 }
127
128 /* LOAD LOGICAL RELATIVE LONG.
129 * If it is the target of an execute-type instruction, the address is relative
130 * to the LLGFRL.
131 */
test_llgfrl(void)132 static void test_llgfrl(void)
133 {
134 uint64_t target, value;
135
136 report_prefix_push("LLGFRL");
137 asm volatile ( ".pushsection .text.exrl_targets\n"
138 " .balign 4\n"
139 //operand of llgfrl must be word aligned
140 "0: llgfrl %[value],0\n"
141 " .popsection\n"
142
143 " llgfrl %[target],0b\n"
144 //align (pad with nop), in case the wrong operand is used
145 " .balignw 4,0x0707\n"
146 " exrl 0,0b\n"
147 : [target] "=d" (target),
148 [value] "=d" (value)
149 );
150
151 report(target == value, "loaded correct value");
152 report_prefix_pop();
153 }
154
155 /*
156 * COMPARE RELATIVE LONG
157 * If it is the target of an execute-type instruction, the address is relative
158 * to the CRL.
159 */
test_crl(void)160 static void test_crl(void)
161 {
162 uint32_t program_mask, cc, crl_word;
163
164 report_prefix_push("CRL");
165 asm volatile ( ".pushsection .text.exrl_targets\n"
166 //operand of crl must be word aligned
167 " .balign 4\n"
168 "0: crl %[crl_word],0\n"
169 " .popsection\n"
170
171 " lrl %[crl_word],0b\n"
172 //align (pad with nop), in case the wrong operand is used
173 " .balignw 4,0x0707\n"
174 " exrl 0,0b\n"
175 " ipm %[program_mask]\n"
176 : [program_mask] "=d" (program_mask),
177 [crl_word] "=d" (crl_word)
178 :: "cc"
179 );
180
181 cc = program_mask >> 28;
182 report(!cc, "operand compared to is relative to CRL");
183 report_prefix_pop();
184 }
185
main(int argc,char ** argv)186 int main(int argc, char **argv)
187 {
188 report_prefix_push("ex");
189 test_basr();
190 test_bras();
191 test_larl();
192 test_llgfrl();
193 test_crl();
194 report_prefix_pop();
195
196 return report_summary();
197 }
198