/* * TOPPERS/ASP Kernel * Toyohashi Open Platform for Embedded Real-Time Systems/ * Advanced Standard Profile Kernel * * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory * Toyohashi Univ. of Technology, JAPAN * Copyright (C) 2005-2009 by Embedded and Real-Time Systems Laboratory * Graduate School of Information Science, Nagoya Univ., JAPAN * Copyright (C) 2017-2019 by TOPPERS PROJECT Educational Working Group. * * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ * と. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに * 報告すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを * 免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ * の責任を負わない. * * @(#) $Id$ */ /* * プロセッサ依存モジュール(RISC-V用) */ #include "kernel_impl.h" #include "check.h" #include "task.h" /* * CPUロックフラグ実現のための変数 */ volatile bool_t lock_flag; /* CPUロックフラグの値を保持する変数 */ volatile uint16_t inest_lvl; /* 割込みネストを保存する変数 */ volatile unsigned long kernel_mie; /* デフォルトのMIE値を保存する変数 */ static unsigned long saved_trap; /* MACHINE TRAPデータの保存変数 */ /* * MACHINE割込みハンドラ領域のテーブル */ volatile EXCVE m_interrupt_handlers[TMAX_MACHNE_INTNO]; #ifndef OMIT_DEFAULT_INT_HANDLER /* * 未登録の割込みが発生した場合に呼び出される */ static void default_int_handler(unsigned long mcause, void *p_excinf) { unsigned long mstatus = *(((uintptr_t*)p_excinf) + P_EXCINF_OFFSET_MSTATUS); uintptr_t pc = *(((uintptr_t*)p_excinf) + P_EXCINF_OFFSET_PC); uintptr_t sp0 = *(((uintptr_t*)p_excinf) + P_EXCONF_OFFSET_SP); uintptr_t sp1 = *(((uintptr_t*)p_excinf) + P_EXCONF_OFFSET_SP + 1); unsigned long excno = mcause & MCAUSE_CAUSE; static int count = 0; if (count == 0) { count++; if((long)mcause < 0) excno += TMAX_MACHNE_INTNO / 2; switch (excno) { case EXC_INSTRUCTION_ADDRESS_MISALIGNED: syslog_0(LOG_EMERG, "\nUnregistered instruction address misaligned occurs."); break; case EXC_INSTRUCTION_ADDRESS_FAULT: syslog_0(LOG_EMERG, "\nUnregistered instruction address fault occurs."); break; case EXC_ILLEGAL_INSTRUCTION: syslog_0(LOG_EMERG, "\nUnregistered illegal instruction occurs."); break; case EXC_BREAKPOINT: syslog_0(LOG_EMERG, "\nUnregistered breakpoint occurs."); break; case EXC_LOAD_ADDRESS_MISALIGNED: syslog_0(LOG_EMERG, "\nUnregistered load address misaligned occurs."); break; case EXC_LOAD_ADDRESS_FAULT: syslog_0(LOG_EMERG, "\nUnregistered load address fault occurs."); break; case EXC_STORE_AMO_ADDRESS_MISALIGNED: syslog_0(LOG_EMERG, "\nUnregistered store AMO address misaligned occurs."); break; case EXC_STORE_AMO_ACCESS_FAUT: syslog_0(LOG_EMERG, "\nUnregistered store AMO access faut occurs."); break; case EXC_ENVIRONMENT_CALL_FROM_MMODE: syslog_0(LOG_EMERG, "\nUnregistered environment call from MMODE occurs."); break; default: syslog_0(LOG_EMERG, "\nUnregistered Interrupt occurs."); break; } syslog_4(LOG_EMERG, "Excno = 0x%02X, PC = 0x%X, mstatus = 0x%X, p_excinf = 0x%X", excno, pc, mstatus, p_excinf); syslog_3(LOG_EMERG, "SP0 = 0x%X, SP1 = 0x%X, runtsk = 0x%X", sp0, sp1, p_runtsk->p_tinib->task); unsigned int *addr = (((unsigned int *)p_excinf) + P_EXCONF_OFFSET_SP + 3); syslog_5(LOG_EMERG, "a0%x:%08X%08X %08X%08X", 0, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a0%x:%08X%08X %08X%08X", 2, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a0%x:%08X%08X %08X%08X", 4, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a0%x:%08X%08X %08X%08X", 6, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a0%x:%08X%08X %08X%08X", 8, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a1%x:%08X%08X %08X%08X", 0, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a1%x:%08X%08X %08X%08X", 2, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a1%x:%08X%08X %08X%08X", 4, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a1%x:%08X%08X %08X%08X", 6, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a1%x:%08X%08X %08X%08X", 8, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a1%x:%08X%08X %08X%08X",10, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a2%x:%08X%08X %08X%08X", 0, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a2%x:%08X%08X %08X%08X", 2, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a2%x:%08X%08X %08X%08X", 4, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a2%x:%08X%08X %08X%08X", 6, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a2%x:%08X%08X %08X%08X", 8, addr[0], addr[1], addr[2], addr[3]); addr+=4; syslog_5(LOG_EMERG, "a2%x:%08X%08X %08X%08X",10, addr[0], addr[1], addr[2], addr[3]); addr+=4; addr = (unsigned int *)((sp0 + 15) / 16); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[-4], addr[-4], addr[-3], addr[-2], addr[-1]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[ 0], addr[ 0], addr[ 1], addr[ 2], addr[ 3]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[ 4], addr[ 4], addr[ 5], addr[ 6], addr[ 7]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[ 8], addr[ 8], addr[ 9], addr[10], addr[11]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[12], addr[12], addr[13], addr[14], addr[15]); addr = (unsigned int *)((sp1 + 15) / 16); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[-4], addr[-4], addr[-3], addr[-2], addr[-1]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[ 0], addr[ 0], addr[ 1], addr[ 2], addr[ 3]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[ 4], addr[ 4], addr[ 5], addr[ 6], addr[ 7]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[ 8], addr[ 8], addr[ 9], addr[10], addr[11]); syslog_5(LOG_EMERG, "%08X:%08X %08X %08X %08X", (unsigned int)&addr[12], addr[12], addr[13], addr[14], addr[15]); } target_exit(); } #endif /* OMIT_DEFAULT_INT_HANDLER */ /* * プロセッサ依存の初期化 */ void prc_initialize(void) { extern void software_init_hook(void); void (*volatile fp)(void) = software_init_hook; int i; /* * software_init_hookへのポインタを,一旦volatile指定のあるfpに代 * 入してから使うのは,0との比較が最適化で削除されないようにするた * めである. */ if (fp != 0) { (*fp)(); } /* * CPUロックフラグ実現のための変数の初期化 */ lock_flag = true; kernel_mie = KERNEL_MIE; clear_csr(mie, KERNEL_MIE); set_csr(mie, MIP_MSIP); inest_lvl = 0; /* * 例外ベクタテーブルの初期化 */ #ifndef OMIT_DEFAULT_INT_HANDLER for(i = 0 ; i < TMAX_MACHNE_INTNO ; i++){ m_interrupt_handlers[i].exc_handler = (FP)default_int_handler; } #endif saved_trap = read_csr(mtvec); write_csr(mtvec, &trap_entry); ena_intm(); /* * FPU拡張の初期化 */ if(read_csr(misa) & (1 << ('F' - 'A'))){ set_csr(mstatus, MSTATUS_FS); /* FPU設定、但し割込みはサポートしない */ write_csr(fcsr, 0); /* ラウンディングモード設定 */ } (void)(i); } /* * プロセッサ依存の終了処理 */ void prc_terminate(void) { extern void software_term_hook(void); void (*volatile fp)(void) = software_term_hook; /* * software_term_hookへのポインタを,一旦volatile指定のあるfpに代 * 入してから使うのは,0との比較が最適化で削除されないようにするた * めである. */ if (fp != 0) { (*fp)(); } write_csr(mtvec, saved_trap); } /* * C言語レベル MACHINE割込みハンドラ */ uint32_t handle_trap(unsigned long mcause, void *p_excinf) { uint32_t intno = mcause & MCAUSE_CAUSE; void (*func)(unsigned long, void *); if(inest_lvl++ == 0) write_csr(mtvec, &trap_nest); if((long)mcause < 0) intno += TMAX_MACHNE_INTNO / 2; if(intno < TMAX_MACHNE_INTNO){ func = (void(*)(unsigned long, void *))m_interrupt_handlers[intno].exc_handler; if(func != NULL) func(mcause, p_excinf); } else{ syslog_1(LOG_EMERG, "Irrigal machine Exception mcause = %08X", (int)intno); } if(--inest_lvl == 0) write_csr(mtvec, &trap_entry); return inest_lvl; } /* * CPU例外の発生状況のログ出力 * * CPU例外ハンドラの中から,CPU例外情報ポインタ(p_excinf)を引数とし * て呼び出すことで,CPU例外の発生状況をシステムログに出力する. */ #ifdef SUPPORT_XLOG_SYS void xlog_sys(void *p_excinf) { unsigned long *excsp = (unsigned long *) p_excinf; syslog_0(LOG_ERROR, "CPU Exception Information:"); syslog_4(LOG_ERROR, "mstatus = %08x PC = %x mcause = %x STACK = %x", *((excsp + P_EXCINF_OFFSET_MSTATUS)), *((excsp + P_EXCINF_OFFSET_PC)), *((excsp + P_EXCINF_OFFSET_MCAUSE)), ((unsigned long)excsp + 19 * 4)); syslog_1(LOG_ERROR, "p_excinf = %x", (unsigned long)excsp); } #endif /* SUPPORT_XLOG_SYS */