383 lines
11 KiB
C
383 lines
11 KiB
C
|
/*
|
|||
|
* File : mips_excpt.c
|
|||
|
* This file is part of RT-Thread RTOS
|
|||
|
* COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
|
|||
|
*
|
|||
|
* This program is free software; you can redistribute it and/or modify
|
|||
|
* it under the terms of the GNU General Public License as published by
|
|||
|
* the Free Software Foundation; either version 2 of the License, or
|
|||
|
* (at your option) any later version.
|
|||
|
*
|
|||
|
* This program is distributed in the hope that it will be useful,
|
|||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
* GNU General Public License for more details.
|
|||
|
*
|
|||
|
* You should have received a copy of the GNU General Public License along
|
|||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|||
|
*
|
|||
|
* Change Logs:
|
|||
|
* Date Author Notes
|
|||
|
* 2016<EFBFBD><EFBFBD>9<EFBFBD><EFBFBD>7<EFBFBD><EFBFBD> Urey the first version
|
|||
|
*/
|
|||
|
|
|||
|
#include <rtthread.h>
|
|||
|
#include <rthw.h>
|
|||
|
#include <stdio.h>
|
|||
|
|
|||
|
#include "mips.h"
|
|||
|
#include "mips_excpt.h"
|
|||
|
|
|||
|
extern int backtrace(void);
|
|||
|
int backtrace_ctx(mips_reg_ctx *ctx);
|
|||
|
|
|||
|
extern long list_thread(void);
|
|||
|
|
|||
|
const static char *regstr[] = {
|
|||
|
"$0 zero", "$1 at", "$2 v0", "$3 v1", "$4 a0", "$5 a1", "$6 a2", "$7 a3",
|
|||
|
"$8 t0", "$9 t1", "$10 t2", "$11 t3", "$12 t4", "$13 t5", "$14 t6", "$15 t7",
|
|||
|
"$16 s0", "$17 s1", "$18 s2", "$19 s3", "$20 s4", "$21 s5", "$22 s6", "$23 s7",
|
|||
|
"$24 t8", "$25 t9", "$26 k0", "$27 k1", "$28 gp", "$29 sp", "$30 fp", "$31 ra"
|
|||
|
};
|
|||
|
|
|||
|
static const char *cause_strings[32] =
|
|||
|
{
|
|||
|
/* 0 */ "Int",
|
|||
|
/* 1 */ "TLB Mods",
|
|||
|
/* 2 */ "TLB Load",
|
|||
|
/* 3 */ "TLB Store",
|
|||
|
/* 4 */ "Address Load",
|
|||
|
/* 5 */ "Address Store",
|
|||
|
/* 6 */ "Instruction Bus Error",
|
|||
|
/* 7 */ "Data Bus Error",
|
|||
|
/* 8 */ "Syscall",
|
|||
|
/* 9 */ "Breakpoint",
|
|||
|
/* 10 */ "Reserved Instruction",
|
|||
|
/* 11 */ "Coprocessor Unuseable",
|
|||
|
/* 12 */ "Overflow",
|
|||
|
/* 13 */ "Trap",
|
|||
|
/* 14 */ "Instruction Virtual Coherency Error",
|
|||
|
/* 15 */ "FP Exception",
|
|||
|
/* 16 */ "Reserved 16",
|
|||
|
/* 17 */ "Reserved 17",
|
|||
|
/* 18 */ "Reserved 18",
|
|||
|
/* 19 */ "Reserved 19",
|
|||
|
/* 20 */ "Reserved 20",
|
|||
|
/* 21 */ "Reserved 21",
|
|||
|
/* 22 */ "Reserved 22",
|
|||
|
/* 23 */ "Watch",
|
|||
|
/* 24 */ "Reserved 24",
|
|||
|
/* 25 */ "Reserved 25",
|
|||
|
/* 26 */ "Reserved 26",
|
|||
|
/* 27 */ "Reserved 27",
|
|||
|
/* 28 */ "Reserved 28",
|
|||
|
/* 29 */ "Reserved 29",
|
|||
|
/* 30 */ "Reserved 30",
|
|||
|
/* 31 */ "Data Virtual Coherency Error"
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* exception handle table
|
|||
|
*/
|
|||
|
exception_func_t sys_exception_handlers[32];
|
|||
|
|
|||
|
static void mod_handler(mips_reg_ctx *regs)
|
|||
|
{
|
|||
|
rt_kprintf("tlb modification exception\n");
|
|||
|
rt_kprintf("exception happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
rt_kprintf(" cause: 0x%08x\n", read_c0_cause());
|
|||
|
|
|||
|
list_thread();
|
|||
|
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
printf("BACKTRACE:\n");
|
|||
|
backtrace();
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static void tlbl_handler(mips_reg_ctx *regs)
|
|||
|
{
|
|||
|
rt_kprintf("tlb exception: load\n");
|
|||
|
rt_kprintf("exception happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
rt_kprintf(" cause: 0x%08x\n", read_c0_cause());
|
|||
|
|
|||
|
list_thread();
|
|||
|
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
printf("BACKTRACE:\n");
|
|||
|
backtrace();
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static void tlbs_handler(mips_reg_ctx *regs)
|
|||
|
{
|
|||
|
rt_kprintf("tlb exception: store\n");
|
|||
|
rt_kprintf("exception happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
rt_kprintf(" cause: 0x%08x\n", read_c0_cause());
|
|||
|
|
|||
|
list_thread();
|
|||
|
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
printf("BACKTRACE:\n");
|
|||
|
backtrace();
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static void adel_handler(mips_reg_ctx *regs)
|
|||
|
{
|
|||
|
rt_kprintf("address error exception: load\n");
|
|||
|
rt_kprintf("exception happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
rt_kprintf(" cause: 0x%08x\n", read_c0_cause());
|
|||
|
|
|||
|
list_thread();
|
|||
|
rt_kprintf("current thread: %.*s\n", RT_NAME_MAX, rt_thread_self()->name);
|
|||
|
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
printf("BACKTRACE:\n");
|
|||
|
backtrace();
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static void ades_handler(mips_reg_ctx *regs)
|
|||
|
{
|
|||
|
rt_kprintf("address error exception: store\n");
|
|||
|
rt_kprintf("exception happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
rt_kprintf(" cause: 0x%08x\n", read_c0_cause());
|
|||
|
|
|||
|
list_thread();
|
|||
|
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
printf("BACKTRACE:\n");
|
|||
|
backtrace();
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static void fpe_handler(mips_reg_ctx *regs)
|
|||
|
{
|
|||
|
rt_kprintf("floating point exception\n");
|
|||
|
rt_kprintf("exception happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
rt_kprintf(" cause: 0x%08x\n", read_c0_cause());
|
|||
|
|
|||
|
list_thread();
|
|||
|
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
printf("BACKTRACE:\n");
|
|||
|
backtrace();
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static void unhandled_exception_handle(mips_reg_ctx *regs)
|
|||
|
{
|
|||
|
int i;
|
|||
|
unsigned int cause = read_c0_cause();
|
|||
|
unsigned int exc = (cause >> 2) & 0x1f;
|
|||
|
|
|||
|
rt_kprintf("exception happens, epc: 0x%08x\n", regs->CP0EPC);
|
|||
|
rt_kprintf(" cause: 0x%08x\n", regs->CP0Cause);
|
|||
|
|
|||
|
for (i = 0; i < 32; i++)
|
|||
|
{
|
|||
|
if (i % 4 == 0)
|
|||
|
printf("\n");
|
|||
|
printf("%8s %08x ", regstr[i], regs->regs[i]);
|
|||
|
}
|
|||
|
printf("\n");
|
|||
|
|
|||
|
list_thread();
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
static void install_default_exception_handler(void)
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for (i=0; i<sizeof(sys_exception_handlers)/sizeof(sys_exception_handlers[0]); i++)
|
|||
|
sys_exception_handlers[i] = (exception_func_t)unhandled_exception_handle;
|
|||
|
|
|||
|
sys_exception_handlers[EX_MOD] = mod_handler;
|
|||
|
sys_exception_handlers[EX_TLBL] = tlbl_handler;
|
|||
|
sys_exception_handlers[EX_TLBS] = tlbs_handler;
|
|||
|
sys_exception_handlers[EX_ADEL] = adel_handler;
|
|||
|
sys_exception_handlers[EX_ADES] = ades_handler;
|
|||
|
sys_exception_handlers[EX_FPE] = fpe_handler;
|
|||
|
}
|
|||
|
|
|||
|
int rt_hw_exception_init(void)
|
|||
|
{
|
|||
|
/* install the default exception handler */
|
|||
|
install_default_exception_handler();
|
|||
|
|
|||
|
return RT_EOK;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 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 > 32) || (!func))
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
sys_exception_handlers[n] = func;
|
|||
|
|
|||
|
return old_handler;
|
|||
|
}
|
|||
|
|
|||
|
void mips_exception_handler(mips_reg_ctx *ctx)
|
|||
|
{
|
|||
|
static int read_epc_count = 0;
|
|||
|
static int epc_save = 0;
|
|||
|
int i;
|
|||
|
unsigned int epc;
|
|||
|
|
|||
|
//<2F><><EFBFBD><EFBFBD> read_epc_count>0 ˵<><CBB5> c_except_handler <20>ڶ<EFBFBD> epc ʱ<><CAB1><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><EFBFBD><EFBFBD> epc <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5>쳣
|
|||
|
if (read_epc_count > 0)
|
|||
|
{
|
|||
|
printf("ERROR: read epc fail when except handle\n");
|
|||
|
epc = epc_save;
|
|||
|
read_epc_count = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
read_epc_count++;
|
|||
|
epc_save = 0;
|
|||
|
epc = read_c0_epc();
|
|||
|
epc_save = epc;
|
|||
|
|
|||
|
if (epc != 0)
|
|||
|
{
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
for (i = 0; i < 4; i++)
|
|||
|
{
|
|||
|
printf("%08x:\t%08x\n",
|
|||
|
(epc - 4 * 4 + i * 4),
|
|||
|
*(unsigned int *) ((epc - 4 * 4 + i * 4) | 0xa0000000));
|
|||
|
}
|
|||
|
for (i = 0; i < 4; i++)
|
|||
|
{
|
|||
|
printf("%08x:\t%08x\n",
|
|||
|
(epc + i * 4),
|
|||
|
*(unsigned int *) ((epc + i * 4) | 0xa0000000));
|
|||
|
}
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
}
|
|||
|
|
|||
|
read_epc_count--;
|
|||
|
}
|
|||
|
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
unsigned int cause = read_c0_cause();
|
|||
|
unsigned int exc = (cause >> 2) & 0x1f;
|
|||
|
printf("CAUSE=%08x --> %s\n", cause, cause_strings[exc]);
|
|||
|
printf("EPC=%08x\n", epc);
|
|||
|
|
|||
|
for (i = 0; i < 32; i++)
|
|||
|
{
|
|||
|
if ((i != 0) && (i % 4 == 0))
|
|||
|
printf("\n");
|
|||
|
printf("%8s %08x ", regstr[i], ctx->regs[i]);
|
|||
|
}
|
|||
|
printf("\n-----------------------------------------------------\n");
|
|||
|
printf("%s: \t %8x\n","CP0Status ", ctx->CP0Status);
|
|||
|
printf("%s: \t %8x\n","CP0DataHI ", ctx->CP0DataHI);
|
|||
|
printf("%s: \t %8x\n","CP0DataLO ", ctx->CP0DataLO);
|
|||
|
printf("%s: \t %8x\n","CP0BadVAddr", ctx->CP0BadVAddr);
|
|||
|
printf("%s: \t %8x\n","CP0Cause ", ctx->CP0Cause);
|
|||
|
printf("%s: \t %8x\n","CP0EPC ", ctx->CP0EPC);
|
|||
|
printf("-----------------------------------------------------\n");
|
|||
|
|
|||
|
#if 0
|
|||
|
switch (exc)
|
|||
|
{
|
|||
|
case EX_MOD:
|
|||
|
/* TLB modified */
|
|||
|
break;
|
|||
|
|
|||
|
case EX_TLBL: /* TLB exc(load or ifetch) */
|
|||
|
case EX_TLBS: /* TLB exception (store) */
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case EX_ADEL: /* Address err(load or ifetch) */
|
|||
|
case EX_ADES: /* Address error (store) */
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case EX_IBE: /* Instruction Bus Error */
|
|||
|
case EX_DBE: /* Data Bus Error */
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case EX_SYS: /* Syscall */
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case EX_BP: /* Breakpoint */
|
|||
|
case EX_TR: /* Trap instruction */
|
|||
|
|
|||
|
break;
|
|||
|
case EX_RI: /* Reserved instruction */
|
|||
|
|
|||
|
break;
|
|||
|
case EX_FPE: /* floating point exception */
|
|||
|
break;
|
|||
|
|
|||
|
case EX_CPU: /* CoProcessor Unusable */
|
|||
|
|
|||
|
break;
|
|||
|
case EX_OV: /* OVerflow */
|
|||
|
case EX_C2E: /* COP2 exception */
|
|||
|
case EX_MDMX: /* MDMX exception */
|
|||
|
case EX_WATCH: /* Watch exception */
|
|||
|
case EX_MCHECK: /* Machine check exception */
|
|||
|
case EX_CacheErr: /* Cache error caused re-entry */
|
|||
|
/* to Debug Mode */
|
|||
|
|
|||
|
break;
|
|||
|
default:
|
|||
|
rt_kprintf("Unknow exception: %d\r\n", exc);
|
|||
|
break;
|
|||
|
}
|
|||
|
#else
|
|||
|
sys_exception_handlers[exc](ctx);
|
|||
|
#endif
|
|||
|
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void mips_cache_error_handler (unsigned int Addr)
|
|||
|
{
|
|||
|
rt_kprintf("cache exception happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
list_thread();
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|
|||
|
|
|||
|
void mips_tlb_refill_handler(void)
|
|||
|
{
|
|||
|
rt_kprintf("tlb-miss happens, epc: 0x%08x\n", read_c0_epc());
|
|||
|
rt_kprintf(" cause: 0x%08x\n", read_c0_cause());
|
|||
|
list_thread();
|
|||
|
rt_kprintf("current thread: %s\n", rt_thread_self()->name);
|
|||
|
rt_hw_cpu_shutdown();
|
|||
|
}
|