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