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