Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nrf51-sdk by
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 }
Generated on Tue Jul 12 2022 14:11:19 by
