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