15e61cba0SAndrew Jones /* 25e61cba0SAndrew Jones * Test the framework itself. These tests confirm that setup works. 35e61cba0SAndrew Jones * 45e61cba0SAndrew Jones * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 55e61cba0SAndrew Jones * 65e61cba0SAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 75e61cba0SAndrew Jones */ 85e61cba0SAndrew Jones #include "libcflat.h" 9*2edfe428SAndrew Jones #include "alloc.h" 105e61cba0SAndrew Jones #include "asm/setup.h" 11*2edfe428SAndrew Jones #include "asm/ptrace.h" 12*2edfe428SAndrew Jones #include "asm/asm-offsets.h" 13*2edfe428SAndrew Jones #include "asm/processor.h" 14*2edfe428SAndrew Jones #include "asm/page.h" 155e61cba0SAndrew Jones 165e61cba0SAndrew Jones #define TESTGRP "selftest" 175e61cba0SAndrew Jones 185e61cba0SAndrew Jones static char testname[64]; 195e61cba0SAndrew Jones 205e61cba0SAndrew Jones static void testname_set(const char *subtest) 215e61cba0SAndrew Jones { 225e61cba0SAndrew Jones strcpy(testname, TESTGRP); 235e61cba0SAndrew Jones if (subtest) { 245e61cba0SAndrew Jones strcat(testname, "::"); 255e61cba0SAndrew Jones strcat(testname, subtest); 265e61cba0SAndrew Jones } 275e61cba0SAndrew Jones } 285e61cba0SAndrew Jones 295e61cba0SAndrew Jones static void assert_args(int num_args, int needed_args) 305e61cba0SAndrew Jones { 315e61cba0SAndrew Jones if (num_args < needed_args) { 325e61cba0SAndrew Jones printf("%s: not enough arguments\n", testname); 335e61cba0SAndrew Jones abort(); 345e61cba0SAndrew Jones } 355e61cba0SAndrew Jones } 365e61cba0SAndrew Jones 375e61cba0SAndrew Jones static char *split_var(char *s, long *val) 385e61cba0SAndrew Jones { 395e61cba0SAndrew Jones char *p; 405e61cba0SAndrew Jones 415e61cba0SAndrew Jones p = strchr(s, '='); 425e61cba0SAndrew Jones if (!p) 435e61cba0SAndrew Jones return NULL; 445e61cba0SAndrew Jones 455e61cba0SAndrew Jones *val = atol(p+1); 465e61cba0SAndrew Jones *p = '\0'; 475e61cba0SAndrew Jones 485e61cba0SAndrew Jones return s; 495e61cba0SAndrew Jones } 505e61cba0SAndrew Jones 515e61cba0SAndrew Jones static void check_setup(int argc, char **argv) 525e61cba0SAndrew Jones { 535e61cba0SAndrew Jones int nr_tests = 0, i; 545e61cba0SAndrew Jones char *var; 555e61cba0SAndrew Jones long val; 565e61cba0SAndrew Jones 575e61cba0SAndrew Jones for (i = 0; i < argc; ++i) { 585e61cba0SAndrew Jones 595e61cba0SAndrew Jones var = split_var(argv[i], &val); 605e61cba0SAndrew Jones if (!var) 615e61cba0SAndrew Jones continue; 625e61cba0SAndrew Jones 635e61cba0SAndrew Jones if (strcmp(var, "mem") == 0) { 645e61cba0SAndrew Jones 655e61cba0SAndrew Jones phys_addr_t memsize = PHYS_END - PHYS_OFFSET; 665e61cba0SAndrew Jones phys_addr_t expected = ((phys_addr_t)val)*1024*1024; 675e61cba0SAndrew Jones 685e61cba0SAndrew Jones report("%s[%s]", memsize == expected, testname, "mem"); 695e61cba0SAndrew Jones ++nr_tests; 705e61cba0SAndrew Jones 715e61cba0SAndrew Jones } else if (strcmp(var, "smp") == 0) { 725e61cba0SAndrew Jones 735e61cba0SAndrew Jones report("%s[%s]", nr_cpus == (int)val, testname, "smp"); 745e61cba0SAndrew Jones ++nr_tests; 755e61cba0SAndrew Jones } 765e61cba0SAndrew Jones } 775e61cba0SAndrew Jones 785e61cba0SAndrew Jones assert_args(nr_tests, 2); 795e61cba0SAndrew Jones } 805e61cba0SAndrew Jones 81*2edfe428SAndrew Jones static struct pt_regs expected_regs; 82*2edfe428SAndrew Jones /* 83*2edfe428SAndrew Jones * Capture the current register state and execute an instruction 84*2edfe428SAndrew Jones * that causes an exception. The test handler will check that its 85*2edfe428SAndrew Jones * capture of the current register state matches the capture done 86*2edfe428SAndrew Jones * here. 87*2edfe428SAndrew Jones * 88*2edfe428SAndrew Jones * NOTE: update clobber list if passed insns needs more than r0,r1 89*2edfe428SAndrew Jones */ 90*2edfe428SAndrew Jones #define test_exception(pre_insns, excptn_insn, post_insns) \ 91*2edfe428SAndrew Jones asm volatile( \ 92*2edfe428SAndrew Jones pre_insns "\n" \ 93*2edfe428SAndrew Jones "mov r0, %0\n" \ 94*2edfe428SAndrew Jones "stmia r0, { r0-lr }\n" \ 95*2edfe428SAndrew Jones "mrs r1, cpsr\n" \ 96*2edfe428SAndrew Jones "str r1, [r0, #" xstr(S_PSR) "]\n" \ 97*2edfe428SAndrew Jones "mov r1, #-1\n" \ 98*2edfe428SAndrew Jones "str r1, [r0, #" xstr(S_OLD_R0) "]\n" \ 99*2edfe428SAndrew Jones "add r1, pc, #8\n" \ 100*2edfe428SAndrew Jones "str r1, [r0, #" xstr(S_R1) "]\n" \ 101*2edfe428SAndrew Jones "str r1, [r0, #" xstr(S_PC) "]\n" \ 102*2edfe428SAndrew Jones excptn_insn "\n" \ 103*2edfe428SAndrew Jones post_insns "\n" \ 104*2edfe428SAndrew Jones :: "r" (&expected_regs) : "r0", "r1") 105*2edfe428SAndrew Jones 106*2edfe428SAndrew Jones static bool check_regs(struct pt_regs *regs) 107*2edfe428SAndrew Jones { 108*2edfe428SAndrew Jones unsigned i; 109*2edfe428SAndrew Jones 110*2edfe428SAndrew Jones /* exception handlers should always run in svc mode */ 111*2edfe428SAndrew Jones if (current_mode() != SVC_MODE) 112*2edfe428SAndrew Jones return false; 113*2edfe428SAndrew Jones 114*2edfe428SAndrew Jones for (i = 0; i < ARRAY_SIZE(regs->uregs); ++i) { 115*2edfe428SAndrew Jones if (regs->uregs[i] != expected_regs.uregs[i]) 116*2edfe428SAndrew Jones return false; 117*2edfe428SAndrew Jones } 118*2edfe428SAndrew Jones 119*2edfe428SAndrew Jones return true; 120*2edfe428SAndrew Jones } 121*2edfe428SAndrew Jones 122*2edfe428SAndrew Jones static bool und_works; 123*2edfe428SAndrew Jones static void und_handler(struct pt_regs *regs) 124*2edfe428SAndrew Jones { 125*2edfe428SAndrew Jones und_works = check_regs(regs); 126*2edfe428SAndrew Jones } 127*2edfe428SAndrew Jones 128*2edfe428SAndrew Jones static bool check_und(void) 129*2edfe428SAndrew Jones { 130*2edfe428SAndrew Jones install_exception_handler(EXCPTN_UND, und_handler); 131*2edfe428SAndrew Jones 132*2edfe428SAndrew Jones /* issue an instruction to a coprocessor we don't have */ 133*2edfe428SAndrew Jones test_exception("", "mcr p2, 0, r0, c0, c0", ""); 134*2edfe428SAndrew Jones 135*2edfe428SAndrew Jones install_exception_handler(EXCPTN_UND, NULL); 136*2edfe428SAndrew Jones 137*2edfe428SAndrew Jones return und_works; 138*2edfe428SAndrew Jones } 139*2edfe428SAndrew Jones 140*2edfe428SAndrew Jones static bool svc_works; 141*2edfe428SAndrew Jones static void svc_handler(struct pt_regs *regs) 142*2edfe428SAndrew Jones { 143*2edfe428SAndrew Jones u32 svc = *(u32 *)(regs->ARM_pc - 4) & 0xffffff; 144*2edfe428SAndrew Jones 145*2edfe428SAndrew Jones if (processor_mode(regs) == SVC_MODE) { 146*2edfe428SAndrew Jones /* 147*2edfe428SAndrew Jones * When issuing an svc from supervisor mode lr_svc will 148*2edfe428SAndrew Jones * get corrupted. So before issuing the svc, callers must 149*2edfe428SAndrew Jones * always push it on the stack. We pushed it to offset 4. 150*2edfe428SAndrew Jones */ 151*2edfe428SAndrew Jones regs->ARM_lr = *(unsigned long *)(regs->ARM_sp + 4); 152*2edfe428SAndrew Jones } 153*2edfe428SAndrew Jones 154*2edfe428SAndrew Jones svc_works = check_regs(regs) && svc == 123; 155*2edfe428SAndrew Jones } 156*2edfe428SAndrew Jones 157*2edfe428SAndrew Jones static bool check_svc(void) 158*2edfe428SAndrew Jones { 159*2edfe428SAndrew Jones install_exception_handler(EXCPTN_SVC, svc_handler); 160*2edfe428SAndrew Jones 161*2edfe428SAndrew Jones if (current_mode() == SVC_MODE) { 162*2edfe428SAndrew Jones /* 163*2edfe428SAndrew Jones * An svc from supervisor mode will corrupt lr_svc and 164*2edfe428SAndrew Jones * spsr_svc. We need to save/restore them separately. 165*2edfe428SAndrew Jones */ 166*2edfe428SAndrew Jones test_exception( 167*2edfe428SAndrew Jones "mrs r0, spsr\n" 168*2edfe428SAndrew Jones "push { r0,lr }\n", 169*2edfe428SAndrew Jones "svc #123\n", 170*2edfe428SAndrew Jones "pop { r0,lr }\n" 171*2edfe428SAndrew Jones "msr spsr_cxsf, r0\n" 172*2edfe428SAndrew Jones ); 173*2edfe428SAndrew Jones } else { 174*2edfe428SAndrew Jones test_exception("", "svc #123", ""); 175*2edfe428SAndrew Jones } 176*2edfe428SAndrew Jones 177*2edfe428SAndrew Jones install_exception_handler(EXCPTN_SVC, NULL); 178*2edfe428SAndrew Jones 179*2edfe428SAndrew Jones return svc_works; 180*2edfe428SAndrew Jones } 181*2edfe428SAndrew Jones 182*2edfe428SAndrew Jones static void check_vectors(void *arg __unused) 183*2edfe428SAndrew Jones { 184*2edfe428SAndrew Jones report("%s", check_und() && check_svc(), testname); 185*2edfe428SAndrew Jones exit(report_summary()); 186*2edfe428SAndrew Jones } 187*2edfe428SAndrew Jones 1885e61cba0SAndrew Jones int main(int argc, char **argv) 1895e61cba0SAndrew Jones { 1905e61cba0SAndrew Jones testname_set(NULL); 1915e61cba0SAndrew Jones assert_args(argc, 1); 1925e61cba0SAndrew Jones testname_set(argv[0]); 1935e61cba0SAndrew Jones 194*2edfe428SAndrew Jones if (strcmp(argv[0], "setup") == 0) { 195*2edfe428SAndrew Jones 1965e61cba0SAndrew Jones check_setup(argc-1, &argv[1]); 1975e61cba0SAndrew Jones 198*2edfe428SAndrew Jones } else if (strcmp(argv[0], "vectors-svc") == 0) { 199*2edfe428SAndrew Jones 200*2edfe428SAndrew Jones check_vectors(NULL); 201*2edfe428SAndrew Jones 202*2edfe428SAndrew Jones } else if (strcmp(argv[0], "vectors-usr") == 0) { 203*2edfe428SAndrew Jones 204*2edfe428SAndrew Jones void *sp = memalign(PAGE_SIZE, PAGE_SIZE); 205*2edfe428SAndrew Jones memset(sp, 0, PAGE_SIZE); 206*2edfe428SAndrew Jones start_usr(check_vectors, NULL, (unsigned long)sp + PAGE_SIZE); 207*2edfe428SAndrew Jones } 208*2edfe428SAndrew Jones 2095e61cba0SAndrew Jones return report_summary(); 2105e61cba0SAndrew Jones } 211