1*7ee966e9SAndrew Jones /* 2*7ee966e9SAndrew Jones * processor control and status functions 3*7ee966e9SAndrew Jones * 4*7ee966e9SAndrew Jones * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 5*7ee966e9SAndrew Jones * 6*7ee966e9SAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 7*7ee966e9SAndrew Jones */ 8*7ee966e9SAndrew Jones #include <libcflat.h> 9*7ee966e9SAndrew Jones #include <asm/ptrace.h> 10*7ee966e9SAndrew Jones #include <asm/processor.h> 11*7ee966e9SAndrew Jones #include <asm/esr.h> 12*7ee966e9SAndrew Jones 13*7ee966e9SAndrew Jones static char *vector_names[] = { 14*7ee966e9SAndrew Jones "el1t_sync", 15*7ee966e9SAndrew Jones "el1t_irq", 16*7ee966e9SAndrew Jones "el1t_fiq", 17*7ee966e9SAndrew Jones "el1t_error", 18*7ee966e9SAndrew Jones "el1h_sync", 19*7ee966e9SAndrew Jones "el1h_irq", 20*7ee966e9SAndrew Jones "el1h_fiq", 21*7ee966e9SAndrew Jones "el1h_error", 22*7ee966e9SAndrew Jones "el0_sync_64", 23*7ee966e9SAndrew Jones "el0_irq_64", 24*7ee966e9SAndrew Jones "el0_fiq_64", 25*7ee966e9SAndrew Jones "el0_error_64", 26*7ee966e9SAndrew Jones "el0_sync_32", 27*7ee966e9SAndrew Jones "el0_irq_32", 28*7ee966e9SAndrew Jones "el0_fiq_32", 29*7ee966e9SAndrew Jones "el0_error_32", 30*7ee966e9SAndrew Jones }; 31*7ee966e9SAndrew Jones 32*7ee966e9SAndrew Jones static char *ec_names[EC_MAX] = { 33*7ee966e9SAndrew Jones [ESR_EL1_EC_UNKNOWN] = "UNKNOWN", 34*7ee966e9SAndrew Jones [ESR_EL1_EC_WFI] = "WFI", 35*7ee966e9SAndrew Jones [ESR_EL1_EC_CP15_32] = "CP15_32", 36*7ee966e9SAndrew Jones [ESR_EL1_EC_CP15_64] = "CP15_64", 37*7ee966e9SAndrew Jones [ESR_EL1_EC_CP14_MR] = "CP14_MR", 38*7ee966e9SAndrew Jones [ESR_EL1_EC_CP14_LS] = "CP14_LS", 39*7ee966e9SAndrew Jones [ESR_EL1_EC_FP_ASIMD] = "FP_ASMID", 40*7ee966e9SAndrew Jones [ESR_EL1_EC_CP10_ID] = "CP10_ID", 41*7ee966e9SAndrew Jones [ESR_EL1_EC_CP14_64] = "CP14_64", 42*7ee966e9SAndrew Jones [ESR_EL1_EC_ILL_ISS] = "ILL_ISS", 43*7ee966e9SAndrew Jones [ESR_EL1_EC_SVC32] = "SVC32", 44*7ee966e9SAndrew Jones [ESR_EL1_EC_SVC64] = "SVC64", 45*7ee966e9SAndrew Jones [ESR_EL1_EC_SYS64] = "SYS64", 46*7ee966e9SAndrew Jones [ESR_EL1_EC_IABT_EL0] = "IABT_EL0", 47*7ee966e9SAndrew Jones [ESR_EL1_EC_IABT_EL1] = "IABT_EL1", 48*7ee966e9SAndrew Jones [ESR_EL1_EC_PC_ALIGN] = "PC_ALIGN", 49*7ee966e9SAndrew Jones [ESR_EL1_EC_DABT_EL0] = "DABT_EL0", 50*7ee966e9SAndrew Jones [ESR_EL1_EC_DABT_EL1] = "DABT_EL1", 51*7ee966e9SAndrew Jones [ESR_EL1_EC_SP_ALIGN] = "SP_ALIGN", 52*7ee966e9SAndrew Jones [ESR_EL1_EC_FP_EXC32] = "FP_EXC32", 53*7ee966e9SAndrew Jones [ESR_EL1_EC_FP_EXC64] = "FP_EXC64", 54*7ee966e9SAndrew Jones [ESR_EL1_EC_SERROR] = "SERROR", 55*7ee966e9SAndrew Jones [ESR_EL1_EC_BREAKPT_EL0] = "BREAKPT_EL0", 56*7ee966e9SAndrew Jones [ESR_EL1_EC_BREAKPT_EL1] = "BREAKPT_EL1", 57*7ee966e9SAndrew Jones [ESR_EL1_EC_SOFTSTP_EL0] = "SOFTSTP_EL0", 58*7ee966e9SAndrew Jones [ESR_EL1_EC_SOFTSTP_EL1] = "SOFTSTP_EL1", 59*7ee966e9SAndrew Jones [ESR_EL1_EC_WATCHPT_EL0] = "WATCHPT_EL0", 60*7ee966e9SAndrew Jones [ESR_EL1_EC_WATCHPT_EL1] = "WATCHPT_EL1", 61*7ee966e9SAndrew Jones [ESR_EL1_EC_BKPT32] = "BKPT32", 62*7ee966e9SAndrew Jones [ESR_EL1_EC_BRK64] = "BRK64", 63*7ee966e9SAndrew Jones }; 64*7ee966e9SAndrew Jones 65*7ee966e9SAndrew Jones void show_regs(struct pt_regs *regs) 66*7ee966e9SAndrew Jones { 67*7ee966e9SAndrew Jones int i; 68*7ee966e9SAndrew Jones 69*7ee966e9SAndrew Jones printf("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n", 70*7ee966e9SAndrew Jones regs->pc, regs->regs[30], regs->pstate); 71*7ee966e9SAndrew Jones printf("sp : %016llx\n", regs->sp); 72*7ee966e9SAndrew Jones 73*7ee966e9SAndrew Jones for (i = 29; i >= 0; --i) { 74*7ee966e9SAndrew Jones printf("x%-2d: %016llx ", i, regs->regs[i]); 75*7ee966e9SAndrew Jones if (i % 2 == 0) 76*7ee966e9SAndrew Jones printf("\n"); 77*7ee966e9SAndrew Jones } 78*7ee966e9SAndrew Jones printf("\n"); 79*7ee966e9SAndrew Jones } 80*7ee966e9SAndrew Jones 81*7ee966e9SAndrew Jones void *get_sp(void) 82*7ee966e9SAndrew Jones { 83*7ee966e9SAndrew Jones register unsigned long sp asm("sp"); 84*7ee966e9SAndrew Jones return (void *)sp; 85*7ee966e9SAndrew Jones } 86*7ee966e9SAndrew Jones 87*7ee966e9SAndrew Jones static void bad_exception(enum vector v, struct pt_regs *regs, 88*7ee966e9SAndrew Jones unsigned int esr, bool bad_vector) 89*7ee966e9SAndrew Jones { 90*7ee966e9SAndrew Jones unsigned int ec = esr >> ESR_EL1_EC_SHIFT; 91*7ee966e9SAndrew Jones 92*7ee966e9SAndrew Jones if (bad_vector) { 93*7ee966e9SAndrew Jones if (v < VECTOR_MAX) 94*7ee966e9SAndrew Jones printf("Unhandled vector %d (%s)\n", v, 95*7ee966e9SAndrew Jones vector_names[v]); 96*7ee966e9SAndrew Jones else 97*7ee966e9SAndrew Jones printf("Got bad vector=%d\n", v); 98*7ee966e9SAndrew Jones } else { 99*7ee966e9SAndrew Jones if (ec_names[ec]) 100*7ee966e9SAndrew Jones printf("Unhandled exception ec=0x%x (%s)\n", ec, 101*7ee966e9SAndrew Jones ec_names[ec]); 102*7ee966e9SAndrew Jones else 103*7ee966e9SAndrew Jones printf("Got bad ec=0x%x\n", ec); 104*7ee966e9SAndrew Jones } 105*7ee966e9SAndrew Jones 106*7ee966e9SAndrew Jones printf("Vector: %d (%s)\n", v, vector_names[v]); 107*7ee966e9SAndrew Jones printf("ESR_EL1: %08lx, ec=0x%x (%s)\n", esr, ec, ec_names[ec]); 108*7ee966e9SAndrew Jones printf("Exception frame registers:\n"); 109*7ee966e9SAndrew Jones show_regs(regs); 110*7ee966e9SAndrew Jones abort(); 111*7ee966e9SAndrew Jones } 112*7ee966e9SAndrew Jones 113*7ee966e9SAndrew Jones static exception_fn exception_handlers[VECTOR_MAX][EC_MAX]; 114*7ee966e9SAndrew Jones 115*7ee966e9SAndrew Jones void install_exception_handler(enum vector v, unsigned int ec, exception_fn fn) 116*7ee966e9SAndrew Jones { 117*7ee966e9SAndrew Jones if (v < VECTOR_MAX && ec < EC_MAX) 118*7ee966e9SAndrew Jones exception_handlers[v][ec] = fn; 119*7ee966e9SAndrew Jones } 120*7ee966e9SAndrew Jones 121*7ee966e9SAndrew Jones static void default_vector_handler(enum vector v, struct pt_regs *regs, 122*7ee966e9SAndrew Jones unsigned int esr) 123*7ee966e9SAndrew Jones { 124*7ee966e9SAndrew Jones unsigned int ec = esr >> ESR_EL1_EC_SHIFT; 125*7ee966e9SAndrew Jones 126*7ee966e9SAndrew Jones if (ec < EC_MAX && exception_handlers[v][ec]) 127*7ee966e9SAndrew Jones exception_handlers[v][ec](regs, esr); 128*7ee966e9SAndrew Jones else 129*7ee966e9SAndrew Jones bad_exception(v, regs, esr, false); 130*7ee966e9SAndrew Jones } 131*7ee966e9SAndrew Jones 132*7ee966e9SAndrew Jones static vector_fn vector_handlers[VECTOR_MAX] = { 133*7ee966e9SAndrew Jones [EL1H_SYNC] = default_vector_handler, 134*7ee966e9SAndrew Jones [EL1H_IRQ] = default_vector_handler, 135*7ee966e9SAndrew Jones [EL0_SYNC_64] = default_vector_handler, 136*7ee966e9SAndrew Jones [EL0_IRQ_64] = default_vector_handler, 137*7ee966e9SAndrew Jones }; 138*7ee966e9SAndrew Jones 139*7ee966e9SAndrew Jones void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr) 140*7ee966e9SAndrew Jones { 141*7ee966e9SAndrew Jones if (v < VECTOR_MAX && vector_handlers[v]) 142*7ee966e9SAndrew Jones vector_handlers[v](v, regs, esr); 143*7ee966e9SAndrew Jones else 144*7ee966e9SAndrew Jones bad_exception(v, regs, esr, true); 145*7ee966e9SAndrew Jones } 146*7ee966e9SAndrew Jones 147*7ee966e9SAndrew Jones void install_vector_handler(enum vector v, vector_fn fn) 148*7ee966e9SAndrew Jones { 149*7ee966e9SAndrew Jones if (v < VECTOR_MAX) 150*7ee966e9SAndrew Jones vector_handlers[v] = fn; 151*7ee966e9SAndrew Jones } 152*7ee966e9SAndrew Jones 153*7ee966e9SAndrew Jones bool user_mode; 154*7ee966e9SAndrew Jones void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) 155*7ee966e9SAndrew Jones { 156*7ee966e9SAndrew Jones sp_usr &= (~15UL); /* stack ptr needs 16-byte alignment */ 157*7ee966e9SAndrew Jones 158*7ee966e9SAndrew Jones user_mode = true; 159*7ee966e9SAndrew Jones 160*7ee966e9SAndrew Jones asm volatile( 161*7ee966e9SAndrew Jones "mov x0, %0\n" 162*7ee966e9SAndrew Jones "msr sp_el0, %1\n" 163*7ee966e9SAndrew Jones "msr elr_el1, %2\n" 164*7ee966e9SAndrew Jones "mov x3, xzr\n" /* clear and "set" PSR_MODE_EL0t */ 165*7ee966e9SAndrew Jones "msr spsr_el1, x3\n" 166*7ee966e9SAndrew Jones "eret\n" 167*7ee966e9SAndrew Jones :: "r" (arg), "r" (sp_usr), "r" (func) : "x0", "x3"); 168*7ee966e9SAndrew Jones } 169