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 smp_cpu_stop(cpu_idx); 209 210 set_flag(0); 211 212 smp_cpu_start(cpu_idx, PSW_WITH_CUR_MASK(restart_write_vector)); 213 214 wait_for_flag(); 215 } 216 217 static int adtl_status_check_unmodified_fields_for_lc(unsigned long lc) 218 { 219 assert (!lc || (lc >= 10 && lc <= 12)); 220 221 if (lc <= 10 && !memisset(&adtl_status.gs_cb, 0xff, sizeof(adtl_status.gs_cb))) 222 return false; 223 224 if (!memisset(adtl_status.reserved200, 0xff, sizeof(adtl_status.reserved200))) 225 return false; 226 227 if (!memisset(adtl_status.reserved420, 0xff, sizeof(adtl_status.reserved420))) 228 return false; 229 230 if (!memisset(adtl_status.reserved800, 0xff, sizeof(adtl_status.reserved800))) 231 return false; 232 233 return true; 234 } 235 236 static void __store_adtl_status_vector_lc(unsigned long lc) 237 { 238 uint32_t status = -1; 239 int cc; 240 241 report_prefix_pushf("LC %lu", lc); 242 243 if (!test_facility(133) && lc) { 244 report_skip("not supported, no guarded-storage facility"); 245 goto out; 246 } 247 248 cpu_write_magic_to_vector_regs(1); 249 smp_cpu_stop(1); 250 251 memset(&adtl_status, 0xff, sizeof(adtl_status)); 252 253 cc = smp_sigp(1, SIGP_STORE_ADDITIONAL_STATUS, 254 (unsigned long)&adtl_status | lc, &status); 255 report(!cc, "CC = 0"); 256 257 report(!memcmp(adtl_status.vregs, 258 expected_vec_contents, sizeof(expected_vec_contents)), 259 "additional status contents match"); 260 261 report(adtl_status_check_unmodified_fields_for_lc(lc), 262 "no write outside expected fields"); 263 264 /* 265 * To avoid the floating point/vector registers being cleaned up, we 266 * stopped CPU1 right in the middle of a function. Hence the cleanup of 267 * the function didn't run yet and the stackpointer is messed up. 268 * Destroy and re-initalize the CPU to fix that. 269 */ 270 smp_cpu_destroy(1); 271 smp_cpu_setup(1, PSW_WITH_CUR_MASK(test_func)); 272 273 out: 274 report_prefix_pop(); 275 } 276 277 static void test_store_adtl_status_vector(void) 278 { 279 report_prefix_push("store additional status vector"); 280 281 if (!test_facility(129)) { 282 report_skip("vector facility not installed"); 283 goto out; 284 } 285 286 __store_adtl_status_vector_lc(0); 287 __store_adtl_status_vector_lc(10); 288 __store_adtl_status_vector_lc(11); 289 __store_adtl_status_vector_lc(12); 290 291 out: 292 report_prefix_pop(); 293 } 294 295 static void restart_write_gs_regs(void) 296 { 297 const unsigned long gs_area = 0x2000000; 298 const unsigned long gsc = 25; /* align = 32 M, section size = 512K */ 299 300 ctl_set_bit(2, CTL2_GUARDED_STORAGE); 301 302 gs_cb.gsd = gs_area | gsc; 303 gs_cb.gssm = 0xfeedc0ffe; 304 gs_cb.gs_epl_a = (uint64_t) &gs_epl; 305 306 load_gs_cb(&gs_cb); 307 308 set_flag(1); 309 310 ctl_clear_bit(2, CTL2_GUARDED_STORAGE); 311 312 /* 313 * Safe to return here. r14 will point to the endless loop in 314 * smp_cpu_setup_state. 315 */ 316 } 317 318 static void cpu_write_to_gs_regs(uint16_t cpu_idx) 319 { 320 smp_cpu_stop(cpu_idx); 321 322 set_flag(0); 323 324 smp_cpu_start(cpu_idx, PSW_WITH_CUR_MASK(restart_write_gs_regs)); 325 326 wait_for_flag(); 327 } 328 329 static void __store_adtl_status_gs(unsigned long lc) 330 { 331 uint32_t status = 0; 332 int cc; 333 334 report_prefix_pushf("LC %lu", lc); 335 336 cpu_write_to_gs_regs(1); 337 smp_cpu_stop(1); 338 339 memset(&adtl_status, 0xff, sizeof(adtl_status)); 340 341 cc = smp_sigp(1, SIGP_STORE_ADDITIONAL_STATUS, 342 (unsigned long)&adtl_status | lc, &status); 343 report(!cc, "CC = 0"); 344 345 report(!memcmp(&adtl_status.gs_cb, &gs_cb, sizeof(gs_cb)), 346 "additional status contents match"); 347 348 report(adtl_status_check_unmodified_fields_for_lc(lc), 349 "no write outside expected fields"); 350 351 report_prefix_pop(); 352 } 353 354 static void test_store_adtl_status_gs(void) 355 { 356 report_prefix_push("store additional status guarded-storage"); 357 358 if (!test_facility(133)) { 359 report_skip("guarded-storage facility not installed"); 360 goto out; 361 } 362 363 __store_adtl_status_gs(11); 364 __store_adtl_status_gs(12); 365 366 out: 367 report_prefix_pop(); 368 } 369 370 int main(void) 371 { 372 report_prefix_push("adtl_status"); 373 374 if (smp_query_num_cpus() == 1) { 375 report_skip("need at least 2 cpus for this test"); 376 goto done; 377 } 378 379 /* Setting up the cpu to give it a stack and lowcore */ 380 smp_cpu_setup(1, PSW_WITH_CUR_MASK(test_func)); 381 smp_cpu_stop(1); 382 383 test_store_adtl_status_unavail(); 384 test_store_adtl_status_vector(); 385 test_store_adtl_status_gs(); 386 test_store_adtl_status(); 387 smp_cpu_destroy(1); 388 389 done: 390 report_prefix_pop(); 391 return report_summary(); 392 } 393