1 /* 2 * processor control and status functions 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 <asm/ptrace.h> 10 #include <asm/processor.h> 11 #include <asm/thread_info.h> 12 13 static const char *processor_modes[] = { 14 "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , 15 "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , 16 "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", 17 "UK12_26", "UK13_26", "UK14_26", "UK15_26", 18 "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , 19 "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , 20 "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , 21 "UK12_32", "UK13_32", "UK14_32", "SYS_32" 22 }; 23 24 static const char *vector_names[] = { 25 "rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq" 26 }; 27 28 void show_regs(struct pt_regs *regs) 29 { 30 unsigned long flags; 31 char buf[64]; 32 33 printf("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" 34 "sp : %08lx ip : %08lx fp : %08lx\n", 35 regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, 36 regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); 37 printf("r10: %08lx r9 : %08lx r8 : %08lx\n", 38 regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); 39 printf("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", 40 regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4); 41 printf("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", 42 regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); 43 44 flags = regs->ARM_cpsr; 45 buf[0] = flags & PSR_N_BIT ? 'N' : 'n'; 46 buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z'; 47 buf[2] = flags & PSR_C_BIT ? 'C' : 'c'; 48 buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; 49 buf[4] = '\0'; 50 51 printf("Flags: %s IRQs o%s FIQs o%s Mode %s\n", 52 buf, interrupts_enabled(regs) ? "n" : "ff", 53 fast_interrupts_enabled(regs) ? "n" : "ff", 54 processor_modes[processor_mode(regs)]); 55 56 if (!user_mode(regs)) { 57 unsigned int ctrl, transbase, dac; 58 asm volatile( 59 "mrc p15, 0, %0, c1, c0\n" 60 "mrc p15, 0, %1, c2, c0\n" 61 "mrc p15, 0, %2, c3, c0\n" 62 : "=r" (ctrl), "=r" (transbase), "=r" (dac)); 63 printf("Control: %08x Table: %08x DAC: %08x\n", 64 ctrl, transbase, dac); 65 } 66 } 67 68 void install_exception_handler(enum vector v, exception_fn fn) 69 { 70 struct thread_info *ti = current_thread_info(); 71 72 if (v < EXCPTN_MAX) 73 ti->exception_handlers[v] = fn; 74 } 75 76 /* Needed to compile with -Wmissing-prototypes */ 77 void do_handle_exception(enum vector v, struct pt_regs *regs); 78 79 void do_handle_exception(enum vector v, struct pt_regs *regs) 80 { 81 struct thread_info *ti = thread_info_sp(regs->ARM_sp); 82 83 if (ti->flags & TIF_USER_MODE) { 84 if (v < EXCPTN_MAX && ti->exception_handlers[v]) { 85 ti->exception_handlers[v](regs); 86 return; 87 } 88 ti = current_thread_info(); 89 } 90 91 if (v < EXCPTN_MAX && ti->exception_handlers[v]) { 92 ti->exception_handlers[v](regs); 93 return; 94 } 95 96 if (v < EXCPTN_MAX) 97 printf("Unhandled exception %d (%s)\n", v, vector_names[v]); 98 else 99 printf("%s called with vector=%d\n", __func__, v); 100 101 printf("Exception frame registers:\n"); 102 show_regs(regs); 103 if (v == EXCPTN_DABT) { 104 unsigned long far, fsr; 105 asm volatile("mrc p15, 0, %0, c6, c0, 0": "=r" (far)); 106 asm volatile("mrc p15, 0, %0, c5, c0, 0": "=r" (fsr)); 107 printf("DFAR: %08lx DFSR: %08lx\n", far, fsr); 108 } else if (v == EXCPTN_PABT) { 109 unsigned long far, fsr; 110 asm volatile("mrc p15, 0, %0, c6, c0, 2": "=r" (far)); 111 asm volatile("mrc p15, 0, %0, c5, c0, 1": "=r" (fsr)); 112 printf("IFAR: %08lx IFSR: %08lx\n", far, fsr); 113 } 114 dump_frame_stack((void *)regs->ARM_pc, (void *)regs->ARM_fp); 115 abort(); 116 } 117 118 void thread_info_init(struct thread_info *ti, unsigned int flags) 119 { 120 memset(ti, 0, sizeof(struct thread_info)); 121 ti->cpu = mpidr_to_cpu(get_mpidr()); 122 ti->flags = flags; 123 } 124 125 void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) 126 { 127 sp_usr &= (~7UL); /* stack ptr needs 8-byte alignment */ 128 129 thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE); 130 thread_info_sp(sp_usr)->pgtable = current_thread_info()->pgtable; 131 132 asm volatile( 133 "mrs r0, cpsr\n" 134 "bic r0, #" xstr(MODE_MASK) "\n" 135 "orr r0, #" xstr(USR_MODE) "\n" 136 "msr cpsr_c, r0\n" 137 "isb\n" 138 "mov r0, %0\n" 139 "mov sp, %1\n" 140 "mov pc, %2\n" 141 :: "r" (arg), "r" (sp_usr), "r" (func) : "r0"); 142 } 143 144 bool is_user(void) 145 { 146 return current_thread_info()->flags & TIF_USER_MODE; 147 } 148 149 bool __mmu_enabled(void) 150 { 151 return read_sysreg(SCTRL) & CR_M; 152 } 153