xref: /kvm-unit-tests/s390x/ex.c (revision c9cda994b48d8e9bc0d001e0d3c5ed2c029a8687)
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