diff options
| author | xuzhuoyi <[email protected]> | 2019-03-31 15:44:24 +0800 |
|---|---|---|
| committer | xuzhuoyi <[email protected]> | 2019-03-31 15:44:24 +0800 |
| commit | 5d166c389d6c81fbeea3e175100d4922453991ee (patch) | |
| tree | bbffc4941c0ebd9157049dd278c102a5c4de3ac8 /libcpu | |
| parent | 459ddc3b06d5a01c4ffc4d283ae05988f7d8ff59 (diff) | |
[bsp][gd32e230k-start] Add GD32E230K-START BSP port
Diffstat (limited to 'libcpu')
| -rw-r--r-- | libcpu/arm/cortex-m23/SConscript | 23 | ||||
| -rw-r--r-- | libcpu/arm/cortex-m23/context_gcc.S | 210 | ||||
| -rw-r--r-- | libcpu/arm/cortex-m23/context_iar.S | 202 | ||||
| -rw-r--r-- | libcpu/arm/cortex-m23/context_rvds.S | 207 | ||||
| -rw-r--r-- | libcpu/arm/cortex-m23/cpuport.c | 403 |
5 files changed, 1045 insertions, 0 deletions
diff --git a/libcpu/arm/cortex-m23/SConscript b/libcpu/arm/cortex-m23/SConscript new file mode 100644 index 0000000000..9ff30a796b --- /dev/null +++ b/libcpu/arm/cortex-m23/SConscript @@ -0,0 +1,23 @@ +# RT-Thread building script for component + +from building import * + +Import('rtconfig') + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +if rtconfig.PLATFORM == 'armcc': + src += Glob('*_rvds.S') + +if rtconfig.PLATFORM == 'gcc': + src += Glob('*_init.S') + src += Glob('*_gcc.S') + +if rtconfig.PLATFORM == 'iar': + src += Glob('*_iar.S') + +group = DefineGroup('cpu', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/libcpu/arm/cortex-m23/context_gcc.S b/libcpu/arm/cortex-m23/context_gcc.S new file mode 100644 index 0000000000..d17a8aa12c --- /dev/null +++ b/libcpu/arm/cortex-m23/context_gcc.S @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2009-10-11 Bernard First version + * 2010-12-29 onelife Modify for EFM32 + * 2011-06-17 onelife Merge all of the assembly source code into context_gcc.S + * 2011-07-12 onelife Add interrupt context check function + * 2013-06-18 aozima add restore MSP feature. + * 2013-07-09 aozima enhancement hard fault exception handler. + */ + + .cpu cortex-m3 + .fpu softvfp + .syntax unified + .thumb + .text + + .equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ + .equ ICSR, 0xE000ED04 /* interrupt control state register */ + .equ PENDSVSET_BIT, 0x10000000 /* value to trigger PendSV exception */ + + .equ SHPR3, 0xE000ED20 /* system priority register (3) */ + .equ PENDSV_PRI_LOWEST, 0x00FF0000 /* PendSV priority value (lowest) */ + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ + .global rt_hw_interrupt_disable + .type rt_hw_interrupt_disable, %function +rt_hw_interrupt_disable: + MRS R0, PRIMASK + CPSID I + BX LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ + .global rt_hw_interrupt_enable + .type rt_hw_interrupt_enable, %function +rt_hw_interrupt_enable: + MSR PRIMASK, R0 + BX LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * R0 --> from + * R1 --> to + */ + .global rt_hw_context_switch_interrupt + .type rt_hw_context_switch_interrupt, %function + .global rt_hw_context_switch + .type rt_hw_context_switch, %function +rt_hw_context_switch_interrupt: +rt_hw_context_switch: + /* set rt_thread_switch_interrupt_flag to 1 */ + LDR R2, =rt_thread_switch_interrupt_flag + LDR R3, [R2] + CMP R3, #1 + BEQ _reswitch + MOV R3, #1 + STR R3, [R2] + + LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */ + STR R0, [R2] + +_reswitch: + LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */ + STR R1, [R2] + + LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */ + LDR R1, =PENDSVSET_BIT + STR R1, [R0] + BX LR + +/* R0 --> switch from thread stack + * R1 --> switch to thread stack + * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack + */ + .global PendSV_Handler + .type PendSV_Handler, %function +PendSV_Handler: + /* disable interrupt to protect context switch */ + MRS R2, PRIMASK + CPSID I + + /* get rt_thread_switch_interrupt_flag */ + LDR R0, =rt_thread_switch_interrupt_flag + LDR R1, [R0] + CBZ R1, pendsv_exit /* pendsv aLReady handled */ + + /* clear rt_thread_switch_interrupt_flag to 0 */ + MOV R1, #0 + STR R1, [R0] + + LDR R0, =rt_interrupt_from_thread + LDR R1, [R0] + CBZ R1, switch_to_thread /* skip register save at the first time */ + + MRS R1, PSP /* get from thread stack pointer */ + STMFD R1!, {R4 - R11} /* push R4 - R11 register */ + LDR R0, [R0] + STR R1, [R0] /* update from thread stack pointer */ + +switch_to_thread: + LDR R1, =rt_interrupt_to_thread + LDR R1, [R1] + LDR R1, [R1] /* load thread stack pointer */ + + LDMFD R1!, {R4 - R11} /* pop R4 - R11 register */ + MSR PSP, R1 /* update stack pointer */ + +pendsv_exit: + /* restore interrupt */ + MSR PRIMASK, R2 + + ORR LR, LR, #0x04 + BX LR + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * R0 --> to + */ + .global rt_hw_context_switch_to + .type rt_hw_context_switch_to, %function +rt_hw_context_switch_to: + LDR R1, =rt_interrupt_to_thread + STR R0, [R1] + + /* set from thread to 0 */ + LDR R1, =rt_interrupt_from_thread + MOV R0, #0 + STR R0, [R1] + + /* set interrupt flag to 1 */ + LDR R1, =rt_thread_switch_interrupt_flag + MOV R0, #1 + STR R0, [R1] + + /* set the PendSV exception priority */ + LDR R0, =SHPR3 + LDR R1, =PENDSV_PRI_LOWEST + LDR.W R2, [R0,#0] /* read */ + ORR R1, R1, R2 /* modify */ + STR R1, [R0] /* write-back */ + + LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */ + LDR R1, =PENDSVSET_BIT + STR R1, [R0] + + /* restore MSP */ + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + /* enable interrupts at processor level */ + CPSIE F + CPSIE I + + /* never reach here! */ + +/* compatible with old version */ + .global rt_hw_interrupt_thread_switch + .type rt_hw_interrupt_thread_switch, %function +rt_hw_interrupt_thread_switch: + BX LR + NOP + + .global HardFault_Handler + .type HardFault_Handler, %function +HardFault_Handler: + /* get current context */ + MRS r0, msp /* get fault context from handler. */ + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _get_sp_done + MRS r0, psp /* get fault context from thread. */ +_get_sp_done: + + STMFD r0!, {r4 - r11} /* push r4 - r11 register */ + STMFD r0!, {lr} /* push exec_return register */ + + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _update_msp + MSR psp, r0 /* update stack pointer to PSP. */ + B _update_done +_update_msp: + MSR msp, r0 /* update stack pointer to MSP. */ +_update_done: + + PUSH {LR} + BL rt_hw_hard_fault_exception + POP {LR} + + ORR LR, LR, #0x04 + BX LR + +/* + * rt_uint32_t rt_hw_interrupt_check(void); + * R0 --> state + */ + .global rt_hw_interrupt_check + .type rt_hw_interrupt_check, %function +rt_hw_interrupt_check: + MRS R0, IPSR + BX LR diff --git a/libcpu/arm/cortex-m23/context_iar.S b/libcpu/arm/cortex-m23/context_iar.S new file mode 100644 index 0000000000..91645c48b3 --- /dev/null +++ b/libcpu/arm/cortex-m23/context_iar.S @@ -0,0 +1,202 @@ +;/* +; * Copyright (c) 2006-2018, RT-Thread Development Team +; * +; * SPDX-License-Identifier: Apache-2.0 +; * +; * Change Logs: +; * Date Author Notes +; * 2009-01-17 Bernard first version +; * 2009-09-27 Bernard add protect when contex switch occurs +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-07-09 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup cortex-m3 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register +NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2) +NVIC_PENDSV_PRI EQU 0x00FF0000 ; PendSV priority value (lowest) +NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception + + SECTION .text:CODE(2) + THUMB + REQUIRE8 + PRESERVE8 + + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ + EXPORT rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS r0, PRIMASK + CPSID I + BX LR + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ + EXPORT rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR PRIMASK, r0 + BX LR + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ + EXPORT rt_hw_context_switch_interrupt + EXPORT rt_hw_context_switch +rt_hw_context_switch_interrupt: +rt_hw_context_switch: + ; set rt_thread_switch_interrupt_flag to 1 + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 + STR r3, [r2] + + LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread + STR r0, [r2] + +_reswitch + LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread + STR r1, [r2] + + LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + BX LR + +; r0 --> switch from thread stack +; r1 --> switch to thread stack +; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack + EXPORT PendSV_Handler +PendSV_Handler: + + ; disable interrupt to protect context switch + MRS r2, PRIMASK + CPSID I + + ; get rt_thread_switch_interrupt_flag + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CBZ r1, pendsv_exit ; pendsv already handled + + ; clear rt_thread_switch_interrupt_flag to 0 + MOV r1, #0x00 + STR r1, [r0] + + LDR r0, =rt_interrupt_from_thread + LDR r1, [r0] + CBZ r1, switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + STMFD r1!, {r4 - r11} ; push r4 - r11 register + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + + LDMFD r1!, {r4 - r11} ; pop r4 - r11 register + MSR psp, r1 ; update stack pointer + +pendsv_exit + ; restore interrupt + MSR PRIMASK, r2 + + ORR lr, lr, #0x04 + BX lr + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ + EXPORT rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR r1, =rt_interrupt_to_thread + STR r0, [r1] + + ; set from thread to 0 + LDR r1, =rt_interrupt_from_thread + MOV r0, #0x0 + STR r0, [r1] + + ; set interrupt flag to 1 + LDR r1, =rt_thread_switch_interrupt_flag + MOV r0, #1 + STR r0, [r1] + + ; set the PendSV exception priority + LDR r0, =NVIC_SYSPRI2 + LDR r1, =NVIC_PENDSV_PRI + LDR.W r2, [r0,#0x00] ; read + ORR r1,r1,r2 ; modify + STR r1, [r0] ; write-back + + LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + +; compatible with old version + EXPORT rt_hw_interrupt_thread_switch +rt_hw_interrupt_thread_switch: + BX lr + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler: + + ; get current context + MRS r0, msp ; get fault context from handler. + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _get_sp_done + MRS r0, psp ; get fault context from thread. +_get_sp_done + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + ;STMFD r0!, {lr} ; push exec_return register + SUB r0, r0, #0x04 + STR lr, [r0] + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _update_msp + MSR psp, r0 ; update stack pointer to PSP. + B _update_done +_update_msp + MSR msp, r0 ; update stack pointer to MSP. +_update_done + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + + END diff --git a/libcpu/arm/cortex-m23/context_rvds.S b/libcpu/arm/cortex-m23/context_rvds.S new file mode 100644 index 0000000000..c0a2130703 --- /dev/null +++ b/libcpu/arm/cortex-m23/context_rvds.S @@ -0,0 +1,207 @@ +;/* +; * Copyright (c) 2006-2018, RT-Thread Development Team +; * +; * SPDX-License-Identifier: Apache-2.0 +; * +; * Change Logs: +; * Date Author Notes +; * 2009-01-17 Bernard first version +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-07-09 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup CORTEX-M23 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register +NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2) +NVIC_PENDSV_PRI EQU 0x00FF0000 ; PendSV priority value (lowest) +NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception + + AREA |.text|, CODE, READONLY, ALIGN=2 + THUMB + REQUIRE8 + PRESERVE8 + + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, PRIMASK + CPSID I + BX LR + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR PRIMASK, r0 + BX LR + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch_interrupt + EXPORT rt_hw_context_switch_interrupt +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + + ; set rt_thread_switch_interrupt_flag to 1 + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 + STR r3, [r2] + + LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread + STR r0, [r2] + +_reswitch + LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread + STR r1, [r2] + + LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + BX LR + ENDP + +; r0 --> switch from thread stack +; r1 --> switch to thread stack +; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack +PendSV_Handler PROC + EXPORT PendSV_Handler + + ; disable interrupt to protect context switch + MRS r2, PRIMASK + CPSID I + + ; get rt_thread_switch_interrupt_flag + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CBZ r1, pendsv_exit ; pendsv already handled + + ; clear rt_thread_switch_interrupt_flag to 0 + MOV r1, #0x00 + STR r1, [r0] + + LDR r0, =rt_interrupt_from_thread + LDR r1, [r0] + CBZ r1, switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + STMFD r1!, {r4 - r11} ; push r4 - r11 register + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + + LDMFD r1!, {r4 - r11} ; pop r4 - r11 register + MSR psp, r1 ; update stack pointer + +pendsv_exit + ; restore interrupt + MSR PRIMASK, r2 + + ORR lr, lr, #0x04 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; * this fucntion is used to perform the first thread switch +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + ; set to thread + LDR r1, =rt_interrupt_to_thread + STR r0, [r1] + + ; set from thread to 0 + LDR r1, =rt_interrupt_from_thread + MOV r0, #0x0 + STR r0, [r1] + + ; set interrupt flag to 1 + LDR r1, =rt_thread_switch_interrupt_flag + MOV r0, #1 + STR r0, [r1] + + ; set the PendSV exception priority + LDR r0, =NVIC_SYSPRI2 + LDR r1, =NVIC_PENDSV_PRI + LDR.W r2, [r0,#0x00] ; read + ORR r1,r1,r2 ; modify + STR r1, [r0] ; write-back + + ; trigger the PendSV exception (causes context switch) + LDR r0, =NVIC_INT_CTRL + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + ENDP + +; compatible with old version +rt_hw_interrupt_thread_switch PROC + EXPORT rt_hw_interrupt_thread_switch + BX lr + ENDP + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler PROC + + ; get current context + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler. + MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread. + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + STMFD r0!, {lr} ; push exec_return register + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP. + MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP. + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + ENDP + + ALIGN 4 + + END diff --git a/libcpu/arm/cortex-m23/cpuport.c b/libcpu/arm/cortex-m23/cpuport.c new file mode 100644 index 0000000000..a386747750 --- /dev/null +++ b/libcpu/arm/cortex-m23/cpuport.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2009-01-05 Bernard first version + * 2011-02-14 onelife Modify for EFM32 + * 2011-06-17 onelife Merge all of the C source code into cpuport.c + * 2012-12-23 aozima stack addr align to 8byte. + * 2012-12-29 Bernard Add exception hook. + * 2013-07-09 aozima enhancement hard fault exception handler. + */ + +#include <rtthread.h> + +struct exception_stack_frame +{ + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r12; + rt_uint32_t lr; + rt_uint32_t pc; + rt_uint32_t psr; +}; + +struct stack_frame +{ + /* r4 ~ r11 register */ + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t r11; + + struct exception_stack_frame exception_stack_frame; +}; + +/* flag in interrupt handling */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; +/* exception hook */ +static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL; + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, + void *parameter, + rt_uint8_t *stack_addr, + void *texit) +{ + struct stack_frame *stack_frame; + rt_uint8_t *stk; + unsigned long i; + + stk = stack_addr + sizeof(rt_uint32_t); + stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8); + stk -= sizeof(struct stack_frame); + + stack_frame = (struct stack_frame *)stk; + + /* init all register */ + for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++) + { + ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef; + } + + stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */ + stack_frame->exception_stack_frame.r1 = 0; /* r1 */ + stack_frame->exception_stack_frame.r2 = 0; /* r2 */ + stack_frame->exception_stack_frame.r3 = 0; /* r3 */ + stack_frame->exception_stack_frame.r12 = 0; /* r12 */ + stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */ + stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */ + stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ + + /* return task's current stack address */ + return stk; +} + +/** + * This function set the hook, which is invoked on fault exception handling. + * + * @param exception_handle the exception handling hook function. + */ +void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context)) +{ + rt_exception_hook = exception_handle; +} + +#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */ +#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */ +#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */ +#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */ +#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */ +#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */ + +#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */ +#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */ +#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */ + +#ifdef RT_USING_FINSH +static void usage_fault_track(void) +{ + rt_kprintf("usage fault:\n"); + rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR); + + if(SCB_CFSR_UFSR & (1<<0)) + { + /* [0]:UNDEFINSTR */ + rt_kprintf("UNDEFINSTR "); + } + + if(SCB_CFSR_UFSR & (1<<1)) + { + /* [1]:INVSTATE */ + rt_kprintf("INVSTATE "); + } + + if(SCB_CFSR_UFSR & (1<<2)) + { + /* [2]:INVPC */ + rt_kprintf("INVPC "); + } + + if(SCB_CFSR_UFSR & (1<<3)) + { + /* [3]:NOCP */ + rt_kprintf("NOCP "); + } + + if(SCB_CFSR_UFSR & (1<<8)) + { + /* [8]:UNALIGNED */ + rt_kprintf("UNALIGNED "); + } + + if(SCB_CFSR_UFSR & (1<<9)) + { + /* [9]:DIVBYZERO */ + rt_kprintf("DIVBYZERO "); + } + + rt_kprintf("\n"); +} + +static void bus_fault_track(void) +{ + rt_kprintf("bus fault:\n"); + rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR); + + if(SCB_CFSR_BFSR & (1<<0)) + { + /* [0]:IBUSERR */ + rt_kprintf("IBUSERR "); + } + + if(SCB_CFSR_BFSR & (1<<1)) + { + /* [1]:PRECISERR */ + rt_kprintf("PRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<2)) + { + /* [2]:IMPRECISERR */ + rt_kprintf("IMPRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<3)) + { + /* [3]:UNSTKERR */ + rt_kprintf("UNSTKERR "); + } + + if(SCB_CFSR_BFSR & (1<<4)) + { + /* [4]:STKERR */ + rt_kprintf("STKERR "); + } + + if(SCB_CFSR_BFSR & (1<<7)) + { + rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void mem_manage_fault_track(void) +{ + rt_kprintf("mem manage fault:\n"); + rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR); + + if(SCB_CFSR_MFSR & (1<<0)) + { + /* [0]:IACCVIOL */ + rt_kprintf("IACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<1)) + { + /* [1]:DACCVIOL */ + rt_kprintf("DACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<3)) + { + /* [3]:MUNSTKERR */ + rt_kprintf("MUNSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<4)) + { + /* [4]:MSTKERR */ + rt_kprintf("MSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<7)) + { + /* [7]:MMARVALID */ + rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void hard_fault_track(void) +{ + if(SCB_HFSR & (1UL<<1)) + { + /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */ + rt_kprintf("failed vector fetch\n"); + } + + if(SCB_HFSR & (1UL<<30)) + { + /* [30]:FORCED, Indicates hard fault is taken because of bus fault, + memory management fault, or usage fault. */ + if(SCB_CFSR_BFSR) + { + bus_fault_track(); + } + + if(SCB_CFSR_MFSR) + { + mem_manage_fault_track(); + } + + if(SCB_CFSR_UFSR) + { + usage_fault_track(); + } + } + + if(SCB_HFSR & (1UL<<31)) + { + /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */ + rt_kprintf("debug event\n"); + } +} +#endif /* RT_USING_FINSH */ + +struct exception_info +{ + rt_uint32_t exc_return; + struct stack_frame stack_frame; +}; + +/* + * fault exception handler + */ +void rt_hw_hard_fault_exception(struct exception_info * exception_info) +{ + extern long list_thread(void); + struct stack_frame* context = &exception_info->stack_frame; + + if (rt_exception_hook != RT_NULL) + { + rt_err_t result; + + result = rt_exception_hook(exception_info); + if (result == RT_EOK) + return; + } + + rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); + + rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0); + rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1); + rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2); + rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3); + rt_kprintf("r04: 0x%08x\n", context->r4); + rt_kprintf("r05: 0x%08x\n", context->r5); + rt_kprintf("r06: 0x%08x\n", context->r6); + rt_kprintf("r07: 0x%08x\n", context->r7); + rt_kprintf("r08: 0x%08x\n", context->r8); + rt_kprintf("r09: 0x%08x\n", context->r9); + rt_kprintf("r10: 0x%08x\n", context->r10); + rt_kprintf("r11: 0x%08x\n", context->r11); + rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12); + rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr); + rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc); + + if(exception_info->exc_return & (1 << 2) ) + { + rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif /* RT_USING_FINSH */ + } + else + { + rt_kprintf("hard fault on handler\r\n\r\n"); + } + +#ifdef RT_USING_FINSH + hard_fault_track(); +#endif /* RT_USING_FINSH */ + + while (1); +} + +/** + * shutdown CPU + */ +void rt_hw_cpu_shutdown(void) +{ + rt_kprintf("shutdown...\n"); + + RT_ASSERT(0); +} + +/** + * reset CPU + */ +RT_WEAK void rt_hw_cpu_reset(void) +{ + SCB_AIRCR = SCB_RESET_VALUE; +} + +#ifdef RT_USING_CPU_FFS +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +#if defined(__CC_ARM) +__asm int __rt_ffs(int value) +{ + CMP r0, #0x00 + BEQ exit + + RBIT r0, r0 + CLZ r0, r0 + ADDS r0, r0, #0x01 + +exit + BX lr +} +#elif defined(__IAR_SYSTEMS_ICC__) +int __rt_ffs(int value) +{ + if (value == 0) return value; + + asm("RBIT %0, %1" : "=r"(value) : "r"(value)); + asm("CLZ %0, %1" : "=r"(value) : "r"(value)); + asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value)); + + return value; +} +#elif defined(__GNUC__) +int __rt_ffs(int value) +{ + return __builtin_ffs(value); +} +#endif + +#endif |
