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