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 */ 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 */ 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 */ 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 */ 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 */ 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 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