/* * Copyright (c) 2006-2019, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-12-04 Jiaxun Yang Initial version */ #include #include #include "exception.h" #include "mips_regs.h" /** * @addtogroup MIPS */ /*@{*/ extern rt_ubase_t __ebase_entry; rt_ubase_t rt_interrupt_from_thread; rt_ubase_t rt_interrupt_to_thread; rt_ubase_t rt_thread_switch_interrupt_flag; rt_base_t rt_hw_interrupt_disable(void) { rt_base_t status = read_c0_status(); clear_c0_status(ST0_IE); return status; } void rt_hw_interrupt_enable(rt_base_t level) { write_c0_status(level); } /** * exception handle table */ #define RT_EXCEPTION_MAX 31 exception_func_t sys_exception_handlers[RT_EXCEPTION_MAX]; /** * setup the exception handle */ exception_func_t rt_set_except_vector(int n, exception_func_t func) { exception_func_t old_handler = sys_exception_handlers[n]; if ((n == 0) || (n > RT_EXCEPTION_MAX) || (!func)) { return 0; } sys_exception_handlers[n] = func; return old_handler; } void mips_dump_regs(struct pt_regs *regs) { int i, j; for (i = 0; i < 32 / 4; i++) { for (j = 0; j < 4; j++) { int reg = 4 * i + j; rt_kprintf("%d: 0x%08x, ", reg, regs->regs[reg]); } rt_kprintf("\n"); } } void tlb_refill_handler(void) { rt_kprintf("TLB-Miss Happens, EPC: 0x%08x\n", read_c0_epc()); rt_hw_cpu_shutdown(); } void cache_error_handler(void) { rt_kprintf("Cache Exception Happens, EPC: 0x%08x\n", read_c0_epc()); rt_hw_cpu_shutdown(); } static void unhandled_exception_handle(struct pt_regs *regs) { rt_kprintf("Unknown Exception, EPC: 0x%08x, CAUSE: 0x%08x\n", read_c0_epc(), read_c0_cause()); rt_kprintf("ST0: 0x%08x ", regs->cp0_status); rt_kprintf("ErrorPC: 0x%08x\n", read_c0_errorepc()); mips_dump_regs(regs); rt_hw_cpu_shutdown(); } static void install_default_exception_handler(void) { rt_int32_t i; for (i = 0; i < RT_EXCEPTION_MAX; i++) sys_exception_handlers[i] = (exception_func_t)unhandled_exception_handle; } int rt_hw_exception_init(void) { rt_ubase_t ebase = (rt_ubase_t)&__ebase_entry; #ifdef ARCH_MIPS64 ebase |= 0xffffffff00000000; #endif write_c0_ebase(ebase); clear_c0_status(ST0_BEV | ST0_ERL | ST0_EXL); clear_c0_status(ST0_IM | ST0_IE); set_c0_status(ST0_CU0); /* install the default exception handler */ install_default_exception_handler(); return RT_EOK; } void rt_general_exc_dispatch(struct pt_regs *regs) { rt_ubase_t cause, exccode; cause = read_c0_cause(); exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE; if (exccode == 0) { rt_ubase_t status, pending; status = read_c0_status(); pending = (cause & CAUSEF_IP) & (status & ST0_IM); if (pending & CAUSEF_IP0) rt_do_mips_cpu_irq(0); if (pending & CAUSEF_IP1) rt_do_mips_cpu_irq(1); if (pending & CAUSEF_IP2) rt_do_mips_cpu_irq(2); if (pending & CAUSEF_IP3) rt_do_mips_cpu_irq(3); if (pending & CAUSEF_IP4) rt_do_mips_cpu_irq(4); if (pending & CAUSEF_IP5) rt_do_mips_cpu_irq(5); if (pending & CAUSEF_IP6) rt_do_mips_cpu_irq(6); if (pending & CAUSEF_IP7) rt_do_mips_cpu_irq(7); } else { if (sys_exception_handlers[exccode]) sys_exception_handlers[exccode](regs); } } /* Mask means disable the interrupt */ void mips_mask_cpu_irq(rt_uint32_t irq) { clear_c0_status(1 << (STATUSB_IP0 + irq)); } /* Unmask means enable the interrupt */ void mips_unmask_cpu_irq(rt_uint32_t irq) { set_c0_status(1 << (STATUSB_IP0 + irq)); } /*@}*/