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/* Arm/Thumb interworking support: 55 56 The interworking scheme expects functions to use a BX instruction 57 to return control to their parent. Since we need this code to work 58 in both interworked and non-interworked environments as well as with 59 older processors which do not have the BX instruction we do the 60 following: 61 Test the return address. 62 If the bottom bit is clear perform an "old style" function exit. 63 (We know that we are in ARM mode and returning to an ARM mode caller). 64 Otherwise use the BX instruction to perform the function exit. 65 66 We know that we will never attempt to perform the BX instruction on 67 an older processor, because that kind of processor will never be 68 interworked, and a return address with the bottom bit set will never 69 be generated. 70 71 In addition, we do not actually assemble the BX instruction as this would 72 require us to tell the assembler that the processor is an ARM7TDMI and 73 it would store this information in the binary. We want this binary to be 74 able to be linked with binaries compiled for older processors however, so 75 we do not want such information stored there. 76 77 If we are running using the APCS-26 convention however, then we never 78 test the bottom bit, because this is part of the processor status. 79 Instead we just do a normal return, since we know that we cannot be 80 returning to a Thumb caller - the Thumb does not support APCS-26. 81 82 Function entry is much simpler. If we are compiling for the Thumb we 83 just switch into ARM mode and then drop through into the rest of the 84 function. The function exit code will take care of the restore to 85 Thumb mode. 86 87 For Thumb-2 do everything in Thumb mode. */ 88 89#if defined(__ARM_ARCH_6M__) 90/* ARMv6-M has to be implemented in Thumb mode. */ 91 92.thumb 93.thumb_func 94 .globl SYM (setjmp) 95 TYPE (setjmp) 96SYM (setjmp): 97 /* Save registers in jump buffer. */ 98 stmia r0!, {r4, r5, r6, r7} 99 mov r1, r8 100 mov r2, r9 101 mov r3, r10 102 mov r4, fp 103 mov r5, sp 104 mov r6, lr 105 stmia r0!, {r1, r2, r3, r4, r5, r6} 106 sub r0, r0, #40 107 /* Restore callee-saved low regs. */ 108 ldmia r0!, {r4, r5, r6, r7} 109 /* Return zero. */ 110 mov r0, #0 111 bx lr 112 113.thumb_func 114 .globl SYM (longjmp) 115 TYPE (longjmp) 116SYM (longjmp): 117 /* Restore High regs. */ 118 add r0, r0, #16 119 ldmia r0!, {r2, r3, r4, r5, r6} 120 mov r8, r2 121 mov r9, r3 122 mov r10, r4 123 mov fp, r5 124 mov sp, r6 125 ldmia r0!, {r3} /* lr */ 126 /* Restore low regs. */ 127 sub r0, r0, #40 128 ldmia r0!, {r4, r5, r6, r7} 129 /* Return the result argument, or 1 if it is zero. */ 130 mov r0, r1 131 bne 1f 132 mov r0, #1 1331: 134 bx r3 135 136#else 137 138#ifdef __APCS_26__ 139#define RET movs pc, lr 140#elif defined(__thumb2__) 141#define RET bx lr 142#else 143#define RET tst lr, #1; \ 144 moveq pc, lr ; \ 145.word 0xe12fff1e /* bx lr */ 146#endif 147 148#ifdef __thumb2__ 149.macro COND where when 150 i\where \when 151.endm 152#else 153.macro COND where when 154.endm 155#endif 156 157#if defined(__thumb2__) 158.syntax unified 159.macro MODE 160 .thumb 161 .thumb_func 162.endm 163.macro PROLOGUE name 164.endm 165 166#elif defined(__thumb__) 167#define MODE .thumb_func 168.macro PROLOGUE name 169 .code 16 170 bx pc 171 nop 172 .code 32 173SYM (.arm_start_of.\name): 174.endm 175#else /* Arm */ 176#define MODE .code 32 177.macro PROLOGUE name 178.endm 179#endif 180 181.macro FUNC_START name 182 .text 183 .align 2 184 MODE 185 .globl SYM (\name) 186 TYPE (\name) 187SYM (\name): 188 PROLOGUE \name 189.endm 190 191.macro FUNC_END name 192 RET 193 SIZE (\name) 194.endm 195 196/* -------------------------------------------------------------------- 197 int setjmp (jmp_buf); 198 -------------------------------------------------------------------- */ 199 200 FUNC_START setjmp 201 202 /* Save all the callee-preserved registers into the jump buffer. */ 203#ifdef __thumb2__ 204 mov ip, sp 205 stmea a1!, { v1-v7, fp, ip, lr } 206#else 207 stmea a1!, { v1-v7, fp, ip} 208 str sp, [a1], #4 209 str lr, [a1], #4 210#endif 211 212#if 0 /* Simulator does not cope with FP instructions yet. */ 213#ifndef __SOFTFP__ 214 /* Save the floating point registers. */ 215 sfmea f4, 4, [a1] 216#endif 217#endif 218 219#ifdef CFG_FTRACE_SUPPORT 220 stmdb sp!, { lr } 221 /* 222 * As ftrace is supported in ARM mode only, so hardcode jmp_buf 223 * offset used to save ftrace return index. 224 */ 225 add a1, a1, #48 226 bl ftrace_setjmp 227 ldmia sp!, { lr } 228#endif 229 230 /* When setting up the jump buffer return 0. */ 231 mov a1, #0 232 233 FUNC_END setjmp 234 235/* -------------------------------------------------------------------- 236 volatile void longjmp (jmp_buf, int); 237 -------------------------------------------------------------------- */ 238 239 FUNC_START longjmp 240 241 /* If we have stack extension code it ought to be handled here. */ 242 243#ifdef CFG_FTRACE_SUPPORT 244 stmdb sp!, { a1, a2, lr } 245 /* 246 * As ftrace is supported in ARM mode only, so hardcode jmp_buf 247 * offset used to restore ftrace return stack. 248 */ 249 add a1, a1, #92 250 bl ftrace_longjmp 251 ldmia sp!, { a1, a2, lr } 252#endif 253 254 /* Restore the registers, retrieving the state when setjmp() was called. */ 255#ifdef __thumb2__ 256 ldmfd a1!, { v1-v7, fp, ip, lr } 257 mov sp, ip 258#else 259 ldmfd a1!, { v1-v7, fp, ip } 260 ldr sp, [a1], #4 261 ldr lr, [a1], #4 262#endif 263 264#if 0 /* Simulator does not cope with FP instructions yet. */ 265#ifndef __SOFTFP__ 266 /* Restore floating point registers as well. */ 267 lfmfd f4, 4, [a1] 268#endif 269#endif 270 /* Put the return value into the integer result register. 271 But if it is zero then return 1 instead. */ 272 movs a1, a2 273#ifdef __thumb2__ 274 it eq 275#endif 276 moveq a1, #1 277 278 FUNC_END longjmp 279#endif 280