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