xref: /kvm-unit-tests/lib/arm64/processor.c (revision a404932284befc6f5507ddd8292617447ced15b9)
17ee966e9SAndrew Jones /*
27ee966e9SAndrew Jones  * processor control and status functions
37ee966e9SAndrew Jones  *
47ee966e9SAndrew Jones  * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
57ee966e9SAndrew Jones  *
67ee966e9SAndrew Jones  * This work is licensed under the terms of the GNU LGPL, version 2.
77ee966e9SAndrew Jones  */
87ee966e9SAndrew Jones #include <libcflat.h>
97ee966e9SAndrew Jones #include <asm/ptrace.h>
107ee966e9SAndrew Jones #include <asm/processor.h>
117ee966e9SAndrew Jones #include <asm/esr.h>
127ee966e9SAndrew Jones 
13*a4049322SAndrew Jones static const char *vector_names[] = {
147ee966e9SAndrew Jones 	"el1t_sync",
157ee966e9SAndrew Jones 	"el1t_irq",
167ee966e9SAndrew Jones 	"el1t_fiq",
177ee966e9SAndrew Jones 	"el1t_error",
187ee966e9SAndrew Jones 	"el1h_sync",
197ee966e9SAndrew Jones 	"el1h_irq",
207ee966e9SAndrew Jones 	"el1h_fiq",
217ee966e9SAndrew Jones 	"el1h_error",
227ee966e9SAndrew Jones 	"el0_sync_64",
237ee966e9SAndrew Jones 	"el0_irq_64",
247ee966e9SAndrew Jones 	"el0_fiq_64",
257ee966e9SAndrew Jones 	"el0_error_64",
267ee966e9SAndrew Jones 	"el0_sync_32",
277ee966e9SAndrew Jones 	"el0_irq_32",
287ee966e9SAndrew Jones 	"el0_fiq_32",
297ee966e9SAndrew Jones 	"el0_error_32",
307ee966e9SAndrew Jones };
317ee966e9SAndrew Jones 
32*a4049322SAndrew Jones static const char *ec_names[EC_MAX] = {
337ee966e9SAndrew Jones 	[ESR_EL1_EC_UNKNOWN]		= "UNKNOWN",
347ee966e9SAndrew Jones 	[ESR_EL1_EC_WFI]		= "WFI",
357ee966e9SAndrew Jones 	[ESR_EL1_EC_CP15_32]		= "CP15_32",
367ee966e9SAndrew Jones 	[ESR_EL1_EC_CP15_64]		= "CP15_64",
377ee966e9SAndrew Jones 	[ESR_EL1_EC_CP14_MR]		= "CP14_MR",
387ee966e9SAndrew Jones 	[ESR_EL1_EC_CP14_LS]		= "CP14_LS",
397ee966e9SAndrew Jones 	[ESR_EL1_EC_FP_ASIMD]		= "FP_ASMID",
407ee966e9SAndrew Jones 	[ESR_EL1_EC_CP10_ID]		= "CP10_ID",
417ee966e9SAndrew Jones 	[ESR_EL1_EC_CP14_64]		= "CP14_64",
427ee966e9SAndrew Jones 	[ESR_EL1_EC_ILL_ISS]		= "ILL_ISS",
437ee966e9SAndrew Jones 	[ESR_EL1_EC_SVC32]		= "SVC32",
447ee966e9SAndrew Jones 	[ESR_EL1_EC_SVC64]		= "SVC64",
457ee966e9SAndrew Jones 	[ESR_EL1_EC_SYS64]		= "SYS64",
467ee966e9SAndrew Jones 	[ESR_EL1_EC_IABT_EL0]		= "IABT_EL0",
477ee966e9SAndrew Jones 	[ESR_EL1_EC_IABT_EL1]		= "IABT_EL1",
487ee966e9SAndrew Jones 	[ESR_EL1_EC_PC_ALIGN]		= "PC_ALIGN",
497ee966e9SAndrew Jones 	[ESR_EL1_EC_DABT_EL0]		= "DABT_EL0",
507ee966e9SAndrew Jones 	[ESR_EL1_EC_DABT_EL1]		= "DABT_EL1",
517ee966e9SAndrew Jones 	[ESR_EL1_EC_SP_ALIGN]		= "SP_ALIGN",
527ee966e9SAndrew Jones 	[ESR_EL1_EC_FP_EXC32]		= "FP_EXC32",
537ee966e9SAndrew Jones 	[ESR_EL1_EC_FP_EXC64]		= "FP_EXC64",
547ee966e9SAndrew Jones 	[ESR_EL1_EC_SERROR]		= "SERROR",
557ee966e9SAndrew Jones 	[ESR_EL1_EC_BREAKPT_EL0]	= "BREAKPT_EL0",
567ee966e9SAndrew Jones 	[ESR_EL1_EC_BREAKPT_EL1]	= "BREAKPT_EL1",
577ee966e9SAndrew Jones 	[ESR_EL1_EC_SOFTSTP_EL0]	= "SOFTSTP_EL0",
587ee966e9SAndrew Jones 	[ESR_EL1_EC_SOFTSTP_EL1]	= "SOFTSTP_EL1",
597ee966e9SAndrew Jones 	[ESR_EL1_EC_WATCHPT_EL0]	= "WATCHPT_EL0",
607ee966e9SAndrew Jones 	[ESR_EL1_EC_WATCHPT_EL1]	= "WATCHPT_EL1",
617ee966e9SAndrew Jones 	[ESR_EL1_EC_BKPT32]		= "BKPT32",
627ee966e9SAndrew Jones 	[ESR_EL1_EC_BRK64]		= "BRK64",
637ee966e9SAndrew Jones };
647ee966e9SAndrew Jones 
657ee966e9SAndrew Jones void show_regs(struct pt_regs *regs)
667ee966e9SAndrew Jones {
677ee966e9SAndrew Jones 	int i;
687ee966e9SAndrew Jones 
697ee966e9SAndrew Jones 	printf("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n",
707ee966e9SAndrew Jones 			regs->pc, regs->regs[30], regs->pstate);
717ee966e9SAndrew Jones 	printf("sp : %016llx\n", regs->sp);
727ee966e9SAndrew Jones 
737ee966e9SAndrew Jones 	for (i = 29; i >= 0; --i) {
747ee966e9SAndrew Jones 		printf("x%-2d: %016llx ", i, regs->regs[i]);
757ee966e9SAndrew Jones 		if (i % 2 == 0)
767ee966e9SAndrew Jones 			printf("\n");
777ee966e9SAndrew Jones 	}
787ee966e9SAndrew Jones 	printf("\n");
797ee966e9SAndrew Jones }
807ee966e9SAndrew Jones 
817ee966e9SAndrew Jones void *get_sp(void)
827ee966e9SAndrew Jones {
837ee966e9SAndrew Jones 	register unsigned long sp asm("sp");
847ee966e9SAndrew Jones 	return (void *)sp;
857ee966e9SAndrew Jones }
867ee966e9SAndrew Jones 
87db328a24SAndrew Jones bool get_far(unsigned int esr, unsigned long *far)
88db328a24SAndrew Jones {
89db328a24SAndrew Jones 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
90db328a24SAndrew Jones 
91db328a24SAndrew Jones 	asm volatile("mrs %0, far_el1": "=r" (*far));
92db328a24SAndrew Jones 
93db328a24SAndrew Jones 	switch (ec) {
94db328a24SAndrew Jones 	case ESR_EL1_EC_IABT_EL0:
95db328a24SAndrew Jones 	case ESR_EL1_EC_IABT_EL1:
96db328a24SAndrew Jones 	case ESR_EL1_EC_PC_ALIGN:
97db328a24SAndrew Jones 	case ESR_EL1_EC_DABT_EL0:
98db328a24SAndrew Jones 	case ESR_EL1_EC_DABT_EL1:
99db328a24SAndrew Jones 	case ESR_EL1_EC_WATCHPT_EL0:
100db328a24SAndrew Jones 	case ESR_EL1_EC_WATCHPT_EL1:
101db328a24SAndrew Jones 		if ((esr & 0x3f /* DFSC */) != 0x10
102db328a24SAndrew Jones 				|| !(esr & 0x400 /* FnV */))
103db328a24SAndrew Jones 			return true;
104db328a24SAndrew Jones 	}
105db328a24SAndrew Jones 	return false;
106db328a24SAndrew Jones }
107db328a24SAndrew Jones 
1087ee966e9SAndrew Jones static void bad_exception(enum vector v, struct pt_regs *regs,
1097ee966e9SAndrew Jones 			  unsigned int esr, bool bad_vector)
1107ee966e9SAndrew Jones {
111db328a24SAndrew Jones 	unsigned long far;
112db328a24SAndrew Jones 	bool far_valid = get_far(esr, &far);
1137ee966e9SAndrew Jones 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
1147ee966e9SAndrew Jones 
1157ee966e9SAndrew Jones 	if (bad_vector) {
1167ee966e9SAndrew Jones 		if (v < VECTOR_MAX)
1177ee966e9SAndrew Jones 			printf("Unhandled vector %d (%s)\n", v,
1187ee966e9SAndrew Jones 					vector_names[v]);
1197ee966e9SAndrew Jones 		else
1207ee966e9SAndrew Jones 			printf("Got bad vector=%d\n", v);
1217ee966e9SAndrew Jones 	} else {
1227ee966e9SAndrew Jones 		if (ec_names[ec])
1237ee966e9SAndrew Jones 			printf("Unhandled exception ec=0x%x (%s)\n", ec,
1247ee966e9SAndrew Jones 					ec_names[ec]);
1257ee966e9SAndrew Jones 		else
1267ee966e9SAndrew Jones 			printf("Got bad ec=0x%x\n", ec);
1277ee966e9SAndrew Jones 	}
1287ee966e9SAndrew Jones 
1297ee966e9SAndrew Jones 	printf("Vector: %d (%s)\n", v, vector_names[v]);
130db328a24SAndrew Jones 	printf("ESR_EL1: %8s%08lx, ec=0x%x (%s)\n", "", esr, ec, ec_names[ec]);
131db328a24SAndrew Jones 	printf("FAR_EL1: %016lx (%svalid)\n", far, far_valid ? "" : "not ");
1327ee966e9SAndrew Jones 	printf("Exception frame registers:\n");
1337ee966e9SAndrew Jones 	show_regs(regs);
1347ee966e9SAndrew Jones 	abort();
1357ee966e9SAndrew Jones }
1367ee966e9SAndrew Jones 
1377ee966e9SAndrew Jones static exception_fn exception_handlers[VECTOR_MAX][EC_MAX];
1387ee966e9SAndrew Jones 
1397ee966e9SAndrew Jones void install_exception_handler(enum vector v, unsigned int ec, exception_fn fn)
1407ee966e9SAndrew Jones {
1417ee966e9SAndrew Jones 	if (v < VECTOR_MAX && ec < EC_MAX)
1427ee966e9SAndrew Jones 		exception_handlers[v][ec] = fn;
1437ee966e9SAndrew Jones }
1447ee966e9SAndrew Jones 
145*a4049322SAndrew Jones void default_vector_handler(enum vector v, struct pt_regs *regs,
1467ee966e9SAndrew Jones 			    unsigned int esr)
1477ee966e9SAndrew Jones {
1487ee966e9SAndrew Jones 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
1497ee966e9SAndrew Jones 
1507ee966e9SAndrew Jones 	if (ec < EC_MAX && exception_handlers[v][ec])
1517ee966e9SAndrew Jones 		exception_handlers[v][ec](regs, esr);
1527ee966e9SAndrew Jones 	else
1537ee966e9SAndrew Jones 		bad_exception(v, regs, esr, false);
1547ee966e9SAndrew Jones }
1557ee966e9SAndrew Jones 
1567ee966e9SAndrew Jones static vector_fn vector_handlers[VECTOR_MAX] = {
1577ee966e9SAndrew Jones 	[EL1H_SYNC]	= default_vector_handler,
1587ee966e9SAndrew Jones 	[EL1H_IRQ]	= default_vector_handler,
1597ee966e9SAndrew Jones 	[EL0_SYNC_64]	= default_vector_handler,
1607ee966e9SAndrew Jones 	[EL0_IRQ_64]	= default_vector_handler,
1617ee966e9SAndrew Jones };
1627ee966e9SAndrew Jones 
1637ee966e9SAndrew Jones void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr)
1647ee966e9SAndrew Jones {
1657ee966e9SAndrew Jones 	if (v < VECTOR_MAX && vector_handlers[v])
1667ee966e9SAndrew Jones 		vector_handlers[v](v, regs, esr);
1677ee966e9SAndrew Jones 	else
1687ee966e9SAndrew Jones 		bad_exception(v, regs, esr, true);
1697ee966e9SAndrew Jones }
1707ee966e9SAndrew Jones 
1717ee966e9SAndrew Jones void install_vector_handler(enum vector v, vector_fn fn)
1727ee966e9SAndrew Jones {
1737ee966e9SAndrew Jones 	if (v < VECTOR_MAX)
1747ee966e9SAndrew Jones 		vector_handlers[v] = fn;
1757ee966e9SAndrew Jones }
1767ee966e9SAndrew Jones 
1777ee966e9SAndrew Jones bool user_mode;
1787ee966e9SAndrew Jones void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
1797ee966e9SAndrew Jones {
1807ee966e9SAndrew Jones 	sp_usr &= (~15UL); /* stack ptr needs 16-byte alignment */
1817ee966e9SAndrew Jones 
1827ee966e9SAndrew Jones 	user_mode = true;
1837ee966e9SAndrew Jones 
1847ee966e9SAndrew Jones 	asm volatile(
1857ee966e9SAndrew Jones 		"mov	x0, %0\n"
1867ee966e9SAndrew Jones 		"msr	sp_el0, %1\n"
1877ee966e9SAndrew Jones 		"msr	elr_el1, %2\n"
1887ee966e9SAndrew Jones 		"mov	x3, xzr\n"	/* clear and "set" PSR_MODE_EL0t */
1897ee966e9SAndrew Jones 		"msr	spsr_el1, x3\n"
1907ee966e9SAndrew Jones 		"eret\n"
1917ee966e9SAndrew Jones 	:: "r" (arg), "r" (sp_usr), "r" (func) : "x0", "x3");
1927ee966e9SAndrew Jones }
193