1 /* 2 * Tests sigp emulation 3 * 4 * Copyright 2019 IBM Corp. 5 * 6 * Authors: 7 * Janosch Frank <frankja@linux.ibm.com> 8 * 9 * This code is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License version 2. 11 */ 12 #include <libcflat.h> 13 #include <asm/asm-offsets.h> 14 #include <asm/interrupt.h> 15 #include <asm/page.h> 16 #include <asm/facility.h> 17 #include <asm-generic/barrier.h> 18 #include <asm/sigp.h> 19 20 #include <smp.h> 21 #include <alloc_page.h> 22 23 static int testflag = 0; 24 25 static void wait_for_flag(void) 26 { 27 while (!testflag) 28 mb(); 29 } 30 31 static void set_flag(int val) 32 { 33 mb(); 34 testflag = val; 35 mb(); 36 } 37 38 static void cpu_loop(void) 39 { 40 for (;;) {} 41 } 42 43 static void test_func(void) 44 { 45 set_flag(1); 46 cpu_loop(); 47 } 48 49 static void test_start(void) 50 { 51 struct psw psw; 52 psw.mask = extract_psw_mask(); 53 psw.addr = (unsigned long)test_func; 54 55 set_flag(0); 56 smp_cpu_start(1, psw); 57 wait_for_flag(); 58 report(1, "start"); 59 } 60 61 static void test_stop(void) 62 { 63 smp_cpu_stop(1); 64 /* 65 * The smp library waits for the CPU to shut down, but let's 66 * also do it here, so we don't rely on the library 67 * implementation 68 */ 69 while (!smp_cpu_stopped(1)) {} 70 report(1, "stop"); 71 } 72 73 static void test_stop_store_status(void) 74 { 75 struct cpu *cpu = smp_cpu_from_addr(1); 76 struct lowcore *lc = (void *)0x0; 77 78 report_prefix_push("stop store status"); 79 lc->prefix_sa = 0; 80 lc->grs_sa[15] = 0; 81 smp_cpu_stop_store_status(1); 82 mb(); 83 report(lc->prefix_sa == (uint32_t)(uintptr_t)cpu->lowcore, "prefix"); 84 report(lc->grs_sa[15], "stack"); 85 report_prefix_pop(); 86 } 87 88 static void test_store_status(void) 89 { 90 struct cpu_status *status = alloc_pages(1); 91 uint32_t r; 92 93 report_prefix_push("store status at address"); 94 memset(status, 0, PAGE_SIZE * 2); 95 96 report_prefix_push("running"); 97 smp_cpu_restart(1); 98 sigp(1, SIGP_STORE_STATUS_AT_ADDRESS, (uintptr_t)status, &r); 99 report(r == SIGP_STATUS_INCORRECT_STATE, "incorrect state"); 100 report(!memcmp(status, (void *)status + PAGE_SIZE, PAGE_SIZE), 101 "status not written"); 102 report_prefix_pop(); 103 104 memset(status, 0, PAGE_SIZE); 105 report_prefix_push("stopped"); 106 smp_cpu_stop(1); 107 sigp(1, SIGP_STORE_STATUS_AT_ADDRESS, (uintptr_t)status, NULL); 108 while (!status->prefix) { mb(); } 109 report(1, "status written"); 110 free_pages(status, PAGE_SIZE * 2); 111 report_prefix_pop(); 112 smp_cpu_stop(1); 113 114 report_prefix_pop(); 115 } 116 117 static void ecall(void) 118 { 119 unsigned long mask; 120 struct lowcore *lc = (void *)0x0; 121 122 expect_ext_int(); 123 ctl_set_bit(0, 13); 124 mask = extract_psw_mask(); 125 mask |= PSW_MASK_EXT; 126 load_psw_mask(mask); 127 set_flag(1); 128 while (lc->ext_int_code != 0x1202) { mb(); } 129 report(1, "received"); 130 set_flag(1); 131 } 132 133 static void test_ecall(void) 134 { 135 struct psw psw; 136 psw.mask = extract_psw_mask(); 137 psw.addr = (unsigned long)ecall; 138 139 report_prefix_push("ecall"); 140 set_flag(0); 141 142 smp_cpu_start(1, psw); 143 wait_for_flag(); 144 set_flag(0); 145 sigp(1, SIGP_EXTERNAL_CALL, 0, NULL); 146 wait_for_flag(); 147 smp_cpu_stop(1); 148 report_prefix_pop(); 149 } 150 151 static void emcall(void) 152 { 153 unsigned long mask; 154 struct lowcore *lc = (void *)0x0; 155 156 expect_ext_int(); 157 ctl_set_bit(0, 14); 158 mask = extract_psw_mask(); 159 mask |= PSW_MASK_EXT; 160 load_psw_mask(mask); 161 set_flag(1); 162 while (lc->ext_int_code != 0x1201) { mb(); } 163 report(1, "received"); 164 set_flag(1); 165 } 166 167 static void test_emcall(void) 168 { 169 struct psw psw; 170 psw.mask = extract_psw_mask(); 171 psw.addr = (unsigned long)emcall; 172 173 report_prefix_push("emcall"); 174 set_flag(0); 175 176 smp_cpu_start(1, psw); 177 wait_for_flag(); 178 set_flag(0); 179 sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL); 180 wait_for_flag(); 181 smp_cpu_stop(1); 182 report_prefix_pop(); 183 } 184 185 static void test_reset_initial(void) 186 { 187 struct cpu_status *status = alloc_pages(0); 188 struct psw psw; 189 190 psw.mask = extract_psw_mask(); 191 psw.addr = (unsigned long)test_func; 192 193 report_prefix_push("reset initial"); 194 smp_cpu_start(1, psw); 195 196 sigp_retry(1, SIGP_INITIAL_CPU_RESET, 0, NULL); 197 sigp(1, SIGP_STORE_STATUS_AT_ADDRESS, (uintptr_t)status, NULL); 198 199 report_prefix_push("clear"); 200 report(!status->psw.mask && !status->psw.addr, "psw"); 201 report(!status->prefix, "prefix"); 202 report(!status->fpc, "fpc"); 203 report(!status->cputm, "cpu timer"); 204 report(!status->todpr, "todpr"); 205 report_prefix_pop(); 206 207 report_prefix_push("initialized"); 208 report(status->crs[0] == 0xE0UL, "cr0 == 0xE0"); 209 report(status->crs[14] == 0xC2000000UL, "cr14 == 0xC2000000"); 210 report_prefix_pop(); 211 212 report(smp_cpu_stopped(1), "cpu stopped"); 213 free_pages(status, PAGE_SIZE); 214 report_prefix_pop(); 215 } 216 217 static void test_reset(void) 218 { 219 struct psw psw; 220 221 psw.mask = extract_psw_mask(); 222 psw.addr = (unsigned long)test_func; 223 224 report_prefix_push("cpu reset"); 225 smp_cpu_start(1, psw); 226 227 sigp_retry(1, SIGP_CPU_RESET, 0, NULL); 228 report(smp_cpu_stopped(1), "cpu stopped"); 229 report_prefix_pop(); 230 } 231 232 int main(void) 233 { 234 struct psw psw; 235 report_prefix_push("smp"); 236 237 if (smp_query_num_cpus() == 1) { 238 report_skip("need at least 2 cpus for this test"); 239 goto done; 240 } 241 242 /* Setting up the cpu to give it a stack and lowcore */ 243 psw.mask = extract_psw_mask(); 244 psw.addr = (unsigned long)cpu_loop; 245 smp_cpu_setup(1, psw); 246 smp_cpu_stop(1); 247 248 test_start(); 249 test_stop(); 250 test_stop_store_status(); 251 test_store_status(); 252 test_ecall(); 253 test_emcall(); 254 test_reset(); 255 test_reset_initial(); 256 smp_cpu_destroy(1); 257 258 done: 259 report_prefix_pop(); 260 return report_summary(); 261 } 262