ARM CM0+ MPU Port (#1005)

* Add MPU Support to the ARM CM0+ GCC Port.
* Co-authored by @aggarg
pull/1016/head^2
Soren Ptak 10 months ago committed by GitHub
parent 625b24a104
commit 345a86d49b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -634,6 +634,7 @@ PREB
PRIA PRIA
Prioritised Prioritised
PRIS PRIS
PRIVDEFENA
PROCDLY PROCDLY
PRODH PRODH
PRODL PRODL

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,523 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 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
*
*/
/* Standard includes. */
#include <stdint.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE ensures that PRIVILEGED_FUNCTION
* is defined correctly and privileged functions are placed in correct sections. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* Portasm includes. */
#include "portasm.h"
/* System call numbers includes. */
#include "mpu_syscall_numbers.h"
/* MPU_WRAPPERS_INCLUDED_FROM_API_FILE is needed to be defined only for the
* header files. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configENABLE_MPU == 1 )
void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .extern pxCurrentTCB \n"
" .syntax unified \n"
" \n"
" program_mpu_first_task: \n"
" \n"
" ldr r3, =pxCurrentTCB \n" /* r3 = &pxCurrentTCB. */
" ldr r0, [r3] \n" /* r0 = pxCurrentTCB.*/
" adds r0, #4 \n" /* r0 = Second item in the TCB which is xMPUSettings. */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" movs r3, #1 \n" /* r3 = 1. */
" bics r2, r3 \n" /* r2 = r2 & ~r3 i.e. Clear the bit 0 in r2. */
" str r2, [r1] \n" /* Disable MPU. */
" \n"
" ldr r1, =0xe000ed9c \n" /* r1 = 0xe000ed9c [Location of RBAR]. */
" ldr r2, =0xe000eda0 \n" /* r2 = 0xe000eda0 [Location of RASR]. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read first set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read second set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read third set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read fourth set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read fifth set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" movs r3, #1 \n" /* r3 = 1. */
" orrs r2, r3 \n" /* r2 = r2 | r3 i.e. Set the bit 0 in r2. */
" str r2, [r1] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" restore_context_first_task: \n"
" ldr r2, =pxCurrentTCB \n" /* r2 = &pxCurrentTCB. */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB.*/
" ldr r1, [r0] \n" /* r1 = Location of saved context in TCB. */
" \n"
" restore_special_regs_first_task: \n"
" subs r1, #12 \n"
" ldmia r1!, {r2-r4} \n" /* r2 = original PSP, r3 = CONTROL, r4 = LR. */
" subs r1, #12 \n"
" msr psp, r2 \n"
" msr control, r3 \n"
" mov lr, r4 \n"
" \n"
" restore_general_regs_first_task: \n"
" subs r1, #32 \n"
" ldmia r1!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */
" stmia r2!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */
" ldmia r1!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */
" stmia r2!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */
" subs r1, #48 \n"
" ldmia r1!, {r4-r7} \n" /* Restore r8-r11. */
" mov r8, r4 \n" /* r8 = r4. */
" mov r9, r5 \n" /* r9 = r5. */
" mov r10, r6 \n" /* r10 = r6. */
" mov r11, r7 \n" /* r11 = r7. */
" subs r1, #32 \n"
" ldmia r1!, {r4-r7} \n" /* Restore r4-r7. */
" subs r1, #16 \n"
" \n"
" restore_context_done_first_task: \n"
" str r1, [r0] \n" /* Save the location where the context should be saved next as the first member of TCB. */
" bx lr \n"
" \n"
" .align 4 \n"
::"i" ( portSVC_START_SCHEDULER ) : "memory"
);
}
#else /* configENABLE_MPU */
void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .extern pxCurrentTCB \n"
" .syntax unified \n"
" \n"
" ldr r2, =pxCurrentTCB \n" /* r2 = &pxCurrentTCB. */
" ldr r1, [r2] \n" /* r1 = pxCurrentTCB.*/
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
" \n"
" ldm r0!, {r2} \n" /* Read from stack - r2 = EXC_RETURN. */
" movs r1, #2 \n" /* r1 = 2. */
" msr CONTROL, r1 \n" /* Switch to use PSP in the thread mode. */
" adds r0, #32 \n" /* Discard everything up to r0. */
" msr psp, r0 \n" /* This is now the new top of stack to use in the task. */
" isb \n"
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
" \n"
" .align 4 \n"
);
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, control \n" /* r0 = CONTROL. */
" movs r1, #1 \n" /* r1 = 1. */
" tst r0, r1 \n" /* Perform r0 & r1 (bitwise AND) and update the conditions flag. */
" beq running_privileged \n" /* If the result of previous AND operation was 0, branch. */
" movs r0, #0 \n" /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
" bx lr \n" /* Return. */
" running_privileged: \n"
" movs r0, #1 \n" /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */
" bx lr \n" /* Return. */
" \n"
" .align 4 \n"
::: "r0", "r1", "memory"
);
}
/*-----------------------------------------------------------*/
void vRaisePrivilege( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, control \n" /* Read the CONTROL register. */
" movs r1, #1 \n" /* r1 = 1. */
" bics r0, r1 \n" /* Clear the bit 0. */
" msr control, r0 \n" /* Write back the new CONTROL value. */
" bx lr \n" /* Return to the caller. */
::: "r0", "r1", "memory"
);
}
/*-----------------------------------------------------------*/
void vResetPrivilege( void ) /* __attribute__ (( naked )) */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, control \n" /* r0 = CONTROL. */
" movs r1, #1 \n" /* r1 = 1. */
" orrs r0, r1 \n" /* r0 = r0 | r1. */
" msr control, r0 \n" /* CONTROL = r0. */
" bx lr \n" /* Return to the caller. */
::: "r0", "r1", "memory"
);
}
/*-----------------------------------------------------------*/
void vStartFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
/* Don't reset the MSP stack as is done on CM3/4 devices. The reason is that
* the Vector Table Offset Register (VTOR) is optional in CM0+ architecture
* and therefore, may not be available on all the devices. */
__asm volatile
(
" .syntax unified \n"
" cpsie i \n" /* Globally enable interrupts. */
" dsb \n"
" isb \n"
" svc %0 \n" /* System call to start the first task. */
" nop \n"
" \n"
" .align 4 \n"
::"i" ( portSVC_START_SCHEDULER ) : "memory"
);
}
/*-----------------------------------------------------------*/
uint32_t ulSetInterruptMask( void ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, PRIMASK \n"
" cpsid i \n"
" bx lr \n"
::: "memory"
);
}
/*-----------------------------------------------------------*/
void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" msr PRIMASK, r0 \n"
" bx lr \n"
::: "memory"
);
}
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .extern pxCurrentTCB \n"
" .syntax unified \n"
" \n"
" ldr r2, =pxCurrentTCB \n" /* r2 = &( pxCurrentTCB ). */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB. */
" ldr r1, [r0] \n" /* r1 = Location in TCB where the context should be saved. */
" mrs r2, psp \n" /* r2 = PSP. */
" \n"
" save_general_regs: \n"
" stmia r1!, {r4-r7} \n" /* Store r4-r7. */
" mov r4, r8 \n" /* r4 = r8. */
" mov r5, r9 \n" /* r5 = r9. */
" mov r6, r10 \n" /* r6 = r10. */
" mov r7, r11 \n" /* r7 = r11. */
" stmia r1!, {r4-r7} \n" /* Store r8-r11. */
" ldmia r2!, {r4-r7} \n" /* Copy half of the hardware saved context into r4-r7. */
" stmia r1!, {r4-r7} \n" /* Store the hardware saved context. */
" ldmia r2!, {r4-r7} \n" /* Copy rest half of the hardware saved context into r4-r7. */
" stmia r1!, {r4-r7} \n" /* Store the hardware saved context. */
" \n"
" save_special_regs: \n"
" mrs r2, psp \n" /* r2 = PSP. */
" mrs r3, control \n" /* r3 = CONTROL. */
" mov r4, lr \n" /* r4 = LR. */
" stmia r1!, {r2-r4} \n" /* Store original PSP (after hardware has saved context), CONTROL and LR. */
" str r1, [r0] \n" /* Save the location from where the context should be restored as the first member of TCB. */
" \n"
" select_next_task: \n"
" cpsid i \n"
" bl vTaskSwitchContext \n"
" cpsie i \n"
" \n"
" program_mpu: \n"
" \n"
" ldr r2, =pxCurrentTCB \n" /* r2 = &( pxCurrentTCB ). */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB. */
" adds r0, #4 \n" /* r0 = Second item in the TCB which is xMPUSettings. */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" movs r3, #1 \n" /* r3 = 1. */
" bics r2, r3 \n" /* r2 = r2 & ~r3 i.e. Clear the bit 0 in r2. */
" str r2, [r1] \n" /* Disable MPU */
" \n"
" ldr r1, =0xe000ed9c \n" /* r1 = 0xe000ed9c [Location of RBAR]. */
" ldr r2, =0xe000eda0 \n" /* r2 = 0xe000eda0 [Location of RASR]. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read first set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read second set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read third set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read fourth set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldmia r0!, {r3-r4} \n" /* Read fifth set of RBAR/RASR registers from TCB. */
" str r3, [r1] \n" /* Program RBAR. */
" str r4, [r2] \n" /* Program RASR. */
" \n"
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" movs r3, #1 \n" /* r3 = 1. */
" orrs r2, r3 \n" /* r2 = r2 | r3 i.e. Set the bit 0 in r2. */
" str r2, [r1] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" restore_context: \n"
" ldr r2, =pxCurrentTCB \n" /* r2 = &pxCurrentTCB. */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB.*/
" ldr r1, [r0] \n" /* r1 = Location of saved context in TCB. */
" \n"
" restore_special_regs: \n"
" subs r1, #12 \n"
" ldmia r1!, {r2-r4} \n" /* r2 = original PSP, r3 = CONTROL, r4 = LR. */
" subs r1, #12 \n"
" msr psp, r2 \n"
" msr control, r3 \n"
" mov lr, r4 \n"
" \n"
" restore_general_regs: \n"
" subs r1, #32 \n"
" ldmia r1!, {r4-r7} \n" /* r4-r7 contain half of the hardware saved context. */
" stmia r2!, {r4-r7} \n" /* Copy half of the the hardware saved context on the task stack. */
" ldmia r1!, {r4-r7} \n" /* r4-r7 contain rest half of the hardware saved context. */
" stmia r2!, {r4-r7} \n" /* Copy rest half of the the hardware saved context on the task stack. */
" subs r1, #48 \n"
" ldmia r1!, {r4-r7} \n" /* Restore r8-r11. */
" mov r8, r4 \n" /* r8 = r4. */
" mov r9, r5 \n" /* r9 = r5. */
" mov r10, r6 \n" /* r10 = r6. */
" mov r11, r7 \n" /* r11 = r7. */
" subs r1, #32 \n"
" ldmia r1!, {r4-r7} \n" /* Restore r4-r7. */
" subs r1, #16 \n"
" \n"
" restore_context_done: \n"
" str r1, [r0] \n" /* Save the location where the context should be saved next as the first member of TCB. */
" bx lr \n"
" \n"
" .align 4 \n"
);
}
#else /* configENABLE_MPU */
void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .extern pxCurrentTCB \n"
" .syntax unified \n"
" \n"
" mrs r0, psp \n" /* Read PSP in r0. */
" ldr r2, =pxCurrentTCB \n" /* r2 = &( pxCurrentTCB ). */
" ldr r1, [r2] \n" /* r1 = pxCurrentTCB. */
" subs r0, r0, #36 \n" /* Make space for LR and the remaining registers on the stack. */
" str r0, [r1] \n" /* Save the new top of stack in TCB. */
" \n"
" mov r3, lr \n" /* r3 = LR/EXC_RETURN. */
" stmia r0!, {r3-r7} \n" /* Store on the stack - LR and low registers that are not automatically saved. */
" mov r4, r8 \n" /* r4 = r8. */
" mov r5, r9 \n" /* r5 = r9. */
" mov r6, r10 \n" /* r6 = r10. */
" mov r7, r11 \n" /* r7 = r11. */
" stmia r0!, {r4-r7} \n" /* Store the high registers that are not saved automatically. */
" \n"
" cpsid i \n"
" bl vTaskSwitchContext \n"
" cpsie i \n"
" \n"
" ldr r2, =pxCurrentTCB \n" /* r2 = &( pxCurrentTCB ). */
" ldr r1, [r2] \n" /* r1 = pxCurrentTCB. */
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
" \n"
" adds r0, r0, #20 \n" /* Move to the high registers. */
" ldmia r0!, {r4-r7} \n" /* Restore the high registers that are not automatically restored. */
" mov r8, r4 \n" /* r8 = r4. */
" mov r9, r5 \n" /* r9 = r5. */
" mov r10, r6 \n" /* r10 = r6. */
" mov r11, r7 \n" /* r11 = r7. */
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
" subs r0, r0, #36 \n" /* Move to the starting of the saved context. */
" ldmia r0!, {r3-r7} \n" /* Read from stack - r3 = LR and r4-r7 restored. */
" bx r3 \n"
" \n"
" .align 4 \n"
);
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" .extern vPortSVCHandler_C \n"
" .extern vSystemCallEnter \n"
" .extern vSystemCallExit \n"
" .extern pxCurrentTCB \n"
" \n"
" movs r0, #4 \n"
" mov r1, lr \n"
" tst r0, r1 \n"
" beq stack_on_msp \n"
" \n"
" stack_on_psp: \n"
" mrs r0, psp \n"
" b route_svc \n"
" \n"
" stack_on_msp: \n"
" mrs r0, msp \n"
" b route_svc \n"
" \n"
" route_svc: \n"
" ldr r3, [r0, #24] \n"
" subs r3, #2 \n"
" ldrb r2, [r3, #0] \n"
" ldr r3, =%0 \n"
" cmp r2, r3 \n"
" blt system_call_enter \n"
" ldr r3, =%1 \n"
" cmp r2, r3 \n"
" beq system_call_exit \n"
" b vPortSVCHandler_C \n"
" \n"
" system_call_enter: \n"
" push {lr} \n"
" bl vSystemCallEnter \n"
" pop {pc} \n"
" \n"
" system_call_exit: \n"
" push {lr} \n"
" bl vSystemCallExit \n"
" pop {pc} \n"
" \n"
" .align 4 \n"
" \n"
: /* No outputs. */
: "i" ( NUM_SYSTEM_CALLS ), "i" ( portSVC_SYSTEM_CALL_EXIT )
: "r0", "r1", "r2", "r3", "memory"
);
}
#else /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" .extern vPortSVCHandler_C \n"
" \n"
" movs r0, #4 \n"
" mov r1, lr \n"
" tst r0, r1 \n"
" beq stacking_used_msp \n"
" \n"
" stacking_used_psp: \n"
" mrs r0, psp \n"
" b vPortSVCHandler_C \n"
" \n"
" stacking_used_msp: \n"
" mrs r0, msp \n"
" b vPortSVCHandler_C \n"
" \n"
" .align 4 \n"
);
}
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/

@ -0,0 +1,99 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 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
*
*/
#ifndef __PORT_ASM_H__
#define __PORT_ASM_H__
/* Scheduler includes. */
#include "FreeRTOS.h"
/* MPU wrappers includes. */
#include "mpu_wrappers.h"
/**
* @brief Restore the context of the first task so that the first task starts
* executing.
*/
void vRestoreContextOfFirstTask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Checks whether or not the processor is privileged.
*
* @return 1 if the processor is already privileged, 0 otherwise.
*/
BaseType_t xIsPrivileged( void ) __attribute__( ( naked ) );
/**
* @brief Raises the privilege level by clearing the bit 0 of the CONTROL
* register.
*
* @note This is a privileged function and should only be called from the kenrel
* code.
*
* Bit 0 of the CONTROL register defines the privilege level of Thread Mode.
* Bit[0] = 0 --> The processor is running privileged
* Bit[0] = 1 --> The processor is running unprivileged.
*/
void vRaisePrivilege( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Lowers the privilege level by setting the bit 0 of the CONTROL
* register.
*
* Bit 0 of the CONTROL register defines the privilege level of Thread Mode.
* Bit[0] = 0 --> The processor is running privileged
* Bit[0] = 1 --> The processor is running unprivileged.
*/
void vResetPrivilege( void ) __attribute__( ( naked ) );
/**
* @brief Starts the first task.
*/
void vStartFirstTask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Disables interrupts.
*/
uint32_t ulSetInterruptMask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Enables interrupts.
*/
void vClearInterruptMask( uint32_t ulMask ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief PendSV Exception handler.
*/
void PendSV_Handler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief SVC Handler.
*/
void SVC_Handler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
#endif /* __PORT_ASM_H__ */

@ -26,7 +26,6 @@
* *
*/ */
#ifndef PORTMACRO_H #ifndef PORTMACRO_H
#define PORTMACRO_H #define PORTMACRO_H
@ -36,17 +35,25 @@
#endif #endif
/* *INDENT-ON* */ /* *INDENT-ON* */
/*----------------------------------------------------------- /*------------------------------------------------------------------------------
* Port specific definitions. * Port specific definitions.
* *
* The settings in this file configure FreeRTOS correctly for the * The settings in this file configure FreeRTOS correctly for the given hardware
* given hardware and compiler. * and compiler.
* *
* These settings should not be altered. * These settings should not be altered.
*----------------------------------------------------------- *------------------------------------------------------------------------------
*/ */
/* Type definitions. */ #ifndef configENABLE_MPU
#error configENABLE_MPU must be defined in FreeRTOSConfig.h. Set configENABLE_MPU to 1 to enable the MPU or 0 to disable the MPU.
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
/**
* @brief Type definitions.
*/
#define portCHAR char #define portCHAR char
#define portFLOAT float #define portFLOAT float
#define portDOUBLE double #define portDOUBLE double
@ -60,33 +67,223 @@ typedef long BaseType_t;
typedef unsigned long UBaseType_t; typedef unsigned long UBaseType_t;
#if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS ) #if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
typedef uint16_t TickType_t; typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff #define portMAX_DELAY ( TickType_t ) 0xffff
#elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS ) #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
typedef uint32_t TickType_t; typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
* not need to be guarded with a critical section. */ * not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#else #else
#error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width. #error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width.
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Architecture specifics. */ /**
#define portSTACK_GROWTH ( -1 ) * Architecture specifics.
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) */
#define portBYTE_ALIGNMENT 8 #define portARCH_NAME "Cortex-M0+"
#define portDONT_DISCARD __attribute__( ( used ) ) #define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__( ( always_inline ) )
#endif
#define portDONT_DISCARD __attribute__( ( used ) )
/*-----------------------------------------------------------*/
/**
* @brief Extern declarations.
*/
extern BaseType_t xPortIsInsideInterrupt( void );
extern void vPortYield( void ) /* PRIVILEGED_FUNCTION */;
extern void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */;
extern void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */;
extern uint32_t ulSetInterruptMask( void ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */;
extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */;
#if ( configENABLE_MPU == 1 )
extern BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */;
extern void vResetPrivilege( void ) /* __attribute__ (( naked )) */;
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/**
* @brief MPU specific constants.
*/
#if ( configENABLE_MPU == 1 )
#define portUSING_MPU_WRAPPERS 1
#define portPRIVILEGE_BIT ( 0x80000000UL )
#else
#define portPRIVILEGE_BIT ( 0x0UL )
#endif /* configENABLE_MPU */
/* Shareable (S), Cacheable (C) and Bufferable (B) bits for flash region. */
#ifndef configS_C_B_FLASH
#define configS_C_B_FLASH ( 0x07UL )
#endif
/* Shareable (S), Cacheable (C) and Bufferable (B) bits for RAM region. */
#ifndef configS_C_B_SRAM
#define configS_C_B_SRAM ( 0x07UL )
#endif
/* MPU regions. */
#define portPRIVILEGED_RAM_REGION ( 7UL )
#define portPRIVILEGED_FLASH_REGION ( 6UL )
#define portUNPRIVILEGED_FLASH_REGION ( 5UL )
#define portSTACK_REGION ( 4UL )
#define portFIRST_CONFIGURABLE_REGION ( 0UL )
#define portLAST_CONFIGURABLE_REGION ( 3UL )
#define portNUM_CONFIGURABLE_REGIONS ( 4UL )
#define portTOTAL_NUM_REGIONS ( portNUM_CONFIGURABLE_REGIONS + 1UL ) /* Plus one to make space for the stack region. */
/* MPU region sizes. This information is encoded in the SIZE bits of the MPU
* Region Attribute and Size Register (RASR). */
#define portMPU_REGION_SIZE_256B ( 0x07UL << 1UL )
#define portMPU_REGION_SIZE_512B ( 0x08UL << 1UL )
#define portMPU_REGION_SIZE_1KB ( 0x09UL << 1UL )
#define portMPU_REGION_SIZE_2KB ( 0x0AUL << 1UL )
#define portMPU_REGION_SIZE_4KB ( 0x0BUL << 1UL )
#define portMPU_REGION_SIZE_8KB ( 0x0CUL << 1UL )
#define portMPU_REGION_SIZE_16KB ( 0x0DUL << 1UL )
#define portMPU_REGION_SIZE_32KB ( 0x0EUL << 1UL )
#define portMPU_REGION_SIZE_64KB ( 0x0FUL << 1UL )
#define portMPU_REGION_SIZE_128KB ( 0x10UL << 1UL )
#define portMPU_REGION_SIZE_256KB ( 0x11UL << 1UL )
#define portMPU_REGION_SIZE_512KB ( 0x12UL << 1UL )
#define portMPU_REGION_SIZE_1MB ( 0x13UL << 1UL )
#define portMPU_REGION_SIZE_2MB ( 0x14UL << 1UL )
#define portMPU_REGION_SIZE_4MB ( 0x15UL << 1UL )
#define portMPU_REGION_SIZE_8MB ( 0x16UL << 1UL )
#define portMPU_REGION_SIZE_16MB ( 0x17UL << 1UL )
#define portMPU_REGION_SIZE_32MB ( 0x18UL << 1UL )
#define portMPU_REGION_SIZE_64MB ( 0x19UL << 1UL )
#define portMPU_REGION_SIZE_128MB ( 0x1AUL << 1UL )
#define portMPU_REGION_SIZE_256MB ( 0x1BUL << 1UL )
#define portMPU_REGION_SIZE_512MB ( 0x1CUL << 1UL )
#define portMPU_REGION_SIZE_1GB ( 0x1DUL << 1UL )
#define portMPU_REGION_SIZE_2GB ( 0x1EUL << 1UL )
#define portMPU_REGION_SIZE_4GB ( 0x1FUL << 1UL )
/* MPU memory types. This information is encoded in the S ( Shareable), C
* (Cacheable) and B (Bufferable) bits of the MPU Region Attribute and Size
* Register (RASR). */
#define portMPU_REGION_STRONGLY_ORDERED_SHAREABLE ( 0x0UL << 16UL ) /* S=NA, C=0, B=0. */
#define portMPU_REGION_DEVICE_SHAREABLE ( 0x1UL << 16UL ) /* S=NA, C=0, B=1. */
#define portMPU_REGION_NORMAL_OIWTNOWA_NONSHARED ( 0x2UL << 16UL ) /* S=0, C=1, B=0. */
#define portMPU_REGION_NORMAL_OIWTNOWA_SHARED ( 0x6UL << 16UL ) /* S=1, C=1, B=0. */
#define portMPU_REGION_NORMAL_OIWBNOWA_NONSHARED ( 0x3UL << 16UL ) /* S=0, C=1, B=1.*/
#define portMPU_REGION_NORMAL_OIWBNOWA_SHARED ( 0x7UL << 16UL ) /* S=1, C=1, B=1.*/
/* MPU access permissions. This information is encoded in the AP and XN bits of
* the MPU Region Attribute and Size Register (RASR). */
#define portMPU_REGION_PRIV_NA_UNPRIV_NA ( 0x0UL << 24UL )
#define portMPU_REGION_PRIV_RW_UNPRIV_NA ( 0x1UL << 24UL )
#define portMPU_REGION_PRIV_RW_UNPRIV_RO ( 0x2UL << 24UL )
#define portMPU_REGION_PRIV_RW_UNPRIV_RW ( 0x3UL << 24UL )
#define portMPU_REGION_PRIV_RO_UNPRIV_NA ( 0x5UL << 24UL )
#define portMPU_REGION_PRIV_RO_UNPRIV_RO ( 0x6UL << 24UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x1UL << 28UL )
#if ( configENABLE_MPU == 1 )
/**
* @brief Settings to define an MPU region.
*/
typedef struct MPURegionSettings
{
uint32_t ulRBAR; /**< MPU Region Base Address Register (RBAR) for the region. */
uint32_t ulRASR; /**< MPU Region Attribute and Size Register (RASR) for the region. */
} MPURegionSettings_t;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
#ifndef configSYSTEM_CALL_STACK_SIZE
#error configSYSTEM_CALL_STACK_SIZE must be defined to the desired size of the system call stack in words for using MPU wrappers v2.
#endif
/**
* @brief System call stack.
*/
typedef struct SYSTEM_CALL_STACK_INFO
{
uint32_t ulSystemCallStackBuffer[ configSYSTEM_CALL_STACK_SIZE ];
uint32_t * pulSystemCallStack;
uint32_t * pulTaskStack;
uint32_t ulLinkRegisterAtSystemCallEntry;
} xSYSTEM_CALL_STACK_INFO;
#endif /* configUSE_MPU_WRAPPERS_V1 == 0 */
/**
* @brief MPU settings as stored in the TCB.
*/
/*
* +----------+-----------------+---------------+-----+
* | r4-r11 | r0-r3, r12, LR, | PSP, CONTROL | |
* | | PC, xPSR | EXC_RETURN | |
* +----------+-----------------+---------------+-----+
*
* <---------><----------------><---------------><---->
* 8 8 3 1
*/
#define CONTEXT_SIZE 20
/* Flags used for xMPU_SETTINGS.ulTaskFlags member. */
#define portSTACK_FRAME_HAS_PADDING_FLAG ( 1UL << 0UL )
#define portTASK_IS_PRIVILEGED_FLAG ( 1UL << 1UL )
/* Size of an Access Control List (ACL) entry in bits. */
#define portACL_ENTRY_SIZE_BITS ( 32U )
typedef struct MPU_SETTINGS
{
MPURegionSettings_t xRegionsSettings[ portTOTAL_NUM_REGIONS ]; /**< Settings for 4 per task regions. */
uint32_t ulContext[ CONTEXT_SIZE ];
uint32_t ulTaskFlags;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
xSYSTEM_CALL_STACK_INFO xSystemCallStackInfo;
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
uint32_t ulAccessControlList[ ( configPROTECTED_KERNEL_OBJECT_POOL_SIZE / portACL_ENTRY_SIZE_BITS ) + 1 ];
#endif
#endif
} xMPU_SETTINGS;
#endif /* configENABLE_MPU == 1 */
/*-----------------------------------------------------------*/
/**
* @brief SVC numbers.
*/
#define portSVC_START_SCHEDULER 100
#define portSVC_RAISE_PRIVILEGE 101
#define portSVC_SYSTEM_CALL_EXIT 102
#define portSVC_YIELD 103
/*-----------------------------------------------------------*/
/**
* @brief Scheduler utilities.
*/
#if ( configENABLE_MPU == 1 )
#define portYIELD() __asm volatile ( "svc %0" ::"i" ( portSVC_YIELD ) : "memory" )
#define portYIELD_WITHIN_API() vPortYield()
#else
#define portYIELD() vPortYield()
#define portYIELD_WITHIN_API() vPortYield()
#endif
/* Scheduler utilities. */
extern void vPortYield( void );
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) ) #define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portYIELD() vPortYield()
#define portEND_SWITCHING_ISR( xSwitchRequired ) \ #define portEND_SWITCHING_ISR( xSwitchRequired ) \
do \ do \
{ \ { \
@ -103,66 +300,84 @@ extern void vPortYield( void );
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/**
/* Critical section management. */ * @brief Critical section management.
extern void vPortEnterCritical( void ); */
extern void vPortExitCritical( void ); #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
extern uint32_t ulSetInterruptMaskFromISR( void ) __attribute__( ( naked ) ); #define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
extern void vClearInterruptMaskFromISR( uint32_t ulMask ) __attribute__( ( naked ) ); #define portDISABLE_INTERRUPTS() __asm volatile ( " cpsid i " ::: "memory" )
#define portENABLE_INTERRUPTS() __asm volatile ( " cpsie i " ::: "memory" )
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR() #define portENTER_CRITICAL() vPortEnterCritical()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMaskFromISR( x ) #define portEXIT_CRITICAL() vPortExitCritical()
#define portDISABLE_INTERRUPTS() __asm volatile ( " cpsid i " ::: "memory" )
#define portENABLE_INTERRUPTS() __asm volatile ( " cpsie i " ::: "memory" )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */ /**
* @brief Tickless idle/low power functionality.
*/
#ifndef portSUPPRESS_TICKS_AND_SLEEP #ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ); extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */ /**
* @brief Task function macros as described on the FreeRTOS.org website.
*/
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/
#define portNOP() #if ( configENABLE_MPU == 1 )
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" ) /**
* @brief Checks whether or not the processor is privileged.
*
* @return 1 if the processor is already privileged, 0 otherwise.
*/
#define portIS_PRIVILEGED() xIsPrivileged()
/**
* @brief Raise an SVC request to raise privilege.
*
* The SVC handler checks that the SVC was raised from a system call and only
* then it raises the privilege. If this is called from any other place,
* the privilege is not raised.
*/
#define portRAISE_PRIVILEGE() __asm volatile ( "svc %0 \n" ::"i" ( portSVC_RAISE_PRIVILEGE ) : "memory" );
#define portINLINE __inline /**
* @brief Lowers the privilege level by setting the bit 0 of the CONTROL
* register.
*/
#define portRESET_PRIVILEGE() vResetPrivilege()
#ifndef portFORCE_INLINE #else
#define portFORCE_INLINE inline __attribute__( ( always_inline ) )
#endif
#define portIS_PRIVILEGED()
#define portRAISE_PRIVILEGE()
#define portRESET_PRIVILEGE()
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void ) #if ( configENABLE_MPU == 1 )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */ extern BaseType_t xPortIsTaskPrivileged( void );
__asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" );
if( ulCurrentInterrupt == 0 ) /**
{ * @brief Checks whether or not the calling task is privileged.
xReturn = pdFALSE; *
} * @return pdTRUE if the calling task is privileged, pdFALSE otherwise.
else */
{ #define portIS_TASK_PRIVILEGED() xPortIsTaskPrivileged()
xReturn = pdTRUE;
}
return xReturn; #endif /* configENABLE_MPU == 1 */
} /*-----------------------------------------------------------*/
/**
* @brief Barriers.
*/
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* *INDENT-OFF* */ /* *INDENT-OFF* */

Loading…
Cancel
Save