1/* SPDX-License-Identifier: BSD-3-Clause */ 2/* 3 * Copyright (c) 1994-2009 Red Hat, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * 3. Neither the name of the copyright holder nor the names of its 17 * contributors may be used to endorse or promote products derived from this 18 * software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32/* This is a simple version of setjmp and longjmp. 33 34 Nick Clifton, Cygnus Solutions, 13 June 1997. */ 35 36/* ANSI concatenation macros. */ 37#define CONCAT(a, b) CONCAT2(a, b) 38#define CONCAT2(a, b) a##b 39 40#ifndef __USER_LABEL_PREFIX__ 41#error __USER_LABEL_PREFIX__ not defined 42#endif 43 44#define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x) 45 46#ifdef __ELF__ 47#define TYPE(x) .type SYM(x),function 48#define SIZE(x) .size SYM(x), . - SYM(x) 49#else 50#define TYPE(x) 51#define SIZE(x) 52#endif 53 54 .section .note.GNU-stack,"",%progbits 55 56/* Arm/Thumb interworking support: 57 58 The interworking scheme expects functions to use a BX instruction 59 to return control to their parent. Since we need this code to work 60 in both interworked and non-interworked environments as well as with 61 older processors which do not have the BX instruction we do the 62 following: 63 Test the return address. 64 If the bottom bit is clear perform an "old style" function exit. 65 (We know that we are in ARM mode and returning to an ARM mode caller). 66 Otherwise use the BX instruction to perform the function exit. 67 68 We know that we will never attempt to perform the BX instruction on 69 an older processor, because that kind of processor will never be 70 interworked, and a return address with the bottom bit set will never 71 be generated. 72 73 In addition, we do not actually assemble the BX instruction as this would 74 require us to tell the assembler that the processor is an ARM7TDMI and 75 it would store this information in the binary. We want this binary to be 76 able to be linked with binaries compiled for older processors however, so 77 we do not want such information stored there. 78 79 If we are running using the APCS-26 convention however, then we never 80 test the bottom bit, because this is part of the processor status. 81 Instead we just do a normal return, since we know that we cannot be 82 returning to a Thumb caller - the Thumb does not support APCS-26. 83 84 Function entry is much simpler. If we are compiling for the Thumb we 85 just switch into ARM mode and then drop through into the rest of the 86 function. The function exit code will take care of the restore to 87 Thumb mode. 88 89 For Thumb-2 do everything in Thumb mode. */ 90 91#if defined(__ARM_ARCH_6M__) 92/* ARMv6-M has to be implemented in Thumb mode. */ 93 94.thumb 95.thumb_func 96 .globl SYM (setjmp) 97 TYPE (setjmp) 98SYM (setjmp): 99 /* Save registers in jump buffer. */ 100 stmia r0!, {r4, r5, r6, r7} 101 mov r1, r8 102 mov r2, r9 103 mov r3, r10 104 mov r4, fp 105 mov r5, sp 106 mov r6, lr 107 stmia r0!, {r1, r2, r3, r4, r5, r6} 108 sub r0, r0, #40 109 /* Restore callee-saved low regs. */ 110 ldmia r0!, {r4, r5, r6, r7} 111 /* Return zero. */ 112 mov r0, #0 113 bx lr 114 115.thumb_func 116 .globl SYM (longjmp) 117 TYPE (longjmp) 118SYM (longjmp): 119 /* Restore High regs. */ 120 add r0, r0, #16 121 ldmia r0!, {r2, r3, r4, r5, r6} 122 mov r8, r2 123 mov r9, r3 124 mov r10, r4 125 mov fp, r5 126 mov sp, r6 127 ldmia r0!, {r3} /* lr */ 128 /* Restore low regs. */ 129 sub r0, r0, #40 130 ldmia r0!, {r4, r5, r6, r7} 131 /* Return the result argument, or 1 if it is zero. */ 132 mov r0, r1 133 bne 1f 134 mov r0, #1 1351: 136 bx r3 137 138#else 139 140#ifdef __APCS_26__ 141#define RET movs pc, lr 142#elif defined(__thumb2__) 143#define RET bx lr 144#else 145#define RET tst lr, #1; \ 146 moveq pc, lr ; \ 147.word 0xe12fff1e /* bx lr */ 148#endif 149 150#ifdef __thumb2__ 151.macro COND where when 152 i\where \when 153.endm 154#else 155.macro COND where when 156.endm 157#endif 158 159#if defined(__thumb2__) 160.syntax unified 161.macro MODE 162 .thumb 163 .thumb_func 164.endm 165.macro PROLOGUE name 166.endm 167 168#elif defined(__thumb__) 169#define MODE .thumb_func 170.macro PROLOGUE name 171 .code 16 172 bx pc 173 nop 174 .code 32 175SYM (.arm_start_of.\name): 176.endm 177#else /* Arm */ 178#define MODE .code 32 179.macro PROLOGUE name 180.endm 181#endif 182 183.macro FUNC_START name 184 .text 185 .align 2 186 MODE 187 .globl SYM (\name) 188 TYPE (\name) 189SYM (\name): 190 PROLOGUE \name 191.endm 192 193.macro FUNC_END name 194 RET 195 SIZE (\name) 196.endm 197 198/* -------------------------------------------------------------------- 199 int setjmp (jmp_buf); 200 -------------------------------------------------------------------- */ 201 202 FUNC_START setjmp 203 204 /* Save all the callee-preserved registers into the jump buffer. */ 205#ifdef __thumb2__ 206 mov ip, sp 207 stmea a1!, { v1-v7, fp, ip, lr } 208#else 209 stmea a1!, { v1-v7, fp, ip} 210 str sp, [a1], #4 211 str lr, [a1], #4 212#endif 213 214#if 0 /* Simulator does not cope with FP instructions yet. */ 215#ifndef __SOFTFP__ 216 /* Save the floating point registers. */ 217 sfmea f4, 4, [a1] 218#endif 219#endif 220 221#ifdef CFG_FTRACE_SUPPORT 222 stmdb sp!, { lr } 223 /* 224 * As ftrace is supported in ARM mode only, so hardcode jmp_buf 225 * offset used to save ftrace return index. 226 */ 227 add a1, a1, #48 228 bl ftrace_setjmp 229 ldmia sp!, { lr } 230#endif 231 232 /* When setting up the jump buffer return 0. */ 233 mov a1, #0 234 235 FUNC_END setjmp 236 237/* -------------------------------------------------------------------- 238 volatile void longjmp (jmp_buf, int); 239 -------------------------------------------------------------------- */ 240 241 FUNC_START longjmp 242 243 /* If we have stack extension code it ought to be handled here. */ 244 245#ifdef CFG_FTRACE_SUPPORT 246 stmdb sp!, { a1, a2, lr } 247 /* 248 * As ftrace is supported in ARM mode only, so hardcode jmp_buf 249 * offset used to restore ftrace return stack. 250 */ 251 add a1, a1, #92 252 bl ftrace_longjmp 253 ldmia sp!, { a1, a2, lr } 254#endif 255 256 /* Restore the registers, retrieving the state when setjmp() was called. */ 257#ifdef __thumb2__ 258 ldmfd a1!, { v1-v7, fp, ip, lr } 259 mov sp, ip 260#else 261 ldmfd a1!, { v1-v7, fp, ip } 262 ldr sp, [a1], #4 263 ldr lr, [a1], #4 264#endif 265 266#if 0 /* Simulator does not cope with FP instructions yet. */ 267#ifndef __SOFTFP__ 268 /* Restore floating point registers as well. */ 269 lfmfd f4, 4, [a1] 270#endif 271#endif 272 /* Put the return value into the integer result register. 273 But if it is zero then return 1 instead. */ 274 movs a1, a2 275#ifdef __thumb2__ 276 it eq 277#endif 278 moveq a1, #1 279 280 FUNC_END longjmp 281#endif 282