Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-rtos by
rtx_ca/ARM/HAL_CA9.c
- Committer:
- mbed_official
- Date:
- 2014-11-06
- Revision:
- 48:e9a2c7cb57a4
File content as of revision 48:e9a2c7cb57a4:
/*---------------------------------------------------------------------------- * RL-ARM - RTX *---------------------------------------------------------------------------- * Name: HAL_CA9.c * Purpose: Hardware Abstraction Layer for Cortex-A9 * Rev.: 3 Sept 2013 *---------------------------------------------------------------------------- * * Copyright (c) 2012 - 2013 ARM Limited * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - 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. * - Neither the name of ARM nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS AND 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. *---------------------------------------------------------------------------*/ #include "rt_TypeDef.h" #include "RTX_Config.h" #include "rt_System.h" #include "rt_Task.h" #include "rt_List.h" #include "rt_MemBox.h" #include "rt_HAL_CA.h" /*---------------------------------------------------------------------------- * Functions *---------------------------------------------------------------------------*/ //For A-class, set USR/SYS stack __asm void rt_set_PSP (U32 stack) { ARM MRS R1, CPSR CPS #MODE_SYS ;no effect in USR mode ISB MOV SP, R0 MSR CPSR_c, R1 ;no effect in USR mode ISB BX LR } //For A-class, get USR/SYS stack __asm U32 rt_get_PSP (void) { ARM MRS R1, CPSR CPS #MODE_SYS ;no effect in USR mode ISB MOV R0, SP MSR CPSR_c, R1 ;no effect in USR mode ISB BX LR } /*--------------------------- _alloc_box ------------------------------------*/ __asm void *_alloc_box (void *box_mem) { /* Function wrapper for Unprivileged/Privileged mode. */ ARM LDR R12,=__cpp(rt_alloc_box) MRS R2, CPSR LSLS R2, #28 BXNE R12 SVC 0 BX LR } /*--------------------------- _free_box -------------------------------------*/ __asm int _free_box (void *box_mem, void *box) { /* Function wrapper for Unprivileged/Privileged mode. */ ARM LDR R12,=__cpp(rt_free_box) MRS R2, CPSR LSLS R2, #28 BXNE R12 SVC 0 BX LR } /*-------------------------- SVC_Handler -----------------------------------*/ #pragma push #pragma arm __asm void SVC_Handler (void) { PRESERVE8 ARM IMPORT rt_tsk_lock IMPORT rt_tsk_unlock IMPORT SVC_Count IMPORT SVC_Table IMPORT rt_stk_check IMPORT FPUEnable Mode_SVC EQU 0x13 SRSFD SP!, #Mode_SVC ; Push LR_SVC and SPRS_SVC onto SVC mode stack PUSH {R4} ; Push R4 so we can use it as a temp MRS R4,SPSR ; Get SPSR TST R4,#CPSR_T_BIT ; Check Thumb Bit LDRNEH R4,[LR,#-2] ; Thumb: Load Halfword BICNE R4,R4,#0xFF00 ; Extract SVC Number LDREQ R4,[LR,#-4] ; ARM: Load Word BICEQ R4,R4,#0xFF000000 ; Extract SVC Number /* Lock out systick and re-enable interrupts */ PUSH {R0-R3,R12,LR} AND R12, SP, #4 ; Ensure stack is 8-byte aligned SUB SP, SP, R12 ; Adjust stack PUSH {R12, LR} ; Store stack adjustment and dummy LR to SVC stack BLX rt_tsk_lock CPSIE i POP {R12, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R12 ; Unadjust stack POP {R0-R3,R12,LR} CMP R4,#0 BNE SVC_User MRS R4,SPSR PUSH {R4} ; Push R4 so we can use it as a temp AND R4, SP, #4 ; Ensure stack is 8-byte aligned SUB SP, SP, R4 ; Adjust stack PUSH {R4, LR} ; Store stack adjustment and dummy LR BLX R12 POP {R4, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R4 ; Unadjust stack POP {R4} ; Restore R4 MSR SPSR_CXSF,R4 /* Here we will be in SVC mode (even if coming in from PendSV_Handler or OS_Tick_Handler) */ Sys_Switch LDR LR,=__cpp(&os_tsk) LDM LR,{R4,LR} ; os_tsk.run, os_tsk.new CMP R4,LR BNE switching PUSH {R0-R3,R12,LR} AND R12, SP, #4 ; Ensure stack is 8-byte aligned SUB SP, SP, R12 ; Adjust stack PUSH {R12, LR} ; Store stack adjustment and dummy LR to SVC stack CPSID i BLX rt_tsk_unlock POP {R12, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R12 ; Unadjust stack POP {R0-R3,R12,LR} POP {R4} RFEFD SP! ; Return from exception, no task switch switching CLREX CMP R4,#0 ADDEQ SP,SP,#12 ; Original R4, LR & SPSR do not need to be popped when we are paging in a different task BEQ SVC_Next ; Runtask deleted? PUSH {R8-R11} //R4 and LR already stacked MOV R10,R4 ; Preserve os_tsk.run MOV R11,LR ; Preserve os_tsk.new ADD R8,SP,#16 ; Unstack R4,LR LDMIA R8,{R4,LR} SUB SP,SP,#4 ; Make space on the stack for the next instn STMIA SP,{SP}^ ; Put User SP onto stack POP {R8} ; Pop User SP into R8 MRS R9,SPSR STMDB R8!,{R9} ; User CPSR STMDB R8!,{LR} ; User PC STMDB R8,{LR}^ ; User LR SUB R8,R8,#4 ; No writeback for store of User LR STMDB R8!,{R0-R3,R12} ; User R0-R3,R12 MOV R3,R10 ; os_tsk.run MOV LR,R11 ; os_tsk.new POP {R9-R12} ADD SP,SP,#12 ; Fix up SP for unstack of R4, LR & SPSR STMDB R8!,{R4-R7,R9-R12} ; User R4-R11 //If applicable, stack VFP state MRC p15,0,R1,c1,c0,2 ; VFP/NEON access enabled? (CPACR) AND R2,R1,#0x00F00000 CMP R2,#0x00F00000 BNE no_outgoing_vfp VMRS R2,FPSCR STMDB R8!,{R2,R4} ; Push FPSCR, maintain 8-byte alignment VSTMDB R8!,{S0-S31} LDRB R2,[R3,#TCB_STACKF] ; Record in TCB that VFP state is stacked ORR R2,#2 STRB R2,[R3,#TCB_STACKF] no_outgoing_vfp STR R8,[R3,#TCB_TSTACK] MOV R4,LR PUSH {R4} ; Push R4 so we can use it as a temp AND R4, SP, #4 ; Ensure stack is 8-byte aligned SUB SP, SP, R4 ; Adjust stack PUSH {R4, LR} ; Store stack adjustment and dummy LR to SVC stack BLX rt_stk_check POP {R4, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R4 ; Unadjust stack POP {R4} ; Restore R4 MOV LR,R4 SVC_Next //R4 == os_tsk.run, LR == os_tsk.new, R0-R3, R5-R12 corruptible LDR R1,=__cpp(&os_tsk) ; os_tsk.run = os_tsk.new STR LR,[R1] LDRB R1,[LR,#TCB_TID] ; os_tsk.run->task_id LSL R1,#8 ; Store PROCID MCR p15,0,R1,c13,c0,1 ; Write CONTEXTIDR LDR R0,[LR,#TCB_TSTACK] ; os_tsk.run->tsk_stack //Does incoming task have VFP state in stack? LDRB R3,[LR,#TCB_STACKF] TST R3,#0x2 MRC p15,0,R1,c1,c0,2 ; Read CPACR ANDEQ R1,R1,#0xFF0FFFFF ; Disable VFP access if incoming task does not have stacked VFP state ORRNE R1,R1,#0x00F00000 ; Enable VFP access if incoming task does have stacked VFP state MCR p15,0,R1,c1,c0,2 ; Write CPACR BEQ no_incoming_vfp ISB ; We only need the sync if we enabled, otherwise we will context switch before next VFP instruction anyway VLDMIA R0!,{S0-S31} LDR R2,[R0] VMSR FPSCR,R2 ADD R0,R0,#8 no_incoming_vfp LDR R1,[R0,#60] ; Restore User CPSR MSR SPSR_CXSF,R1 LDMIA R0!,{R4-R11} ; Restore User R4-R11 ADD R0,R0,#4 ; Restore User R1-R3,R12 LDMIA R0!,{R1-R3,R12} LDMIA R0,{LR}^ ; Restore User LR ADD R0,R0,#4 ; No writeback for load to user LR LDMIA R0!,{LR} ; Restore User PC ADD R0,R0,#4 ; Correct User SP for unstacked user CPSR PUSH {R0} ; Push R0 onto stack LDMIA SP,{SP}^ ; Get R0 off stack into User SP ADD SP,SP,#4 ; Put SP back LDR R0,[R0,#-32] ; Restore R0 PUSH {R0-R3,R12,LR} AND R12, SP, #4 ; Ensure stack is 8-byte aligned SUB SP, SP, R12 ; Adjust stack PUSH {R12, LR} ; Store stack adjustment and dummy LR to SVC stack CPSID i BLX rt_tsk_unlock POP {R12, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R12 ; Unadjust stack POP {R0-R3,R12,LR} MOVS PC,LR ; Return from exception /*------------------- User SVC -------------------------------*/ SVC_User LDR R12,=SVC_Count LDR R12,[R12] CMP R4,R12 ; Check for overflow BHI SVC_Done LDR R12,=SVC_Table-4 LDR R12,[R12,R4,LSL #2] ; Load SVC Function Address MRS R4,SPSR ; Save SPSR PUSH {R4} ; Push R4 so we can use it as a temp AND R4, SP, #4 ; Ensure stack is 8-byte aligned SUB SP, SP, R4 ; Adjust stack PUSH {R4, LR} ; Store stack adjustment and dummy LR BLX R12 ; Call SVC Function POP {R4, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R4 ; Unadjust stack POP {R4} ; Restore R4 MSR SPSR_CXSF,R4 ; Restore SPSR SVC_Done PUSH {R0-R3,R12,LR} PUSH {R4} ; Push R4 so we can use it as a temp AND R4, SP, #4 ; Ensure stack is 8-byte aligned SUB SP, SP, R4 ; Adjust stack PUSH {R4, LR} ; Store stack adjustment and dummy LR CPSID i BLX rt_tsk_unlock POP {R4, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R4 ; Unadjust stack POP {R4} ; Restore R4 POP {R0-R3,R12,LR} POP {R4} RFEFD SP! ; Return from exception } #pragma pop #pragma push #pragma arm __asm void PendSV_Handler (U32 IRQn) { ARM IMPORT rt_tsk_lock IMPORT IRQNestLevel ADD SP,SP,#8 //fix up stack pointer (R0 has been pushed and will never be popped, R1 was pushed for stack alignment) //Disable systick interrupts, then write EOIR. We want interrupts disabled before we enter the context switcher. PUSH {R0, R1} BLX rt_tsk_lock POP {R0, R1} LDR R1, =__cpp(&GICInterface_BASE) LDR R1, [R1, #0] STR R0, [R1, #0x10] LDR R0, =IRQNestLevel ; Get address of nesting counter LDR R1, [R0] SUB R1, R1, #1 ; Decrement nesting counter STR R1, [R0] BLX __cpp(rt_pop_req) POP {R1, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R1 ; Unadjust stack LDR R0,[SP,#24] MSR SPSR_CXSF,R0 POP {R0-R3,R12} ; Leave SPSR & LR on the stack PUSH {R4} B Sys_Switch } #pragma pop #pragma push #pragma arm __asm void OS_Tick_Handler (U32 IRQn) { ARM IMPORT rt_tsk_lock IMPORT IRQNestLevel ADD SP,SP,#8 //fix up stack pointer (R0 has been pushed and will never be popped, R1 was pushed for stack alignment) PUSH {R0, R1} BLX rt_tsk_lock POP {R0, R1} LDR R1, =__cpp(&GICInterface_BASE) LDR R1, [R1, #0] STR R0, [R1, #0x10] LDR R0, =IRQNestLevel ; Get address of nesting counter LDR R1, [R0] SUB R1, R1, #1 ; Decrement nesting counter STR R1, [R0] BLX __cpp(os_tick_irqack) BLX __cpp(rt_systick) POP {R1, LR} ; Get stack adjustment & discard dummy LR ADD SP, SP, R1 ; Unadjust stack LDR R0,[SP,#24] MSR SPSR_CXSF,R0 POP {R0-R3,R12} ; Leave SPSR & LR on the stack PUSH {R4} B Sys_Switch } #pragma pop /*---------------------------------------------------------------------------- * end of file *---------------------------------------------------------------------------*/