From df9f0a9c69a034cca45fd28ef22e3a26d9d8bd81 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Mon, 28 Sep 2009 14:26:40 +0000 Subject: [PATCH] Added CM3 MPU demo. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@856 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../FreeRTOSConfig.h | 110 +++ .../CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Startup.s | 196 +++++ .../CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Target.js | 28 + Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzp | 52 ++ Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzs | 56 ++ .../flash_placement.xml | 24 + Demo/CORTEX_MPU_LM3Sxxxx_Rowley/main.c | 742 ++++++++++++++++++ Demo/CORTEX_MPU_LM3Sxxxx_Rowley/thumb_crt0.s | 233 ++++++ 8 files changed, 1441 insertions(+) create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/FreeRTOSConfig.h create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Startup.s create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Target.js create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzp create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzs create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/flash_placement.xml create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/main.c create mode 100644 Demo/CORTEX_MPU_LM3Sxxxx_Rowley/thumb_crt0.s diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/FreeRTOSConfig.h b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/FreeRTOSConfig.h new file mode 100644 index 000000000..c57ad43cd --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/FreeRTOSConfig.h @@ -0,0 +1,110 @@ +/* + FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation and modified by the FreeRTOS exception. + **NOTE** The exception to the GPL is included to allow you to distribute a + combined work that includes FreeRTOS without being obliged to provide the + source code for proprietary components outside of the FreeRTOS kernel. + Alternative commercial license and support terms are also available upon + request. See the licensing section of http://www.FreeRTOS.org for full + license details. + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59 + Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + + *************************************************************************** + * * + * Looking for a quick start? Then check out the FreeRTOS eBook! * + * See http://www.FreeRTOS.org/Documentation for details * + * * + *************************************************************************** + + 1 tab == 4 spaces! + + Please ensure to read the configuration and relevant port sections of the + online documentation. + + http://www.FreeRTOS.org - Documentation, latest information, license and + contact details. + + http://www.SafeRTOS.com - A version that is certified for use in safety + critical systems. + + http://www.OpenRTOS.com - Commercial support, development, porting, + licensing and training services. +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 1 +#define configCPU_CLOCK_HZ ( ( unsigned portLONG ) 50000000 ) +#define configTICK_RATE_HZ ( ( portTickType ) 1000 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 100 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 24000 ) ) +#define configMAX_TASK_NAME_LEN ( 12 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 10 +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_MALLOC_FAILED_HOOK 1 + +#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 + +#ifdef __NVIC_PRIO_BITS + #define configPRIO_BITS __NVIC_PRIO_BITS +#else + #define configPRIO_BITS 3 +#endif +#define configUNUSED_PRIO_BITS ( ( unsigned portCHAR ) ( 8 - configPRIO_BITS ) ) + +#define configKERNEL_INTERRUPT_PRIORITY ( ( unsigned portCHAR ) 7 << configUNUSED_PRIO_BITS ) /* Priority 7, or 255 as only the top three bits are implemented. This is the lowest priority. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( ( unsigned portCHAR ) 5 << configUNUSED_PRIO_BITS ) /* Priority 5, or 160 as only the top three bits are implemented. */ + +#define pvPortMallocAligned( x, puxStackBuffer ) ( ( puxStackBuffer == NULL ) ? ( pvPortMalloc( x ) ) : ( puxStackBuffer ) ) +#define vPortFreeAligned( x ) ( void ) x + +#endif /* FREERTOS_CONFIG_H */ diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Startup.s b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Startup.s new file mode 100644 index 000000000..cbf6ecf8c --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Startup.s @@ -0,0 +1,196 @@ +/***************************************************************************** + * Copyright (c) 2006 Rowley Associates Limited. * + * * + * This file may be distributed under the terms of the License Agreement * + * provided with this software. * + * * + * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE * + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + *****************************************************************************/ + +/***************************************************************************** + * Preprocessor Definitions + * ------------------------ + * + * STARTUP_FROM_RESET + * + * If defined, the program will startup from power-on/reset. If not defined + * the program will just loop endlessly from power-on/reset. + * + * This definition is not defined by default on this target because the + * debugger is unable to reset this target and maintain control of it over the + * JTAG interface. The advantage of doing this is that it allows the debugger + * to reset the CPU and run programs from a known reset CPU state on each run. + * It also acts as a safety net if you accidently download a program in FLASH + * that crashes and prevents the debugger from taking control over JTAG + * rendering the target unusable over JTAG. The obvious disadvantage of doing + * this is that your application will not startup without the debugger. + * + * We advise that on this target you keep STARTUP_FROM_RESET undefined whilst + * you are developing and only define STARTUP_FROM_RESET when development is + * complete. + * + *****************************************************************************/ + +.extern xPortPendSVHandler +.extern xPortSysTickHandler +.extern vPortSVCHandler + +.global reset_handler + +.macro DEFAULT_ISR_HANDLER name= + .thumb_func + .weak \name +\name: +1: b 1b /* endless loop */ +.endm + + .section .vectors, "ax" + .code 16 + .align 0 + .global _vectors + +_vectors: + .word __stack_end__ +#ifdef STARTUP_FROM_RESET + .word reset_handler +#else + .word reset_wait +#endif /* STARTUP_FROM_RESET */ + .word Nmi_ISR + .word Fault_ISR + .word MPU_Fault_ISR + .word 0 /* Populate if using Bus fault */ + .word 0 /* Populate if using Usage fault */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word vPortSVCHandler + .word 0 /* Populate if using a debug monitor */ + .word 0 /* Reserved */ + .word xPortPendSVHandler + .word xPortSysTickHandler + .word GPIO_Port_A_ISR + .word GPIO_Port_B_ISR + .word GPIO_Port_C_ISR + .word GPIO_Port_D_ISR + .word GPIO_Port_E_ISR + .word UART0_ISR + .word UART1_ISR + .word SSI_ISR + .word I2C_ISR + .word PWM_Fault_ISR + .word PWM_Generator_0_ISR + .word PWM_Generator_1_ISR + .word PWM_Generator_2_ISR + .word QEI_ISR + .word ADC_Sequence_0_ISR + .word ADC_Sequence_1_ISR + .word ADC_Sequence_2_ISR + .word ADC_Sequence_3_ISR + .word Watchdog_Timer_ISR + .word Timer0A_ISR + .word Timer0B_ISR + .word Timer1A_ISR + .word Timer1B_ISR + .word Timer2A_ISR + .word Timer2B_ISR + .word Analog_Comparator_0_ISR + .word Analog_Comparator_1_ISR + .word Analog_Comparator_2_ISR + .word System_Control_ISR + .word FLASH_Control_ISR + .word GPIO_Port_F_ISR + .word GPIO_Port_G_ISR + .word GPIO_Port_H_ISR + .word UART2_ISR + .word SSI1_ISR + .word Timer3A_ISR + .word Timer3B_ISR + .word I2C1_ISR + .word QEI1_ISR + .word CAN0_ISR + .word CAN1_ISR + .word CAN2_ISR + .word EMAC_ISR + .word HIBERNATE_ISR + .word USB0_ISR + .word PWM_Generator_3_ISR + .word uDMA_Software_Transfer_ISR + .word uDMA_Error_ISR +_vectors_end: + + .section .init, "ax" + .thumb_func + +reset_handler: +#ifdef __RAM_BUILD + /* If this is a RAM build, configure vector table offset register to point + to the RAM vector table. */ + ldr r0, =0xE000ED08 + ldr r1, =_vectors + str r1, [r0] +#endif + b _start + +DEFAULT_ISR_HANDLER Nmi_ISR +/*DEFAULT_ISR_HANDLER Fault_ISR*/ +/*DEFAULT_ISR_HANDLER MPU_Fault_ISR*/ +DEFAULT_ISR_HANDLER SVCall_ISR +DEFAULT_ISR_HANDLER SysTick_ISR +DEFAULT_ISR_HANDLER PendSV_ISR +DEFAULT_ISR_HANDLER GPIO_Port_A_ISR +DEFAULT_ISR_HANDLER GPIO_Port_B_ISR +DEFAULT_ISR_HANDLER GPIO_Port_C_ISR +DEFAULT_ISR_HANDLER GPIO_Port_D_ISR +DEFAULT_ISR_HANDLER GPIO_Port_E_ISR +DEFAULT_ISR_HANDLER UART0_ISR +DEFAULT_ISR_HANDLER UART1_ISR +DEFAULT_ISR_HANDLER SSI_ISR +DEFAULT_ISR_HANDLER I2C_ISR +DEFAULT_ISR_HANDLER PWM_Fault_ISR +DEFAULT_ISR_HANDLER PWM_Generator_0_ISR +DEFAULT_ISR_HANDLER PWM_Generator_1_ISR +DEFAULT_ISR_HANDLER PWM_Generator_2_ISR +DEFAULT_ISR_HANDLER QEI_ISR +DEFAULT_ISR_HANDLER ADC_Sequence_0_ISR +DEFAULT_ISR_HANDLER ADC_Sequence_1_ISR +DEFAULT_ISR_HANDLER ADC_Sequence_2_ISR +DEFAULT_ISR_HANDLER ADC_Sequence_3_ISR +DEFAULT_ISR_HANDLER Watchdog_Timer_ISR +DEFAULT_ISR_HANDLER Timer0A_ISR +DEFAULT_ISR_HANDLER Timer0B_ISR +DEFAULT_ISR_HANDLER Timer1A_ISR +DEFAULT_ISR_HANDLER Timer1B_ISR +DEFAULT_ISR_HANDLER Timer2A_ISR +DEFAULT_ISR_HANDLER Timer2B_ISR +DEFAULT_ISR_HANDLER Analog_Comparator_0_ISR +DEFAULT_ISR_HANDLER Analog_Comparator_1_ISR +DEFAULT_ISR_HANDLER Analog_Comparator_2_ISR +DEFAULT_ISR_HANDLER System_Control_ISR +DEFAULT_ISR_HANDLER FLASH_Control_ISR +DEFAULT_ISR_HANDLER GPIO_Port_F_ISR +DEFAULT_ISR_HANDLER GPIO_Port_G_ISR +DEFAULT_ISR_HANDLER GPIO_Port_H_ISR +DEFAULT_ISR_HANDLER UART2_ISR +DEFAULT_ISR_HANDLER SSI1_ISR +DEFAULT_ISR_HANDLER Timer3A_ISR +DEFAULT_ISR_HANDLER Timer3B_ISR +DEFAULT_ISR_HANDLER I2C1_ISR +DEFAULT_ISR_HANDLER QEI1_ISR +DEFAULT_ISR_HANDLER CAN0_ISR +DEFAULT_ISR_HANDLER CAN1_ISR +DEFAULT_ISR_HANDLER CAN2_ISR +DEFAULT_ISR_HANDLER ETHERNET_ISR +DEFAULT_ISR_HANDLER HIBERNATE_ISR +DEFAULT_ISR_HANDLER USB0_ISR +DEFAULT_ISR_HANDLER PWM_Generator_3_ISR +DEFAULT_ISR_HANDLER uDMA_Software_Transfer_ISR +DEFAULT_ISR_HANDLER uDMA_Error_ISR +DEFAULT_ISR_HANDLER EMAC_ISR + +#ifndef STARTUP_FROM_RESET +DEFAULT_ISR_HANDLER reset_wait +#endif /* STARTUP_FROM_RESET */ + diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Target.js b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Target.js new file mode 100644 index 000000000..55a9c2c7c --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/LM3S_Target.js @@ -0,0 +1,28 @@ +/****************************************************************************** + Target Script for LM3S. + + Copyright (c) 2006 Rowley Associates Limited. + + This file may be distributed under the terms of the License Agreement + provided with this software. + + THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE + WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ******************************************************************************/ + +function Reset() +{ + TargetInterface.resetAndStop(1000); +} + +function RAMReset() +{ + Reset(); +} + +function FLASHReset() +{ + Reset(); +} + + diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzp b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzp new file mode 100644 index 000000000..0c93f888c --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzp @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzs b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzs new file mode 100644 index 000000000..c8a7a4037 --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/RTOSDemo.hzs @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/flash_placement.xml b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/flash_placement.xml new file mode 100644 index 000000000..800479d00 --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/flash_placement.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/main.c b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/main.c new file mode 100644 index 000000000..67628e011 --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/main.c @@ -0,0 +1,742 @@ +/* + FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation and modified by the FreeRTOS exception. + **NOTE** The exception to the GPL is included to allow you to distribute a + combined work that includes FreeRTOS without being obliged to provide the + source code for proprietary components outside of the FreeRTOS kernel. + Alternative commercial license and support terms are also available upon + request. See the licensing section of http://www.FreeRTOS.org for full + license details. + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59 + Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + + *************************************************************************** + * * + * Looking for a quick start? Then check out the FreeRTOS eBook! * + * See http://www.FreeRTOS.org/Documentation for details * + * * + *************************************************************************** + + 1 tab == 4 spaces! + + Please ensure to read the configuration and relevant port sections of the + online documentation. + + http://www.FreeRTOS.org - Documentation, latest information, license and + contact details. + + http://www.SafeRTOS.com - A version that is certified for use in safety + critical systems. + + http://www.OpenRTOS.com - Commercial support, development, porting, + licensing and training services. +*/ + +/* Standard includes. */ +#include +#include <__cross_studio_io.h> + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* Hardware library includes. */ +#include "hw_types.h" +#include "hw_sysctl.h" +#include "sysctl.h" + +/* + * This file demonstrates the use of MPU using just three tasks - two 'reg test' + * tasks and one 'check' task. Read the comments above the + * function prototypes for more information. + */ + +/*-----------------------------------------------------------*/ + +/* Misc constants. */ +#define mainDONT_BLOCK ( 0 ) + +/* Definitions for the messages that can be sent to the check task. */ +#define mainREG_TEST_1_STILL_EXECUTING ( 0 ) +#define mainREG_TEST_2_STILL_EXECUTING ( 1 ) +#define mainPRINT_SYSTEM_STATUS ( 2 ) + +/* GCC specifics. */ +#define mainALIGN_TO( x ) __attribute__((aligned(x))) + + +/*-----------------------------------------------------------*/ +/* Prototypes for functions that implement tasks. -----------*/ +/*-----------------------------------------------------------*/ + +/* + * Prototype for the reg test tasks. Amongst other things, these fill the CPU + * registers with known values before checking that the registers still contain + * the expected values. Each of the two tasks use different values so an error + * in the context switch mechanism can be caught. Both reg test tasks execute + * at the idle priority so will get preempted regularly. + */ +static void prvRegTest1Task( void *pvParameters ); +static void prvRegTest2Task( void *pvParameters ); + +/* + * Prototype for the check task. The check task demonstrates various features + * of the MPU before entering a loop where it waits for commands to arrive on a + * queue. + * + * The check task will periodically be commanded to print out a status message. + * If both the reg tests tasks are executing as expected the check task will + * print "PASS" to the debug port, otherwise it will print 'FAIL'. Debug port + * messages can be viewed within the CrossWorks IDE. + */ +static void prvCheckTask( void *pvParameters ); + + + +/*-----------------------------------------------------------*/ +/* Prototypes for other misc functions. --------------------*/ +/*-----------------------------------------------------------*/ + +/* + * Just configures any clocks and IO necessary. + */ +static void prvSetupHardware( void ); + +/* + * Simply deletes the calling task. The function is provided only because it + * is simpler to call from asm code than the normal vTaskDelete() API function. + * It has the noinline attribute because it is called from asm code. + */ +static void prvDeleteMe( void ) __attribute__((noinline)); + +/* + * Used by both reg test tasks to send messages to the check task. The message + * just lets the check task know that the sending is still functioning correctly. + * If a reg test task detects an error it will delete itself, and in so doing + * prevent itself from sending any more 'I'm Alive' messages to the check task. + */ +static void prvSendImAlive( xQueueHandle xHandle, unsigned long ulTaskNumber ); + +/* + * The check task is created with access to three memory regions (plus its + * stack). Each memory region is configured with different parameters and + * prvTestMemoryRegions() demonstrates what can and cannot be accessed for each + * region. prvTestMemoryRegions() also demonstrates a task that was created + * as a privileged task settings its own privilege level down to that of a user + * task. + */ +static void prvTestMemoryRegions( void ); + +/*-----------------------------------------------------------*/ + +/* The handle of the queue used to communicate between tasks and between tasks +and interrupts. Note that this is a file scope variable that falls outside of +any MPU region. As such other techniques have to be used to allow the tasks +to gain access to the queue. See the comments in the tasks themselves for +further information. */ +static xQueueHandle xFileScopeCheckQueue = NULL; + + + +/*-----------------------------------------------------------*/ +/* Data used by the 'check' task. ---------------------------*/ +/*-----------------------------------------------------------*/ + +/* Define the constants used to allocate the check task stack. Note that the +stack size is defined in words, not bytes. */ +#define mainCHECK_TASK_STACK_SIZE_WORDS 128 +#define mainCHECK_TASK_STACK_ALIGNMENT ( mainCHECK_TASK_STACK_SIZE_WORDS * sizeof( portSTACK_TYPE ) ) + +/* Declare the stack that will be used by the check task. The kernel will + automatically create an MPU region for the stack. The stack alignment must + match its size, so if 128 words are reserved for the stack then it must be + aligned to ( 128 * 4 ) bytes. */ +static portSTACK_TYPE xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS ] mainALIGN_TO( mainCHECK_TASK_STACK_ALIGNMENT ); + +/* Declare three arrays - an MPU region will be created for each array + using the xTaskParameters structure below. Note that the arrays allocate +slightly more RAM than is actually assigned to the MPU region. This is to +permit writes off the end of the array to be detected even when the arrays are +placed in adjacent memory locations (with no gaps between them). The align +size must be a power of two. */ +#define mainREAD_WRITE_ARRAY_SIZE 130 +#define mainREAD_WRITE_ALIGN_SIZE 128 +char cReadWriteArray[ mainREAD_WRITE_ARRAY_SIZE ] mainALIGN_TO( mainREAD_WRITE_ALIGN_SIZE ); + +#define mainREAD_ONLY_ARRAY_SIZE 260 +#define mainREAD_ONLY_ALIGN_SIZE 256 +char cReadOnlyArray[ mainREAD_ONLY_ARRAY_SIZE ] mainALIGN_TO( mainREAD_ONLY_ALIGN_SIZE ); + +#define mainPRIVILEGED_ONLY_ACCESS_ARRAY_SIZE 130 +#define mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE 128 +char cPrivilegedOnlyAccessArray[ mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ] mainALIGN_TO( mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ); + +/* Fill in a xTaskParameters structure to define the check task. */ +static const xTaskParameters xCheckTaskParameters = +{ + prvCheckTask, /* pvTaskCode - the function that implements the task. */ + ( signed char * ) "Check", /* pcName */ + mainCHECK_TASK_STACK_SIZE_WORDS, /* usStackDepth - defined in words, not bytes. */ + ( void * ) 0x12121212, /* pvParameters - this value is just to test that the parameter is being passed into the task correctly. */ + ( tskIDLE_PRIORITY + 1 ) | portPRIVILEGE_BIT,/* uxPriority - this is the highest priority task in the system. The task is created in privileged mode to demonstrate accessing the privileged only data. */ + xCheckTaskStack, /* puxStackBuffer - the array to use as the task stack, as declared above. */ + + /* xRegions - In this case the xRegions array is used to create MPU regions + for all three of the arrays declared directly above. Each MPU region is + created with different parameters. */ + { + /* Base address Length Parameters */ + { cReadWriteArray, mainREAD_WRITE_ALIGN_SIZE, portMPU_REGION_READ_WRITE }, + { cReadOnlyArray, mainREAD_ONLY_ALIGN_SIZE, portMPU_REGION_READ_ONLY }, + { cPrivilegedOnlyAccessArray, mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE, portMPU_REGION_PRIVILEGED_READ_WRITE } + } +}; + +/* Three MPU regions are defined for use by the 'check' task when the task is +created. These are only used to demonstrate the MPU features and are not +actually necessary for the check task to fulfill its primary purpose. Instead +the MPU regions are replaced with those defined by xAltRegions prior to the +check task receiving any data on the queue or printing any messages to the +debug console. The region configured by xAltRegions just gives the check task +access to the debug variables that form part of the Rowley library, and are +accessed within the debug_printf() function. */ +extern unsigned long dbgCntrlWord_mempoll; +static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] = + { + /* Base address Length Parameters */ + { ( void * ) &dbgCntrlWord_mempoll, 32, portMPU_REGION_READ_WRITE }, + { 0, 0, 0 }, + { 0, 0, 0 } + }; + + + +/*-----------------------------------------------------------*/ +/* Data used by the 'reg test' tasks. -----------------------*/ +/*-----------------------------------------------------------*/ + +/* Define the constants used to allocate the reg test task stacks. Note that +that stack size is defined in words, not bytes. */ +#define mainREG_TEST_STACK_SIZE_WORDS 128 +#define mainREG_TEST_STACK_ALIGNMENT ( mainREG_TEST_STACK_SIZE_WORDS * sizeof( portSTACK_TYPE ) ) + +/* Declare the stacks that will be used by the reg test tasks. The kernel will +automatically create an MPU region for the stack. The stack alignment must +match its size, so if 128 words are reserved for the stack then it must be +aligned to ( 128 * 4 ) bytes. */ +static portSTACK_TYPE xRegTest1Stack[ mainREG_TEST_STACK_SIZE_WORDS ] mainALIGN_TO( mainREG_TEST_STACK_ALIGNMENT ); +static portSTACK_TYPE xRegTest2Stack[ mainREG_TEST_STACK_SIZE_WORDS ] mainALIGN_TO( mainREG_TEST_STACK_ALIGNMENT ); + +/* Fill in a xTaskParameters structure per reg test task to define the tasks. */ +static const xTaskParameters xRegTest1Parameters = +{ + prvRegTest1Task, /* pvTaskCode - the function that implements the task. */ + ( signed char * ) "RegTest1", /* pcName */ + mainREG_TEST_STACK_SIZE_WORDS, /* usStackDepth */ + ( void * ) 0x12345678, /* pvParameters - this value is just to test that the parameter is being passed into the task correctly. */ + tskIDLE_PRIORITY | portPRIVILEGE_BIT, /* uxPriority - note that this task is created with privileges to demonstrate one method of passing a queue handle into the task. */ + xRegTest1Stack, /* puxStackBuffer - the array to use as the task stack, as declared above. */ + { /* xRegions - this task does not use any non-stack data. */ + /* Base address Length Parameters */ + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00 } + } +}; +/*-----------------------------------------------------------*/ + +static xTaskParameters xRegTest2Parameters = +{ + prvRegTest2Task, /* pvTaskCode - the function that implements the task. */ + ( signed char * ) "RegTest2", /* pcName */ + mainREG_TEST_STACK_SIZE_WORDS, /* usStackDepth */ + ( void * ) NULL, /* pvParameters - this task uses the parameter to pass in a queue handle, but the queue is not created yet. */ + tskIDLE_PRIORITY, /* uxPriority */ + xRegTest2Stack, /* puxStackBuffer - the array to use as the task stack, as declared above. */ + { /* xRegions - this task does not use any non-stack data. */ + /* Base address Length Parameters */ + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00 } + } +}; + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + prvSetupHardware(); + + /* Create the queue used to pass "I'm alive" messages to the check task. */ + xFileScopeCheckQueue = xQueueCreate( 1, sizeof( unsigned long ) ); + + /* One check task uses the task parameter to receive the queue handle. + This allows the file scope variable to be accessed from within the task. + The pvParameters member of xRegTest2Parameters can only be set after the + queue has been created. */ + xRegTest2Parameters.pvParameters = xFileScopeCheckQueue; + + /* Create the three test tasks. Handles to the created tasks are not + required, hence the second parameter is NULL. */ + xTaskCreateRestricted( &xRegTest1Parameters, NULL ); + xTaskCreateRestricted( &xRegTest2Parameters, NULL ); + xTaskCreateRestricted( &xCheckTaskParameters, NULL ); + + /* Start the scheduler. */ + vTaskStartScheduler(); + + /* Will only get here if there was insufficient memory to create the idle + task. */ + for( ;; ); + return 0; +} +/*-----------------------------------------------------------*/ + +static void prvCheckTask( void *pvParameters ) +{ +/* This task is created in privileged mode so can access the file scope +queue variable. Take a stack copy of this before the task is set into user +mode. Once that task is in user mode the file scope queue variable will no +longer be accessible but the stack copy will. */ +xQueueHandle xQueue = xFileScopeCheckQueue; +long lMessage; +unsigned long ulStillAliveCounts[ 2 ] = { 0 }; +const char *pcStatusMessage = "PASS\r\n"; + + /* Just to remove compiler warning. */ + ( void ) pvParameters; + + /* Demonstrate how the various memory regions can and can't be accessed. + The task privilege is set down to user mode within this function. */ + prvTestMemoryRegions(); + + /* Change the memory regions allocated to this task to those initially + set up for demonstration purposes to those actually required by the task. */ + vTaskAllocateMPURegions( NULL, xAltRegions ); + + /* This loop performs the main function of the task, which is blocking + on a message queue then processing each message as it arrives. */ + for( ;; ) + { + /* Wait for the next message to arrive. */ + xQueueReceive( xQueue, &lMessage, portMAX_DELAY ); + + switch( lMessage ) + { + case mainREG_TEST_1_STILL_EXECUTING : + /* Message from task 1, so task 1 must still be executing. */ + ( ulStillAliveCounts[ 0 ] )++; + break; + + case mainREG_TEST_2_STILL_EXECUTING : + /* Message from task 2, so task 2 must still be executing. */ + ( ulStillAliveCounts[ 1 ] )++; + break; + + case mainPRINT_SYSTEM_STATUS : + /* Message from tick hook, time to print out the system + status. If messages has stopped arriving from either reg + test task then the status must be set to fail. */ + if( ( ulStillAliveCounts[ 0 ] == 0 ) || ( ulStillAliveCounts[ 1 ] == 0 ) ) + { + /* One or both of the test tasks are no longer sending + 'still alive' messages. */ + pcStatusMessage = "FAIL\r\n"; + } + + /* Print a pass/fail message to the terminal. This will be + visible in the CrossWorks IDE. */ + debug_printf( pcStatusMessage ); + + /* Reset the count of 'still alive' messages. */ + memset( ulStillAliveCounts, 0x00, sizeof( ulStillAliveCounts ) ); + break; + + default : + /* Something unexpected happened. Delete this task so the + error is apparent (no output will be displayed). */ + prvDeleteMe(); + break; + } + } +} +/*-----------------------------------------------------------*/ + +static void prvTestMemoryRegions( void ) +{ +long l; +char cTemp; + + /* The check task is created in the privileged mode. The privileged array + can be both read from and written to while this task is privileged. */ + cPrivilegedOnlyAccessArray[ 0 ] = 'a'; + if( cPrivilegedOnlyAccessArray[ 0 ] != 'a' ) + { + /* Something unexpected happened. Delete this task so the error is + apparent (no output will be displayed). */ + prvDeleteMe(); + } + + /* Writing off the end of the RAM allocated to this task will *NOT* cause a + protection fault because the task is still executing in a privileged mode. + Uncomment the following to test. */ + /*cPrivilegedOnlyAccessArray[ mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ] = 'a';*/ + + /* Now set the task into user mode. */ + portSWITCH_TO_USER_MODE(); + + /* Accessing the privileged only array will now cause a fault. Uncomment + the following line to test. */ + /*cPrivilegedOnlyAccessArray[ 0 ] = 'a';*/ + + /* The read/write array can still be successfully read and written. */ + for( l = 0; l < mainREAD_WRITE_ALIGN_SIZE; l++ ) + { + cReadWriteArray[ l ] = 'a'; + if( cReadWriteArray[ l ] != 'a' ) + { + /* Something unexpected happened. Delete this task so the error is + apparent (no output will be displayed). */ + prvDeleteMe(); + } + } + + /* But attempting to read or write off the end of the RAM allocated to this + task will cause a fault. Uncomment either of the following two lines to + test. */ + /* cReadWriteArray[ 0 ] = cReadWriteArray[ -1 ]; */ + /* cReadWriteArray[ mainREAD_WRITE_ALIGN_SIZE ] = 0x00; */ + + /* The read only array can be successfully read... */ + for( l = 0; l < mainREAD_ONLY_ALIGN_SIZE; l++ ) + { + cTemp = cReadOnlyArray[ l ]; + } + + /* ...but cannot be written. Uncomment the following line to test. */ + /* cReadOnlyArray[ 0 ] = 'a'; */ + + /* Writing to the first and last locations in the stack array should not + cause a protection fault. Note that doing this will cause the kernel to + detect a stack overflow if configCHECK_FOR_STACK_OVERFLOW is greater than + 1. */ + xCheckTaskStack[ 0 ] = 0; + xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS - 1 ] = 0; + + /* Writing off either end of the stack array should cause a protection + fault, uncomment either of the following two lines to test. */ + /* xCheckTaskStack[ -1 ] = 0; */ + /* xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS ] = 0; */ +} +/*-----------------------------------------------------------*/ + +static void prvRegTest1Task( void *pvParameters ) +{ +/* This task is created in privileged mode so can access the file scope +queue variable. Take a stack copy of this before the task is set into user +mode. Once that task is in user mode the file scope queue variable will no +longer be accessible but the stack copy will. */ +xQueueHandle xQueue = xFileScopeCheckQueue; + + /* Now the queue handle has been obtained the task can switch to user + mode. This is just one method of passing a handle into a protected + task, the other reg test task uses the task parameter instead. */ + portSWITCH_TO_USER_MODE(); + + /* First check that the parameter value is as expected. */ + if( pvParameters != ( void * ) 0x12345678 ) + { + /* Error detected. Delete the task so it stops communicating with + the check task. */ + prvDeleteMe(); + } + + + for( ;; ) + { + /* This task tests the kernel context switch mechanism by reading and + writing directly to registers - which requires the test to be written + in assembly code. */ + __asm volatile + ( + " MOV R4, #104 \n" /* Set registers to a known value. R0 to R1 are done in the loop below. */ + " MOV R5, #105 \n" + " MOV R6, #106 \n" + " MOV R8, #108 \n" + " MOV R9, #109 \n" + " MOV R10, #110 \n" + " MOV R11, #111 \n" + "reg1loop: \n" + " MOV R0, #100 \n" /* Set the scratch registers to known values - done inside the loop as they get clobbered. */ + " MOV R1, #101 \n" + " MOV R2, #102 \n" + " MOV R3, #103 \n" + " MOV R12, #112 \n" + " SVC #1 \n" /* Yield just to increase test coverage. */ + " CMP R0, #100 \n" /* Check all the registers still contain their expected values. */ + " BNE prvDeleteMe \n" /* Value was not as expected, delete the task so it stops communicating with the check task. */ + " CMP R1, #101 \n" + " BNE prvDeleteMe \n" + " CMP R2, #102 \n" + " BNE prvDeleteMe \n" + " CMP R3, #103 \n" + " BNE prvDeleteMe \n" + " CMP R4, #104 \n" + " BNE prvDeleteMe \n" + " CMP R5, #105 \n" + " BNE prvDeleteMe \n" + " CMP R6, #106 \n" + " BNE prvDeleteMe \n" + " CMP R8, #108 \n" + " BNE prvDeleteMe \n" + " CMP R9, #109 \n" + " BNE prvDeleteMe \n" + " CMP R10, #110 \n" + " BNE prvDeleteMe \n" + " CMP R11, #111 \n" + " BNE prvDeleteMe \n" + " CMP R12, #112 \n" + " BNE prvDeleteMe \n" + ); + + /* Send mainREG_TEST_1_STILL_EXECUTING to the check task to indicate that this + task is still functioning. */ + prvSendImAlive( xQueue, mainREG_TEST_1_STILL_EXECUTING ); + + /* Go back to check all the register values again. */ + __asm volatile( " B reg1loop " ); + } +} +/*-----------------------------------------------------------*/ + +static void prvRegTest2Task( void *pvParameters ) +{ +/* The queue handle is passed in as the task parameter. This is one method of +passing data into a protected task, the other check task uses a different +method. */ +xQueueHandle xQueue = ( xQueueHandle ) pvParameters; + + for( ;; ) + { + /* This task tests the kernel context switch mechanism by reading and + writing directly to registers - which requires the test to be written + in assembly code. */ + __asm volatile + ( + " MOV R4, #4 \n" /* Set registers to a known value. R0 to R1 are done in the loop below. */ + " MOV R5, #5 \n" + " MOV R6, #6 \n" + " MOV R8, #8 \n" /* Frame pointer is omitted as it must not be changed. */ + " MOV R9, #9 \n" + " MOV R10, 10 \n" + " MOV R11, #11 \n" + "reg2loop: \n" + " MOV R0, #13 \n" /* Set the scratch registers to known values - done inside the loop as they get clobbered. */ + " MOV R1, #1 \n" + " MOV R2, #2 \n" + " MOV R3, #3 \n" + " MOV R12, #12 \n" + " CMP R0, #13 \n" /* Check all the registers still contain their expected values. */ + " BNE prvDeleteMe \n" /* Value was not as expected, delete the task so it stops communicating with the check task */ + " CMP R1, #1 \n" + " BNE prvDeleteMe \n" + " CMP R2, #2 \n" + " BNE prvDeleteMe \n" + " CMP R3, #3 \n" + " BNE prvDeleteMe \n" + " CMP R4, #4 \n" + " BNE prvDeleteMe \n" + " CMP R5, #5 \n" + " BNE prvDeleteMe \n" + " CMP R6, #6 \n" + " BNE prvDeleteMe \n" + " CMP R8, #8 \n" + " BNE prvDeleteMe \n" + " CMP R9, #9 \n" + " BNE prvDeleteMe \n" + " CMP R10, #10 \n" + " BNE prvDeleteMe \n" + " CMP R11, #11 \n" + " BNE prvDeleteMe \n" + " CMP R12, #12 \n" + " BNE prvDeleteMe \n" + ); + + /* Send mainREG_TEST_2_STILL_EXECUTING to the check task to indicate that this + task is still functioning. */ + prvSendImAlive( xQueue, mainREG_TEST_2_STILL_EXECUTING ); + + /* Go back to check all the register values again. */ + __asm volatile( " B reg2loop " ); + } +} +/*-----------------------------------------------------------*/ + +static void prvDeleteMe( void ) +{ + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvSendImAlive( xQueueHandle xHandle, unsigned long ulTaskNumber ) +{ + if( xHandle != NULL ) + { + xQueueSend( xHandle, &ulTaskNumber, mainDONT_BLOCK ); + } +} +/*-----------------------------------------------------------*/ + +static void prvSetupHardware( void ) +{ + /* If running on Rev A2 silicon, turn the LDO voltage up to 2.75V. This is + a workaround to allow the PLL to operate reliably. */ + if( DEVICE_IS_REVA2 ) + { + SysCtlLDOSet( SYSCTL_LDO_2_75V ); + } + + /* Set the clocking to run from the PLL at 50 MHz */ + SysCtlClockSet( SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ ); +} +/*-----------------------------------------------------------*/ + +void vApplicationTickHook( void ) +{ +static unsigned long ulCallCount; +const unsigned long ulCallsBetweenSends = 5000 / portTICK_RATE_MS; +const unsigned long ulMessage = mainPRINT_SYSTEM_STATUS; +portBASE_TYPE xDummy; + + /* If configUSE_TICK_HOOK is set to 1 then this function will get called + from each RTOS tick. It is called from the tick interrupt and therefore + will be executing in the privileged state. */ + + ulCallCount++; + + /* Is it time to print out the pass/fail message again? */ + if( ulCallCount >= ulCallsBetweenSends ) + { + ulCallCount = 0; + + /* Send a message to the check task to command it to check that all + the tasks are still running then print out the status. + + This is running in an ISR so has to use the "FromISR" version of + xQueueSend(). Because it is in an ISR it is running with privileges + so can access xFileScopeCheckQueue directly. */ + xQueueSendFromISR( xFileScopeCheckQueue, &ulMessage, &xDummy ); + } +} +/*-----------------------------------------------------------*/ + +void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName ) +{ + /* If configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2 then this + function will automatically get called if a task overflows its stack. */ + ( void ) pxTask; + ( void ) pcTaskName; + for( ;; ); +} +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* If configUSE_MALLOC_FAILED_HOOK is set to 1 then this function will + be called automatically if a call to pvPortMalloc() fails. pvPortMalloc() + is called automatically when a task, queue or semaphore is created. */ + for( ;; ); +} +/*-----------------------------------------------------------*/ + +/* Just to keep the linker happy. */ +void __error__( char *pcFilename, unsigned long ulLine ) +{ + ( void ) pcFilename; + ( void ) ulLine; + for( ;; ); +} +/*-----------------------------------------------------------*/ + +/* Just to keep the linker happy. */ +int uipprintf( const char *fmt, ... ) +{ + ( void ) fmt; + return( 0 ); +} +/*-----------------------------------------------------------*/ + +void hard_fault_handler(unsigned int * hardfault_args) +{ +unsigned int stacked_r0; +unsigned int stacked_r1; +unsigned int stacked_r2; +unsigned int stacked_r3; +unsigned int stacked_r12; +unsigned int stacked_lr; +unsigned int stacked_pc; +unsigned int stacked_psr; + + stacked_r0 = ((unsigned long) hardfault_args[0]); + stacked_r1 = ((unsigned long) hardfault_args[1]); + stacked_r2 = ((unsigned long) hardfault_args[2]); + stacked_r3 = ((unsigned long) hardfault_args[3]); + + stacked_r12 = ((unsigned long) hardfault_args[4]); + stacked_lr = ((unsigned long) hardfault_args[5]); + stacked_pc = ((unsigned long) hardfault_args[6]); + stacked_psr = ((unsigned long) hardfault_args[7]); + + /* Inspect stacked_pc to locate the offending instruction. */ + for( ;; ); +} +/*-----------------------------------------------------------*/ + +void Fault_ISR( void ) __attribute__((naked)); +void Fault_ISR( void ) +{ + __asm volatile + ( + " tst lr, #4 \n" + " ite eq \n" + " mrseq r0, msp \n" + " mrsne r0, psp \n" + " ldr r1, [r0, #24] \n" + " ldr r2, handler_address_const \n" + " bx r2 \n" + " handler_address_const: .word hard_fault_handler \n" + ); +} +/*-----------------------------------------------------------*/ + +void MPU_Fault_ISR( void ) __attribute__((naked)); +void MPU_Fault_ISR( void ) +{ + __asm volatile + ( + " tst lr, #4 \n" + " ite eq \n" + " mrseq r0, msp \n" + " mrsne r0, psp \n" + " ldr r1, [r0, #24] \n" + " ldr r2, handler_address_const \n" + " bx r2 \n" + " handler2_address_const: .word hard_fault_handler \n" + ); +} +/*-----------------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/thumb_crt0.s b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/thumb_crt0.s new file mode 100644 index 000000000..ec6d5090a --- /dev/null +++ b/Demo/CORTEX_MPU_LM3Sxxxx_Rowley/thumb_crt0.s @@ -0,0 +1,233 @@ +/***************************************************************************** + * Copyright (c) 2009 Rowley Associates Limited. * + * * + * This file may be distributed under the terms of the License Agreement * + * provided with this software. * + * * + * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE * + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + *****************************************************************************/ + +/***************************************************************************** + * Preprocessor Definitions + * ------------------------ + * APP_ENTRY_POINT + * + * Defines the application entry point function, if undefined this setting + * defaults to "main". + * + * USE_PROCESS_STACK + * + * If defined, thread mode will be configured to use the process stack if + * the size of the process stack is greater than zero bytes in length. + * + * INITIALIZE_STACK + * + * If defined, the contents of the stack will be initialized to a the + * value 0xCC. + * + * FULL_LIBRARY + * + * If defined then + * - argc, argv are setup by the debug_getargs. + * - the exit symbol is defined and executes on return from main. + * - the exit symbol calls destructors, atexit functions and then debug_exit. + * + * If not defined then + * - argc and argv are zero. + * - no exit symbol, code loops on return from main. + *****************************************************************************/ + +#ifndef APP_ENTRY_POINT +#define APP_ENTRY_POINT main +#endif + +#ifndef ARGSSPACE +#define ARGSSPACE 128 +#endif + + .global _start + .syntax unified + .extern APP_ENTRY_POINT +#ifdef FULL_LIBRARY + .global exit +#endif + + .section .init, "ax" + .code 16 + .align 2 + .thumb_func + +_start: +#ifdef __RAM_BUILD + ldr r1, =__stack_end__ + mov sp, r1 +#endif +#ifdef INITIALIZE_STACK + mov r2, #0xCC + ldr r0, =__stack_start__ +#ifndef __RAM_BUILD + mov r1, sp +#endif + bl memory_set +#endif + +#ifdef USE_PROCESS_STACK + /* Set up process stack if size > 0 */ + ldr r1, =__stack_process_end__ + ldr r0, =__stack_process_start__ + subs r2, r1, r0 + beq 1f + msr psp, r1 + mov r2, #2 + msr control, r2 +#ifdef INITIALIZE_STACK + mov r2, #0xCC + bl memory_set +#endif +1: +#endif + /* Copy initialised memory sections into RAM (if necessary). */ + ldr r0, =__data_load_start__ + ldr r1, =__data_start__ + ldr r2, =__data_end__ + bl memory_copy + ldr r0, =__text_load_start__ + ldr r1, =__text_start__ + ldr r2, =__text_end__ + bl memory_copy + ldr r0, =__fast_load_start__ + ldr r1, =__fast_start__ + ldr r2, =__fast_end__ + bl memory_copy + ldr r0, =__ctors_load_start__ + ldr r1, =__ctors_start__ + ldr r2, =__ctors_end__ + bl memory_copy + ldr r0, =__dtors_load_start__ + ldr r1, =__dtors_start__ + ldr r2, =__dtors_end__ + bl memory_copy + ldr r0, =__rodata_load_start__ + ldr r1, =__rodata_start__ + ldr r2, =__rodata_end__ + bl memory_copy + + /* Zero the bss. */ + ldr r0, =__bss_start__ + ldr r1, =__bss_end__ + mov r2, #0 + bl memory_set + + /* Zereo the privileged data. */ + ldr r0, =__privileged_data_start__ + ldr r1, =__privileged_data_end__ + mov r2, #0 + bl memory_set + + /* Initialise the heap */ + ldr r0, = __heap_start__ + ldr r1, = __heap_end__ + sub r1, r1, r0 + mov r2, #0 + str r2, [r0] + add r0, r0, #4 + str r1, [r0] + + /* Call constructors */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0] + add r0, #4 + push {r0-r1} + blx r2 + pop {r0-r1} + b ctor_loop +ctor_end: + + /* Setup initial call frame */ + mov r0, #0 + mov lr, r0 + mov r12, sp + +start: + /* Jump to application entry point */ +#ifdef FULL_LIBRARY + mov r0, #ARGSSPACE + ldr r1, =args + ldr r2, =debug_getargs + blx r2 + ldr r1, =args +#else + mov r0, #0 + mov r1, #0 +#endif + ldr r2, =APP_ENTRY_POINT + blx r2 + +#ifdef FULL_LIBRARY + .thumb_func +exit: + mov r5, r0 // save the exit parameter/return result + + /* Call destructors */ + ldr r0, =__dtors_start__ + ldr r1, =__dtors_end__ +dtor_loop: + cmp r0, r1 + beq dtor_end + ldr r2, [r0] + add r0, #4 + push {r0-r1} + blx r2 + pop {r0-r1} + b dtor_loop +dtor_end: + + /* Call atexit functions */ + ldr r2, =_execute_at_exit_fns + blx r2 + + /* Call debug_exit with return result/exit parameter */ + mov r0, r5 + ldr r2, =debug_exit + blx r2 +#endif + + /* Returned from application entry point, loop forever. */ +exit_loop: + b exit_loop + +memory_copy: + cmp r0, r1 + beq 2f + subs r2, r2, r1 + beq 2f +1: + ldrb r3, [r0] + add r0, r0, #1 + strb r3, [r1] + add r1, r1, #1 + subs r2, r2, #1 + bne 1b +2: + bx lr + +memory_set: + cmp r0, r1 + beq 1f + strb r2, [r0] + add r0, r0, #1 + b memory_set +1: + bx lr + +#ifdef FULL_LIBRARY + .bss +args: + .space ARGSSPACE +#endif + -- 2.39.5