/**
* @file
*
* @ingroup ScoreCPU
*
* @brief Epiphany exception support implementation.
*/
/*
* Copyright (c) 2015 University of York.
* Hesham ALMatary <hmka501@york.ac.uk>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/cpu.h>
#include <rtems/asm.h>
#include <rtems/score/percpu.h>
EXTERN(bsp_start_vector_table_begin)
EXTERN(_Thread_Dispatch)
PUBLIC(ISR_Handler)
.section .text, "ax"
.align 4
TYPE_FUNC(ISR_Handler)
SYM(ISR_Handler):
/* Reserve space for CPU_Exception_frame */
sub sp, sp, #(CPU_EXCEPTION_FRAME_SIZE)
str r0, [sp]
str r1, [sp,1]
str r2, [sp,2]
str r3, [sp,3]
str r4, [sp,4]
str r5, [sp,5]
str r6, [sp,6]
str r7, [sp,7]
str r8, [sp,8]
str r9, [sp,9]
str r10, [sp,10]
str fp, [sp,11]
str r12, [sp,12]
/* Save interrupted task stack pointer */
add r1, sp, #(CPU_EXCEPTION_FRAME_SIZE + 8)
str r1,[sp,13]
str lr, [sp,14]
str r15, [sp,15]
str r16, [sp,16]
str r17, [sp,17]
str r18, [sp,18]
str r19, [sp,19]
str r20, [sp,20]
str r21, [sp,21]
str r22, [sp,22]
str r23, [sp,23]
str r24, [sp,24]
str r25, [sp,25]
str r26, [sp,26]
str r27, [sp,27]
str r28, [sp,28]
str r29, [sp,29]
str r30, [sp,30]
str r31, [sp,31]
str r32, [sp,32]
str r33, [sp,33]
str r34, [sp,34]
str r35, [sp,35]
str r36, [sp,36]
str r37, [sp,37]
str r38, [sp,38]
str r39, [sp,39]
str r40, [sp,40]
str r41, [sp,41]
str r42, [sp,42]
str r43, [sp,43]
str r44, [sp,44]
str r45, [sp,45]
str r46, [sp,46]
str r47, [sp,47]
str r48, [sp,48]
str r49, [sp,49]
str r50, [sp,50]
str r51, [sp,51]
str r52, [sp,52]
str r53, [sp,53]
str r54, [sp,54]
str r55, [sp,55]
str r56, [sp,56]
str r57, [sp,57]
str r58, [sp,58]
str r59, [sp,59]
str r60, [sp,60]
str r61, [sp,61]
/* r62 and r63 are saved from start.S interrupt entry
* and hold vector number and _ISR_Handler address repsectively.
*/
/* Save status register */
movfs r1,status
str r1, [sp,62]
/* Save config register */
movfs r1,config
str r1, [sp,63]
/* Save interrupt return address register */
movfs r1,iret
str r1, [sp,64]
mov r33, %low(__Per_CPU_Information)
movt r33, %high(__Per_CPU_Information)
add r6, r33, #(PER_CPU_ISR_NEST_LEVEL)
add r8, r33, #(PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)
/* Increment nesting level and disable thread dispatch */
ldr r5, [r6]
ldr r7, [r8]
add r5, r5, #1
add r7, r7, #1
str r5, [r6]
str r7, [r8]
/* Keep sp (Exception frame address) in r32 - Callee saved */
mov r32, sp
/* Keep __Per_CPU_Information address in r33 - Callee saved */
mov r33, r18
/* Call the exception handler from vector table.
* First function arg for C handler is vector number,
* and the second is a pointer to exception frame.
*/
mov r0, r62
mov r1, sp
mov r27, r62
lsl r27, r27, #2
mov r26, %low(_bsp_start_vector_table_begin)
movt r15, #0
add r27, r27, r26
ldr r27, [r27]
/* Do not switch stacks if we are in a nested interrupt. At
* this point r5 should be holding ISR_NEST_LEVEL value.
*/
sub r37, r5, #1
bgtu jump_to_c_handler
/* Switch to RTEMS dedicated interrupt stack */
add sp, r18, #(PER_CPU_INTERRUPT_STACK_HIGH)
ldr sp, [sp]
jump_to_c_handler:
jalr r27
/* Switch back to the interrupted task stack */
mov sp, r32
/* Get the address of __Per_CPU_Information */
mov r18, r33
/* Decrement nesting level and enable multitasking */
add r6, r18, #(PER_CPU_ISR_NEST_LEVEL)
add r8, r18, #(PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)
ldr r5, [r6]
ldr r7, [r8]
sub r5, r5, #1
sub r7, r7, #1
str r5, [r6]
str r7, [r8]
/* Check if _ISR_Nest_level > 0 */
sub r37, r5, #0
bgtu exception_frame_restore
/* Check if _Thread_Dispatch_disable_level > 0 */
sub r37, r7, #0
bgtu exception_frame_restore
/* Check if dispatch needed */
add r31, r18, #(PER_CPU_DISPATCH_NEEDED)
ldr r31, [r31]
sub r35, r31, #0
beq exception_frame_restore
mov r35, %low(__Thread_Dispatch)
movt r35, %high(__Thread_Dispatch)
jalr r35
exception_frame_restore:
ldr r1, [sp,1]
ldr r2, [sp,2]
ldr r3, [sp,3]
ldr r4, [sp,4]
ldr r5, [sp,5]
ldr r6, [sp,6]
ldr r7, [sp,7]
ldr r8, [sp,8]
ldr r9, [sp,9]
ldr r10, [sp,10]
ldr fp, [sp,11]
ldr r12, [sp,12]
ldr lr, [sp,14]
ldr r15, [sp,15]
ldr r16, [sp,16]
ldr r17, [sp,17]
ldr r18, [sp,18]
ldr r19, [sp,19]
ldr r20, [sp,20]
ldr r21, [sp,21]
ldr r22, [sp,22]
ldr r23, [sp,23]
ldr r24, [sp,24]
ldr r25, [sp,25]
ldr r26, [sp,26]
ldr r27, [sp,27]
ldr r28, [sp,28]
ldr r29, [sp,29]
ldr r30, [sp,30]
ldr r31, [sp,31]
ldr r32, [sp,32]
ldr r34, [sp,34]
ldr r36, [sp,36]
ldr r38, [sp,38]
ldr r39, [sp,39]
ldr r40, [sp,40]
ldr r41, [sp,41]
ldr r42, [sp,42]
ldr r43, [sp,43]
ldr r44, [sp,44]
ldr r45, [sp,45]
ldr r46, [sp,46]
ldr r47, [sp,47]
ldr r48, [sp,48]
ldr r49, [sp,49]
ldr r50, [sp,50]
ldr r51, [sp,51]
ldr r52, [sp,52]
ldr r53, [sp,53]
ldr r54, [sp,54]
ldr r55, [sp,55]
ldr r56, [sp,56]
ldr r57, [sp,57]
ldr r58, [sp,58]
ldr r59, [sp,59]
ldr r60, [sp,60]
ldr r61, [sp,61]
/* Restore status register */
ldr r0,[sp,62]
movts status, r0
/* Restore config register */
ldr r0, [sp,63]
movts config, r0
/* Restore interrupt return address register */
ldr r0, [sp,64]
movts iret, r0
ldr r0,[sp]
/* Restore interrupted task's stack pointer */
ldr sp, [sp,13]
/* r62 and r63 are saved from start.S interrupt entry
* and hold vector number and _ISR_Handler address repsectively.
*/
ldr r62, [sp, -8]
ldr r63, [sp, -4]
/* return from interrupt */
rti