Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2014 Wind River Systems, Inc.
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : :
7 : : /**
8 : : * @file
9 : : * @brief Kernel fatal error handler for ARM Cortex-M and Cortex-R
10 : : *
11 : : * This module provides the z_arm_fatal_error() routine for ARM Cortex-M
12 : : * and Cortex-R CPUs.
13 : : */
14 : :
15 : : #include <kernel.h>
16 : : #include <kernel_arch_data.h>
17 : : #include <logging/log.h>
18 : : LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
19 : :
20 : 0 : static void esf_dump(const z_arch_esf_t *esf)
21 : : {
22 [ # # ]: 0 : LOG_ERR("r0/a1: 0x%08x r1/a2: 0x%08x r2/a3: 0x%08x",
23 : : esf->basic.a1, esf->basic.a2, esf->basic.a3);
24 [ # # ]: 0 : LOG_ERR("r3/a4: 0x%08x r12/ip: 0x%08x r14/lr: 0x%08x",
25 : : esf->basic.a4, esf->basic.ip, esf->basic.lr);
26 [ # # ]: 0 : LOG_ERR(" xpsr: 0x%08x", esf->basic.xpsr);
27 : : #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
28 : : for (int i = 0; i < ARRAY_SIZE(esf->s); i += 4) {
29 : : LOG_ERR("s[%2d]: 0x%08x s[%2d]: 0x%08x"
30 : : " s[%2d]: 0x%08x s[%2d]: 0x%08x",
31 : : i, (uint32_t)esf->s[i],
32 : : i + 1, (uint32_t)esf->s[i + 1],
33 : : i + 2, (uint32_t)esf->s[i + 2],
34 : : i + 3, (uint32_t)esf->s[i + 3]);
35 : : }
36 : : LOG_ERR("fpscr: 0x%08x", esf->fpscr);
37 : : #endif
38 : : #if defined(CONFIG_EXTRA_EXCEPTION_INFO)
39 : : const struct _callee_saved *callee = esf->extra_info.callee;
40 : :
41 : : if (callee != NULL) {
42 : : LOG_ERR("r4/v1: 0x%08x r5/v2: 0x%08x r6/v3: 0x%08x",
43 : : callee->v1, callee->v2, callee->v3);
44 : : LOG_ERR("r7/v4: 0x%08x r8/v5: 0x%08x r9/v6: 0x%08x",
45 : : callee->v4, callee->v5, callee->v6);
46 : : LOG_ERR("r10/v7: 0x%08x r11/v8: 0x%08x psp: 0x%08x",
47 : : callee->v7, callee->v8, callee->psp);
48 : : }
49 : :
50 : : LOG_ERR("EXC_RETURN: 0x%0x", esf->extra_info.exc_return);
51 : :
52 : : #endif /* CONFIG_EXTRA_EXCEPTION_INFO */
53 [ # # ]: 0 : LOG_ERR("Faulting instruction address (r15/pc): 0x%08x",
54 : : esf->basic.pc);
55 : 0 : }
56 : :
57 : 0 : void z_arm_fatal_error(unsigned int reason, const z_arch_esf_t *esf)
58 : : {
59 : :
60 [ # # ]: 0 : if (esf != NULL) {
61 : 0 : esf_dump(esf);
62 : : }
63 : 0 : z_fatal_error(reason, esf);
64 : 0 : }
65 : :
66 : : /**
67 : : * @brief Handle a software-generated fatal exception
68 : : * (e.g. kernel oops, panic, etc.).
69 : : *
70 : : * Notes:
71 : : * - the function is invoked in SVC Handler
72 : : * - if triggered from nPRIV mode, only oops and stack fail error reasons
73 : : * may be propagated to the fault handling process.
74 : : * - We expect the supplied exception stack frame to always be a valid
75 : : * frame. That is because, if the ESF cannot be stacked during an SVC,
76 : : * a processor fault (e.g. stacking error) will be generated, and the
77 : : * fault handler will executed instead of the SVC.
78 : : *
79 : : * @param esf exception frame
80 : : */
81 : 0 : void z_do_kernel_oops(const z_arch_esf_t *esf)
82 : : {
83 : : /* Stacked R0 holds the exception reason. */
84 : 0 : unsigned int reason = esf->basic.r0;
85 : :
86 : : #if defined(CONFIG_USERSPACE)
87 : : if (z_arm_preempted_thread_in_user_mode(esf)) {
88 : : /*
89 : : * Exception triggered from user mode.
90 : : *
91 : : * User mode is only allowed to induce oopses and stack check
92 : : * failures via software-triggered system fatal exceptions.
93 : : */
94 : : if (!((esf->basic.r0 == K_ERR_KERNEL_OOPS) ||
95 : : (esf->basic.r0 == K_ERR_STACK_CHK_FAIL))) {
96 : :
97 : : reason = K_ERR_KERNEL_OOPS;
98 : : }
99 : : }
100 : :
101 : : #endif /* CONFIG_USERSPACE */
102 : :
103 : : #if !defined(CONFIG_EXTRA_EXCEPTION_INFO)
104 : 0 : z_arm_fatal_error(reason, esf);
105 : : #else
106 : : /* extra exception info is not collected for kernel oops
107 : : * path today so we make a copy of the ESF and zero out
108 : : * that information
109 : : */
110 : : z_arch_esf_t esf_copy;
111 : :
112 : : memcpy(&esf_copy, esf, offsetof(z_arch_esf_t, extra_info));
113 : : esf_copy.extra_info = (struct __extra_esf_info) { 0 };
114 : : z_arm_fatal_error(reason, &esf_copy);
115 : : #endif /* CONFIG_EXTRA_EXCEPTION_INFO */
116 : 0 : }
117 : :
118 : 0 : FUNC_NORETURN void arch_syscall_oops(void *ssf_ptr)
119 : : {
120 : 0 : uint32_t *ssf_contents = ssf_ptr;
121 : 0 : z_arch_esf_t oops_esf = { 0 };
122 : :
123 : : /* TODO: Copy the rest of the register set out of ssf_ptr */
124 : 0 : oops_esf.basic.pc = ssf_contents[3];
125 : :
126 : 0 : z_arm_fatal_error(K_ERR_KERNEL_OOPS, &oops_esf);
127 : 0 : CODE_UNREACHABLE;
128 : : }
|