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