xref: /kvm-unit-tests/lib/arm64/processor.c (revision 201b9e8bdc84c6436dd53b45d93a60c681b92719)
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 #include <asm/thread_info.h>
12 
13 static const char *vector_names[] = {
14 	"el1t_sync",
15 	"el1t_irq",
16 	"el1t_fiq",
17 	"el1t_error",
18 	"el1h_sync",
19 	"el1h_irq",
20 	"el1h_fiq",
21 	"el1h_error",
22 	"el0_sync_64",
23 	"el0_irq_64",
24 	"el0_fiq_64",
25 	"el0_error_64",
26 	"el0_sync_32",
27 	"el0_irq_32",
28 	"el0_fiq_32",
29 	"el0_error_32",
30 };
31 
32 static const char *ec_names[EC_MAX] = {
33 	[ESR_EL1_EC_UNKNOWN]		= "UNKNOWN",
34 	[ESR_EL1_EC_WFI]		= "WFI",
35 	[ESR_EL1_EC_CP15_32]		= "CP15_32",
36 	[ESR_EL1_EC_CP15_64]		= "CP15_64",
37 	[ESR_EL1_EC_CP14_MR]		= "CP14_MR",
38 	[ESR_EL1_EC_CP14_LS]		= "CP14_LS",
39 	[ESR_EL1_EC_FP_ASIMD]		= "FP_ASMID",
40 	[ESR_EL1_EC_CP10_ID]		= "CP10_ID",
41 	[ESR_EL1_EC_CP14_64]		= "CP14_64",
42 	[ESR_EL1_EC_ILL_ISS]		= "ILL_ISS",
43 	[ESR_EL1_EC_SVC32]		= "SVC32",
44 	[ESR_EL1_EC_SVC64]		= "SVC64",
45 	[ESR_EL1_EC_SYS64]		= "SYS64",
46 	[ESR_EL1_EC_SVE]		= "SVE",
47 	[ESR_EL1_EC_IABT_EL0]		= "IABT_EL0",
48 	[ESR_EL1_EC_IABT_EL1]		= "IABT_EL1",
49 	[ESR_EL1_EC_PC_ALIGN]		= "PC_ALIGN",
50 	[ESR_EL1_EC_DABT_EL0]		= "DABT_EL0",
51 	[ESR_EL1_EC_DABT_EL1]		= "DABT_EL1",
52 	[ESR_EL1_EC_SP_ALIGN]		= "SP_ALIGN",
53 	[ESR_EL1_EC_FP_EXC32]		= "FP_EXC32",
54 	[ESR_EL1_EC_FP_EXC64]		= "FP_EXC64",
55 	[ESR_EL1_EC_SERROR]		= "SERROR",
56 	[ESR_EL1_EC_BREAKPT_EL0]	= "BREAKPT_EL0",
57 	[ESR_EL1_EC_BREAKPT_EL1]	= "BREAKPT_EL1",
58 	[ESR_EL1_EC_SOFTSTP_EL0]	= "SOFTSTP_EL0",
59 	[ESR_EL1_EC_SOFTSTP_EL1]	= "SOFTSTP_EL1",
60 	[ESR_EL1_EC_WATCHPT_EL0]	= "WATCHPT_EL0",
61 	[ESR_EL1_EC_WATCHPT_EL1]	= "WATCHPT_EL1",
62 	[ESR_EL1_EC_BKPT32]		= "BKPT32",
63 	[ESR_EL1_EC_BRK64]		= "BRK64",
64 };
65 
show_regs(struct pt_regs * regs)66 void show_regs(struct pt_regs *regs)
67 {
68 	int i;
69 
70 	printf("pc : [<%016lx>] lr : [<%016lx>] pstate: %08lx\n",
71 			regs->pc, regs->regs[30], regs->pstate);
72 	printf("sp : %016lx\n", regs->sp);
73 
74 	for (i = 29; i >= 0; --i) {
75 		printf("x%-2d: %016lx ", i, regs->regs[i]);
76 		if (i % 2 == 0)
77 			printf("\n");
78 	}
79 	printf("\n");
80 }
81 
get_far(unsigned int esr,unsigned long * far)82 bool get_far(unsigned int esr, unsigned long *far)
83 {
84 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
85 
86 	asm volatile("mrs %0, far_el1": "=r" (*far));
87 
88 	switch (ec) {
89 	case ESR_EL1_EC_IABT_EL0:
90 	case ESR_EL1_EC_IABT_EL1:
91 	case ESR_EL1_EC_PC_ALIGN:
92 	case ESR_EL1_EC_DABT_EL0:
93 	case ESR_EL1_EC_DABT_EL1:
94 	case ESR_EL1_EC_WATCHPT_EL0:
95 	case ESR_EL1_EC_WATCHPT_EL1:
96 		if ((esr & 0x3f /* DFSC */) != 0x10
97 				|| !(esr & 0x400 /* FnV */))
98 			return true;
99 	}
100 	return false;
101 }
102 
103 extern unsigned long _text;
104 
bad_exception(enum vector v,struct pt_regs * regs,unsigned int esr,bool esr_valid,bool bad_vector)105 static void bad_exception(enum vector v, struct pt_regs *regs,
106 			  unsigned int esr, bool esr_valid, bool bad_vector)
107 {
108 	unsigned long far;
109 	bool far_valid = get_far(esr, &far);
110 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
111 	uintptr_t text = (uintptr_t)&_text;
112 
113 	printf("Load address: %" PRIxPTR "\n", text);
114 	printf("PC: %" PRIxPTR " PC offset: %" PRIxPTR "\n",
115 	       (uintptr_t)regs->pc, (uintptr_t)regs->pc - text);
116 
117 	if (bad_vector) {
118 		if (v < VECTOR_MAX)
119 			printf("Unhandled vector %d (%s)\n", v,
120 					vector_names[v]);
121 		else
122 			printf("Got bad vector=%d\n", v);
123 	} else if (esr_valid) {
124 		if (ec_names[ec])
125 			printf("Unhandled exception ec=%#x (%s)\n", ec,
126 					ec_names[ec]);
127 		else
128 			printf("Got bad ec=%#x\n", ec);
129 	}
130 
131 	printf("Vector: %d (%s)\n", v, vector_names[v]);
132 	printf("ESR_EL1: %8s%08x, ec=%#x (%s)\n", "", esr, ec, ec_names[ec]);
133 	printf("FAR_EL1: %016lx (%svalid)\n", far, far_valid ? "" : "not ");
134 	printf("Exception frame registers:\n");
135 	show_regs(regs);
136 	dump_frame_stack((void *)regs->pc, (void *)regs->regs[29]);
137 	abort();
138 }
139 
install_exception_handler(enum vector v,unsigned int ec,exception_fn fn)140 void install_exception_handler(enum vector v, unsigned int ec, exception_fn fn)
141 {
142 	struct thread_info *ti = current_thread_info();
143 
144 	if (v < VECTOR_MAX && ec < EC_MAX)
145 		ti->exception_handlers[v][ec] = fn;
146 }
147 
install_irq_handler(enum vector v,irq_handler_fn fn)148 void install_irq_handler(enum vector v, irq_handler_fn fn)
149 {
150 	struct thread_info *ti = current_thread_info();
151 
152 	if (v < VECTOR_MAX)
153 		ti->exception_handlers[v][0] = (exception_fn)fn;
154 }
155 
default_vector_sync_handler(enum vector v,struct pt_regs * regs,unsigned int esr)156 void default_vector_sync_handler(enum vector v, struct pt_regs *regs,
157 				 unsigned int esr)
158 {
159 	struct thread_info *ti = thread_info_sp(regs->sp);
160 	unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
161 
162 	if (ti->flags & TIF_USER_MODE) {
163 		if (ec < EC_MAX && ti->exception_handlers[v][ec]) {
164 			ti->exception_handlers[v][ec](regs, esr);
165 			return;
166 		}
167 		ti = current_thread_info();
168 	}
169 
170 	if (ec < EC_MAX && ti->exception_handlers[v][ec])
171 		ti->exception_handlers[v][ec](regs, esr);
172 	else
173 		bad_exception(v, regs, esr, true, false);
174 }
175 
default_vector_irq_handler(enum vector v,struct pt_regs * regs,unsigned int esr)176 void default_vector_irq_handler(enum vector v, struct pt_regs *regs,
177 				unsigned int esr)
178 {
179 	struct thread_info *ti = thread_info_sp(regs->sp);
180 	irq_handler_fn irq_handler =
181 		(irq_handler_fn)ti->exception_handlers[v][0];
182 
183 	if (ti->flags & TIF_USER_MODE) {
184 		if (irq_handler) {
185 			irq_handler(regs);
186 			return;
187 		}
188 		ti = current_thread_info();
189 		irq_handler = (irq_handler_fn)ti->exception_handlers[v][0];
190 	}
191 
192 	if (irq_handler)
193 		irq_handler(regs);
194 	else
195 		bad_exception(v, regs, esr, false, false);
196 }
197 
vector_handlers_default_init(vector_fn * handlers)198 void vector_handlers_default_init(vector_fn *handlers)
199 {
200 	handlers[EL1H_SYNC]	= default_vector_sync_handler;
201 	handlers[EL1H_IRQ]	= default_vector_irq_handler;
202 	handlers[EL0_SYNC_64]	= default_vector_sync_handler;
203 	handlers[EL0_IRQ_64]	= default_vector_irq_handler;
204 }
205 
206 /* Needed to compile with -Wmissing-prototypes */
207 void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr);
208 
do_handle_exception(enum vector v,struct pt_regs * regs,unsigned int esr)209 void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr)
210 {
211 	struct thread_info *ti = thread_info_sp(regs->sp);
212 
213 	if (ti->flags & TIF_USER_MODE) {
214 		if (v < VECTOR_MAX && ti->vector_handlers[v]) {
215 			ti->vector_handlers[v](v, regs, esr);
216 			return;
217 		}
218 		ti = current_thread_info();
219 	}
220 
221 	if (v < VECTOR_MAX && ti->vector_handlers[v])
222 		ti->vector_handlers[v](v, regs, esr);
223 	else
224 		bad_exception(v, regs, esr, true, true);
225 }
226 
install_vector_handler(enum vector v,vector_fn fn)227 void install_vector_handler(enum vector v, vector_fn fn)
228 {
229 	struct thread_info *ti = current_thread_info();
230 
231 	if (v < VECTOR_MAX)
232 		ti->vector_handlers[v] = fn;
233 }
234 
__thread_info_init(struct thread_info * ti,unsigned int flags)235 static void __thread_info_init(struct thread_info *ti, unsigned int flags)
236 {
237 	memset(ti, 0, sizeof(struct thread_info));
238 	ti->cpu = mpidr_to_cpu(get_mpidr());
239 	ti->flags = flags;
240 }
241 
thread_info_init(struct thread_info * ti,unsigned int flags)242 void thread_info_init(struct thread_info *ti, unsigned int flags)
243 {
244 	__thread_info_init(ti, flags);
245 	vector_handlers_default_init(ti->vector_handlers);
246 }
247 
start_usr(void (* func)(void * arg),void * arg,unsigned long sp_usr)248 void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
249 {
250 	sp_usr &= (~15UL); /* stack ptr needs 16-byte alignment */
251 
252 	__thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE);
253 	thread_info_sp(sp_usr)->pgtable = current_thread_info()->pgtable;
254 
255 	asm volatile(
256 		"mov	x0, %0\n"
257 		"msr	sp_el0, %1\n"
258 		"msr	elr_el1, %2\n"
259 		"mov	x3, xzr\n"	/* clear and "set" PSR_MODE_EL0t */
260 		"msr	spsr_el1, x3\n"
261 		"eret\n"
262 	:: "r" (arg), "r" (sp_usr), "r" (func) : "x0", "x3");
263 }
264 
is_user(void)265 bool is_user(void)
266 {
267 	return current_thread_info()->flags & TIF_USER_MODE;
268 }
269 
__mmu_enabled(void)270 bool __mmu_enabled(void)
271 {
272 	return read_sysreg(sctlr_el1) & SCTLR_EL1_M;
273 }
274