/* ***************************************************************************** * The MIT License * exception handling and task switcher, (C) 2017 night_ghost@ykoctpa.ru adedd some useful info to __error handler and debugger, dual stacks support and task switching code based on: * Copyright (c) 2010 Perry Hung. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * ****************************************************************************/ # On an exception, push a fake stack thread mode stack frame and redirect # thread execution to a thread mode error handler # From RM008: # The SP is decremented by eight words by the completion of the stack push. # Figure 5-1 shows the contents of the stack after an exception pre-empts the # current program flow. # # Old SP--> # xPSR 28 # PC 24 # LR 20 # r12 16 # r3 12 # r2 8 # r1 4 # SP--> r0 0 .syntax unified .cpu cortex-m4 .text .globl HardFault_Handler .globl NMI_Handler .globl MemManage_Handler .globl BusFault_Handler .globl UsageFault_Handler .globl __default_exc .globl __do_context_switch .code 16 .thumb_func HardFault_Handler: mov r0, #2 b __default_exc .thumb_func MemManage_Handler: mov r0, #3 b __default_exc .thumb_func BusFault_Handler: mov r0, #4 b __default_exc .thumb_func UsageFault_Handler: mov r0, #5 b __default_exc .thumb_func FLASH_IRQHandler: mov r0, #6 b __default_exc .thumb_func __default_exc: tst lr, #4 ite eq mrseq r1, msp mrsne r1, psp ldr r3, [r1, #24] @ PC of exception - if access to wrong address ldr r1, [r1, #20] @ LR of exception - if call to wrong address ldr r2, BFAR @ for debug, to see what happens ldr r2, [r2] ldr r2, CFSR ldr r2, [r2] ldr r2, HFSR ldr r2, [r2] ldr r2, DFSR ldr r2, [r2] ldr r2, AFSR ldr r2, [r2] ldr r2, SHCSR ldr r2, [r2] ldr r2, MMFAR ldr r2, [r2] mov r12, r1 ldr r2, NVIC_CCR @ Enable returning to thread mode even if there are mov r1 ,#1 @ pending exceptions. See flag NONEBASETHRDENA - http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Cihcbadd.html str r1, [r2] cpsid i @ Disable global interrupts mov r1, #0 ldr r2, SYSTICK_CSR @ Disable systick handler str r1, [r2] ldr r2, MPU_CTRL @ disable MPU str r1, [r2] ldr r1, CPSR_MASK @ Set default CPSR mov r2, r12 push {r1} @ SP+4 ldr r1, TARGET_PC @ Set target pc push {r1} @ SP+8 push {r1} @ target LR - the same SP+12 ldr r1, [sp, #12] @ R0 of interrupted program push {r1} @ will be in R12 SP+16 ldr r1, [sp, #28] @ R3 of interrupted program (12+16) push {r1} @ will be in R3 push {r2} @ R2 - LR push {r3} @ R1 - PC of exception push {r0} @ R0 - exception code tst lr, #4 ite eq ldreq r1, EXC_RETURN @ Return to thread mode with PSP ldrne r1, EXC_RETURN @ Return to thread mode with MSP mov lr, r1 bx lr @ Exception exit .thumb_func __do_context_switch: @ we already in interrupt so all interrupts with higher priority will use MSP - so dont need to disable interrupts MRS R0, PSP @ PSP is process stack pointer TST LR, #0x10 @ exc_return[4]=0? (it means that current process IT EQ @ has active floating point context) VSTMDBEQ R0!, {S16-S31} @ if so - save it. STMDB R0!, {R4-R11, LR} @ save remaining regs r4-11 and LR (EXC_RETURN) on process stack @ At this point, entire context of process has been saved LDR R2, px_running @ address of s_running LDR R1, [R2] @ value of s_running - address of old task_t STR R0, [R1] @ store stack pointer LDR R3, px_nextTask @ address of next_task LDR R1, [R3] @ value of next_task - address of new task_t STR R1, [R2] @ save to s_running LDR R0, [R1] @ R0 is new process SP @load context of new process LDMIA R0!, {R4-R11, LR} @ Restore r4-11 and LR from new process stack TST LR, #0x10 @ exc_return[4]=0? (it means that new process IT EQ @ has active floating point context) VLDMIAEQ R0!, {S16-S31} @ if so - restore it. MSR PSP, R0 @ Load PSP with new process SP BX LR @ Return to saved exc_return. Exception return will restore remaining context .align 4 CPSR_MASK: .word 0x61000000 EXC_RETURN: .word 0xFFFFFFF9 EXC_RETURN_PSP: .word 0xFFFFFFFD TARGET_PC: .word __error NVIC_CCR: .word 0xE000ED14 @ NVIC configuration control register SYSTICK_CSR: .word 0xE000E010 @ Systick control register MPU_CTRL: .word 0xE000ED94 @ MPU Control register BFAR: .word 0xE000ED38 CFSR: .word 0xE000ED28 HFSR: .word 0xE000ED2C DFSR: .word 0xE000ED30 AFSR: .word 0xE000ED3C SHCSR: .word 0xE000ED24 MMFAR: .word 0xE000ED34 @ MemManage Fault Address register px_running: .word s_running px_nextTask: .word next_task