updates

Fork of nrf51-sdk by Lancaster University

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers bootloader_util.c Source File

bootloader_util.c

00001 /*
00002  * Copyright (c) Nordic Semiconductor ASA
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without modification,
00006  * are permitted provided that the following conditions are met:
00007  *
00008  *   1. Redistributions of source code must retain the above copyright notice, this
00009  *   list of conditions and the following disclaimer.
00010  *
00011  *   2. Redistributions in binary form must reproduce the above copyright notice, this
00012  *   list of conditions and the following disclaimer in the documentation and/or
00013  *   other materials provided with the distribution.
00014  *
00015  *   3. Neither the name of Nordic Semiconductor ASA nor the names of other
00016  *   contributors to this software may be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00024  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  */
00032 
00033 #include "bootloader_util.h "
00034 #include <stdint.h>
00035 #include <string.h>
00036 
00037 
00038 /**
00039  * @brief Function for aborting current application/bootloader jump to to other app/bootloader.
00040  *
00041  * @details This functions will use the address provide to swap the stack pointer and then load 
00042  *          the address of the reset handler to be executed. It will check current system mode 
00043  *          (thread/handler) and if in thread mode it will reset into other application.
00044  *          If in handler mode \ref isr_abort will be executed to ensure correct exit of handler 
00045  *          mode and jump into reset handler of other application.
00046  *
00047  * @param[in]  start_addr  Start address of other application. This address must point to the 
00048                initial stack pointer of the application.
00049  *
00050  * @note This function will never return but issue a reset into provided application.
00051  */
00052 #if defined ( __CC_ARM )
00053 __asm static void bootloader_util_reset(uint32_t start_addr)
00054 {
00055     LDR   R5, [R0]              ; Get App initial MSP for bootloader.
00056     MSR   MSP, R5               ; Set the main stack pointer to the applications MSP.
00057     LDR   R0, [R0, #0x04]       ; Load Reset handler into R0. This will be first argument to branch instruction (BX).
00058 
00059     MOVS  R4, #0xFF             ; Load ones to R4.
00060     SXTB  R4, R4                ; Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
00061     MRS   R5, IPSR              ; Load IPSR to R5 to check for handler or thread mode.
00062     CMP   R5, #0x00             ; Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
00063     BNE   isr_abort             ; If not zero we need to exit current ISR and jump to reset handler of bootloader.
00064 
00065     MOV   LR, R4                ; Clear the link register and set to ones to ensure no return, R4 = 0xFFFFFFFF.
00066     BX    R0                    ; Branch to reset handler of bootloader.
00067 
00068 isr_abort
00069                                 ; R4 contains ones from line above. Will be popped as R12 when exiting ISR (Cleaning up the registers).
00070     MOV   R5, R4                ; Fill with ones before jumping to reset handling. We be popped as LR when exiting ISR. Ensures no return to application.
00071     MOV   R6, R0                ; Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
00072     MOVS  r7, #0x21             ; Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
00073     REV   r7, r7                ; Reverse byte order to put 0x21 as MSB.
00074     PUSH  {r4-r7}               ; Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
00075 
00076     MOVS  R4, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
00077     MOVS  R5, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
00078     MOVS  R6, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
00079     MOVS  R7, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
00080     PUSH  {r4-r7}               ; Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
00081 
00082     MOVS  R0, #0xF9             ; Move the execution return command into register, 0xFFFFFFF9.
00083     SXTB  R0, R0                ; Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
00084     BX    R0                    ; No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
00085     ALIGN
00086 }
00087 #elif defined ( __GNUC__ )
00088 static inline void bootloader_util_reset(uint32_t start_addr)
00089 {
00090     __asm volatile(
00091         "ldr   r0, [%0]\t\n"            // Get App initial MSP for bootloader.
00092         "msr   msp, r0\t\n"             // Set the main stack pointer to the applications MSP.
00093         "ldr   r0, [%0, #0x04]\t\n"     // Load Reset handler into R0.
00094 
00095         "movs  r4, #0xFF\t\n"           // Move ones to R4.
00096         "sxtb  r4, r4\t\n"              // Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
00097 
00098         "mrs   r5, IPSR\t\n"            // Load IPSR to R5 to check for handler or thread mode.
00099         "cmp   r5, #0x00\t\n"           // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
00100         "bne   isr_abort\t\n"           // If not zero we need to exit current ISR and jump to reset handler of bootloader.
00101 
00102         "mov   lr, r4\t\n"              // Clear the link register and set to ones to ensure no return.
00103         "bx    r0\t\n"                  // Branch to reset handler of bootloader.
00104 
00105         "isr_abort:  \t\n"
00106 
00107         "mov   r5, r4\t\n"              // Fill with ones before jumping to reset handling. Will be popped as LR when exiting ISR. Ensures no return to application.
00108         "mov   r6, r0\t\n"              // Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
00109         "movs  r7, #0x21\t\n"           // Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
00110         "rev   r7, r7\t\n"              // Reverse byte order to put 0x21 as MSB.
00111         "push  {r4-r7}\t\n"             // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
00112 
00113         "movs  r4, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
00114         "movs  r5, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
00115         "movs  r6, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
00116         "movs  r7, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
00117         "push  {r4-r7}\t\n"             // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
00118 
00119         "movs  r0, #0xF9\t\n"           // Move the execution return command into register, 0xFFFFFFF9.
00120         "sxtb  r0, r0\t\n"              // Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
00121         "bx    r0\t\n"                  // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
00122         ".align\t\n"
00123         :: "r" (start_addr)             // Argument list for the gcc assembly. start_addr is %0.
00124         :  "r0", "r4", "r5", "r6", "r7" // List of register maintained manually.
00125     );
00126 }
00127 #elif defined ( __ICCARM__ )
00128 static inline void bootloader_util_reset(uint32_t start_addr)
00129 {
00130     asm("ldr   r5, [%0]\n"                    // Get App initial MSP for bootloader.
00131         "msr   msp, r5\n"                     // Set the main stack pointer to the applications MSP.
00132         "ldr   r0, [%0, #0x04]\n"             // Load Reset handler into R0.
00133 
00134         "movs  r4, #0x00\n"                   // Load zero into R4.
00135         "mvns  r4, r4\n"                      // Invert R4 to ensure it contain ones.
00136 
00137         "mrs   r5, IPSR\n"                    // Load IPSR to R5 to check for handler or thread mode 
00138         "cmp   r5, #0x00\n"                   // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
00139         "bne   isr_abort\n"                   // If not zero we need to exit current ISR and jump to reset handler of bootloader.
00140 
00141         "mov   lr, r4\n"                      // Clear the link register and set to ones to ensure no return.
00142         "bx    r0\n"                          // Branch to reset handler of bootloader.
00143 
00144         "isr_abort: \n"
00145                                               // R4 contains ones from line above. We be popped as R12 when exiting ISR (Cleaning up the registers).
00146         "mov   r5, r4\n"                      // Fill with ones before jumping to reset handling. Will be popped as LR when exiting ISR. Ensures no return to application.
00147         "mov   r6, r0\n"                      // Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
00148         "movs  r7, #0x21\n"                   // Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
00149         "rev   r7, r7\n"                      // Reverse byte order to put 0x21 as MSB.
00150         "push  {r4-r7}\n"                     // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
00151 
00152         "movs  r4, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
00153         "movs  r5, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
00154         "movs  r6, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
00155         "movs  r7, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
00156         "push  {r4-r7}\n"                     // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
00157 
00158         "movs  r0, #0x06\n"                   // Load 0x06 into R6 to prepare for exec return command.
00159         "mvns  r0, r0\n"                      // Invert 0x06 to obtain EXEC_RETURN, 0xFFFFFFF9.
00160         "bx    r0\n"                          // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
00161         :: "r" (start_addr)                   // Argument list for the IAR assembly. start_addr is %0.
00162         :  "r0", "r4", "r5", "r6", "r7");     // List of register maintained manually.
00163 }
00164 #else
00165 #error Compiler not supported.
00166 #endif
00167 
00168 
00169 void bootloader_util_app_start(uint32_t start_addr)
00170 {
00171     bootloader_util_reset(start_addr);
00172 }