1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-12-04 Jiaxun Yang Initial version
9 */
10
11 #include <rtthread.h>
12 #include <rthw.h>
13 #include "exception.h"
14 #include "mips_regs.h"
15
16 /**
17 * @addtogroup MIPS
18 */
19
20 /*@{*/
21
22 extern rt_ubase_t __ebase_entry;
23 rt_ubase_t rt_interrupt_from_thread;
24 rt_ubase_t rt_interrupt_to_thread;
25 rt_ubase_t rt_thread_switch_interrupt_flag;
26
27 const char *exception_name[] = {
28 "Interrupt",
29 "(X)TLB Modify Exception",
30 "(X)TLB Read/Fetch Exception",
31 "(X)TLB Write Exception",
32 "Address Read/Fetch Exception",
33 "Address Write Exception",
34 "",
35 "",
36 "Syscall",
37 "Breakpoint",
38 "Reversed Instruction Exception",
39 "Coprocessor Unit Invalid",
40 "Overflow",
41 "Trap",
42 "FPU Exception in Vector Instruction",
43 "FPU Exception",
44 "Loongson Custom Exception",
45 "",
46 "",
47 "(X)TLB Read Denied Exception",
48 "(X)TLB Execute Denied Exception",
49 "Vector Module Disabled Exception",
50 "",
51 "",
52 "",
53 "",
54 "",
55 "",
56 "",
57 "",
58 "Cache Error Exception",
59 ""
60 };
61
rt_hw_interrupt_disable(void)62 rt_base_t rt_hw_interrupt_disable(void)
63 {
64 register rt_base_t status = read_c0_status();
65 clear_c0_status(ST0_IE);
66 return status;
67 }
68
rt_hw_interrupt_enable(rt_base_t level)69 void rt_hw_interrupt_enable(rt_base_t level)
70 {
71 write_c0_status(level);
72 }
73
74 /**
75 * exception handle table
76 */
77 #define RT_EXCEPTION_MAX 32
78 exception_func_t sys_exception_handlers[RT_EXCEPTION_MAX];
79
80 /**
81 * setup the exception handle
82 */
rt_set_except_vector(int n,exception_func_t func)83 exception_func_t rt_set_except_vector(int n, exception_func_t func)
84 {
85 exception_func_t old_handler;
86
87 if ((n < 0) || (n >= RT_EXCEPTION_MAX) || (!func))
88 {
89 return 0;
90 }
91
92 old_handler = sys_exception_handlers[n];
93 sys_exception_handlers[n] = func;
94
95 return old_handler;
96 }
97
mips_dump_regs(struct pt_regs * regs)98 void mips_dump_regs(struct pt_regs *regs)
99 {
100 int i, j;
101 for (i = 0; i < 32 / 4; i++)
102 {
103 for (j = 0; j < 4; j++)
104 {
105 int reg = 4 * i + j;
106 rt_kprintf("%d: 0x%08x, ", reg, regs->regs[reg]);
107 }
108 rt_kprintf("\n");
109 }
110 }
111
tlb_refill_handler(void)112 void tlb_refill_handler(void)
113 {
114 rt_kprintf("TLB-Miss Happens, EPC: 0x%08x\n", read_c0_epc());
115 rt_hw_cpu_shutdown();
116 }
117
cache_error_handler(void)118 void cache_error_handler(void)
119 {
120 rt_kprintf("Cache Exception Happens, EPC: 0x%08x\n", read_c0_epc());
121 rt_hw_cpu_shutdown();
122 }
123
unhandled_exception_handle(struct pt_regs * regs)124 static void unhandled_exception_handle(struct pt_regs *regs)
125 {
126 rt_kprintf("Unknown Exception, EPC: 0x%p, CAUSE: 0x%08x\n", read_c0_epc(), read_c0_cause());
127 rt_kprintf("Exception Name:%s\n",exception_name[(read_c0_cause() >> 2) & 0x1f]);
128 #ifdef SOC_LS2K1000
129 rt_kprintf("ExeCode = 0x%08x,BadAddr = 0x%p\n",(read_c0_cause() >> 2) & 0x1f,mmu_tlb_get_bad_vaddr());
130 #else
131 rt_kprintf("ExeCode = 0x%08x\n",(read_c0_cause() >> 2) & 0x1f);
132 #endif
133 rt_kprintf("ST0: 0x%08x ",regs->cp0_status);
134 rt_kprintf("ErrorPC: 0x%p\n",read_c0_errorepc());
135 mips_dump_regs(regs);
136 rt_hw_cpu_shutdown();
137 }
138
install_default_exception_handler(void)139 static void install_default_exception_handler(void)
140 {
141 rt_int32_t i;
142
143 for (i = 0; i < RT_EXCEPTION_MAX; i++)
144 sys_exception_handlers[i] =
145 (exception_func_t)unhandled_exception_handle;
146 }
147
rt_hw_exception_init(void)148 int rt_hw_exception_init(void)
149 {
150 rt_ubase_t ebase = (rt_ubase_t)&__ebase_entry;
151 #ifdef ARCH_MIPS64
152 ebase |= 0xffffffff00000000;
153 #endif
154 write_c0_ebase(ebase);
155 clear_c0_status(ST0_BEV | ST0_ERL | ST0_EXL);
156 clear_c0_status(ST0_IM | ST0_IE);
157 set_c0_status(ST0_CU0);
158 /* install the default exception handler */
159 install_default_exception_handler();
160
161 return RT_EOK;
162 }
163
rt_general_exc_dispatch(struct pt_regs * regs)164 void rt_general_exc_dispatch(struct pt_regs *regs)
165 {
166 rt_ubase_t cause, exccode;
167 cause = read_c0_cause();
168 exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
169
170 if (exccode == 0)
171 {
172 rt_ubase_t status, pending;
173
174 status = read_c0_status();
175 pending = (cause & CAUSEF_IP) & (status & ST0_IM);
176 if (pending & CAUSEF_IP0)
177 rt_do_mips_cpu_irq(0);
178 if (pending & CAUSEF_IP1)
179 rt_do_mips_cpu_irq(1);
180 if (pending & CAUSEF_IP2)
181 rt_do_mips_cpu_irq(2);
182 if (pending & CAUSEF_IP3)
183 rt_do_mips_cpu_irq(3);
184 if (pending & CAUSEF_IP4)
185 rt_do_mips_cpu_irq(4);
186 if (pending & CAUSEF_IP5)
187 rt_do_mips_cpu_irq(5);
188 if (pending & CAUSEF_IP6)
189 rt_do_mips_cpu_irq(6);
190 if (pending & CAUSEF_IP7)
191 rt_do_mips_cpu_irq(7);
192 }
193 else
194 {
195 if (sys_exception_handlers[exccode])
196 sys_exception_handlers[exccode](regs);
197 }
198 }
199
200 /* Mask means disable the interrupt */
mips_mask_cpu_irq(rt_uint32_t irq)201 void mips_mask_cpu_irq(rt_uint32_t irq)
202 {
203 clear_c0_status(1 << (STATUSB_IP0 + irq));
204 }
205
206 /* Unmask means enable the interrupt */
mips_unmask_cpu_irq(rt_uint32_t irq)207 void mips_unmask_cpu_irq(rt_uint32_t irq)
208 {
209 set_c0_status(1 << (STATUSB_IP0 + irq));
210 }
211
212 /*@}*/
213