xref: /kvm-unit-tests/lib/arm/processor.c (revision 153d193674069bd25373e1dce6bdc9a1b86e0e33)
12edfe428SAndrew Jones /*
22edfe428SAndrew Jones  * processor control and status functions
32edfe428SAndrew Jones  *
42edfe428SAndrew Jones  * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
52edfe428SAndrew Jones  *
62edfe428SAndrew Jones  * This work is licensed under the terms of the GNU LGPL, version 2.
72edfe428SAndrew Jones  */
82edfe428SAndrew Jones #include "libcflat.h"
92edfe428SAndrew Jones #include "asm/ptrace.h"
102edfe428SAndrew Jones #include "asm/processor.h"
112edfe428SAndrew Jones 
122edfe428SAndrew Jones static const char *processor_modes[] = {
132edfe428SAndrew Jones 	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
142edfe428SAndrew Jones 	"UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
152edfe428SAndrew Jones 	"UK8_26" , "UK9_26" , "UK10_26", "UK11_26",
162edfe428SAndrew Jones 	"UK12_26", "UK13_26", "UK14_26", "UK15_26",
172edfe428SAndrew Jones 	"USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" ,
182edfe428SAndrew Jones 	"UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
192edfe428SAndrew Jones 	"UK8_32" , "UK9_32" , "UK10_32", "UND_32" ,
202edfe428SAndrew Jones 	"UK12_32", "UK13_32", "UK14_32", "SYS_32"
212edfe428SAndrew Jones };
222edfe428SAndrew Jones 
232edfe428SAndrew Jones static char *vector_names[] = {
242edfe428SAndrew Jones 	"rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq"
252edfe428SAndrew Jones };
262edfe428SAndrew Jones 
272edfe428SAndrew Jones void show_regs(struct pt_regs *regs)
282edfe428SAndrew Jones {
292edfe428SAndrew Jones 	unsigned long flags;
302edfe428SAndrew Jones 	char buf[64];
312edfe428SAndrew Jones 
322edfe428SAndrew Jones 	printf("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
332edfe428SAndrew Jones 	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
342edfe428SAndrew Jones 		regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
352edfe428SAndrew Jones 		regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
362edfe428SAndrew Jones 	printf("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
372edfe428SAndrew Jones 		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
382edfe428SAndrew Jones 	printf("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
392edfe428SAndrew Jones 		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
402edfe428SAndrew Jones 	printf("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
412edfe428SAndrew Jones 		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
422edfe428SAndrew Jones 
432edfe428SAndrew Jones 	flags = regs->ARM_cpsr;
442edfe428SAndrew Jones 	buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
452edfe428SAndrew Jones 	buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
462edfe428SAndrew Jones 	buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
472edfe428SAndrew Jones 	buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
482edfe428SAndrew Jones 	buf[4] = '\0';
492edfe428SAndrew Jones 
502edfe428SAndrew Jones 	printf("Flags: %s  IRQs o%s  FIQs o%s  Mode %s\n",
512edfe428SAndrew Jones 		buf, interrupts_enabled(regs) ? "n" : "ff",
522edfe428SAndrew Jones 		fast_interrupts_enabled(regs) ? "n" : "ff",
532edfe428SAndrew Jones 		processor_modes[processor_mode(regs)]);
542edfe428SAndrew Jones 
552edfe428SAndrew Jones 	if (!user_mode(regs)) {
562edfe428SAndrew Jones 		unsigned int ctrl, transbase, dac;
572edfe428SAndrew Jones 		asm volatile(
582edfe428SAndrew Jones 			"mrc p15, 0, %0, c1, c0\n"
592edfe428SAndrew Jones 			"mrc p15, 0, %1, c2, c0\n"
602edfe428SAndrew Jones 			"mrc p15, 0, %2, c3, c0\n"
612edfe428SAndrew Jones 		: "=r" (ctrl), "=r" (transbase), "=r" (dac));
622edfe428SAndrew Jones 		printf("Control: %08x  Table: %08x  DAC: %08x\n",
632edfe428SAndrew Jones 			ctrl, transbase, dac);
642edfe428SAndrew Jones 	}
652edfe428SAndrew Jones }
662edfe428SAndrew Jones 
672edfe428SAndrew Jones void *get_sp(void)
682edfe428SAndrew Jones {
692edfe428SAndrew Jones 	register unsigned long sp asm("sp");
702edfe428SAndrew Jones 	return (void *)sp;
712edfe428SAndrew Jones }
722edfe428SAndrew Jones 
732edfe428SAndrew Jones static exception_fn exception_handlers[EXCPTN_MAX];
742edfe428SAndrew Jones 
752edfe428SAndrew Jones void install_exception_handler(enum vector v, exception_fn fn)
762edfe428SAndrew Jones {
772edfe428SAndrew Jones 	if (v < EXCPTN_MAX)
782edfe428SAndrew Jones 		exception_handlers[v] = fn;
792edfe428SAndrew Jones }
802edfe428SAndrew Jones 
812edfe428SAndrew Jones void do_handle_exception(enum vector v, struct pt_regs *regs)
822edfe428SAndrew Jones {
832edfe428SAndrew Jones 	if (v < EXCPTN_MAX && exception_handlers[v]) {
842edfe428SAndrew Jones 		exception_handlers[v](regs);
852edfe428SAndrew Jones 		return;
862edfe428SAndrew Jones 	}
872edfe428SAndrew Jones 
882edfe428SAndrew Jones 	if (v < EXCPTN_MAX)
892edfe428SAndrew Jones 		printf("Unhandled exception %d (%s)\n", v, vector_names[v]);
902edfe428SAndrew Jones 	else
912edfe428SAndrew Jones 		printf("%s called with vector=%d\n", __func__, v);
922edfe428SAndrew Jones 
932edfe428SAndrew Jones 	printf("Exception frame registers:\n");
942edfe428SAndrew Jones 	show_regs(regs);
95*153d1936SAndrew Jones 	if (v == EXCPTN_DABT) {
96*153d1936SAndrew Jones 		unsigned long far, fsr;
97*153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c6, c0, 0": "=r" (far));
98*153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c5, c0, 0": "=r" (fsr));
99*153d1936SAndrew Jones 		printf("DFAR: %08lx    DFSR: %08lx\n", far, fsr);
100*153d1936SAndrew Jones 	} else if (v == EXCPTN_PABT) {
101*153d1936SAndrew Jones 		unsigned long far, fsr;
102*153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c6, c0, 2": "=r" (far));
103*153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c5, c0, 1": "=r" (fsr));
104*153d1936SAndrew Jones 		printf("IFAR: %08lx    IFSR: %08lx\n", far, fsr);
105*153d1936SAndrew Jones 	}
1062edfe428SAndrew Jones 	abort();
1072edfe428SAndrew Jones }
1082edfe428SAndrew Jones 
1092edfe428SAndrew Jones void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
1102edfe428SAndrew Jones {
1112edfe428SAndrew Jones 	sp_usr &= (~7UL); /* stack ptr needs 8-byte alignment */
1122edfe428SAndrew Jones 
1132edfe428SAndrew Jones 	asm volatile(
1142edfe428SAndrew Jones 		"mrs	r0, cpsr\n"
1152edfe428SAndrew Jones 		"bic	r0, #" xstr(MODE_MASK) "\n"
1162edfe428SAndrew Jones 		"orr	r0, #" xstr(USR_MODE) "\n"
1172edfe428SAndrew Jones 		"msr	cpsr_c, r0\n"
1182edfe428SAndrew Jones 		"mov	r0, %0\n"
1192edfe428SAndrew Jones 		"mov	sp, %1\n"
1202edfe428SAndrew Jones 		"mov	pc, %2\n"
1212edfe428SAndrew Jones 	:: "r" (arg), "r" (sp_usr), "r" (func) : "r0");
1222edfe428SAndrew Jones }
123