xref: /kvm-unit-tests/lib/arm64/processor.c (revision 7ee966e98ee6e326b4149ed28330a71d6e96b10d)
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