1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Tests sigp store additional status order 4 * 5 * Copyright IBM Corp. 2022 6 * 7 * Authors: 8 * Nico Boehr <nrb@linux.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <asm/asm-offsets.h> 12 #include <asm/interrupt.h> 13 #include <asm/facility.h> 14 #include <asm-generic/barrier.h> 15 #include <asm/sigp.h> 16 #include <asm/vector.h> 17 18 #include <smp.h> 19 #include <gs.h> 20 21 static int testflag = 0; 22 23 #define INVALID_CPU_ADDRESS -4711 24 25 struct mcesa_lc12 { 26 uint8_t vregs[0x200]; /* 0x000 */ 27 uint8_t reserved200[0x400 - 0x200]; /* 0x200 */ 28 struct gs_cb gs_cb; /* 0x400 */ 29 uint8_t reserved420[0x800 - 0x420]; /* 0x420 */ 30 uint8_t reserved800[0x1000 - 0x800]; /* 0x800 */ 31 }; 32 33 static struct mcesa_lc12 adtl_status __attribute__((aligned(4096))); 34 35 static uint8_t expected_vec_contents[VEC_REGISTER_NUM][VEC_REGISTER_SIZE]; 36 37 static struct gs_cb gs_cb; 38 static struct gs_epl gs_epl; 39 40 static bool memisset(void *s, int c, size_t n) 41 { 42 uint8_t *p = s; 43 size_t i; 44 45 for (i = 0; i < n; i++) { 46 if (p[i] != c) 47 return false; 48 } 49 50 return true; 51 } 52 53 static void wait_for_flag(void) 54 { 55 while (!testflag) 56 mb(); 57 } 58 59 static void set_flag(int val) 60 { 61 mb(); 62 testflag = val; 63 mb(); 64 } 65 66 static void test_func(void) 67 { 68 set_flag(1); 69 } 70 71 static bool have_adtl_status(void) 72 { 73 return test_facility(133) || test_facility(129); 74 } 75 76 static void test_store_adtl_status(void) 77 { 78 uint32_t status = -1; 79 int cc; 80 81 report_prefix_push("store additional status"); 82 83 if (!have_adtl_status()) { 84 report_skip("no guarded-storage or vector facility installed"); 85 goto out; 86 } 87 88 memset(&adtl_status, 0xff, sizeof(adtl_status)); 89 90 report_prefix_push("running"); 91 smp_cpu_restart(1); 92 93 cc = smp_sigp(1, SIGP_STORE_ADDITIONAL_STATUS, 94 (unsigned long)&adtl_status, &status); 95 96 report(cc == 1, "CC = 1"); 97 report(status == SIGP_STATUS_INCORRECT_STATE, "status = INCORRECT_STATE"); 98 report(memisset(&adtl_status, 0xff, sizeof(adtl_status)), 99 "additional status not touched"); 100 101 report_prefix_pop(); 102 103 report_prefix_push("invalid CPU address"); 104 105 cc = sigp(INVALID_CPU_ADDRESS, SIGP_STORE_ADDITIONAL_STATUS, 106 (unsigned long)&adtl_status, &status); 107 report(cc == 3, "CC = 3"); 108 report(memisset(&adtl_status, 0xff, sizeof(adtl_status)), 109 "additional status not touched"); 110 111 report_prefix_pop(); 112 113 report_prefix_push("unaligned"); 114 smp_cpu_stop(1); 115 116 cc = smp_sigp(1, SIGP_STORE_ADDITIONAL_STATUS, 117 (unsigned long)&adtl_status + 256, &status); 118 report(cc == 1, "CC = 1"); 119 report(status == SIGP_STATUS_INVALID_PARAMETER, "status = INVALID_PARAMETER"); 120 report(memisset(&adtl_status, 0xff, sizeof(adtl_status)), 121 "additional status not touched"); 122 123 report_prefix_pop(); 124 125 out: 126 report_prefix_pop(); 127 } 128 129 static void test_store_adtl_status_unavail(void) 130 { 131 uint32_t status = 0; 132 int cc; 133 134 report_prefix_push("store additional status unavailable"); 135 136 if (have_adtl_status()) { 137 report_skip("guarded-storage or vector facility installed"); 138 goto out; 139 } 140 141 report_prefix_push("not accepted"); 142 smp_cpu_stop(1); 143 144 memset(&adtl_status, 0xff, sizeof(adtl_status)); 145 146 cc = smp_sigp(1, SIGP_STORE_ADDITIONAL_STATUS, 147 (unsigned long)&adtl_status, &status); 148 149 report(cc == 1, "CC = 1"); 150 report(status == SIGP_STATUS_INVALID_ORDER, 151 "status = INVALID_ORDER"); 152 report(memisset(&adtl_status, 0xff, sizeof(adtl_status)), 153 "additional status not touched"); 154 155 report_prefix_pop(); 156 157 out: 158 report_prefix_pop(); 159 } 160 161 static void restart_write_vector(void) 162 { 163 uint8_t *vec_reg; 164 /* vlm handles at most 16 registers at a time */ 165 uint8_t *vec_reg_16_31 = &expected_vec_contents[16][0]; 166 uint64_t cr0, cr0_mask = ~BIT_ULL(CTL0_VECTOR); 167 int i; 168 169 for (i = 0; i < VEC_REGISTER_NUM; i++) { 170 vec_reg = &expected_vec_contents[i][0]; 171 /* i+1 to avoid zero content */ 172 memset(vec_reg, i + 1, VEC_REGISTER_SIZE); 173 } 174 175 ctl_set_bit(0, CTL0_VECTOR); 176 177 asm volatile ( 178 " .machine z13\n" 179 /* load vector registers */ 180 " vlm 0,15, %[vec_reg_0_15]\n" 181 " vlm 16,31, %[vec_reg_16_31]\n" 182 /* turn off vector instructions */ 183 " stctg 0,0, %[cr0]\n" 184 " ng %[cr0_mask], %[cr0]\n" 185 " stg %[cr0_mask], %[cr0]\n" 186 " lctlg 0,0, %[cr0]\n" 187 /* inform CPU 0 we are done by setting testflag to 1 */ 188 " mvhi %[testflag], 1\n" 189 /* 190 * infinite loop. function epilogue will restore floating point 191 * registers and hence destroy vector register contents 192 */ 193 "0: j 0\n" 194 : [cr0_mask] "+&d"(cr0_mask) 195 : [vec_reg_0_15] "Q"(expected_vec_contents), 196 [vec_reg_16_31] "Q"(*vec_reg_16_31), 197 [cr0] "Q"(cr0), 198 [testflag] "T"(testflag) 199 : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", 200 "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", 201 "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", 202 "v28", "v29", "v30", "v31", "cc", "memory" 203 ); 204 } 205 206 static void cpu_write_magic_to_vector_regs(uint16_t cpu_idx) 207 { 208 struct psw new_psw; 209 210 smp_cpu_stop(cpu_idx); 211 212 new_psw.mask = extract_psw_mask(); 213 new_psw.addr = (unsigned long)restart_write_vector; 214 215 set_flag(0); 216 217 smp_cpu_start(cpu_idx, new_psw); 218 219 wait_for_flag(); 220 } 221 222 static int adtl_status_check_unmodified_fields_for_lc(unsigned long lc) 223 { 224 assert (!lc || (lc >= 10 && lc <= 12)); 225 226 if (lc <= 10 && !memisset(&adtl_status.gs_cb, 0xff, sizeof(adtl_status.gs_cb))) 227 return false; 228 229 if (!memisset(adtl_status.reserved200, 0xff, sizeof(adtl_status.reserved200))) 230 return false; 231 232 if (!memisset(adtl_status.reserved420, 0xff, sizeof(adtl_status.reserved420))) 233 return false; 234 235 if (!memisset(adtl_status.reserved800, 0xff, sizeof(adtl_status.reserved800))) 236 return false; 237 238 return true; 239 } 240 241 static void __store_adtl_status_vector_lc(unsigned long lc) 242 { 243 uint32_t status = -1; 244 struct psw psw; 245 int cc; 246 247 report_prefix_pushf("LC %lu", lc); 248 249 if (!test_facility(133) && lc) { 250 report_skip("not supported, no guarded-storage facility"); 251 goto out; 252 } 253 254 cpu_write_magic_to_vector_regs(1); 255 smp_cpu_stop(1); 256 257 memset(&adtl_status, 0xff, sizeof(adtl_status)); 258 259 cc = smp_sigp(1, SIGP_STORE_ADDITIONAL_STATUS, 260 (unsigned long)&adtl_status | lc, &status); 261 report(!cc, "CC = 0"); 262 263 report(!memcmp(adtl_status.vregs, 264 expected_vec_contents, sizeof(expected_vec_contents)), 265 "additional status contents match"); 266 267 report(adtl_status_check_unmodified_fields_for_lc(lc), 268 "no write outside expected fields"); 269 270 /* 271 * To avoid the floating point/vector registers being cleaned up, we 272 * stopped CPU1 right in the middle of a function. Hence the cleanup of 273 * the function didn't run yet and the stackpointer is messed up. 274 * Destroy and re-initalize the CPU to fix that. 275 */ 276 smp_cpu_destroy(1); 277 psw.mask = extract_psw_mask(); 278 psw.addr = (unsigned long)test_func; 279 smp_cpu_setup(1, psw); 280 281 out: 282 report_prefix_pop(); 283 } 284 285 static void test_store_adtl_status_vector(void) 286 { 287 report_prefix_push("store additional status vector"); 288 289 if (!test_facility(129)) { 290 report_skip("vector facility not installed"); 291 goto out; 292 } 293 294 __store_adtl_status_vector_lc(0); 295 __store_adtl_status_vector_lc(10); 296 __store_adtl_status_vector_lc(11); 297 __store_adtl_status_vector_lc(12); 298 299 out: 300 report_prefix_pop(); 301 } 302 303 static void restart_write_gs_regs(void) 304 { 305 const unsigned long gs_area = 0x2000000; 306 const unsigned long gsc = 25; /* align = 32 M, section size = 512K */ 307 308 ctl_set_bit(2, CTL2_GUARDED_STORAGE); 309 310 gs_cb.gsd = gs_area | gsc; 311 gs_cb.gssm = 0xfeedc0ffe; 312 gs_cb.gs_epl_a = (uint64_t) &gs_epl; 313 314 load_gs_cb(&gs_cb); 315 316 set_flag(1); 317 318 ctl_clear_bit(2, CTL2_GUARDED_STORAGE); 319 320 /* 321 * Safe to return here. r14 will point to the endless loop in 322 * smp_cpu_setup_state. 323 */ 324 } 325 326 static void cpu_write_to_gs_regs(uint16_t cpu_idx) 327 { 328 struct psw new_psw; 329 330 smp_cpu_stop(cpu_idx); 331 332 new_psw.mask = extract_psw_mask(); 333 new_psw.addr = (unsigned long)restart_write_gs_regs; 334 335 set_flag(0); 336 337 smp_cpu_start(cpu_idx, new_psw); 338 339 wait_for_flag(); 340 } 341 342 static void __store_adtl_status_gs(unsigned long lc) 343 { 344 uint32_t status = 0; 345 int cc; 346 347 report_prefix_pushf("LC %lu", lc); 348 349 cpu_write_to_gs_regs(1); 350 smp_cpu_stop(1); 351 352 memset(&adtl_status, 0xff, sizeof(adtl_status)); 353 354 cc = smp_sigp(1, SIGP_STORE_ADDITIONAL_STATUS, 355 (unsigned long)&adtl_status | lc, &status); 356 report(!cc, "CC = 0"); 357 358 report(!memcmp(&adtl_status.gs_cb, &gs_cb, sizeof(gs_cb)), 359 "additional status contents match"); 360 361 report(adtl_status_check_unmodified_fields_for_lc(lc), 362 "no write outside expected fields"); 363 364 report_prefix_pop(); 365 } 366 367 static void test_store_adtl_status_gs(void) 368 { 369 report_prefix_push("store additional status guarded-storage"); 370 371 if (!test_facility(133)) { 372 report_skip("guarded-storage facility not installed"); 373 goto out; 374 } 375 376 __store_adtl_status_gs(11); 377 __store_adtl_status_gs(12); 378 379 out: 380 report_prefix_pop(); 381 } 382 383 int main(void) 384 { 385 struct psw psw; 386 report_prefix_push("adtl_status"); 387 388 if (smp_query_num_cpus() == 1) { 389 report_skip("need at least 2 cpus for this test"); 390 goto done; 391 } 392 393 /* Setting up the cpu to give it a stack and lowcore */ 394 psw.mask = extract_psw_mask(); 395 psw.addr = (unsigned long)test_func; 396 smp_cpu_setup(1, psw); 397 smp_cpu_stop(1); 398 399 test_store_adtl_status_unavail(); 400 test_store_adtl_status_vector(); 401 test_store_adtl_status_gs(); 402 test_store_adtl_status(); 403 smp_cpu_destroy(1); 404 405 done: 406 report_prefix_pop(); 407 return report_summary(); 408 } 409