xref: /kvm-unit-tests/lib/arm/processor.c (revision 36b50de9859794dca717d19c850864c614a24ae3)
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  */
88cca5668SAndrew Jones #include <libcflat.h>
98cca5668SAndrew Jones #include <asm/ptrace.h>
108cca5668SAndrew Jones #include <asm/processor.h>
11ad14f089SAndrew Jones #include <asm/thread_info.h>
122edfe428SAndrew Jones 
132edfe428SAndrew Jones static const char *processor_modes[] = {
142edfe428SAndrew Jones 	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
152edfe428SAndrew Jones 	"UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
162edfe428SAndrew Jones 	"UK8_26" , "UK9_26" , "UK10_26", "UK11_26",
172edfe428SAndrew Jones 	"UK12_26", "UK13_26", "UK14_26", "UK15_26",
182edfe428SAndrew Jones 	"USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" ,
192edfe428SAndrew Jones 	"UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
202edfe428SAndrew Jones 	"UK8_32" , "UK9_32" , "UK10_32", "UND_32" ,
212edfe428SAndrew Jones 	"UK12_32", "UK13_32", "UK14_32", "SYS_32"
222edfe428SAndrew Jones };
232edfe428SAndrew Jones 
24a4049322SAndrew Jones static const char *vector_names[] = {
252edfe428SAndrew Jones 	"rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq"
262edfe428SAndrew Jones };
272edfe428SAndrew Jones 
282edfe428SAndrew Jones void show_regs(struct pt_regs *regs)
292edfe428SAndrew Jones {
302edfe428SAndrew Jones 	unsigned long flags;
312edfe428SAndrew Jones 	char buf[64];
322edfe428SAndrew Jones 
332edfe428SAndrew Jones 	printf("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
342edfe428SAndrew Jones 	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
352edfe428SAndrew Jones 		regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
362edfe428SAndrew Jones 		regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
372edfe428SAndrew Jones 	printf("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
382edfe428SAndrew Jones 		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
392edfe428SAndrew Jones 	printf("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
402edfe428SAndrew Jones 		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
412edfe428SAndrew Jones 	printf("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
422edfe428SAndrew Jones 		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
432edfe428SAndrew Jones 
442edfe428SAndrew Jones 	flags = regs->ARM_cpsr;
452edfe428SAndrew Jones 	buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
462edfe428SAndrew Jones 	buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
472edfe428SAndrew Jones 	buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
482edfe428SAndrew Jones 	buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
492edfe428SAndrew Jones 	buf[4] = '\0';
502edfe428SAndrew Jones 
512edfe428SAndrew Jones 	printf("Flags: %s  IRQs o%s  FIQs o%s  Mode %s\n",
522edfe428SAndrew Jones 		buf, interrupts_enabled(regs) ? "n" : "ff",
532edfe428SAndrew Jones 		fast_interrupts_enabled(regs) ? "n" : "ff",
542edfe428SAndrew Jones 		processor_modes[processor_mode(regs)]);
552edfe428SAndrew Jones 
562edfe428SAndrew Jones 	if (!user_mode(regs)) {
572edfe428SAndrew Jones 		unsigned int ctrl, transbase, dac;
582edfe428SAndrew Jones 		asm volatile(
592edfe428SAndrew Jones 			"mrc p15, 0, %0, c1, c0\n"
602edfe428SAndrew Jones 			"mrc p15, 0, %1, c2, c0\n"
612edfe428SAndrew Jones 			"mrc p15, 0, %2, c3, c0\n"
622edfe428SAndrew Jones 		: "=r" (ctrl), "=r" (transbase), "=r" (dac));
632edfe428SAndrew Jones 		printf("Control: %08x  Table: %08x  DAC: %08x\n",
642edfe428SAndrew Jones 			ctrl, transbase, dac);
652edfe428SAndrew Jones 	}
662edfe428SAndrew Jones }
672edfe428SAndrew Jones 
682edfe428SAndrew Jones void install_exception_handler(enum vector v, exception_fn fn)
692edfe428SAndrew Jones {
70ad14f089SAndrew Jones 	struct thread_info *ti = current_thread_info();
71ad14f089SAndrew Jones 
722edfe428SAndrew Jones 	if (v < EXCPTN_MAX)
73ad14f089SAndrew Jones 		ti->exception_handlers[v] = fn;
742edfe428SAndrew Jones }
752edfe428SAndrew Jones 
762edfe428SAndrew Jones void do_handle_exception(enum vector v, struct pt_regs *regs)
772edfe428SAndrew Jones {
78ad14f089SAndrew Jones 	struct thread_info *ti = thread_info_sp(regs->ARM_sp);
79ad14f089SAndrew Jones 
80ad14f089SAndrew Jones 	if (ti->flags & TIF_USER_MODE) {
81ad14f089SAndrew Jones 		if (v < EXCPTN_MAX && ti->exception_handlers[v]) {
82ad14f089SAndrew Jones 			ti->exception_handlers[v](regs);
83ad14f089SAndrew Jones 			return;
84ad14f089SAndrew Jones 		}
85ad14f089SAndrew Jones 		ti = current_thread_info();
86ad14f089SAndrew Jones 	}
87ad14f089SAndrew Jones 
88ad14f089SAndrew Jones 	if (v < EXCPTN_MAX && ti->exception_handlers[v]) {
89ad14f089SAndrew Jones 		ti->exception_handlers[v](regs);
902edfe428SAndrew Jones 		return;
912edfe428SAndrew Jones 	}
922edfe428SAndrew Jones 
932edfe428SAndrew Jones 	if (v < EXCPTN_MAX)
942edfe428SAndrew Jones 		printf("Unhandled exception %d (%s)\n", v, vector_names[v]);
952edfe428SAndrew Jones 	else
962edfe428SAndrew Jones 		printf("%s called with vector=%d\n", __func__, v);
972edfe428SAndrew Jones 
982edfe428SAndrew Jones 	printf("Exception frame registers:\n");
992edfe428SAndrew Jones 	show_regs(regs);
100153d1936SAndrew Jones 	if (v == EXCPTN_DABT) {
101153d1936SAndrew Jones 		unsigned long far, fsr;
102153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c6, c0, 0": "=r" (far));
103153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c5, c0, 0": "=r" (fsr));
104153d1936SAndrew Jones 		printf("DFAR: %08lx    DFSR: %08lx\n", far, fsr);
105153d1936SAndrew Jones 	} else if (v == EXCPTN_PABT) {
106153d1936SAndrew Jones 		unsigned long far, fsr;
107153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c6, c0, 2": "=r" (far));
108153d1936SAndrew Jones 		asm volatile("mrc p15, 0, %0, c5, c0, 1": "=r" (fsr));
109153d1936SAndrew Jones 		printf("IFAR: %08lx    IFSR: %08lx\n", far, fsr);
110153d1936SAndrew Jones 	}
1112c92230aSAndrew Jones 	dump_frame_stack((void *)regs->ARM_pc, (void *)regs->ARM_fp);
1122edfe428SAndrew Jones 	abort();
1132edfe428SAndrew Jones }
1142edfe428SAndrew Jones 
115f6d10793SAndrew Jones void thread_info_init(struct thread_info *ti, unsigned int flags)
116f6d10793SAndrew Jones {
117f6d10793SAndrew Jones 	memset(ti, 0, sizeof(struct thread_info));
118f6d10793SAndrew Jones 	ti->cpu = mpidr_to_cpu(get_mpidr());
119f6d10793SAndrew Jones 	ti->flags = flags;
120f6d10793SAndrew Jones }
121f6d10793SAndrew Jones 
1222edfe428SAndrew Jones void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
1232edfe428SAndrew Jones {
1242edfe428SAndrew Jones 	sp_usr &= (~7UL); /* stack ptr needs 8-byte alignment */
1252edfe428SAndrew Jones 
126f6d10793SAndrew Jones 	thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE);
127*36b50de9SAndrew Jones 	thread_info_sp(sp_usr)->pgtable = current_thread_info()->pgtable;
128f6d10793SAndrew Jones 
1292edfe428SAndrew Jones 	asm volatile(
1302edfe428SAndrew Jones 		"mrs	r0, cpsr\n"
1312edfe428SAndrew Jones 		"bic	r0, #" xstr(MODE_MASK) "\n"
1322edfe428SAndrew Jones 		"orr	r0, #" xstr(USR_MODE) "\n"
1332edfe428SAndrew Jones 		"msr	cpsr_c, r0\n"
1341392497bSAndrew Jones 		"isb\n"
1352edfe428SAndrew Jones 		"mov	r0, %0\n"
1362edfe428SAndrew Jones 		"mov	sp, %1\n"
1372edfe428SAndrew Jones 		"mov	pc, %2\n"
1382edfe428SAndrew Jones 	:: "r" (arg), "r" (sp_usr), "r" (func) : "r0");
1392edfe428SAndrew Jones }
140f6d10793SAndrew Jones 
141f6d10793SAndrew Jones bool is_user(void)
142f6d10793SAndrew Jones {
143f6d10793SAndrew Jones 	return current_thread_info()->flags & TIF_USER_MODE;
144f6d10793SAndrew Jones }
145