1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Emulator tests - for s390x CPU instructions that are usually interpreted 4 * by the hardware 5 * 6 * Copyright (c) 2017 Red Hat Inc 7 * 8 * Authors: 9 * David Hildenbrand <david@redhat.com> 10 */ 11 #include <libcflat.h> 12 #include <asm/cpacf.h> 13 #include <asm/interrupt.h> 14 #include <asm/float.h> 15 #include <linux/compiler.h> 16 17 struct lowcore *lc = NULL; 18 19 static inline void __test_spm_ipm(uint8_t cc, uint8_t key) 20 { 21 uint64_t in = (cc << 28) | (key << 24); 22 uint64_t out = ~0ULL; 23 24 report_prefix_pushf("cc=%d,key=%x", cc, key); 25 26 asm volatile ("spm %1\n" 27 "ipm %0\n" 28 : "+r"(out) : "r"(in) : "cc"); 29 30 report(!(out & 0xc0000000UL), "bit 32 and 33 set to zero"); 31 report((out & ~0xff000000ULL) == ~0xff000000ULL, 32 "bit 0-31, 40-63 unchanged"); 33 report(!((in ^ out) & 0x3f000000UL), "cc and key applied"); 34 35 report_prefix_pop(); 36 } 37 38 /* Test the SET PROGRAM PARAMETER and INSERT PROGRAM PARAMETER instruction */ 39 static void test_spm_ipm(void) 40 { 41 __test_spm_ipm(0, 0xf); 42 __test_spm_ipm(1, 0x9); 43 __test_spm_ipm(2, 0x5); 44 __test_spm_ipm(3, 0x3); 45 __test_spm_ipm(0, 0); 46 } 47 48 static __always_inline void __test_cpacf(unsigned int opcode, unsigned long func, 49 unsigned int r1, unsigned int r2, 50 unsigned int r3) 51 { 52 register unsigned long gr0 asm("0") = func; 53 cpacf_mask_t mask; 54 register unsigned long gr1 asm("1") = (unsigned long)&mask; 55 56 asm volatile(".insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],0\n" 57 : : "d" (gr0), "d" (gr1), [opc] "i" (opcode), 58 [r1] "i" (r1), [r2] "i" (r2), [r3] "i" (r3)); 59 } 60 61 static __always_inline void __test_cpacf_r1_odd(unsigned int opcode) 62 { 63 report_prefix_push("r1 odd"); 64 expect_pgm_int(); 65 __test_cpacf(opcode, 0, 1, 4, 6); 66 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 67 report_prefix_pop(); 68 } 69 70 static __always_inline void __test_cpacf_r1_null(unsigned int opcode) 71 { 72 report_prefix_push("r1 null"); 73 expect_pgm_int(); 74 __test_cpacf(opcode, 0, 0, 4, 6); 75 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 76 report_prefix_pop(); 77 } 78 79 static __always_inline void __test_cpacf_r2_odd(unsigned int opcode) 80 { 81 report_prefix_push("r2 odd"); 82 expect_pgm_int(); 83 __test_cpacf(opcode, 0, 2, 3, 6); 84 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 85 report_prefix_pop(); 86 } 87 88 static __always_inline void __test_cpacf_r2_null(unsigned int opcode) 89 { 90 report_prefix_push("r2 null"); 91 expect_pgm_int(); 92 __test_cpacf(opcode, 0, 2, 0, 6); 93 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 94 report_prefix_pop(); 95 } 96 97 static __always_inline void __test_cpacf_r3_odd(unsigned int opcode) 98 { 99 report_prefix_push("r3 odd"); 100 expect_pgm_int(); 101 __test_cpacf(opcode, 0, 2, 4, 5); 102 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 103 report_prefix_pop(); 104 } 105 106 static __always_inline void __test_cpacf_r3_null(unsigned int opcode) 107 { 108 report_prefix_push("r3 null"); 109 expect_pgm_int(); 110 __test_cpacf(opcode, 0, 2, 4, 0); 111 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 112 report_prefix_pop(); 113 } 114 115 static __always_inline void __test_cpacf_mod_bit(unsigned int opcode) 116 { 117 report_prefix_push("mod bit"); 118 expect_pgm_int(); 119 __test_cpacf(opcode, CPACF_DECRYPT, 2, 4, 6); 120 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 121 report_prefix_pop(); 122 } 123 124 static __always_inline void __test_cpacf_invalid_func(unsigned int opcode) 125 { 126 report_prefix_push("invalid subfunction"); 127 expect_pgm_int(); 128 /* 127 is unassigned for now. We don't simply use any, as HW 129 * might simply mask valid codes in query but they might still work */ 130 if (cpacf_query_func(opcode, 127)) { 131 report_skip("127 not invalid"); 132 } else { 133 __test_cpacf(opcode, 127, 2, 4, 6); 134 } 135 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 136 report_prefix_pop(); 137 } 138 139 static __always_inline void __test_cpacf_invalid_parm(unsigned int opcode) 140 { 141 report_prefix_push("invalid parm address"); 142 expect_pgm_int(); 143 __cpacf_query(opcode, (void *) -1); 144 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 145 report_prefix_pop(); 146 } 147 148 static __always_inline void __test_cpacf_protected_parm(unsigned int opcode) 149 { 150 report_prefix_push("protected parm address"); 151 expect_pgm_int(); 152 low_prot_enable(); 153 __cpacf_query(opcode, (void *) 8); 154 low_prot_disable(); 155 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 156 report_prefix_pop(); 157 } 158 159 static __always_inline void __test_basic_cpacf_opcode(unsigned int opcode) 160 { 161 bool mod_bit_allowed = false; 162 163 if (!__cpacf_check_opcode(opcode)) { 164 report_skip("not available"); 165 return; 166 } 167 report(cpacf_query_func(opcode, 0), "query indicated in query"); 168 169 switch (opcode) { 170 case CPACF_KMCTR: 171 __test_cpacf_r3_odd(opcode); 172 __test_cpacf_r3_null(opcode); 173 /* FALL THROUGH */ 174 case CPACF_PRNO: 175 case CPACF_KMF: 176 case CPACF_KMC: 177 case CPACF_KMO: 178 case CPACF_KM: 179 __test_cpacf_r1_odd(opcode); 180 __test_cpacf_r1_null(opcode); 181 mod_bit_allowed = true; 182 /* FALL THROUGH */ 183 case CPACF_KMAC: 184 case CPACF_KIMD: 185 case CPACF_KLMD: 186 __test_cpacf_r2_odd(opcode); 187 __test_cpacf_r2_null(opcode); 188 break; 189 } 190 if (!mod_bit_allowed) 191 __test_cpacf_mod_bit(opcode); 192 __test_cpacf_invalid_func(opcode); 193 __test_cpacf_invalid_parm(opcode); 194 __test_cpacf_protected_parm(opcode); 195 } 196 197 /* COMPUTE MESSAGE AUTHENTICATION CODE */ 198 static void test_kmac(void) 199 { 200 __test_basic_cpacf_opcode(CPACF_KMAC); 201 } 202 203 /* CIPHER MESSAGE */ 204 static void test_km(void) 205 { 206 __test_basic_cpacf_opcode(CPACF_KM); 207 } 208 /* CIPHER MESSAGE WITH CHAINING */ 209 static void test_kmc(void) 210 { 211 __test_basic_cpacf_opcode(CPACF_KMC); 212 } 213 214 /* COMPUTE INTERMEDIATE MESSAGE DIGEST */ 215 static void test_kimd(void) 216 { 217 __test_basic_cpacf_opcode(CPACF_KIMD); 218 } 219 220 /* COMPUTE LAST MESSAGE DIGEST */ 221 static void test_klmd(void) 222 { 223 __test_basic_cpacf_opcode(CPACF_KLMD); 224 } 225 226 /* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ 227 static void test_pckmo(void) 228 { 229 __test_basic_cpacf_opcode(CPACF_PCKMO); 230 } 231 232 /* CIPHER MESSAGE WITH CIPHER FEEDBACK */ 233 static void test_kmf(void) 234 { 235 __test_basic_cpacf_opcode(CPACF_KMF); 236 } 237 238 /* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ 239 static void test_kmo(void) 240 { 241 __test_basic_cpacf_opcode(CPACF_KMO); 242 } 243 244 /* PERFORM CRYPTOGRAPHIC COMPUTATION */ 245 static void test_pcc(void) 246 { 247 __test_basic_cpacf_opcode(CPACF_PCC); 248 } 249 250 /* CIPHER MESSAGE WITH COUNTER */ 251 static void test_kmctr(void) 252 { 253 __test_basic_cpacf_opcode(CPACF_KMCTR); 254 } 255 256 /* PERFORM RANDOM NUMBER OPERATION (formerly PPNO) */ 257 static void test_prno(void) 258 { 259 __test_basic_cpacf_opcode(CPACF_PRNO); 260 } 261 262 static void test_dxc(void) 263 { 264 /* DXC (0xff) is to be stored in LC and FPC on a trap (CRT) with AFP */ 265 lc->dxc_vxc = 0x12345678; 266 set_fpc_dxc(0); 267 268 report_prefix_push("afp"); 269 expect_pgm_int(); 270 asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n" 271 : : "r"(0) : "memory"); 272 check_pgm_int_code(PGM_INT_CODE_DATA); 273 274 report(lc->dxc_vxc == 0xff, "dxc in LC"); 275 report(get_fpc_dxc() == 0xff, "dxc in FPC"); 276 report_prefix_pop(); 277 278 /* DXC (0xff) is to be stored in LC only on a trap (CRT) without AFP */ 279 lc->dxc_vxc = 0x12345678; 280 set_fpc_dxc(0); 281 282 report_prefix_push("no-afp"); 283 expect_pgm_int(); 284 /* temporarily disable AFP */ 285 afp_disable(); 286 asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n" 287 : : "r"(0) : "memory"); 288 afp_enable(); 289 check_pgm_int_code(PGM_INT_CODE_DATA); 290 291 report(lc->dxc_vxc == 0xff, "dxc in LC"); 292 report(get_fpc_dxc() == 0, "dxc not in FPC"); 293 report_prefix_pop(); 294 } 295 296 static struct { 297 const char *name; 298 void (*func)(void); 299 } tests[] = { 300 { "spm/ipm", test_spm_ipm }, 301 { "kmac", test_kmac }, 302 { "km", test_km }, 303 { "kmc", test_kmc }, 304 { "kimd", test_kimd }, 305 { "klmd", test_klmd }, 306 { "pckmo", test_pckmo }, 307 { "kmf", test_kmf }, 308 { "kmo", test_kmo }, 309 { "pcc", test_pcc }, 310 { "kmctr", test_kmctr }, 311 { "prno", test_prno }, 312 { "dxc", test_dxc }, 313 { NULL, NULL } 314 }; 315 316 int main(int argc, char**argv) 317 { 318 int i; 319 320 report_prefix_push("emulator"); 321 for (i = 0; tests[i].name; i++) { 322 report_prefix_push(tests[i].name); 323 tests[i].func(); 324 report_prefix_pop(); 325 } 326 report_prefix_pop(); 327 328 return report_summary(); 329 } 330