0
mirror of https://github.com/OneOfEleven/uv-k5-firmware-custom.git synced 2025-06-20 15:08:37 +03:00

Initial commit

This commit is contained in:
OneOfEleven
2023-09-09 08:03:56 +01:00
parent 92305117f1
commit 54441e27d9
3388 changed files with 582553 additions and 0 deletions

View File

@ -0,0 +1,255 @@
/*
* Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: ARMv6-M Exception handlers
*
* -----------------------------------------------------------------------------
*/
.syntax unified
#include "rtx_def.h"
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
.equ TCB_SP_OFS, 56 // TCB.SP offset
.equ TCB_ZONE_OFS, 68 // TCB.zone offset
.equ osRtxErrorStackOverflow, 1 // Stack overflow
.equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
irqRtxLib:
.byte 0
.thumb
.section ".text"
.align 2
.eabi_attribute Tag_ABI_align_preserved, 1
.thumb_func
.type SVC_Handler, %function
.global SVC_Handler
.fnstart
.cantunwind
SVC_Handler:
mov r0,lr
lsrs r0,r0,#3 // Determine return stack from EXC_RETURN bit 2
bcc SVC_MSP // Branch if return stack is MSP
mrs r0,psp // Get PSP
SVC_Number:
ldr r1,[r0,#24] // Load saved PC from stack
subs r1,r1,#2 // Point to SVC instruction
ldrb r1,[r1] // Load SVC number
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
#ifdef RTX_SVC_PTR_CHECK
subs r1,r7,#0x01 // Clear T-bit of function address
lsls r2,r1,#29 // Check if 8-byte aligned
beq SVC_PtrBoundsCheck // Branch if address is aligned
SVC_PtrInvalid:
push {r0,lr} // Save SP and EXC_RETURN
movs r0,#osRtxErrorSVC // Parameter: code
mov r1,r7 // Parameter: object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
pop {r2,r3} // Restore SP and EXC_RETURN
mov lr,r3 // Set EXC_RETURN
b SVC_Context // Branch to context handling
SVC_PtrBoundsCheck:
ldr r2,=Image$$RTX_SVC_VENEERS$$Base
ldr r3,=Image$$RTX_SVC_VENEERS$$Length
subs r2,r1,r2 // Subtract SVC table base address
cmp r2,r3 // Compare with SVC table boundaries
bhs SVC_PtrInvalid // Branch if address is out of bounds
#endif // RTX_SVC_PTR_CHECK
push {r0,lr} // Save SP and EXC_RETURN
ldmia r0,{r0-r3} // Load function parameters from stack
blx r7 // Call service function
pop {r2,r3} // Restore SP and EXC_RETURN
str r0,[r2] // Store function return value
mov lr,r3 // Set EXC_RETURN
SVC_Context:
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldmia r3!,{r1,r2} // Load osRtxInfo.thread.run: curr & next
cmp r1,r2 // Check if thread switch is required
beq SVC_Exit // Branch when threads are the same
subs r3,r3,#8 // Adjust address
str r2,[r3] // osRtxInfo.thread.run: curr = next
cmp r1,#0
beq SVC_ContextRestore // Branch if running thread is deleted
SVC_ContextSave:
mrs r0,psp // Get PSP
subs r0,r0,#32 // Calculate SP: space for R4..R11
str r0,[r1,#TCB_SP_OFS] // Store SP
#ifdef RTX_STACK_CHECK
push {r1,r2} // Save osRtxInfo.thread.run: curr & next
mov r0,r1 // Parameter: osRtxInfo.thread.run.curr
bl osRtxThreadStackCheck // Check if thread stack is overrun
pop {r1,r2} // Restore osRtxInfo.thread.run: curr & next
cmp r0,#0
bne SVC_ContextSaveRegs // Branch when stack check is ok
movs r0,#osRtxErrorStackOverflow // Parameter: r0=code, r1=object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
movs r1,#0 // Simulate deleted running thread
b SVC_ContextRestore // Branch to context restore handling
SVC_ContextSaveRegs:
ldr r0,[r1,#TCB_SP_OFS] // Load SP
#endif // RTX_STACK_CHECK
stmia r0!,{r4-r7} // Save R4..R7
mov r4,r8
mov r5,r9
mov r6,r10
mov r7,r11
stmia r0!,{r4-r7} // Save R8..R11
SVC_ContextRestore:
movs r4,r2 // Assign osRtxInfo.thread.run.next to R4
#ifdef RTX_EXECUTION_ZONE
movs r3,#TCB_ZONE_OFS // Get TCB.zone offset
ldrb r0,[r2,r3] // Load osRtxInfo.thread.run.next: zone
cmp r1,#0
beq SVC_ZoneSetup // Branch if running thread is deleted
ldrb r1,[r1,r3] // Load osRtxInfo.thread.run.curr: zone
cmp r0,r1 // Check if next:zone == curr:zone
beq SVC_ContextRestore_N // Branch if zone has not changed
SVC_ZoneSetup:
bl osZoneSetup_Callback // Setup zone for next thread
#endif // RTX_EXECUTION_ZONE
SVC_ContextRestore_N:
ldr r0,[r4,#TCB_SP_OFS] // Load SP
adds r0,r0,#16 // Adjust address
ldmia r0!,{r4-r7} // Restore R8..R11
mov r8,r4
mov r9,r5
mov r10,r6
mov r11,r7
msr psp,r0 // Set PSP
subs r0,r0,#32 // Adjust address
ldmia r0!,{r4-r7} // Restore R4..R7
movs r0,#2 // Binary complement of 0xFFFFFFFD
mvns r0,r0 // Set EXC_RETURN value
bx r0 // Exit from handler
SVC_MSP:
mrs r0,msp // Get MSP
b SVC_Number
SVC_Exit:
bx lr // Exit from handler
SVC_User:
ldr r2,=osRtxUserSVC // Load address of SVC table
ldr r3,[r2] // Load SVC maximum number
cmp r1,r3 // Check SVC number range
bhi SVC_Exit // Branch if out of range
push {r0,lr} // Save SP and EXC_RETURN
lsls r1,r1,#2
ldr r3,[r2,r1] // Load address of SVC function
mov r12,r3
ldmia r0,{r0-r3} // Load function parameters from stack
blx r12 // Call service function
pop {r2,r3} // Restore SP and EXC_RETURN
str r0,[r2] // Store function return value
bx r3 // Return from handler
.fnend
.size SVC_Handler, .-SVC_Handler
.thumb_func
.type PendSV_Handler, %function
.global PendSV_Handler
.fnstart
.cantunwind
PendSV_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxPendSV_Handler // Call osRtxPendSV_Handler
pop {r0,r1} // Restore EXC_RETURN
mov lr,r1 // Set EXC_RETURN
b SVC_Context // Branch to context handling
.fnend
.size PendSV_Handler, .-PendSV_Handler
.thumb_func
.type SysTick_Handler, %function
.global SysTick_Handler
.fnstart
.cantunwind
SysTick_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxTick_Handler // Call osRtxTick_Handler
pop {r0,r1} // Restore EXC_RETURN
mov lr,r1 // Set EXC_RETURN
b SVC_Context // Branch to context handling
.fnend
.size SysTick_Handler, .-SysTick_Handler
#ifdef RTX_SAFETY_FEATURES
.thumb_func
.type osFaultResume, %function
.global osFaultResume
.fnstart
.cantunwind
osFaultResume:
b SVC_Context // Branch to context handling
.fnend
.size osFaultResume, .-osFaultResume
#endif // RTX_SAFETY_FEATURES
.end

View File

@ -0,0 +1,485 @@
/*
* Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: ARMv7-A Exception handlers
*
* -----------------------------------------------------------------------------
*/
.syntax unified
#include "rtx_def.h"
.equ MODE_FIQ, 0x11
.equ MODE_IRQ, 0x12
.equ MODE_SVC, 0x13
.equ MODE_ABT, 0x17
.equ MODE_UND, 0x1B
.equ CPSR_BIT_T, 0x20
.equ K_STATE_RUNNING, 2 // osKernelState_t::osKernelRunning
.equ I_K_STATE_OFS, 8 // osRtxInfo.kernel.state offset
.equ I_TICK_IRQN_OFS, 16 // osRtxInfo.tick_irqn offset
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
.equ TCB_SP_FRAME, 34 // osRtxThread_t.stack_frame offset
.equ TCB_SP_OFS, 56 // osRtxThread_t.sp offset
.equ TCB_ZONE_OFS, 68 // osRtxThread_t.zone offset
.section ".rodata"
.global irqRtxLib // Non weak library reference
irqRtxLib:
.byte 0
.section ".data"
.global SVC_Active
.global IRQ_PendSV
IRQ_NestLevel:
.word 0 // IRQ nesting level counter
SVC_Active:
.byte 0 // SVC Handler Active
IRQ_PendSV:
.byte 0 // Pending SVC flag
.arm
.section ".text"
.align 4
.type Undef_Handler, %function
.global Undef_Handler
.fnstart
.cantunwind
Undef_Handler:
srsfd sp!, #MODE_UND
push {r0-r4, r12} // Save APCS corruptible registers to UND mode stack
mrs r0, spsr
tst r0, #CPSR_BIT_T // Check mode
moveq r1, #4 // R1 = 4 ARM mode
movne r1, #2 // R1 = 2 Thumb mode
sub r0, lr, r1
ldreq r0, [r0] // ARM mode - R0 points to offending instruction
beq Undef_Cont
// Thumb instruction
// Determine if it is a 32-bit Thumb instruction
ldrh r0, [r0]
mov r2, #0x1C
cmp r2, r0, lsr #11
bhs Undef_Cont // 16-bit Thumb instruction
// 32-bit Thumb instruction. Unaligned - reconstruct the offending instruction
ldrh r2, [lr]
orr r0, r2, r0, lsl #16
Undef_Cont:
mov r2, lr // Set LR to third argument
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
// R0 =Offending instruction, R1 =2(Thumb) or =4(ARM)
bl CUndefHandler
pop {r12, lr} // Get stack adjustment & discard dummy LR
add sp, sp, r12 // Unadjust stack
ldr lr, [sp, #24] // Restore stacked LR and possibly adjust for retry
sub lr, lr, r0
ldr r0, [sp, #28] // Restore stacked SPSR
msr spsr_cxsf, r0
clrex // Clear exclusive monitor
pop {r0-r4, r12} // Restore stacked APCS registers
add sp, sp, #8 // Adjust SP for already-restored banked registers
movs pc, lr
.fnend
.size Undef_Handler, .-Undef_Handler
.type PAbt_Handler, %function
.global PAbt_Handler
.fnstart
.cantunwind
PAbt_Handler:
sub lr, lr, #4 // Pre-adjust LR
srsfd sp!, #MODE_ABT // Save LR and SPRS to ABT mode stack
push {r0-r4, r12} // Save APCS corruptible registers to ABT mode stack
mrc p15, 0, r0, c5, c0, 1 // IFSR
mrc p15, 0, r1, c6, c0, 2 // IFAR
mov r2, lr // Set LR to third argument
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
bl CPAbtHandler
pop {r12, lr} // Get stack adjustment & discard dummy LR
add sp, sp, r12 // Unadjust stack
clrex // Clear exclusive monitor
pop {r0-r4, r12} // Restore stack APCS registers
rfefd sp! // Return from exception
.fnend
.size PAbt_Handler, .-PAbt_Handler
.type DAbt_Handler, %function
.global DAbt_Handler
.fnstart
.cantunwind
DAbt_Handler:
sub lr, lr, #8 // Pre-adjust LR
srsfd sp!, #MODE_ABT // Save LR and SPRS to ABT mode stack
push {r0-r4, r12} // Save APCS corruptible registers to ABT mode stack
mrc p15, 0, r0, c5, c0, 0 // DFSR
mrc p15, 0, r1, c6, c0, 0 // DFAR
mov r2, lr // Set LR to third argument
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
bl CDAbtHandler
pop {r12, lr} // Get stack adjustment & discard dummy LR
add sp, sp, r12 // Unadjust stack
clrex // Clear exclusive monitor
pop {r0-r4, r12} // Restore stacked APCS registers
rfefd sp! // Return from exception
.fnend
.size DAbt_Handler, .-DAbt_Handler
.type IRQ_Handler, %function
.global IRQ_Handler
.fnstart
.cantunwind
IRQ_Handler:
sub lr, lr, #4 // Pre-adjust LR
srsfd sp!, #MODE_SVC // Save LR_irq and SPSR_irq on to the SVC stack
cps #MODE_SVC // Change to SVC mode
push {r0-r3, r12, lr} // Save APCS corruptible registers
ldr r0, =IRQ_NestLevel
ldr r1, [r0]
add r1, r1, #1 // Increment IRQ nesting level
str r1, [r0]
mov r3, sp // Move SP into R3
and r3, r3, #4 // Get stack adjustment to ensure 8-byte alignment
sub sp, sp, r3 // Adjust stack
push {r3, r4} // Store stack adjustment(R3) and user data(R4)
blx IRQ_GetActiveIRQ // Retrieve interrupt ID into R0
mov r4, r0 // Move interrupt ID to R4
blx IRQ_GetHandler // Retrieve interrupt handler address for current ID
cmp r0, #0 // Check if handler address is 0
beq IRQ_End // If 0, end interrupt and return
cpsie i // Re-enable interrupts
blx r0 // Call IRQ handler
cpsid i // Disable interrupts
IRQ_End:
mov r0, r4 // Move interrupt ID to R0
blx IRQ_EndOfInterrupt // Signal end of interrupt
pop {r3, r4} // Restore stack adjustment(R3) and user data(R4)
add sp, sp, r3 // Unadjust stack
bl osRtxContextSwitch // Continue in context switcher
ldr r0, =IRQ_NestLevel
ldr r1, [r0]
subs r1, r1, #1 // Decrement IRQ nesting level
str r1, [r0]
clrex // Clear exclusive monitor for interrupted code
pop {r0-r3, r12, lr} // Restore stacked APCS registers
rfefd sp! // Return from IRQ handler
.fnend
.size IRQ_Handler, .-IRQ_Handler
.type SVC_Handler, %function
.global SVC_Handler
.fnstart
.cantunwind
SVC_Handler:
srsfd sp!, #MODE_SVC // Store SPSR_svc and LR_svc onto SVC stack
push {r12, lr}
mrs r12, spsr // Load SPSR
tst r12, #CPSR_BIT_T // Thumb bit set?
ldrhne r12, [lr,#-2] // Thumb: load halfword
bicne r12, r12, #0xFF00 // extract SVC number
ldreq r12, [lr,#-4] // ARM: load word
biceq r12, r12, #0xFF000000 // extract SVC number
cmp r12, #0 // Compare SVC number
bne SVC_User // Branch if User SVC
push {r0-r3} // Push arguments to stack
ldr r0, =SVC_Active
mov r1, #1
strb r1, [r0] // Set SVC Handler Active
ldr r0, =IRQ_NestLevel
ldr r1, [r0]
add r1, r1, #1 // Increment IRQ nesting level
str r1, [r0]
ldr r0, =osRtxInfo
ldr r1, [r0, #I_K_STATE_OFS] // Load RTX5 kernel state
cmp r1, #K_STATE_RUNNING // Check osKernelRunning
blt SVC_FuncCall // Continue if kernel is not running
ldr r0, [r0, #I_TICK_IRQN_OFS] // Load OS Tick irqn
blx IRQ_Disable // Disable OS Tick interrupt
SVC_FuncCall:
ldm sp, {r0-r3, r12} // Reload R0-R3 and R12 from stack
cpsie i // Re-enable interrupts
blx r12 // Branch to SVC function
cpsid i // Disable interrupts
str r0, [sp] // Store function return value
ldr r0, =osRtxInfo
ldr r1, [r0, #I_K_STATE_OFS] // Load RTX5 kernel state
cmp r1, #K_STATE_RUNNING // Check osKernelRunning
blt SVC_ContextCheck // Continue if kernel is not running
ldr r0, [r0, #I_TICK_IRQN_OFS] // Load OS Tick irqn
blx IRQ_Enable // Enable OS Tick interrupt
SVC_ContextCheck:
bl osRtxContextSwitch // Continue in context switcher
ldr r0, =IRQ_NestLevel
ldr r1, [r0]
sub r1, r1, #1 // Decrement IRQ nesting level
str r1, [r0]
ldr r0, =SVC_Active
mov r1, #0
strb r1, [r0] // Clear SVC Handler Active
clrex // Clear exclusive monitor
pop {r0-r3, r12, lr} // Restore stacked APCS registers
rfefd sp! // Return from exception
SVC_User:
push {r4, r5}
ldr r5,=osRtxUserSVC // Load address of SVC table
ldr r4,[r5] // Load SVC maximum number
cmp r12,r4 // Check SVC number range
bhi SVC_Done // Branch if out of range
ldr r12,[r5,r12,lsl #2] // Load SVC Function Address
blx r12 // Call SVC Function
SVC_Done:
clrex // Clear exclusive monitor
pop {r4, r5, r12, lr}
rfefd sp! // Return from exception
.fnend
.size SVC_Handler, .-SVC_Handler
.type osRtxContextSwitch, %function
.global osRtxContextSwitch
.fnstart
.cantunwind
osRtxContextSwitch:
push {lr}
// Check interrupt nesting level
ldr r0, =IRQ_NestLevel
ldr r1, [r0] // Load IRQ nest level
cmp r1, #1
bne osRtxContextExit // Nesting interrupts, exit context switcher
ldr r12, =osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
ldm r12, {r0, r1} // Load osRtxInfo.thread.run: curr & next
ldr r2, =IRQ_PendSV // Load address of IRQ_PendSV flag
ldrb r3, [r2] // Load PendSV flag
cmp r0, r1 // Check if context switch is required
bne osRtxContextCheck // Not equal, check if context save required
cmp r3, #1 // Compare IRQ_PendSV value
bne osRtxContextExit // No post processing (and no context switch requested)
osRtxContextCheck:
str r1, [r12] // Store run.next as run.curr
// R0 = curr, R1 = next, R2 = &IRQ_PendSV, R12 = &osRtxInfo.thread.run
push {r0-r2, r12}
cmp r0, #0 // Is osRtxInfo.thread.run.curr == 0
beq osRtxPostProcess // Current deleted, skip context save
osRtxContextSave:
mov lr, r0 // Move &osRtxInfo.thread.run.curr to LR
mov r0, sp // Move SP_svc into R0
add r0, r0, #20 // Adjust SP_svc to R0 of the basic frame
sub sp, sp, #4
stm sp, {sp}^ // Save SP_usr to current stack
pop {r1} // Pop SP_usr into R1
sub r1, r1, #64 // Adjust SP_usr to R4 of the basic frame
stmia r1!, {r4-r11} // Save R4-R11 to user stack
ldmia r0!, {r4-r8} // Load stacked R0-R3,R12 into R4-R8
stmia r1!, {r4-r8} // Store them to user stack
stm r1, {lr}^ // Store LR_usr directly
add r1, r1, #4 // Adjust user sp to PC
ldmib r0!, {r5-r6} // Load stacked PC, CPSR
stmia r1!, {r5-r6} // Store them to user stack
sub r1, r1, #64 // Adjust SP_usr to stacked R4
// Check if VFP state need to be saved
mrc p15, 0, r2, c1, c0, 2 // VFP/NEON access enabled? (CPACR)
and r2, r2, #0x00F00000
cmp r2, #0x00F00000
bne osRtxContextSaveSP // Continue, no VFP
vmrs r2, fpscr
stmdb r1!, {r2,r12} // Push FPSCR, maintain 8-byte alignment
vstmdb r1!, {d0-d15} // Save D0-D15
#if defined(__ARM_NEON) && (__ARM_NEON == 1)
vstmdb r1!, {d16-d31} // Save D16-D31
#endif
ldrb r2, [lr, #TCB_SP_FRAME] // Load osRtxInfo.thread.run.curr frame info
#if defined(__ARM_NEON) && (__ARM_NEON == 1)
orr r2, r2, #4 // NEON state
#else
orr r2, r2, #2 // VFP state
#endif
strb r2, [lr, #TCB_SP_FRAME] // Store VFP/NEON state
osRtxContextSaveSP:
str r1, [lr, #TCB_SP_OFS] // Store user sp to osRtxInfo.thread.run.curr
osRtxPostProcess:
// RTX IRQ post processing check
pop {r8-r11} // Pop R8 = curr, R9 = next, R10 = &IRQ_PendSV, R11 = &osRtxInfo.thread.run
ldrb r0, [r10] // Load PendSV flag
cmp r0, #1 // Compare PendSV value
bne osRtxContextRestore // Skip post processing if not pending
mov r4, sp // Move SP_svc into R4
and r4, r4, #4 // Get stack adjustment to ensure 8-byte alignment
sub sp, sp, r4 // Adjust stack
// Disable OS Tick
ldr r5, =osRtxInfo // Load address of osRtxInfo
ldr r5, [r5, #I_TICK_IRQN_OFS] // Load OS Tick irqn
mov r0, r5 // Set it as function parameter
blx IRQ_Disable // Disable OS Tick interrupt
mov r6, #0 // Set PendSV clear value
b osRtxPendCheck
osRtxPendExec:
strb r6, [r10] // Clear PendSV flag
cpsie i // Re-enable interrupts
blx osRtxPendSV_Handler // Post process pending objects
cpsid i // Disable interrupts
osRtxPendCheck:
ldr r9, [r11, #4] // Load osRtxInfo.thread.run.next
str r9, [r11] // Store run.next as run.curr
ldrb r0, [r10] // Load PendSV flag
cmp r0, #1 // Compare PendSV value
beq osRtxPendExec // Branch to PendExec if PendSV is set
// Re-enable OS Tick
mov r0, r5 // Restore irqn as function parameter
blx IRQ_Enable // Enable OS Tick interrupt
add sp, sp, r4 // Restore stack adjustment
osRtxContextRestore:
#ifdef RTX_EXECUTION_ZONE
ldrb r0, [r9, #TCB_ZONE_OFS] // Load osRtxInfo.thread.run.next: zone
cmp r8, #0
beq osRtxZoneSetup // Branch if running thread is deleted
ldrb r1, [r8, #TCB_ZONE_OFS] // Load osRtxInfo.thread.run.curr: zone
cmp r0, r1 // Check if next:zone == curr:zone
beq osRtxContextRestoreFrame // Branch if zone has not changed
osRtxZoneSetup:
bl osZoneSetup_Callback // Setup zone for next thread
#endif
osRtxContextRestoreFrame:
ldr lr, [r9, #TCB_SP_OFS] // Load next osRtxThread_t.sp
ldrb r2, [r9, #TCB_SP_FRAME] // Load next osRtxThread_t.stack_frame
ands r2, r2, #0x6 // Check stack frame for VFP context
mrc p15, 0, r2, c1, c0, 2 // Read CPACR
andeq r2, r2, #0xFF0FFFFF // VFP/NEON state not stacked, disable VFP/NEON
orrne r2, r2, #0x00F00000 // VFP/NEON state is stacked, enable VFP/NEON
mcr p15, 0, r2, c1, c0, 2 // Write CPACR
beq osRtxContextRestoreRegs // No VFP
isb // Sync if VFP was enabled
#if defined(__ARM_NEON) && (__ARM_NEON == 1)
vldmia lr!, {d16-d31} // Restore D16-D31
#endif
vldmia lr!, {d0-d15} // Restore D0-D15
ldr r2, [lr]
vmsr fpscr, r2 // Restore FPSCR
add lr, lr, #8 // Adjust sp pointer to R4
osRtxContextRestoreRegs:
ldmia lr!, {r4-r11} // Restore R4-R11
add r12, lr, #32 // Adjust sp and save it into R12
push {r12} // Push sp onto stack
ldm sp, {sp}^ // Restore SP_usr directly
add sp, sp, #4 // Adjust SP_svc
ldmia lr!, {r0-r3, r12} // Load user registers R0-R3,R12
stmib sp!, {r0-r3, r12} // Store them to SP_svc
ldm lr, {lr}^ // Restore LR_usr directly
ldmib lr!, {r0-r1} // Load user registers PC,CPSR
add sp, sp, #4
stmib sp!, {r0-r1} // Store them to SP_svc
sub sp, sp, #32 // Adjust SP_svc to stacked LR
osRtxContextExit:
pop {pc} // Return
.fnend
.size osRtxContextSwitch, .-osRtxContextSwitch
.end

View File

@ -0,0 +1,281 @@
/*
* Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: ARMv7-M Exception handlers
*
* -----------------------------------------------------------------------------
*/
.syntax unified
#include "rtx_def.h"
#if (defined(__ARM_FP) && (__ARM_FP > 0))
.equ FPU_USED, 1
#else
.equ FPU_USED, 0
#endif
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
.equ TCB_SP_OFS, 56 // TCB.SP offset
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
.equ TCB_ZONE_OFS, 68 // TCB.zone offset
.equ FPCCR, 0xE000EF34 // FPCCR Address
.equ osRtxErrorStackOverflow, 1 // Stack overflow
.equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
irqRtxLib:
.byte 0
.thumb
.section ".text"
.align 2
.eabi_attribute Tag_ABI_align_preserved, 1
.thumb_func
.type SVC_Handler, %function
.global SVC_Handler
.fnstart
.cantunwind
SVC_Handler:
tst lr,#0x04 // Determine return stack from EXC_RETURN bit 2
ite eq
mrseq r0,msp // Get MSP if return stack is MSP
mrsne r0,psp // Get PSP if return stack is PSP
ldr r1,[r0,#24] // Load saved PC from stack
ldrb r1,[r1,#-2] // Load SVC number
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
#ifdef RTX_SVC_PTR_CHECK
ldr r12,[r0,#16] // Load function address from stack
sub r1,r12,#1 // Clear T-bit of function address
lsls r2,r1,#30 // Check if 4-byte aligned
beq SVC_PtrBoundsCheck // Branch if address is aligned
SVC_PtrInvalid:
push {r0,lr} // Save SP and EXC_RETURN
movs r0,#osRtxErrorSVC // Parameter: code
mov r1,r12 // Parameter: object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
pop {r12,lr} // Restore SP and EXC_RETURN
b SVC_Context // Branch to context handling
SVC_PtrBoundsCheck:
ldr r2,=Image$$RTX_SVC_VENEERS$$Base
ldr r3,=Image$$RTX_SVC_VENEERS$$Length
subs r2,r1,r2 // Subtract SVC table base address
cmp r2,r3 // Compare with SVC table boundaries
bhs SVC_PtrInvalid // Branch if address is out of bounds
#endif // RTX_SVC_PTR_CHECK
push {r0,lr} // Save SP and EXC_RETURN
ldm r0,{r0-r3,r12} // Load function parameters and address from stack
blx r12 // Call service function
pop {r12,lr} // Restore SP and EXC_RETURN
str r0,[r12] // Store function return value
SVC_Context:
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldm r3,{r1,r2} // Load osRtxInfo.thread.run: curr & next
cmp r1,r2 // Check if thread switch is required
it eq
bxeq lr // Exit when threads are the same
str r2,[r3] // osRtxInfo.thread.run: curr = next
.if (FPU_USED != 0)
cbnz r1,SVC_ContextSave // Branch if running thread is not deleted
SVC_FP_LazyState:
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
bne SVC_ContextRestore // Branch if not extended stack frame
ldr r3,=FPCCR // FPCCR Address
ldr r0,[r3] // Load FPCCR
bic r0,r0,#1 // Clear LSPACT (Lazy state preservation)
str r0,[r3] // Store FPCCR
b SVC_ContextRestore // Branch to context restore handling
.else
cbz r1,SVC_ContextRestore // Branch if running thread is deleted
.endif
SVC_ContextSave:
#ifdef RTX_STACK_CHECK
sub r12,r12,#32 // Calculate SP: space for R4..R11
.if (FPU_USED != 0)
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
subeq r12,r12,#64 // Additional space for S16..S31
strb lr, [r1,#TCB_SF_OFS] // Store stack frame information
.endif
str r12,[r1,#TCB_SP_OFS] // Store SP
push {r1,r2} // Save osRtxInfo.thread.run: curr & next
mov r0,r1 // Parameter: osRtxInfo.thread.run.curr
bl osRtxThreadStackCheck // Check if thread stack is overrun
pop {r1,r2} // Restore osRtxInfo.thread.run: curr & next
cbnz r0,SVC_ContextSaveRegs // Branch when stack check is ok
.if (FPU_USED != 0)
mov r4,r1 // Assign osRtxInfo.thread.run.curr to R4
.endif
movs r0,#osRtxErrorStackOverflow // Parameter: r0=code, r1=object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
movs r1,#0 // Simulate deleted running thread
.if (FPU_USED != 0)
ldrsb lr,[r4,#TCB_SF_OFS] // Load stack frame information
b SVC_FP_LazyState // Branch to FP lazy state handling
.else
b SVC_ContextRestore // Branch to context restore handling
.endif
SVC_ContextSaveRegs:
ldr r12,[r1,#TCB_SP_OFS] // Load SP
.if (FPU_USED != 0)
ldrsb lr, [r1,#TCB_SF_OFS] // Load stack frame information
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
vstmiaeq r12!,{s16-s31} // Save VFP S16..S31
.endif
stm r12,{r4-r11} // Save R4..R11
#else
stmdb r12!,{r4-r11} // Save R4..R11
.if (FPU_USED != 0)
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
vstmdbeq r12!,{s16-s31} // Save VFP S16.S31
strb lr, [r1,#TCB_SF_OFS] // Store stack frame information
.endif
str r12,[r1,#TCB_SP_OFS] // Store SP
#endif // RTX_STACK_CHECK
SVC_ContextRestore:
movs r4,r2 // Assign osRtxInfo.thread.run.next to R4, clear Z flag
#ifdef RTX_EXECUTION_ZONE
ldrb r0,[r2,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.next: zone
cbz r1,SVC_ZoneSetup // Branch if running thread is deleted (Z flag unchanged)
ldrb r1,[r1,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.curr: zone
cmp r0,r1 // Check if next:zone == curr:zone
SVC_ZoneSetup:
it ne // If zone has changed or running thread is deleted
blne osZoneSetup_Callback // Setup zone for next thread
#endif // RTX_EXECUTION_ZONE
ldr r0,[r4,#TCB_SP_OFS] // Load SP
.if (FPU_USED != 0)
ldrsb lr,[r4,#TCB_SF_OFS] // Load stack frame information
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
vldmiaeq r0!,{s16-s31} // Restore VFP S16..S31
.else
mvn lr,#~0xFFFFFFFD // Set EXC_RETURN value
.endif
ldmia r0!,{r4-r11} // Restore R4..R11
msr psp,r0 // Set PSP
SVC_Exit:
bx lr // Exit from handler
SVC_User:
ldr r2,=osRtxUserSVC // Load address of SVC table
ldr r3,[r2] // Load SVC maximum number
cmp r1,r3 // Check SVC number range
bhi SVC_Exit // Branch if out of range
push {r0,lr} // Save SP and EXC_RETURN
ldr r12,[r2,r1,lsl #2] // Load address of SVC function
ldm r0,{r0-r3} // Load function parameters from stack
blx r12 // Call service function
pop {r12,lr} // Restore SP and EXC_RETURN
str r0,[r12] // Store function return value
bx lr // Return from handler
.fnend
.size SVC_Handler, .-SVC_Handler
.thumb_func
.type PendSV_Handler, %function
.global PendSV_Handler
.fnstart
.cantunwind
PendSV_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxPendSV_Handler // Call osRtxPendSV_Handler
pop {r0,lr} // Restore EXC_RETURN
mrs r12,psp // Save PSP to R12
b SVC_Context // Branch to context handling
.fnend
.size PendSV_Handler, .-PendSV_Handler
.thumb_func
.type SysTick_Handler, %function
.global SysTick_Handler
.fnstart
.cantunwind
SysTick_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxTick_Handler // Call osRtxTick_Handler
pop {r0,lr} // Restore EXC_RETURN
mrs r12,psp // Save PSP to R12
b SVC_Context // Branch to context handling
.fnend
.size SysTick_Handler, .-SysTick_Handler
#ifdef RTX_SAFETY_FEATURES
.thumb_func
.type osFaultResume, %function
.global osFaultResume
.fnstart
.cantunwind
osFaultResume:
mrs r12,psp // Save PSP to R12
b SVC_Context // Branch to context handling
.fnend
.size osFaultResume, .-osFaultResume
#endif // RTX_SAFETY_FEATURES
.end

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2016-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: ARMv8-M Baseline Exception handlers
*
* -----------------------------------------------------------------------------
*/
.syntax unified
#include "rtx_def.h"
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
.equ TCB_SM_OFS, 48 // TCB.stack_mem offset
.equ TCB_SP_OFS, 56 // TCB.SP offset
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
.equ TCB_TZM_OFS, 64 // TCB.tz_memory offset
.equ TCB_ZONE_OFS,68 // TCB.zone offset
.equ osRtxErrorStackOverflow, 1 // Stack overflow
.equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
irqRtxLib:
.byte 0
.thumb
.section ".text"
.align 2
.eabi_attribute Tag_ABI_align_preserved, 1
.thumb_func
.type SVC_Handler, %function
.global SVC_Handler
.fnstart
.cantunwind
SVC_Handler:
mov r0,lr
lsrs r0,r0,#3 // Determine return stack from EXC_RETURN bit 2
bcc SVC_MSP // Branch if return stack is MSP
mrs r0,psp // Get PSP
SVC_Number:
ldr r1,[r0,#24] // Load saved PC from stack
subs r1,r1,#2 // Point to SVC instruction
ldrb r1,[r1] // Load SVC number
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
#ifdef RTX_SVC_PTR_CHECK
subs r1,r7,#0x01 // Clear T-bit of function address
lsls r2,r1,#29 // Check if 8-byte aligned
beq SVC_PtrBoundsCheck // Branch if address is aligned
SVC_PtrInvalid:
push {r0,lr} // Save SP and EXC_RETURN
movs r0,#osRtxErrorSVC // Parameter: code
mov r1,r7 // Parameter: object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
pop {r2,r3} // Restore SP and EXC_RETURN
mov lr,r3 // Set EXC_RETURN
b SVC_Context // Branch to context handling
SVC_PtrBoundsCheck:
ldr r2,=Image$$RTX_SVC_VENEERS$$Base
ldr r3,=Image$$RTX_SVC_VENEERS$$Length
subs r2,r1,r2 // Subtract SVC table base address
cmp r2,r3 // Compare with SVC table boundaries
bhs SVC_PtrInvalid // Branch if address is out of bounds
#endif // RTX_SVC_PTR_CHECK
push {r0,lr} // Save SP and EXC_RETURN
ldmia r0,{r0-r3} // Load function parameters from stack
blx r7 // Call service function
pop {r2,r3} // Restore SP and EXC_RETURN
str r0,[r2] // Store function return value
mov lr,r3 // Set EXC_RETURN
SVC_Context:
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldmia r3!,{r1,r2} // Load osRtxInfo.thread.run: curr & next
cmp r1,r2 // Check if thread switch is required
beq SVC_Exit // Branch when threads are the same
subs r3,r3,#8 // Adjust address
str r2,[r3] // osRtxInfo.thread.run: curr = next
cbz r1,SVC_ContextRestore // Branch if running thread is deleted
SVC_ContextSave:
#ifdef RTX_TZ_CONTEXT
mov r3,lr // Get EXC_RETURN
ldr r0,[r1,#TCB_TZM_OFS] // Load TrustZone memory identifier
cbz r0,SVC_ContextSave_NS // Branch if there is no secure context
push {r0-r3} // Save registers
bl TZ_StoreContext_S // Store secure context
pop {r0-r3} // Restore registers
mov lr,r3 // Set EXC_RETURN
#endif
SVC_ContextSave_NS:
mrs r0,psp // Get PSP
#if (DOMAIN_NS != 0)
mov r3,lr // Get EXC_RETURN
lsls r3,r3,#25 // Check domain of interrupted thread
bmi SVC_ContextSaveSP // Branch if secure
#endif
#ifdef RTX_STACK_CHECK
subs r0,r0,#32 // Calculate SP: space for R4..R11
SVC_ContextSaveSP:
str r0,[r1,#TCB_SP_OFS] // Store SP
mov r3,lr // Get EXC_RETURN
movs r0,#TCB_SF_OFS // Get TCB.stack_frame offset
strb r3,[r1,r0] // Store stack frame information
push {r1,r2} // Save osRtxInfo.thread.run: curr & next
mov r0,r1 // Parameter: osRtxInfo.thread.run.curr
bl osRtxThreadStackCheck // Check if thread stack is overrun
pop {r1,r2} // Restore osRtxInfo.thread.run: curr & next
cbnz r0,SVC_ContextSaveRegs // Branch when stack check is ok
movs r0,#osRtxErrorStackOverflow // Parameter: r0=code, r1=object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
movs r1,#0 // Simulate deleted running thread
b SVC_ContextRestore // Branch to context restore handling
SVC_ContextSaveRegs:
#if (DOMAIN_NS != 0)
movs r0,#TCB_SF_OFS // Get TCB.stack_frame offset
ldrsb r3,[r1,r0] // Load stack frame information
lsls r3,r3,#25 // Check domain of interrupted thread
bmi SVC_ContextRestore // Branch if secure
#endif
ldr r0,[r1,#TCB_SP_OFS] // Load SP
stmia r0!,{r4-r7} // Save R4..R7
mov r4,r8
mov r5,r9
mov r6,r10
mov r7,r11
stmia r0!,{r4-r7} // Save R8..R11
#else
subs r0,r0,#32 // Calculate SP: space for R4..R11
stmia r0!,{r4-r7} // Save R4..R7
mov r4,r8
mov r5,r9
mov r6,r10
mov r7,r11
stmia r0!,{r4-r7} // Save R8..R11
subs r0,r0,#32 // Adjust address
SVC_ContextSaveSP:
str r0,[r1,#TCB_SP_OFS] // Store SP
mov r3,lr // Get EXC_RETURN
movs r0,#TCB_SF_OFS // Get TCB.stack_frame offset
strb r3,[r1,r0] // Store stack frame information
#endif // RTX_STACK_CHECK
SVC_ContextRestore:
movs r4,r2 // Assign osRtxInfo.thread.run.next to R4
#ifdef RTX_EXECUTION_ZONE
movs r3,#TCB_ZONE_OFS // Get TCB.zone offset
ldrb r0,[r2,r3] // Load osRtxInfo.thread.run.next: zone
cbz r1,SVC_ZoneSetup // Branch if running thread is deleted
ldrb r1,[r1,r3] // Load osRtxInfo.thread.run.curr: zone
cmp r0,r1 // Check if next:zone == curr:zone
beq SVC_ContextRestore_S // Branch if zone has not changed
SVC_ZoneSetup:
bl osZoneSetup_Callback // Setup zone for next thread
#endif // RTX_EXECUTION_ZONE
SVC_ContextRestore_S:
#ifdef RTX_TZ_CONTEXT
ldr r0,[r4,#TCB_TZM_OFS] // Load TrustZone memory identifier
cbz r0,SVC_ContextRestore_NS // Branch if there is no secure context
bl TZ_LoadContext_S // Load secure context
#endif
SVC_ContextRestore_NS:
ldr r0,[r4,#TCB_SM_OFS] // Load stack memory base
msr psplim,r0 // Set PSPLIM
movs r0,#TCB_SF_OFS // Get TCB.stack_frame offset
ldrsb r3,[r4,r0] // Load stack frame information
mov lr,r3 // Set EXC_RETURN
ldr r0,[r4,#TCB_SP_OFS] // Load SP
#if (DOMAIN_NS != 0)
lsls r3,r3,#25 // Check domain of interrupted thread
bmi SVC_ContextRestoreSP // Branch if secure
#endif
adds r0,r0,#16 // Adjust address
ldmia r0!,{r4-r7} // Restore R8..R11
mov r8,r4
mov r9,r5
mov r10,r6
mov r11,r7
subs r0,r0,#32 // Adjust address
ldmia r0!,{r4-r7} // Restore R4..R7
adds r0,r0,#16 // Adjust address
SVC_ContextRestoreSP:
msr psp,r0 // Set PSP
SVC_Exit:
bx lr // Exit from handler
SVC_MSP:
mrs r0,msp // Get MSP
b SVC_Number
SVC_User:
ldr r2,=osRtxUserSVC // Load address of SVC table
ldr r3,[r2] // Load SVC maximum number
cmp r1,r3 // Check SVC number range
bhi SVC_Exit // Branch if out of range
push {r0,lr} // Save SP and EXC_RETURN
lsls r1,r1,#2
ldr r3,[r2,r1] // Load address of SVC function
mov r12,r3
ldmia r0,{r0-r3} // Load function parameters from stack
blx r12 // Call service function
pop {r2,r3} // Restore SP and EXC_RETURN
str r0,[r2] // Store function return value
bx r3 // Return from handler
.fnend
.size SVC_Handler, .-SVC_Handler
.thumb_func
.type PendSV_Handler, %function
.global PendSV_Handler
.fnstart
.cantunwind
PendSV_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxPendSV_Handler // Call osRtxPendSV_Handler
pop {r0,r1} // Restore EXC_RETURN
mov lr,r1 // Set EXC_RETURN
b SVC_Context // Branch to context handling
.fnend
.size PendSV_Handler, .-PendSV_Handler
.thumb_func
.type SysTick_Handler, %function
.global SysTick_Handler
.fnstart
.cantunwind
SysTick_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxTick_Handler // Call osRtxTick_Handler
pop {r0,r1} // Restore EXC_RETURN
mov lr,r1 // Set EXC_RETURN
b SVC_Context // Branch to context handling
.fnend
.size SysTick_Handler, .-SysTick_Handler
#ifdef RTX_SAFETY_FEATURES
.thumb_func
.type osFaultResume, %function
.global osFaultResume
.fnstart
.cantunwind
osFaultResume:
b SVC_Context // Branch to context handling
.fnend
.size osFaultResume, .-osFaultResume
#endif // RTX_SAFETY_FEATURES
.end

View File

@ -0,0 +1,324 @@
/*
* Copyright (c) 2016-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: ARMv8-M Mainline Exception handlers
*
* -----------------------------------------------------------------------------
*/
.syntax unified
#include "rtx_def.h"
#if (defined(__ARM_FP) && (__ARM_FP > 0))
.equ FPU_USED, 1
#else
.equ FPU_USED, 0
#endif
#if (defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE > 0))
.equ MVE_USED, 1
#else
.equ MVE_USED, 0
#endif
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
.equ TCB_SM_OFS, 48 // TCB.stack_mem offset
.equ TCB_SP_OFS, 56 // TCB.SP offset
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
.equ TCB_TZM_OFS, 64 // TCB.tz_memory offset
.equ TCB_ZONE_OFS,68 // TCB.zone offset
.equ FPCCR, 0xE000EF34 // FPCCR Address
.equ osRtxErrorStackOverflow, 1 // Stack overflow
.equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
irqRtxLib:
.byte 0
.thumb
.section ".text"
.align 2
.eabi_attribute Tag_ABI_align_preserved, 1
.thumb_func
.type SVC_Handler, %function
.global SVC_Handler
.fnstart
.cantunwind
SVC_Handler:
tst lr,#0x04 // Determine return stack from EXC_RETURN bit 2
ite eq
mrseq r0,msp // Get MSP if return stack is MSP
mrsne r0,psp // Get PSP if return stack is PSP
ldr r1,[r0,#24] // Load saved PC from stack
ldrb r1,[r1,#-2] // Load SVC number
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
#ifdef RTX_SVC_PTR_CHECK
ldr r12,[r0,#16] // Load function address from stack
sub r1,r12,#1 // Clear T-bit of function address
lsls r2,r1,#30 // Check if 4-byte aligned
beq SVC_PtrBoundsCheck // Branch if address is aligned
SVC_PtrInvalid:
push {r0,lr} // Save SP and EXC_RETURN
movs r0,#osRtxErrorSVC // Parameter: code
mov r1,r12 // Parameter: object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
pop {r12,lr} // Restore SP and EXC_RETURN
b SVC_Context // Branch to context handling
SVC_PtrBoundsCheck:
ldr r2,=Image$$RTX_SVC_VENEERS$$Base
ldr r3,=Image$$RTX_SVC_VENEERS$$Length
subs r2,r1,r2 // Subtract SVC table base address
cmp r2,r3 // Compare with SVC table boundaries
bhs SVC_PtrInvalid // Branch if address is out of bounds
#endif // RTX_SVC_PTR_CHECK
push {r0,lr} // Save SP and EXC_RETURN
ldm r0,{r0-r3,r12} // Load function parameters and address from stack
blx r12 // Call service function
pop {r12,lr} // Restore SP and EXC_RETURN
str r0,[r12] // Store function return value
SVC_Context:
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldm r3,{r1,r2} // Load osRtxInfo.thread.run: curr & next
cmp r1,r2 // Check if thread switch is required
it eq
bxeq lr // Exit when threads are the same
str r2,[r3] // osRtxInfo.thread.run: curr = next
.if (FPU_USED != 0) || (MVE_USED != 0)
cbnz r1,SVC_ContextSave // Branch if running thread is not deleted
SVC_FP_LazyState:
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
bne SVC_ContextRestore // Branch if not extended stack frame
ldr r3,=FPCCR // FPCCR Address
ldr r0,[r3] // Load FPCCR
bic r0,r0,#1 // Clear LSPACT (Lazy state preservation)
str r0,[r3] // Store FPCCR
b SVC_ContextRestore // Branch to context restore handling
.else
cbz r1,SVC_ContextRestore // Branch if running thread is deleted
.endif
SVC_ContextSave:
#ifdef RTX_TZ_CONTEXT
ldr r0,[r1,#TCB_TZM_OFS] // Load TrustZone memory identifier
cbz r0,SVC_ContextSave_NS // Branch if there is no secure context
push {r1,r2,r12,lr} // Save registers and EXC_RETURN
bl TZ_StoreContext_S // Store secure context
pop {r1,r2,r12,lr} // Restore registers and EXC_RETURN
#endif
SVC_ContextSave_NS:
#if (DOMAIN_NS != 0)
tst lr,#0x40 // Check domain of interrupted thread
bne SVC_ContextSaveSP // Branch if secure
#endif
#ifdef RTX_STACK_CHECK
sub r12,r12,#32 // Calculate SP: space for R4..R11
.if (FPU_USED != 0) || (MVE_USED != 0)
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
subeq r12,r12,#64 // Additional space for S16..S31
.endif
SVC_ContextSaveSP:
str r12,[r1,#TCB_SP_OFS] // Store SP
strb lr, [r1,#TCB_SF_OFS] // Store stack frame information
push {r1,r2} // Save osRtxInfo.thread.run: curr & next
mov r0,r1 // Parameter: osRtxInfo.thread.run.curr
bl osRtxThreadStackCheck // Check if thread stack is overrun
pop {r1,r2} // Restore osRtxInfo.thread.run: curr & next
cbnz r0,SVC_ContextSaveRegs // Branch when stack check is ok
.if (FPU_USED != 0) || (MVE_USED != 0)
mov r4,r1 // Assign osRtxInfo.thread.run.curr to R4
.endif
movs r0,#osRtxErrorStackOverflow // Parameter: r0=code, r1=object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
movs r1,#0 // Simulate deleted running thread
.if (FPU_USED != 0) || (MVE_USED != 0)
ldrsb lr,[r4,#TCB_SF_OFS] // Load stack frame information
b SVC_FP_LazyState // Branch to FP lazy state handling
.else
b SVC_ContextRestore // Branch to context restore handling
.endif
SVC_ContextSaveRegs:
ldrsb lr,[r1,#TCB_SF_OFS] // Load stack frame information
#if (DOMAIN_NS != 0)
tst lr,#0x40 // Check domain of interrupted thread
bne SVC_ContextRestore // Branch if secure
#endif
ldr r12,[r1,#TCB_SP_OFS] // Load SP
.if (FPU_USED != 0) || (MVE_USED != 0)
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
vstmiaeq r12!,{s16-s31} // Save VFP S16..S31
.endif
stm r12,{r4-r11} // Save R4..R11
#else
stmdb r12!,{r4-r11} // Save R4..R11
.if (FPU_USED != 0) || (MVE_USED != 0)
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
vstmdbeq r12!,{s16-s31} // Save VFP S16.S31
.endif
SVC_ContextSaveSP:
str r12,[r1,#TCB_SP_OFS] // Store SP
strb lr, [r1,#TCB_SF_OFS] // Store stack frame information
#endif // RTX_STACK_CHECK
SVC_ContextRestore:
movs r4,r2 // Assign osRtxInfo.thread.run.next to R4, clear Z flag
#ifdef RTX_EXECUTION_ZONE
ldrb r0,[r2,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.next: zone
cbz r1,SVC_ZoneSetup // Branch if running thread is deleted (Z flag unchanged)
ldrb r1,[r1,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.curr: zone
cmp r0,r1 // Check if next:zone == curr:zone
SVC_ZoneSetup:
it ne // If zone has changed or running thread is deleted
blne osZoneSetup_Callback // Setup zone for next thread
#endif // RTX_EXECUTION_ZONE
#ifdef RTX_TZ_CONTEXT
ldr r0,[r4,#TCB_TZM_OFS] // Load TrustZone memory identifier
cmp r0,#0
it ne // If TrustZone memory allocated
blne TZ_LoadContext_S // Load secure context
#endif
ldr r0,[r4,#TCB_SP_OFS] // Load SP
ldr r1,[r4,#TCB_SM_OFS] // Load stack memory base
msr psplim,r1 // Set PSPLIM
ldrsb lr,[r4,#TCB_SF_OFS] // Load stack frame information
#if (DOMAIN_NS != 0)
tst lr,#0x40 // Check domain of interrupted thread
itt ne // If secure
msrne psp,r0 // Set PSP
bxne lr // Exit from handler
#endif
.if (FPU_USED != 0) || (MVE_USED != 0)
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
vldmiaeq r0!,{s16-s31} // Restore VFP S16..S31
.endif
ldmia r0!,{r4-r11} // Restore R4..R11
msr psp,r0 // Set PSP
SVC_Exit:
bx lr // Exit from handler
SVC_User:
ldr r2,=osRtxUserSVC // Load address of SVC table
ldr r3,[r2] // Load SVC maximum number
cmp r1,r3 // Check SVC number range
bhi SVC_Exit // Branch if out of range
push {r0,lr} // Save SP and EXC_RETURN
ldr r12,[r2,r1,lsl #2] // Load address of SVC function
ldm r0,{r0-r3} // Load function parameters from stack
blx r12 // Call service function
pop {r12,lr} // Restore SP and EXC_RETURN
str r0,[r12] // Store function return value
bx lr // Return from handler
.fnend
.size SVC_Handler, .-SVC_Handler
.thumb_func
.type PendSV_Handler, %function
.global PendSV_Handler
.fnstart
.cantunwind
PendSV_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxPendSV_Handler // Call osRtxPendSV_Handler
pop {r0,lr} // Restore EXC_RETURN
mrs r12,psp // Save PSP to R12
b SVC_Context // Branch to context handling
.fnend
.size PendSV_Handler, .-PendSV_Handler
.thumb_func
.type SysTick_Handler, %function
.global SysTick_Handler
.fnstart
.cantunwind
SysTick_Handler:
push {r0,lr} // Save EXC_RETURN
bl osRtxTick_Handler // Call osRtxTick_Handler
pop {r0,lr} // Restore EXC_RETURN
mrs r12,psp // Save PSP to R12
b SVC_Context // Branch to context handling
.fnend
.size SysTick_Handler, .-SysTick_Handler
#ifdef RTX_SAFETY_FEATURES
.thumb_func
.type osFaultResume, %function
.global osFaultResume
.fnstart
.cantunwind
osFaultResume:
mrs r12,psp // Save PSP to R12
b SVC_Context // Branch to context handling
.fnend
.size osFaultResume, .-osFaultResume
#endif // RTX_SAFETY_FEATURES
.end