mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-09-01 11:53:53 -04:00
Add ARMv7-R MPU Port (#938)
* Apply git review patch created by @aggargr * Add necessary changes to the CMakeLists.txt file to build the port
This commit is contained in:
parent
839ccb719b
commit
61111b1460
10 changed files with 3022 additions and 2 deletions
498
portable/GCC/ARM_CRx_MPU/portASM.S
Normal file
498
portable/GCC/ARM_CRx_MPU/portASM.S
Normal file
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
*/
|
||||
|
||||
.arm
|
||||
.syntax unified
|
||||
.section privileged_functions
|
||||
|
||||
#define FREERTOS_ASSEMBLY
|
||||
#include "portmacro_asm.h"
|
||||
#include "mpu_syscall_numbers.h"
|
||||
#undef FREERTOS_ASSEMBLY
|
||||
|
||||
/* External FreeRTOS-Kernel variables. */
|
||||
.extern pxCurrentTCB
|
||||
.extern uxSystemCallImplementations
|
||||
.extern ulPortInterruptNesting
|
||||
.extern ulPortYieldRequired
|
||||
|
||||
/* External Llnker script variables. */
|
||||
.extern __syscalls_flash_start__
|
||||
.extern __syscalls_flash_end__
|
||||
|
||||
/* External FreeRTOS-Kernel functions. */
|
||||
.extern vTaskSwitchContext
|
||||
.extern vApplicationIRQHandler
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/* Save the context of a FreeRTOS Task. */
|
||||
.macro portSAVE_CONTEXT
|
||||
DSB
|
||||
ISB
|
||||
/* Push R0 and LR to the stack for current mode. */
|
||||
PUSH { R0, LR }
|
||||
|
||||
LDR LR, =pxCurrentTCB /* LR = &( pxCurrentTCB ). */
|
||||
LDR LR, [LR] /* LR = pxCurrentTCB. */
|
||||
LDR LR, [LR] /* LR = pxTopOfStack i.e. the address where to store the task context. */
|
||||
|
||||
LDR R0, =ulCriticalNesting /* R0 = &( ulCriticalNesting ). */
|
||||
LDR R0, [R0] /* R0 = ulCriticalNesting. */
|
||||
STM LR!, { R0 } /* Store ulCriticalNesting. ! increments LR after storing. */
|
||||
|
||||
#if ( portENABLE_FPU == 1 )
|
||||
VMRS R0, FPSCR /* R0 = FPSCR. */
|
||||
STM LR!, { R0 } /* Store FPSCR. */
|
||||
VSTM LR!, { D0-D15 } /* Store D0-D15. */
|
||||
#endif /* ( portENABLE_FPU == 1 ) */
|
||||
|
||||
POP { R0 } /* Restore R0 to pre-exception value. */
|
||||
/* STM (user registers) - In a PL1 mode other than System mode, STM (user
|
||||
* registers) instruction stores multiple User mode registers to
|
||||
* consecutive memory locations using an address from a base register. The
|
||||
* processor reads the base register value normally, using the current mode
|
||||
* to determine the correct Banked version of the register. This instruction
|
||||
* cannot writeback to the base register.
|
||||
*
|
||||
* The following can be derived from the above description:
|
||||
* - The macro portSAVE_CONTEXT MUST be called from a PL1 mode other than
|
||||
* the System mode.
|
||||
* - Base register LR of the current mode will be used which contains the
|
||||
* location to store the context.
|
||||
* - It will store R0-R14 of User mode i.e. pre-exception SP(R13) and LR(R14)
|
||||
* will be stored. */
|
||||
STM LR, { R0-R14 }^
|
||||
ADD LR, LR, #60 /* R0-R14 - Total 155 register, each 4 byte wide. */
|
||||
|
||||
POP { R0 } /* Pre-exception PC is in R0. */
|
||||
MRS R1, SPSR /* R1 = Pre-exception CPSR. */
|
||||
STM LR!, { R0-R1 } /* Store pre-exception PC and CPSR. */
|
||||
|
||||
.endm
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/* Restore the context of a FreeRTOS Task. */
|
||||
.macro portRESTORE_CONTEXT
|
||||
/* Load the pointer to the current task's Task Control Block (TCB). */
|
||||
LDR LR, =pxCurrentTCB /* LR = &( pxCurrentTCB ). */
|
||||
LDR LR, [LR] /* LR = pxCurrentTCB. */
|
||||
ADD R1, LR, #0x4 /* R1 now points to the xMPUSettings in TCB. */
|
||||
LDR LR, [LR] /* LR = pxTopOfStack i.e. the address where to restore the task context from. */
|
||||
|
||||
/* When creating a loop label in a macro it has to be a numeric label.
|
||||
* for( R5 = portFIRST_CONFIGURABLE_REGION ; R5 <= portNUM_CONFIGURABLE_REGIONS ; R5++ ) */
|
||||
MOV R5, #portFIRST_CONFIGURABLE_REGION
|
||||
123:
|
||||
LDMIA R1!, { R2-R4 } /* R2 = ulRegionSize, R3 = ulRegionAttribute, R4 = ulRegionBaseAddress. */
|
||||
|
||||
MCR p15, #0, R5, c6, c2, #0 /* MPU Region Number Register. */
|
||||
MCR p15, #0, R4, c6, c1, #0 /* MPU Region Base Address Register. */
|
||||
MCR p15, #0, R3, c6, c1, #4 /* MPU Region Access Control Register. */
|
||||
MCR p15, #0, R2, c6, c1, #2 /* MPU Region Size and Enable Register. */
|
||||
|
||||
ADD R5, R5, #1
|
||||
CMP R5, #portNUM_CONFIGURABLE_REGIONS
|
||||
BLE 123b
|
||||
|
||||
LDR R1, =ulCriticalNesting /* R1 = &( ulCriticalNesting ). */
|
||||
LDM LR!, { R2 } /* R2 = Stored ulCriticalNesting. */
|
||||
STR R2, [R1] /* Restore ulCriticalNesting. */
|
||||
|
||||
#if ( portENABLE_FPU == 1 )
|
||||
LDM LR!, { R1 } /* R1 = Stored FPSCR. */
|
||||
VMSR FPSCR, R1 /* Restore FPSCR. */
|
||||
VLDM LR!, { D0-D15 } /* Restore D0-D15. */
|
||||
#endif /* portENABLE_FPU*/
|
||||
|
||||
/* LDM (User registers) - In a PL1 mode other than System mode, LDM (User
|
||||
* registers) loads multiple User mode registers from consecutive memory
|
||||
* locations using an address from a base register. The registers loaded
|
||||
* cannot include the PC. The processor reads the base register value
|
||||
* normally, using the current mode to determine the correct Banked version
|
||||
* of the register. This instruction cannot writeback to the base register.
|
||||
*
|
||||
* The following can be derived from the above description:
|
||||
* - The macro portRESTORE_CONTEXT MUST be called from a PL1 mode other than
|
||||
* the System mode.
|
||||
* - Base register LR of the current mode will be used which contains the
|
||||
* location to restore the context from.
|
||||
* - It will restore R0-R14 of User mode i.e. SP(R13) and LR(R14) of User
|
||||
* mode will be restored.
|
||||
*/
|
||||
LDM LR, { R0-R14 }^
|
||||
ADD LR, LR, #60 /* R0-R14 - Total 155 register, each 4 byte wide. */
|
||||
|
||||
RFE LR /* Restore PC and CPSR from the context. */
|
||||
|
||||
.endm
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vPortStartFirstTask( void );
|
||||
*/
|
||||
.align 4
|
||||
.global vPortStartFirstTask
|
||||
.type vPortStartFirstTask, %function
|
||||
vPortStartFirstTask:
|
||||
/* This function is called from System Mode to start the FreeRTOS-Kernel.
|
||||
* As described in the portRESTORE_CONTEXT macro, portRESTORE_CONTEXT cannot
|
||||
* be called from the System mode. We, therefore, switch to the Supervisor
|
||||
* mode before calling portRESTORE_CONTEXT. */
|
||||
CPS #SVC_MODE
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
.align 4
|
||||
.global FreeRTOS_SVC_Handler
|
||||
.type FreeRTOS_SVC_Handler, %function
|
||||
FreeRTOS_SVC_Handler:
|
||||
PUSH { R11-R12 }
|
||||
|
||||
/* ------------------------- Caller Flash Location Check ------------------------- */
|
||||
|
||||
LDR R11, =__syscalls_flash_start__
|
||||
LDR R12, =__syscalls_flash_end__
|
||||
CMP LR, R11 /* If SVC instruction address is less than __syscalls_flash_start__, exit. */
|
||||
BLT svcHandlerExit
|
||||
CMP LR, R12 /* If SVC instruction address is greater than __syscalls_flash_end__, exit. */
|
||||
BGT svcHandlerExit
|
||||
|
||||
/* ---------------------------- Get Caller SVC Number ---------------------------- */
|
||||
|
||||
MRS R11, SPSR /* LR = CPSR at the time of SVC. */
|
||||
TST R11, #0x20 /* Check Thumb bit (5) in CPSR. */
|
||||
LDRHNE R11, [LR, #-0x2] /* If Thumb, load halfword. */
|
||||
BICNE R11, R11, #0xFF00 /* And extract immidiate field (i.e. SVC number). */
|
||||
LDREQ R11, [LR, #-0x4] /* If ARM, load word. */
|
||||
BICEQ R11, R11, #0xFF000000 /* And extract immidiate field (i.e. SVC number). */
|
||||
|
||||
/* --------------------------------- SVC Routing --------------------------------- */
|
||||
|
||||
/* If SVC Number < #NUM_SYSTEM_CALLS, go to svcSystemCallEnter. */
|
||||
CMP R11, #NUM_SYSTEM_CALLS
|
||||
BLT svcSystemCallEnter
|
||||
|
||||
/* If SVC Number == #portSVC_SYSTEM_CALL_EXIT, go to svcSystemCallExit. */
|
||||
CMP R11, #portSVC_SYSTEM_CALL_EXIT
|
||||
BEQ svcSystemCallExit
|
||||
|
||||
/* If SVC Number == #portSVC_YIELD, go to svcPortYield. */
|
||||
CMP R11, #portSVC_YIELD
|
||||
BEQ svcPortYield
|
||||
|
||||
svcHandlerExit:
|
||||
POP { R11-R12 }
|
||||
MOVS PC, LR /* Copies the SPSR into the CPSR, performing the mode swap. */
|
||||
|
||||
svcPortYield:
|
||||
POP { R11-R12 }
|
||||
portSAVE_CONTEXT
|
||||
BL vTaskSwitchContext
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
svcSystemCallExit:
|
||||
LDR R11, =pxCurrentTCB /* R11 = &( pxCurrentTCB ). */
|
||||
LDR R11, [R11] /* R11 = pxCurrentTCB. */
|
||||
ADD R11, R11, #portSYSTEM_CALL_INFO_OFFSET /* R11 now points to xSystemCallStackInfo in TCB. */
|
||||
|
||||
/* Restore the user mode SP and LR. */
|
||||
LDM R11, { R13-R14 }^
|
||||
|
||||
AND R12, R12, #0x0 /* R12 = 0. */
|
||||
STR R12, [R11] /* xSystemCallStackInfo.pulTaskStackPointer = NULL. */
|
||||
STR R12, [R11, #0x4] /* xSystemCallStackInfo.pulLinkRegisterAtSystemCallEntry = NULL. */
|
||||
|
||||
LDMDB R11, { R12 } /* R12 = ulTaskFlags. */
|
||||
|
||||
TST R12, #portTASK_IS_PRIVILEGED_FLAG
|
||||
/* If the task is privileged, we can exit now. */
|
||||
BNE svcHandlerExit
|
||||
/* Otherwise, we need to switch back to User mode. */
|
||||
MRS R12, SPSR
|
||||
BIC R12, R12, #0x0F
|
||||
MSR SPSR_cxsf, R12
|
||||
|
||||
B svcHandlerExit
|
||||
|
||||
svcSystemCallEnter:
|
||||
LDR R12, =uxSystemCallImplementations /* R12 = uxSystemCallImplementations. */
|
||||
/* R12 = uxSystemCallImplementations[ R12 + ( R11 << 2 ) ].
|
||||
* R12 now contains the address of the system call impl function. */
|
||||
LDR R12, [R12, R11, lsl #2]
|
||||
|
||||
/* If R12 == NULL, exit. */
|
||||
CMP R12, #0x0
|
||||
BEQ svcHandlerExit
|
||||
|
||||
/* It is okay to clobber LR here because we do not need to return to the
|
||||
* SVC enter location anymore. LR now contains the address of the system
|
||||
* call impl function. */
|
||||
MOV LR, R12
|
||||
|
||||
LDR R11, =pxCurrentTCB /* R11 = &( pxCurrentTCB ). */
|
||||
LDR R11, [R11] /* R11 = pxCurrentTCB. */
|
||||
ADD R11, R11, #portSYSTEM_CALL_INFO_OFFSET /* R11 now points to xSystemCallStackInfo in TCB. */
|
||||
|
||||
/* Store User mode SP and LR in xSystemCallStackInfo.pulTaskStackPointer and
|
||||
* xSystemCallStackInfo.pulLinkRegisterAtSystemCallEntry. */
|
||||
STM R11, { R13-R14 }^
|
||||
ADD R11, R11, 0x8
|
||||
|
||||
/* Load User mode SP an LR with xSystemCallStackInfo.pulSystemCallStackPointer
|
||||
* and xSystemCallStackInfo.pulSystemCallExitAddress. */
|
||||
LDM R11, { R13-R14 }^
|
||||
|
||||
/* Change to SYS_MODE for the System Call. */
|
||||
MRS R12, SPSR
|
||||
ORR R12, R12, #SYS_MODE
|
||||
MSR SPSR_cxsf, R12
|
||||
|
||||
B svcHandlerExit
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vPortDisableInterrupts( void );
|
||||
*/
|
||||
.align 4
|
||||
.global vPortDisableInterrupts
|
||||
.type vPortDisableInterrupts, %function
|
||||
vPortDisableInterrupts:
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vPortEnableInterrupts( void );
|
||||
*/
|
||||
.align 4
|
||||
.global vPortEnableInterrupts
|
||||
.type vPortEnableInterrupts, %function
|
||||
vPortEnableInterrupts:
|
||||
CPSIE I
|
||||
BX LR
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vMPUSetRegion( uint32_t ulRegionNumber,
|
||||
* uint32_t ulBaseAddress,
|
||||
* uint32_t ulRegionSize,
|
||||
* uint32_t ulRegionPermissions );
|
||||
*
|
||||
* According to the Procedure Call Standard for the ARM Architecture (AAPCS),
|
||||
* paramters are passed in the following registers:
|
||||
* R0 = ulRegionNumber.
|
||||
* R1 = ulBaseAddress.
|
||||
* R2 = ulRegionSize.
|
||||
* R3 = ulRegionPermissions.
|
||||
*/
|
||||
.align 4
|
||||
.global vMPUSetRegion
|
||||
.type vMPUSetRegion, %function
|
||||
vMPUSetRegion:
|
||||
AND R0, R0, #0x0F /* R0 = R0 & 0x0F. Max possible region number is 15. */
|
||||
|
||||
MCR p15, #0, R0, c6, c2, #0 /* MPU Region Number Register. */
|
||||
MCR p15, #0, R1, c6, c1, #0 /* MPU Region Base Address Register. */
|
||||
MCR p15, #0, R3, c6, c1, #4 /* MPU Region Access Control Register. */
|
||||
MCR p15, #0, R2, c6, c1, #2 /* MPU Region Size and Enable Register. */
|
||||
|
||||
BX LR
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vMPUEnable( void );
|
||||
*/
|
||||
.align 4
|
||||
.global vMPUEnable
|
||||
.type vMPUEnable, %function
|
||||
vMPUEnable:
|
||||
PUSH { R0 }
|
||||
|
||||
MRC p15, #0, R0, c1, c0, #0 /* R0 = System Control Register (SCTLR). */
|
||||
ORR R0, R0, #0x1 /* R0 = R0 | 0x1. Set the M bit in SCTLR. */
|
||||
DSB
|
||||
MCR p15, #0, R0, c1, c0, #0 /* SCTLR = R0. */
|
||||
ISB
|
||||
|
||||
POP { R0 }
|
||||
BX LR
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vMPUDisable( void );
|
||||
*/
|
||||
.align 4
|
||||
.global vMPUDisable
|
||||
.type vMPUDisable, %function
|
||||
vMPUDisable:
|
||||
PUSH { R0 }
|
||||
|
||||
MRC p15, #0, R0, c1, c0, #0 /* R0 = System Control Register (SCTLR). */
|
||||
BIC R0, R0, #1 /* R0 = R0 & ~0x1. Clear the M bit in SCTLR. */
|
||||
/* Wait for all pending data accesses to complete. */
|
||||
DSB
|
||||
MCR p15, #0, R0, c1, c0, #0 /* SCTLR = R0. */
|
||||
/* Flush the pipeline and prefetch buffer(s) in the processor to ensure that
|
||||
* all following instructions are fetched from cache or memory. */
|
||||
ISB
|
||||
|
||||
POP { R0 }
|
||||
BX LR
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vMPUEnableBackgroundRegion( void );
|
||||
*/
|
||||
.align 4
|
||||
.global vMPUEnableBackgroundRegion
|
||||
.type vMPUEnableBackgroundRegion, %function
|
||||
vMPUEnableBackgroundRegion:
|
||||
PUSH { R0 }
|
||||
|
||||
MRC p15, #0, R0, c1, c0, #0 /* R0 = System Control Register (SCTLR). */
|
||||
ORR R0, R0, #0x20000 /* R0 = R0 | 0x20000. Set the BR bit in SCTLR. */
|
||||
MCR p15, #0, R0, c1, c0, #0 /* SCTLR = R0. */
|
||||
|
||||
POP { R0 }
|
||||
BX LR
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* void vMPUDisableBackgroundRegion( void );
|
||||
*/
|
||||
.align 4
|
||||
.global vMPUDisableBackgroundRegion
|
||||
.type vMPUDisableBackgroundRegion, %function
|
||||
vMPUDisableBackgroundRegion:
|
||||
PUSH { R0 }
|
||||
|
||||
MRC p15, 0, R0, c1, c0, 0 /* R0 = System Control Register (SCTLR). */
|
||||
BIC R0, R0, #0x20000 /* R0 = R0 & ~0x20000. Clear the BR bit in SCTLR. */
|
||||
MCR p15, 0, R0, c1, c0, 0 /* SCTLR = R0. */
|
||||
|
||||
POP { R0 }
|
||||
BX LR
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
.align 4
|
||||
.global FreeRTOS_IRQ_Handler
|
||||
.type FreeRTOS_IRQ_Handler, %function
|
||||
FreeRTOS_IRQ_Handler:
|
||||
SUB LR, LR, #4 /* Return to the interrupted instruction. */
|
||||
SRSDB SP!, #IRQ_MODE /* Save return state (i.e. SPSR_irq and LR_irq) to the IRQ stack. */
|
||||
|
||||
/* Change to supervisor mode to allow reentry. It is necessary to ensure
|
||||
* that a BL instruction within the interrupt handler code does not
|
||||
* overwrite LR_irq. */
|
||||
CPS #SVC_MODE
|
||||
|
||||
PUSH { R0-R3, R12 } /* Push AAPCS callee saved registers. */
|
||||
|
||||
/* Update interrupt nesting count. */
|
||||
LDR R0, =ulPortInterruptNesting /* R0 = &( ulPortInterruptNesting ). */
|
||||
LDR R1, [R0] /* R1 = ulPortInterruptNesting. */
|
||||
ADD R2, R1, #1 /* R2 = R1 + 1. */
|
||||
STR R2, [R0] /* Store the updated nesting count. */
|
||||
|
||||
/* Call the application provided IRQ handler. */
|
||||
PUSH { R0-R3, LR }
|
||||
BL vApplicationIRQHandler
|
||||
POP { R0-R3, LR }
|
||||
|
||||
/* Disable IRQs incase vApplicationIRQHandler enabled them for re-entry. */
|
||||
CPSID I
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* Restore the old interrupt nesting count. R0 holds the address of
|
||||
* ulPortInterruptNesting and R1 holds original value of
|
||||
* ulPortInterruptNesting. */
|
||||
STR R1, [R0]
|
||||
|
||||
/* Context swtich is only performed when interrupt nesting count is 0. */
|
||||
CMP R1, #0
|
||||
BNE exit_without_switch
|
||||
|
||||
/* Check ulPortInterruptNesting to see if the interrupt requested a context
|
||||
* switch. */
|
||||
LDR R1, =ulPortYieldRequired /* R1 = &( ulPortYieldRequired ). */
|
||||
LDR R0, [R1] /* R0 = ulPortYieldRequired. */
|
||||
/* If ulPortYieldRequired != 0, goto switch_before_exit. */
|
||||
CMP R0, #0
|
||||
BNE switch_before_exit
|
||||
|
||||
exit_without_switch:
|
||||
POP { R0-R3, R12 } /* Restore AAPCS callee saved registers. */
|
||||
CPS #IRQ_MODE
|
||||
RFE SP!
|
||||
|
||||
switch_before_exit:
|
||||
/* A context swtich is to be performed. Clear ulPortYieldRequired. R1 holds
|
||||
* the address of ulPortYieldRequired. */
|
||||
MOV R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* Restore AAPCS callee saved registers, SPSR_irq and LR_irq before saving
|
||||
* the task context. */
|
||||
POP { R0-R3, R12 }
|
||||
CPS #IRQ_MODE
|
||||
/* The contents of the IRQ stack at this point is the following:
|
||||
* +----------+
|
||||
* SP+4 | SPSR_irq |
|
||||
* +----------+
|
||||
* SP | LR_irq |
|
||||
* +----------+
|
||||
*/
|
||||
LDMIB SP!, { LR }
|
||||
MSR SPSR_cxsf, LR
|
||||
LDMDB SP, { LR }
|
||||
ADD SP, SP, 0x4
|
||||
portSAVE_CONTEXT
|
||||
|
||||
/* Call the function that selects the new task to execute. */
|
||||
BLX vTaskSwitchContext
|
||||
|
||||
/* Restore the context of, and branch to, the task selected to execute
|
||||
* next. */
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
/* ----------------------------------------------------------------------------------- */
|
||||
|
||||
.end
|
Loading…
Add table
Add a link
Reference in a new issue