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