xref: /kvm-unit-tests/lib/arm64/processor.c (revision 201b9e8bdc84c6436dd53b45d93a60c681b92719)
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>
11ad14f089SAndrew Jones #include <asm/thread_info.h>
127ee966e9SAndrew Jones 
13a4049322SAndrew 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 
32a4049322SAndrew 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",
46*1afc6fb7SJoey Gouly 	[ESR_EL1_EC_SVE]		= "SVE",
477ee966e9SAndrew Jones 	[ESR_EL1_EC_IABT_EL0]		= "IABT_EL0",
487ee966e9SAndrew Jones 	[ESR_EL1_EC_IABT_EL1]		= "IABT_EL1",
497ee966e9SAndrew Jones 	[ESR_EL1_EC_PC_ALIGN]		= "PC_ALIGN",
507ee966e9SAndrew Jones 	[ESR_EL1_EC_DABT_EL0]		= "DABT_EL0",
517ee966e9SAndrew Jones 	[ESR_EL1_EC_DABT_EL1]		= "DABT_EL1",
527ee966e9SAndrew Jones 	[ESR_EL1_EC_SP_ALIGN]		= "SP_ALIGN",
537ee966e9SAndrew Jones 	[ESR_EL1_EC_FP_EXC32]		= "FP_EXC32",
547ee966e9SAndrew Jones 	[ESR_EL1_EC_FP_EXC64]		= "FP_EXC64",
557ee966e9SAndrew Jones 	[ESR_EL1_EC_SERROR]		= "SERROR",
567ee966e9SAndrew Jones 	[ESR_EL1_EC_BREAKPT_EL0]	= "BREAKPT_EL0",
577ee966e9SAndrew Jones 	[ESR_EL1_EC_BREAKPT_EL1]	= "BREAKPT_EL1",
587ee966e9SAndrew Jones 	[ESR_EL1_EC_SOFTSTP_EL0]	= "SOFTSTP_EL0",
597ee966e9SAndrew Jones 	[ESR_EL1_EC_SOFTSTP_EL1]	= "SOFTSTP_EL1",
607ee966e9SAndrew Jones 	[ESR_EL1_EC_WATCHPT_EL0]	= "WATCHPT_EL0",
617ee966e9SAndrew Jones 	[ESR_EL1_EC_WATCHPT_EL1]	= "WATCHPT_EL1",
627ee966e9SAndrew Jones 	[ESR_EL1_EC_BKPT32]		= "BKPT32",
637ee966e9SAndrew Jones 	[ESR_EL1_EC_BRK64]		= "BRK64",
647ee966e9SAndrew Jones };
657ee966e9SAndrew Jones 
show_regs(struct pt_regs * regs)667ee966e9SAndrew Jones void show_regs(struct pt_regs *regs)
677ee966e9SAndrew Jones {
687ee966e9SAndrew Jones 	int i;
697ee966e9SAndrew Jones 
7060eb32bfSAndrew Jones 	printf("pc : [<%016lx>] lr : [<%016lx>] pstate: %08lx\n",
717ee966e9SAndrew Jones 			regs->pc, regs->regs[30], regs->pstate);
7260eb32bfSAndrew Jones 	printf("sp : %016lx\n", regs->sp);
737ee966e9SAndrew Jones 
747ee966e9SAndrew Jones 	for (i = 29; i >= 0; --i) {
7560eb32bfSAndrew Jones 		printf("x%-2d: %016lx ", i, regs->regs[i]);
767ee966e9SAndrew Jones 		if (i % 2 == 0)
777ee966e9SAndrew Jones 			printf("\n");
787ee966e9SAndrew Jones 	}
797ee966e9SAndrew Jones 	printf("\n");
807ee966e9SAndrew Jones }
817ee966e9SAndrew Jones 
get_far(unsigned int esr,unsigned long * far)82db328a24SAndrew Jones bool get_far(unsigned int esr, unsigned long *far)
83db328a24SAndrew Jones {
84db328a24SAndrew Jones 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
85db328a24SAndrew Jones 
86db328a24SAndrew Jones 	asm volatile("mrs %0, far_el1": "=r" (*far));
87db328a24SAndrew Jones 
88db328a24SAndrew Jones 	switch (ec) {
89db328a24SAndrew Jones 	case ESR_EL1_EC_IABT_EL0:
90db328a24SAndrew Jones 	case ESR_EL1_EC_IABT_EL1:
91db328a24SAndrew Jones 	case ESR_EL1_EC_PC_ALIGN:
92db328a24SAndrew Jones 	case ESR_EL1_EC_DABT_EL0:
93db328a24SAndrew Jones 	case ESR_EL1_EC_DABT_EL1:
94db328a24SAndrew Jones 	case ESR_EL1_EC_WATCHPT_EL0:
95db328a24SAndrew Jones 	case ESR_EL1_EC_WATCHPT_EL1:
96db328a24SAndrew Jones 		if ((esr & 0x3f /* DFSC */) != 0x10
97db328a24SAndrew Jones 				|| !(esr & 0x400 /* FnV */))
98db328a24SAndrew Jones 			return true;
99db328a24SAndrew Jones 	}
100db328a24SAndrew Jones 	return false;
101db328a24SAndrew Jones }
102db328a24SAndrew Jones 
103a09aa3fbSAndrew Jones extern unsigned long _text;
104a09aa3fbSAndrew Jones 
bad_exception(enum vector v,struct pt_regs * regs,unsigned int esr,bool esr_valid,bool bad_vector)1057ee966e9SAndrew Jones static void bad_exception(enum vector v, struct pt_regs *regs,
1069ae19a63SAndrew Jones 			  unsigned int esr, bool esr_valid, bool bad_vector)
1077ee966e9SAndrew Jones {
108db328a24SAndrew Jones 	unsigned long far;
109db328a24SAndrew Jones 	bool far_valid = get_far(esr, &far);
1107ee966e9SAndrew Jones 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
111a09aa3fbSAndrew Jones 	uintptr_t text = (uintptr_t)&_text;
112a09aa3fbSAndrew Jones 
113a09aa3fbSAndrew Jones 	printf("Load address: %" PRIxPTR "\n", text);
114a09aa3fbSAndrew Jones 	printf("PC: %" PRIxPTR " PC offset: %" PRIxPTR "\n",
115a09aa3fbSAndrew Jones 	       (uintptr_t)regs->pc, (uintptr_t)regs->pc - text);
1167ee966e9SAndrew Jones 
1177ee966e9SAndrew Jones 	if (bad_vector) {
1187ee966e9SAndrew Jones 		if (v < VECTOR_MAX)
1197ee966e9SAndrew Jones 			printf("Unhandled vector %d (%s)\n", v,
1207ee966e9SAndrew Jones 					vector_names[v]);
1217ee966e9SAndrew Jones 		else
1227ee966e9SAndrew Jones 			printf("Got bad vector=%d\n", v);
1239ae19a63SAndrew Jones 	} else if (esr_valid) {
1247ee966e9SAndrew Jones 		if (ec_names[ec])
125fd6aada0SRadim Krčmář 			printf("Unhandled exception ec=%#x (%s)\n", ec,
1267ee966e9SAndrew Jones 					ec_names[ec]);
1277ee966e9SAndrew Jones 		else
128fd6aada0SRadim Krčmář 			printf("Got bad ec=%#x\n", ec);
1297ee966e9SAndrew Jones 	}
1307ee966e9SAndrew Jones 
1317ee966e9SAndrew Jones 	printf("Vector: %d (%s)\n", v, vector_names[v]);
132fd6aada0SRadim Krčmář 	printf("ESR_EL1: %8s%08x, ec=%#x (%s)\n", "", esr, ec, ec_names[ec]);
133db328a24SAndrew Jones 	printf("FAR_EL1: %016lx (%svalid)\n", far, far_valid ? "" : "not ");
1347ee966e9SAndrew Jones 	printf("Exception frame registers:\n");
1357ee966e9SAndrew Jones 	show_regs(regs);
13622944767SAndrew Jones 	dump_frame_stack((void *)regs->pc, (void *)regs->regs[29]);
1377ee966e9SAndrew Jones 	abort();
1387ee966e9SAndrew Jones }
1397ee966e9SAndrew Jones 
install_exception_handler(enum vector v,unsigned int ec,exception_fn fn)1407ee966e9SAndrew Jones void install_exception_handler(enum vector v, unsigned int ec, exception_fn fn)
1417ee966e9SAndrew Jones {
142ad14f089SAndrew Jones 	struct thread_info *ti = current_thread_info();
143ad14f089SAndrew Jones 
1447ee966e9SAndrew Jones 	if (v < VECTOR_MAX && ec < EC_MAX)
145ad14f089SAndrew Jones 		ti->exception_handlers[v][ec] = fn;
1467ee966e9SAndrew Jones }
1477ee966e9SAndrew Jones 
install_irq_handler(enum vector v,irq_handler_fn fn)1489ae19a63SAndrew Jones void install_irq_handler(enum vector v, irq_handler_fn fn)
1499ae19a63SAndrew Jones {
1509ae19a63SAndrew Jones 	struct thread_info *ti = current_thread_info();
1519ae19a63SAndrew Jones 
1529ae19a63SAndrew Jones 	if (v < VECTOR_MAX)
1539ae19a63SAndrew Jones 		ti->exception_handlers[v][0] = (exception_fn)fn;
1549ae19a63SAndrew Jones }
1559ae19a63SAndrew Jones 
default_vector_sync_handler(enum vector v,struct pt_regs * regs,unsigned int esr)1569ae19a63SAndrew Jones void default_vector_sync_handler(enum vector v, struct pt_regs *regs,
1577ee966e9SAndrew Jones 				 unsigned int esr)
1587ee966e9SAndrew Jones {
159ad14f089SAndrew Jones 	struct thread_info *ti = thread_info_sp(regs->sp);
1607ee966e9SAndrew Jones 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
1617ee966e9SAndrew Jones 
162ad14f089SAndrew Jones 	if (ti->flags & TIF_USER_MODE) {
163ad14f089SAndrew Jones 		if (ec < EC_MAX && ti->exception_handlers[v][ec]) {
164ad14f089SAndrew Jones 			ti->exception_handlers[v][ec](regs, esr);
165ad14f089SAndrew Jones 			return;
166ad14f089SAndrew Jones 		}
167ad14f089SAndrew Jones 		ti = current_thread_info();
168ad14f089SAndrew Jones 	}
169ad14f089SAndrew Jones 
170ad14f089SAndrew Jones 	if (ec < EC_MAX && ti->exception_handlers[v][ec])
171ad14f089SAndrew Jones 		ti->exception_handlers[v][ec](regs, esr);
1727ee966e9SAndrew Jones 	else
1739ae19a63SAndrew Jones 		bad_exception(v, regs, esr, true, false);
1749ae19a63SAndrew Jones }
1759ae19a63SAndrew Jones 
default_vector_irq_handler(enum vector v,struct pt_regs * regs,unsigned int esr)1769ae19a63SAndrew Jones void default_vector_irq_handler(enum vector v, struct pt_regs *regs,
1779ae19a63SAndrew Jones 				unsigned int esr)
1789ae19a63SAndrew Jones {
1799ae19a63SAndrew Jones 	struct thread_info *ti = thread_info_sp(regs->sp);
1809ae19a63SAndrew Jones 	irq_handler_fn irq_handler =
1819ae19a63SAndrew Jones 		(irq_handler_fn)ti->exception_handlers[v][0];
1829ae19a63SAndrew Jones 
1839ae19a63SAndrew Jones 	if (ti->flags & TIF_USER_MODE) {
1849ae19a63SAndrew Jones 		if (irq_handler) {
1859ae19a63SAndrew Jones 			irq_handler(regs);
1869ae19a63SAndrew Jones 			return;
1879ae19a63SAndrew Jones 		}
1889ae19a63SAndrew Jones 		ti = current_thread_info();
1899ae19a63SAndrew Jones 		irq_handler = (irq_handler_fn)ti->exception_handlers[v][0];
1909ae19a63SAndrew Jones 	}
1919ae19a63SAndrew Jones 
1929ae19a63SAndrew Jones 	if (irq_handler)
1939ae19a63SAndrew Jones 		irq_handler(regs);
1949ae19a63SAndrew Jones 	else
1959ae19a63SAndrew Jones 		bad_exception(v, regs, esr, false, false);
1967ee966e9SAndrew Jones }
1977ee966e9SAndrew Jones 
vector_handlers_default_init(vector_fn * handlers)198ad14f089SAndrew Jones void vector_handlers_default_init(vector_fn *handlers)
199ad14f089SAndrew Jones {
2009ae19a63SAndrew Jones 	handlers[EL1H_SYNC]	= default_vector_sync_handler;
2019ae19a63SAndrew Jones 	handlers[EL1H_IRQ]	= default_vector_irq_handler;
2029ae19a63SAndrew Jones 	handlers[EL0_SYNC_64]	= default_vector_sync_handler;
2039ae19a63SAndrew Jones 	handlers[EL0_IRQ_64]	= default_vector_irq_handler;
204ad14f089SAndrew Jones }
2057ee966e9SAndrew Jones 
2060df901e0SAndrew Jones /* Needed to compile with -Wmissing-prototypes */
2070df901e0SAndrew Jones void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr);
2080df901e0SAndrew Jones 
do_handle_exception(enum vector v,struct pt_regs * regs,unsigned int esr)2097ee966e9SAndrew Jones void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr)
2107ee966e9SAndrew Jones {
211ad14f089SAndrew Jones 	struct thread_info *ti = thread_info_sp(regs->sp);
212ad14f089SAndrew Jones 
213ad14f089SAndrew Jones 	if (ti->flags & TIF_USER_MODE) {
214ad14f089SAndrew Jones 		if (v < VECTOR_MAX && ti->vector_handlers[v]) {
215ad14f089SAndrew Jones 			ti->vector_handlers[v](v, regs, esr);
216ad14f089SAndrew Jones 			return;
217ad14f089SAndrew Jones 		}
218ad14f089SAndrew Jones 		ti = current_thread_info();
219ad14f089SAndrew Jones 	}
220ad14f089SAndrew Jones 
221ad14f089SAndrew Jones 	if (v < VECTOR_MAX && ti->vector_handlers[v])
222ad14f089SAndrew Jones 		ti->vector_handlers[v](v, regs, esr);
2237ee966e9SAndrew Jones 	else
2249ae19a63SAndrew Jones 		bad_exception(v, regs, esr, true, true);
2257ee966e9SAndrew Jones }
2267ee966e9SAndrew Jones 
install_vector_handler(enum vector v,vector_fn fn)2277ee966e9SAndrew Jones void install_vector_handler(enum vector v, vector_fn fn)
2287ee966e9SAndrew Jones {
229ad14f089SAndrew Jones 	struct thread_info *ti = current_thread_info();
230ad14f089SAndrew Jones 
2317ee966e9SAndrew Jones 	if (v < VECTOR_MAX)
232ad14f089SAndrew Jones 		ti->vector_handlers[v] = fn;
2337ee966e9SAndrew Jones }
2347ee966e9SAndrew Jones 
__thread_info_init(struct thread_info * ti,unsigned int flags)235f1a7b2b2SAndrew Jones static void __thread_info_init(struct thread_info *ti, unsigned int flags)
236f6d10793SAndrew Jones {
237f6d10793SAndrew Jones 	memset(ti, 0, sizeof(struct thread_info));
238f6d10793SAndrew Jones 	ti->cpu = mpidr_to_cpu(get_mpidr());
239f6d10793SAndrew Jones 	ti->flags = flags;
240f1a7b2b2SAndrew Jones }
241f1a7b2b2SAndrew Jones 
thread_info_init(struct thread_info * ti,unsigned int flags)242f1a7b2b2SAndrew Jones void thread_info_init(struct thread_info *ti, unsigned int flags)
243f1a7b2b2SAndrew Jones {
244f1a7b2b2SAndrew Jones 	__thread_info_init(ti, flags);
245ad14f089SAndrew Jones 	vector_handlers_default_init(ti->vector_handlers);
246f6d10793SAndrew Jones }
247f6d10793SAndrew Jones 
start_usr(void (* func)(void * arg),void * arg,unsigned long sp_usr)2487ee966e9SAndrew Jones void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
2497ee966e9SAndrew Jones {
2507ee966e9SAndrew Jones 	sp_usr &= (~15UL); /* stack ptr needs 16-byte alignment */
2517ee966e9SAndrew Jones 
252f1a7b2b2SAndrew Jones 	__thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE);
25336b50de9SAndrew Jones 	thread_info_sp(sp_usr)->pgtable = current_thread_info()->pgtable;
2547ee966e9SAndrew Jones 
2557ee966e9SAndrew Jones 	asm volatile(
2567ee966e9SAndrew Jones 		"mov	x0, %0\n"
2577ee966e9SAndrew Jones 		"msr	sp_el0, %1\n"
2587ee966e9SAndrew Jones 		"msr	elr_el1, %2\n"
2597ee966e9SAndrew Jones 		"mov	x3, xzr\n"	/* clear and "set" PSR_MODE_EL0t */
2607ee966e9SAndrew Jones 		"msr	spsr_el1, x3\n"
2617ee966e9SAndrew Jones 		"eret\n"
2627ee966e9SAndrew Jones 	:: "r" (arg), "r" (sp_usr), "r" (func) : "x0", "x3");
2637ee966e9SAndrew Jones }
264f6d10793SAndrew Jones 
is_user(void)265f6d10793SAndrew Jones bool is_user(void)
266f6d10793SAndrew Jones {
267f6d10793SAndrew Jones 	return current_thread_info()->flags & TIF_USER_MODE;
268f6d10793SAndrew Jones }
2690917dc65SNikos Nikoleris 
__mmu_enabled(void)2700917dc65SNikos Nikoleris bool __mmu_enabled(void)
2710917dc65SNikos Nikoleris {
2720917dc65SNikos Nikoleris 	return read_sysreg(sctlr_el1) & SCTLR_EL1_M;
2730917dc65SNikos Nikoleris }
274