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