Skip to content

Commit 829df31

Browse files
committed
arch: microblaze: Fault Management
Internal references: FWRIVERHD-4979 Signed-off-by: Alp Sayin <alpsayin@gmail.com>
1 parent 9969562 commit 829df31

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

arch/microblaze/core/fatal.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Copyright (c) 2023 Advanced Micro Devices, Inc. (AMD)
3+
* Copyright (c) 2023 Alp Sayin <alpsayin@gmail.com>
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
9+
10+
#include <zephyr/init.h>
11+
#include <zephyr/kernel.h>
12+
#include <zephyr/logging/log.h>
13+
#include <zephyr/sys/printk.h>
14+
15+
#include <offsets_short.h>
16+
17+
/* Hardware includes. */
18+
#include "microblaze/mb_interface.h"
19+
#include "microblaze/microblaze_regs.h"
20+
21+
LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
22+
23+
/* The number of bytes a MicroBlaze instruction consumes. */
24+
#define MICROBLAZE_INSTRUCTION_SIZE 4
25+
26+
extern void _exception_handler_entry(void *exception_id);
27+
28+
/* Used by assembly routine _exception_handler_entry to store sp */
29+
void *stack_pointer_on_exception_entry;
30+
31+
FUNC_NORETURN void z_microblaze_fatal_error(unsigned int reason,
32+
const microblaze_register_dump_t *dump)
33+
{
34+
if (dump != NULL && IS_ENABLED(CONFIG_MICROBLAZE_DUMP_ON_EXCEPTION)) {
35+
printk("r1:\t0x%08x\t(sp)\n", dump->esf.r1);
36+
printk("r2:\t0x%08x\t(small data area)\n", dump->esf.r2);
37+
printk("r3:\t0x%x\t\t(retval 1)\n", dump->esf.r3);
38+
printk("r4:\t0x%x\t\t(retval 2)\n", dump->esf.r4);
39+
printk("r5:\t0x%x\t\t(arg1)\n", dump->esf.r5);
40+
printk("r6:\t0x%x\t\t(arg2)\n", dump->esf.r6);
41+
printk("r7:\t0x%x\t\t(arg3)\n", dump->esf.r7);
42+
printk("r8:\t0x%x\t\t(arg4)\n", dump->esf.r8);
43+
printk("r9:\t0x%x\t\t(arg5)\n", dump->esf.r9);
44+
printk("r10:\t0x%x\t\t(arg6)\n", dump->esf.r10);
45+
printk("r11:\t0x%08x\t(temp1)\n", dump->esf.r11);
46+
printk("r12:\t0x%08x\t(temp2)\n", dump->esf.r12);
47+
printk("r13:\t0x%08x\t(rw small data area)\n", dump->esf.r13);
48+
printk("r14:\t0x%08x\t(return from interrupt)\n", dump->esf.r14);
49+
printk("r15:\t0x%08x\t(return from subroutine)\n", dump->esf.r15);
50+
printk("r16:\t0x%08x\t(return from trap)\n", dump->esf.r16);
51+
printk("r17:\t0x%08x\t(return from exception)\n", dump->esf.r17);
52+
printk("r18:\t0x%08x\t(compiler/assembler temp)\n", dump->esf.r18);
53+
printk("r19:\t0x%08x\t(global offset table ptr)\n", dump->esf.r19);
54+
printk("r20:\t0x%x\n", dump->esf.r20);
55+
printk("r21:\t0x%x\n", dump->esf.r21);
56+
printk("r22:\t0x%x\n", dump->esf.r22);
57+
printk("r23:\t0x%x\n", dump->esf.r23);
58+
printk("r24:\t0x%x\n", dump->esf.r24);
59+
printk("r25:\t0x%x\n", dump->esf.r25);
60+
printk("r26:\t0x%x\n", dump->esf.r26);
61+
printk("r27:\t0x%x\n", dump->esf.r27);
62+
printk("r28:\t0x%x\n", dump->esf.r28);
63+
printk("r29:\t0x%x\n", dump->esf.r29);
64+
printk("r30:\t0x%x\n", dump->esf.r30);
65+
printk("r31:\t0x%x\n", dump->esf.r31);
66+
67+
printk("MSR:\t0x%08x\t(exc)\n", dump->esf.msr);
68+
#if defined(CONFIG_USE_HARDWARE_FLOAT_INSTR)
69+
printk("FSR:\t%08x\n", dump->esf.fsr);
70+
#endif
71+
printk("ESR:\t0x%08x\n", dump->esr);
72+
printk("EAR:\t0x%x\n", dump->ear);
73+
printk("EDR:\t0x%x\n", dump->edr);
74+
printk("PC:\t0x%x\n", dump->pc);
75+
}
76+
77+
/* This hack allows us to re-enable exceptions properly before continuing.
78+
* r15 is safe to use becaue this function is noreturn.
79+
*/
80+
__asm__ volatile("\tmfs r15, rpc\n"
81+
"\trted r15, 0x8\n"
82+
"\tnop\n");
83+
84+
printk("MSR:\t0x%08x\t(%s)\n", mfmsr(), __func__);
85+
86+
z_fatal_error(reason, &dump->esf);
87+
CODE_UNREACHABLE;
88+
}
89+
90+
#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
91+
static char *cause_str(uint32_t cause)
92+
{
93+
switch (cause) {
94+
case 0:
95+
return "stream exception";
96+
case 1:
97+
return "unaligned data access exception";
98+
case 2:
99+
return "illegal op-code exception";
100+
case 3:
101+
return "instruction bus error exception";
102+
case 4:
103+
return "data bus error exception";
104+
case 5:
105+
return "divide exception";
106+
case 6:
107+
return "floating point unit exception";
108+
case 7:
109+
return "privileged instruction exception";
110+
case 8:
111+
return "stack protection violation exception";
112+
case 9:
113+
return "data storage exception";
114+
case 10:
115+
return "instruction storage exception";
116+
case 11:
117+
return "data TLB miss exception";
118+
case 12:
119+
return "instruction TLB miss exception";
120+
default:
121+
return "unknown";
122+
}
123+
}
124+
#endif /* defined(CONFIG_EXTRA_EXCEPTION_INFO) */
125+
126+
FUNC_NORETURN void _Fault(uint32_t esr, uint32_t ear, uint32_t edr)
127+
{
128+
static microblaze_register_dump_t microblaze_register_dump = {0};
129+
/* Log the simplest possible exception information before anything */
130+
uint32_t cause = (mfesr() & CAUSE_EXP_MASK) >> CAUSE_EXP_SHIFT;
131+
132+
LOG_ERR("");
133+
#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
134+
LOG_ERR("Cause: %d, %s", cause, cause_str(cause));
135+
#endif /* defined(CONFIG_EXTRA_EXCEPTION_INFO) */
136+
137+
/* Fill an register dump structure with the MicroBlaze context as it
138+
* was immediately before the exception occurrence.
139+
*/
140+
141+
__ASSERT_NO_MSG(stack_pointer_on_exception_entry);
142+
z_arch_esf_t *sp_ptr = (z_arch_esf_t *)stack_pointer_on_exception_entry;
143+
144+
/* Obtain the values of registers that were stacked prior to this function
145+
* being called, and may have changed since they were stacked.
146+
*/
147+
microblaze_register_dump.esf = *sp_ptr;
148+
microblaze_register_dump.esf.r1 = ((uint32_t)sp_ptr) + sizeof(z_arch_esf_t);
149+
microblaze_register_dump.esr = esr;
150+
microblaze_register_dump.ear = ear;
151+
microblaze_register_dump.edr = edr;
152+
153+
/* Move the saved program counter back to the instruction that was executed
154+
* when the exception occurred. This is only valid for certain types of
155+
* exception.
156+
*/
157+
microblaze_register_dump.pc =
158+
microblaze_register_dump.esf.r17 - MICROBLAZE_INSTRUCTION_SIZE;
159+
160+
/* Also fill in a string that describes what type of exception this is.
161+
* The string uses the same ID names as defined in the MicroBlaze standard
162+
* library exception header files.
163+
*/
164+
#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
165+
microblaze_register_dump.exception_cause_str = cause_str(cause);
166+
#endif /* defined(CONFIG_EXTRA_EXCEPTION_INFO) */
167+
168+
z_microblaze_fatal_error(K_ERR_CPU_EXCEPTION, &microblaze_register_dump);
169+
CODE_UNREACHABLE;
170+
}

0 commit comments

Comments
 (0)