1 /* 2 * Test the framework itself. These tests confirm that setup works. 3 * 4 * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 5 * 6 * This work is licensed under the terms of the GNU LGPL, version 2. 7 */ 8 #include <libcflat.h> 9 #include <util.h> 10 #include <devicetree.h> 11 #include <asm/setup.h> 12 #include <asm/ptrace.h> 13 #include <asm/asm-offsets.h> 14 #include <asm/processor.h> 15 #include <asm/thread_info.h> 16 #include <asm/psci.h> 17 #include <asm/smp.h> 18 #include <asm/barrier.h> 19 20 static void __user_psci_system_off(void) 21 { 22 psci_system_off(); 23 halt(); 24 __builtin_unreachable(); 25 } 26 27 static void check_setup(int argc, char **argv) 28 { 29 int nr_tests = 0, len, i; 30 long val; 31 32 for (i = 0; i < argc; ++i) { 33 34 len = parse_keyval(argv[i], &val); 35 if (len == -1) 36 continue; 37 38 argv[i][len] = '\0'; 39 report_prefix_push(argv[i]); 40 41 if (strcmp(argv[i], "mem") == 0) { 42 43 phys_addr_t memsize = PHYS_END - PHYS_OFFSET; 44 phys_addr_t expected = ((phys_addr_t)val)*1024*1024; 45 46 report("size = %" PRIu64 " MB", memsize == expected, 47 memsize/1024/1024); 48 ++nr_tests; 49 50 } else if (strcmp(argv[i], "smp") == 0) { 51 52 report("nr_cpus = %d", nr_cpus == (int)val, nr_cpus); 53 ++nr_tests; 54 } 55 56 report_prefix_pop(); 57 } 58 59 if (nr_tests < 2) 60 report_abort("missing input"); 61 } 62 63 static struct pt_regs expected_regs; 64 static bool und_works; 65 static bool svc_works; 66 #if defined(__arm__) 67 /* 68 * Capture the current register state and execute an instruction 69 * that causes an exception. The test handler will check that its 70 * capture of the current register state matches the capture done 71 * here. 72 * 73 * NOTE: update clobber list if passed insns needs more than r0,r1 74 */ 75 #define test_exception(pre_insns, excptn_insn, post_insns) \ 76 asm volatile( \ 77 pre_insns "\n" \ 78 "mov r0, %0\n" \ 79 "stmia r0, { r0-lr }\n" \ 80 "mrs r1, cpsr\n" \ 81 "str r1, [r0, #" xstr(S_PSR) "]\n" \ 82 "mov r1, #-1\n" \ 83 "str r1, [r0, #" xstr(S_OLD_R0) "]\n" \ 84 "add r1, pc, #8\n" \ 85 "str r1, [r0, #" xstr(S_R1) "]\n" \ 86 "str r1, [r0, #" xstr(S_PC) "]\n" \ 87 excptn_insn "\n" \ 88 post_insns "\n" \ 89 :: "r" (&expected_regs) : "r0", "r1") 90 91 static bool check_regs(struct pt_regs *regs) 92 { 93 unsigned i; 94 95 /* exception handlers should always run in svc mode */ 96 if (current_mode() != SVC_MODE) 97 return false; 98 99 for (i = 0; i < ARRAY_SIZE(regs->uregs); ++i) { 100 if (regs->uregs[i] != expected_regs.uregs[i]) 101 return false; 102 } 103 104 return true; 105 } 106 107 static void und_handler(struct pt_regs *regs) 108 { 109 und_works = check_regs(regs); 110 } 111 112 static bool check_und(void) 113 { 114 install_exception_handler(EXCPTN_UND, und_handler); 115 116 /* issue an instruction to a coprocessor we don't have */ 117 test_exception("", "mcr p2, 0, r0, c0, c0", ""); 118 119 install_exception_handler(EXCPTN_UND, NULL); 120 121 return und_works; 122 } 123 124 static void svc_handler(struct pt_regs *regs) 125 { 126 u32 svc = *(u32 *)(regs->ARM_pc - 4) & 0xffffff; 127 128 if (processor_mode(regs) == SVC_MODE) { 129 /* 130 * When issuing an svc from supervisor mode lr_svc will 131 * get corrupted. So before issuing the svc, callers must 132 * always push it on the stack. We pushed it to offset 4. 133 */ 134 regs->ARM_lr = *(unsigned long *)(regs->ARM_sp + 4); 135 } 136 137 svc_works = check_regs(regs) && svc == 123; 138 } 139 140 static bool check_svc(void) 141 { 142 install_exception_handler(EXCPTN_SVC, svc_handler); 143 144 if (current_mode() == SVC_MODE) { 145 /* 146 * An svc from supervisor mode will corrupt lr_svc and 147 * spsr_svc. We need to save/restore them separately. 148 */ 149 test_exception( 150 "mrs r0, spsr\n" 151 "push { r0,lr }\n", 152 "svc #123\n", 153 "pop { r0,lr }\n" 154 "msr spsr_cxsf, r0\n" 155 ); 156 } else { 157 test_exception("", "svc #123", ""); 158 } 159 160 install_exception_handler(EXCPTN_SVC, NULL); 161 162 return svc_works; 163 } 164 165 static void user_psci_system_off(struct pt_regs *regs) 166 { 167 __user_psci_system_off(); 168 } 169 #elif defined(__aarch64__) 170 171 /* 172 * Capture the current register state and execute an instruction 173 * that causes an exception. The test handler will check that its 174 * capture of the current register state matches the capture done 175 * here. 176 * 177 * NOTE: update clobber list if passed insns needs more than x0,x1 178 */ 179 #define test_exception(pre_insns, excptn_insn, post_insns) \ 180 asm volatile( \ 181 pre_insns "\n" \ 182 "mov x1, %0\n" \ 183 "ldr x0, [x1, #" xstr(S_PSTATE) "]\n" \ 184 "mrs x1, nzcv\n" \ 185 "orr w0, w0, w1\n" \ 186 "mov x1, %0\n" \ 187 "str w0, [x1, #" xstr(S_PSTATE) "]\n" \ 188 "mov x0, sp\n" \ 189 "str x0, [x1, #" xstr(S_SP) "]\n" \ 190 "adr x0, 1f\n" \ 191 "str x0, [x1, #" xstr(S_PC) "]\n" \ 192 "stp x2, x3, [x1, #16]\n" \ 193 "stp x4, x5, [x1, #32]\n" \ 194 "stp x6, x7, [x1, #48]\n" \ 195 "stp x8, x9, [x1, #64]\n" \ 196 "stp x10, x11, [x1, #80]\n" \ 197 "stp x12, x13, [x1, #96]\n" \ 198 "stp x14, x15, [x1, #112]\n" \ 199 "stp x16, x17, [x1, #128]\n" \ 200 "stp x18, x19, [x1, #144]\n" \ 201 "stp x20, x21, [x1, #160]\n" \ 202 "stp x22, x23, [x1, #176]\n" \ 203 "stp x24, x25, [x1, #192]\n" \ 204 "stp x26, x27, [x1, #208]\n" \ 205 "stp x28, x29, [x1, #224]\n" \ 206 "str x30, [x1, #" xstr(S_LR) "]\n" \ 207 "stp x0, x1, [x1]\n" \ 208 "1:" excptn_insn "\n" \ 209 post_insns "\n" \ 210 :: "r" (&expected_regs) : "x0", "x1") 211 212 static bool check_regs(struct pt_regs *regs) 213 { 214 unsigned i; 215 216 /* exception handlers should always run in EL1 */ 217 if (current_level() != CurrentEL_EL1) 218 return false; 219 220 for (i = 0; i < ARRAY_SIZE(regs->regs); ++i) { 221 if (regs->regs[i] != expected_regs.regs[i]) 222 return false; 223 } 224 225 regs->pstate &= 0xf0000000 /* NZCV */ | 0x3c0 /* DAIF */ 226 | PSR_MODE_MASK; 227 228 return regs->sp == expected_regs.sp 229 && regs->pc == expected_regs.pc 230 && regs->pstate == expected_regs.pstate; 231 } 232 233 static enum vector check_vector_prep(void) 234 { 235 unsigned long daif; 236 237 if (is_user()) 238 return EL0_SYNC_64; 239 240 asm volatile("mrs %0, daif" : "=r" (daif) ::); 241 expected_regs.pstate = daif | PSR_MODE_EL1h; 242 return EL1H_SYNC; 243 } 244 245 static void unknown_handler(struct pt_regs *regs, unsigned int esr __unused) 246 { 247 und_works = check_regs(regs); 248 regs->pc += 4; 249 } 250 251 static bool check_und(void) 252 { 253 enum vector v = check_vector_prep(); 254 255 install_exception_handler(v, ESR_EL1_EC_UNKNOWN, unknown_handler); 256 257 /* try to read an el2 sysreg from el0/1 */ 258 test_exception("", "mrs x0, sctlr_el2", ""); 259 260 install_exception_handler(v, ESR_EL1_EC_UNKNOWN, NULL); 261 262 return und_works; 263 } 264 265 static void svc_handler(struct pt_regs *regs, unsigned int esr) 266 { 267 u16 svc = esr & 0xffff; 268 269 expected_regs.pc += 4; 270 svc_works = check_regs(regs) && svc == 123; 271 } 272 273 static bool check_svc(void) 274 { 275 enum vector v = check_vector_prep(); 276 277 install_exception_handler(v, ESR_EL1_EC_SVC64, svc_handler); 278 279 test_exception("", "svc #123", ""); 280 281 install_exception_handler(v, ESR_EL1_EC_SVC64, NULL); 282 283 return svc_works; 284 } 285 286 static void user_psci_system_off(struct pt_regs *regs, unsigned int esr) 287 { 288 __user_psci_system_off(); 289 } 290 #endif 291 292 static void check_vectors(void *arg __unused) 293 { 294 report("und", check_und()); 295 report("svc", check_svc()); 296 if (is_user()) { 297 #ifdef __arm__ 298 install_exception_handler(EXCPTN_UND, user_psci_system_off); 299 #else 300 install_exception_handler(EL0_SYNC_64, ESR_EL1_EC_UNKNOWN, 301 user_psci_system_off); 302 #endif 303 } 304 exit(report_summary()); 305 } 306 307 static bool psci_check(void) 308 { 309 const struct fdt_property *method; 310 int node, len, ver; 311 312 node = fdt_node_offset_by_compatible(dt_fdt(), -1, "arm,psci-0.2"); 313 if (node < 0) { 314 printf("PSCI v0.2 compatibility required\n"); 315 return false; 316 } 317 318 method = fdt_get_property(dt_fdt(), node, "method", &len); 319 if (method == NULL) { 320 printf("bad psci device tree node\n"); 321 return false; 322 } 323 324 if (len < 4 || strcmp(method->data, "hvc") != 0) { 325 printf("psci method must be hvc\n"); 326 return false; 327 } 328 329 ver = psci_invoke(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); 330 printf("PSCI version %d.%d\n", PSCI_VERSION_MAJOR(ver), 331 PSCI_VERSION_MINOR(ver)); 332 333 return true; 334 } 335 336 static void cpu_report(void *data __unused) 337 { 338 uint64_t mpidr = get_mpidr(); 339 int cpu = smp_processor_id(); 340 341 report("CPU(%3d) mpidr=%010" PRIx64, 342 mpidr_to_cpu(mpidr) == cpu, cpu, mpidr); 343 } 344 345 int main(int argc, char **argv) 346 { 347 report_prefix_push("selftest"); 348 349 if (argc < 2) 350 report_abort("no test specified"); 351 352 report_prefix_push(argv[1]); 353 354 if (strcmp(argv[1], "setup") == 0) { 355 356 check_setup(argc-2, &argv[2]); 357 358 } else if (strcmp(argv[1], "vectors-kernel") == 0) { 359 360 check_vectors(NULL); 361 362 } else if (strcmp(argv[1], "vectors-user") == 0) { 363 364 start_usr(check_vectors, NULL, 365 (unsigned long)thread_stack_alloc()); 366 367 } else if (strcmp(argv[1], "smp") == 0) { 368 369 report("PSCI version", psci_check()); 370 on_cpus(cpu_report, NULL); 371 372 } else { 373 printf("Unknown subtest\n"); 374 abort(); 375 } 376 377 return report_summary(); 378 } 379