1 /*
2  * Copyright (c) 2014 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Common fault handler for ARCv2
10  *
11  * Common fault handler for ARCv2 processors.
12  */
13 
14 #include <zephyr/toolchain.h>
15 #include <zephyr/linker/sections.h>
16 #include <inttypes.h>
17 
18 #include <zephyr/kernel.h>
19 #include <kernel_internal.h>
20 #include <zephyr/kernel_structs.h>
21 #include <zephyr/arch/common/exc_handle.h>
22 #include <zephyr/logging/log.h>
23 #include <err_dump_handling.h>
24 
25 LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
26 
27 #ifdef CONFIG_USERSPACE
28 Z_EXC_DECLARE(z_arc_user_string_nlen);
29 
30 static const struct z_exc_handle exceptions[] = {
31 	Z_EXC_HANDLE(z_arc_user_string_nlen)
32 };
33 #endif
34 
35 #if defined(CONFIG_MPU_STACK_GUARD)
36 /**
37  * @brief Assess occurrence of current thread's stack corruption
38  *
39  * This function performs an assessment whether a memory fault (on a given
40  * memory address) is the result of a stack overflow of the current thread.
41  *
42  * When called, we know at this point that we received an ARC
43  * protection violation, with any cause code, with the protection access
44  * error either "MPU" or "Secure MPU". In other words, an MPU fault of
45  * some kind. Need to determine whether this is a general MPU access
46  * exception or the specific case of a stack overflow.
47  *
48  * @param fault_addr memory address on which memory access violation
49  *                   has been reported.
50  * @param sp stack pointer when exception comes out
51  * @retval True if this appears to be a stack overflow
52  * @retval False if this does not appear to be a stack overflow
53  */
z_check_thread_stack_fail(const uint32_t fault_addr,uint32_t sp)54 static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp)
55 {
56 #if defined(CONFIG_MULTITHREADING)
57 	uint32_t guard_end, guard_start;
58 	const struct k_thread *thread = arch_current_thread();
59 
60 	if (!thread) {
61 		/* TODO: Under what circumstances could we get here ? */
62 		return false;
63 	}
64 
65 #ifdef CONFIG_USERSPACE
66 	if ((thread->base.user_options & K_USER) != 0) {
67 		if ((z_arc_v2_aux_reg_read(_ARC_V2_ERSTATUS) &
68 		     _ARC_V2_STATUS32_U) != 0) {
69 			/* Normal user mode context. There is no specific
70 			 * "guard" installed in this case, instead what's
71 			 * happening is that the stack pointer is crashing
72 			 * into the privilege mode stack buffer which
73 			 * immediately precedes it.
74 			 */
75 			guard_end = thread->stack_info.start;
76 			guard_start = (uint32_t)thread->stack_obj;
77 		} else {
78 			/* Special case: handling a syscall on privilege stack.
79 			 * There is guard memory reserved immediately before
80 			 * it.
81 			 */
82 			guard_end = thread->arch.priv_stack_start;
83 			guard_start = guard_end - Z_ARC_STACK_GUARD_SIZE;
84 		}
85 	} else
86 #endif /* CONFIG_USERSPACE */
87 	{
88 		/* Supervisor thread */
89 		guard_end = thread->stack_info.start;
90 		guard_start = guard_end - Z_ARC_STACK_GUARD_SIZE;
91 	}
92 
93 	 /* treat any MPU exceptions within the guard region as a stack
94 	  * overflow.As some instrustions
95 	  * (like enter_s {r13-r26, fp, blink}) push a collection of
96 	  * registers on to the stack. In this situation, the fault_addr
97 	  * will less than guard_end, but sp will greater than guard_end.
98 	  */
99 	if (fault_addr < guard_end && fault_addr >= guard_start) {
100 		return true;
101 	}
102 #endif /* CONFIG_MULTITHREADING */
103 
104 	return false;
105 }
106 #endif
107 
108 #ifdef CONFIG_EXCEPTION_DEBUG
109 /* For EV_ProtV, the numbering/semantics of the parameter are consistent across
110  * several codes, although not all combination will be reported.
111  *
112  * These codes and parameters do not have associated* names in
113  * the technical manual, just switch on the values in Table 6-5
114  */
get_protv_access_err(uint32_t parameter)115 static const char *get_protv_access_err(uint32_t parameter)
116 {
117 	switch (parameter) {
118 	case 0x1:
119 		return "code protection scheme";
120 	case 0x2:
121 		return "stack checking scheme";
122 	case 0x4:
123 		return "MPU";
124 	case 0x8:
125 		return "MMU";
126 	case 0x10:
127 		return "NVM";
128 	case 0x24:
129 		return "Secure MPU";
130 	case 0x44:
131 		return "Secure MPU with SID mismatch";
132 	default:
133 		return "unknown";
134 	}
135 }
136 
dump_protv_exception(uint32_t cause,uint32_t parameter)137 static void dump_protv_exception(uint32_t cause, uint32_t parameter)
138 {
139 	switch (cause) {
140 	case 0x0:
141 		ARC_EXCEPTION_DUMP("Instruction fetch violation (%s)",
142 			get_protv_access_err(parameter));
143 		break;
144 	case 0x1:
145 		ARC_EXCEPTION_DUMP("Memory read protection violation (%s)",
146 			get_protv_access_err(parameter));
147 		break;
148 	case 0x2:
149 		ARC_EXCEPTION_DUMP("Memory write protection violation (%s)",
150 			get_protv_access_err(parameter));
151 		break;
152 	case 0x3:
153 		ARC_EXCEPTION_DUMP("Memory read-modify-write violation (%s)",
154 			get_protv_access_err(parameter));
155 		break;
156 	case 0x10:
157 		ARC_EXCEPTION_DUMP("Normal vector table in secure memory");
158 		break;
159 	case 0x11:
160 		ARC_EXCEPTION_DUMP("NS handler code located in S memory");
161 		break;
162 	case 0x12:
163 		ARC_EXCEPTION_DUMP("NSC Table Range Violation");
164 		break;
165 	default:
166 		ARC_EXCEPTION_DUMP("unknown");
167 		break;
168 	}
169 }
170 
dump_machine_check_exception(uint32_t cause,uint32_t parameter)171 static void dump_machine_check_exception(uint32_t cause, uint32_t parameter)
172 {
173 	switch (cause) {
174 	case 0x0:
175 		ARC_EXCEPTION_DUMP("double fault");
176 		break;
177 	case 0x1:
178 		ARC_EXCEPTION_DUMP("overlapping TLB entries");
179 		break;
180 	case 0x2:
181 		ARC_EXCEPTION_DUMP("fatal TLB error");
182 		break;
183 	case 0x3:
184 		ARC_EXCEPTION_DUMP("fatal cache error");
185 		break;
186 	case 0x4:
187 		ARC_EXCEPTION_DUMP("internal memory error on instruction fetch");
188 		break;
189 	case 0x5:
190 		ARC_EXCEPTION_DUMP("internal memory error on data fetch");
191 		break;
192 	case 0x6:
193 		ARC_EXCEPTION_DUMP("illegal overlapping MPU entries");
194 		if (parameter == 0x1) {
195 			ARC_EXCEPTION_DUMP(" - jump and branch target");
196 		}
197 		break;
198 	case 0x10:
199 		ARC_EXCEPTION_DUMP("secure vector table not located in secure memory");
200 		break;
201 	case 0x11:
202 		ARC_EXCEPTION_DUMP("NSC jump table not located in secure memory");
203 		break;
204 	case 0x12:
205 		ARC_EXCEPTION_DUMP("secure handler code not located in secure memory");
206 		break;
207 	case 0x13:
208 		ARC_EXCEPTION_DUMP("NSC target address not located in secure memory");
209 		break;
210 	case 0x80:
211 		ARC_EXCEPTION_DUMP("uncorrectable ECC or parity error in vector memory");
212 		break;
213 	default:
214 		ARC_EXCEPTION_DUMP("unknown");
215 		break;
216 	}
217 }
218 
dump_privilege_exception(uint32_t cause,uint32_t parameter)219 static void dump_privilege_exception(uint32_t cause, uint32_t parameter)
220 {
221 	switch (cause) {
222 	case 0x0:
223 		ARC_EXCEPTION_DUMP("Privilege violation");
224 		break;
225 	case 0x1:
226 		ARC_EXCEPTION_DUMP("disabled extension");
227 		break;
228 	case 0x2:
229 		ARC_EXCEPTION_DUMP("action point hit");
230 		break;
231 	case 0x10:
232 		switch (parameter) {
233 		case 0x1:
234 			ARC_EXCEPTION_DUMP("N to S return using incorrect return mechanism");
235 			break;
236 		case 0x2:
237 			ARC_EXCEPTION_DUMP("N to S return with incorrect operating mode");
238 			break;
239 		case 0x3:
240 			ARC_EXCEPTION_DUMP("IRQ/exception return fetch from wrong mode");
241 			break;
242 		case 0x4:
243 			ARC_EXCEPTION_DUMP("attempt to halt secure processor in NS mode");
244 			break;
245 		case 0x20:
246 			ARC_EXCEPTION_DUMP("attempt to access secure resource from normal mode");
247 			break;
248 		case 0x40:
249 			ARC_EXCEPTION_DUMP("SID violation on resource access (APEX/UAUX/key NVM)");
250 			break;
251 		default:
252 			ARC_EXCEPTION_DUMP("unknown");
253 			break;
254 		}
255 		break;
256 	case 0x13:
257 		switch (parameter) {
258 		case 0x20:
259 			ARC_EXCEPTION_DUMP("attempt to access secure APEX feature from NS mode");
260 			break;
261 		case 0x40:
262 			ARC_EXCEPTION_DUMP("SID violation on access to APEX feature");
263 			break;
264 		default:
265 			ARC_EXCEPTION_DUMP("unknown");
266 			break;
267 		}
268 		break;
269 	default:
270 		ARC_EXCEPTION_DUMP("unknown");
271 		break;
272 	}
273 }
274 
dump_exception_info(uint32_t vector,uint32_t cause,uint32_t parameter)275 static void dump_exception_info(uint32_t vector, uint32_t cause, uint32_t parameter)
276 {
277 	if (vector >= 0x10 && vector <= 0xFF) {
278 		ARC_EXCEPTION_DUMP("interrupt %u", vector);
279 		return;
280 	}
281 
282 	/* Names are exactly as they appear in Designware ARCv2 ISA
283 	 * Programmer's reference manual for easy searching
284 	 */
285 	switch (vector) {
286 	case ARC_EV_RESET:
287 		ARC_EXCEPTION_DUMP("Reset");
288 		break;
289 	case ARC_EV_MEM_ERROR:
290 		ARC_EXCEPTION_DUMP("Memory Error");
291 		break;
292 	case ARC_EV_INS_ERROR:
293 		ARC_EXCEPTION_DUMP("Instruction Error");
294 		break;
295 	case ARC_EV_MACHINE_CHECK:
296 		ARC_EXCEPTION_DUMP("EV_MachineCheck");
297 		dump_machine_check_exception(cause, parameter);
298 		break;
299 	case ARC_EV_TLB_MISS_I:
300 		ARC_EXCEPTION_DUMP("EV_TLBMissI");
301 		break;
302 	case ARC_EV_TLB_MISS_D:
303 		ARC_EXCEPTION_DUMP("EV_TLBMissD");
304 		break;
305 	case ARC_EV_PROT_V:
306 		ARC_EXCEPTION_DUMP("EV_ProtV");
307 		dump_protv_exception(cause, parameter);
308 		break;
309 	case ARC_EV_PRIVILEGE_V:
310 		ARC_EXCEPTION_DUMP("EV_PrivilegeV");
311 		dump_privilege_exception(cause, parameter);
312 		break;
313 	case ARC_EV_SWI:
314 		ARC_EXCEPTION_DUMP("EV_SWI");
315 		break;
316 	case ARC_EV_TRAP:
317 		ARC_EXCEPTION_DUMP("EV_Trap");
318 		break;
319 	case ARC_EV_EXTENSION:
320 		ARC_EXCEPTION_DUMP("EV_Extension");
321 		break;
322 	case ARC_EV_DIV_ZERO:
323 		ARC_EXCEPTION_DUMP("EV_DivZero");
324 		break;
325 	case ARC_EV_DC_ERROR:
326 		ARC_EXCEPTION_DUMP("EV_DCError");
327 		break;
328 	case ARC_EV_MISALIGNED:
329 		ARC_EXCEPTION_DUMP("EV_Misaligned");
330 		break;
331 	case ARC_EV_VEC_UNIT:
332 		ARC_EXCEPTION_DUMP("EV_VecUnit");
333 		break;
334 	default:
335 		ARC_EXCEPTION_DUMP("unknown");
336 		break;
337 	}
338 }
339 #endif /* CONFIG_EXCEPTION_DEBUG */
340 
341 /*
342  * @brief Fault handler
343  *
344  * This routine is called when fatal error conditions are detected by hardware
345  * and is responsible only for reporting the error. Once reported, it then
346  * invokes the user provided routine k_sys_fatal_error_handler() which is
347  * responsible for implementing the error handling policy.
348  */
_Fault(struct arch_esf * esf,uint32_t old_sp)349 void _Fault(struct arch_esf *esf, uint32_t old_sp)
350 {
351 	uint32_t vector, cause, parameter;
352 	uint32_t exc_addr = z_arc_v2_aux_reg_read(_ARC_V2_EFA);
353 	uint32_t ecr = z_arc_v2_aux_reg_read(_ARC_V2_ECR);
354 
355 #ifdef CONFIG_USERSPACE
356 	for (int i = 0; i < ARRAY_SIZE(exceptions); i++) {
357 		uint32_t start = (uint32_t)exceptions[i].start;
358 		uint32_t end = (uint32_t)exceptions[i].end;
359 
360 		if (esf->pc >= start && esf->pc < end) {
361 			esf->pc = (uint32_t)(exceptions[i].fixup);
362 			return;
363 		}
364 	}
365 #endif
366 
367 	vector = Z_ARC_V2_ECR_VECTOR(ecr);
368 	cause =  Z_ARC_V2_ECR_CODE(ecr);
369 	parameter = Z_ARC_V2_ECR_PARAMETER(ecr);
370 
371 	/* exception raised by kernel */
372 	if (vector == ARC_EV_TRAP && parameter == _TRAP_S_CALL_RUNTIME_EXCEPT) {
373 		/*
374 		 * in user mode software-triggered system fatal exceptions only allow
375 		 * K_ERR_KERNEL_OOPS and K_ERR_STACK_CHK_FAIL
376 		 */
377 #ifdef CONFIG_USERSPACE
378 		if ((esf->status32 & _ARC_V2_STATUS32_U) &&
379 			esf->r0 != K_ERR_STACK_CHK_FAIL) {
380 			esf->r0 = K_ERR_KERNEL_OOPS;
381 		}
382 #endif
383 
384 		z_arc_fatal_error(esf->r0, esf);
385 		return;
386 	}
387 
388 #ifdef CONFIG_EXCEPTION_DEBUG
389 	ARC_EXCEPTION_DUMP("***** Exception vector: 0x%x, cause code: 0x%x, parameter 0x%x",
390 		vector, cause, parameter);
391 	ARC_EXCEPTION_DUMP("Address 0x%x", exc_addr);
392 
393 	dump_exception_info(vector, cause, parameter);
394 #endif
395 
396 #ifdef CONFIG_ARC_STACK_CHECKING
397 	/* Vector 6 = EV_ProV. Regardless of cause, parameter 2 means stack
398 	 * check violation
399 	 * stack check and mpu violation can come out together, then
400 	 * parameter = 0x2 | [0x4 | 0x8 | 0x1]
401 	 */
402 	if (vector == ARC_EV_PROT_V && parameter & 0x2) {
403 		z_arc_fatal_error(K_ERR_STACK_CHK_FAIL, esf);
404 		return;
405 	}
406 #endif
407 
408 #ifdef CONFIG_MPU_STACK_GUARD
409 	if (vector == ARC_EV_PROT_V && ((parameter == 0x4) ||
410 					(parameter == 0x24))) {
411 		if (z_check_thread_stack_fail(exc_addr, old_sp)) {
412 			z_arc_fatal_error(K_ERR_STACK_CHK_FAIL, esf);
413 			return;
414 		}
415 	}
416 #endif
417 	z_arc_fatal_error(K_ERR_CPU_EXCEPTION, esf);
418 }
419