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, sp, lr } 208#endif 209 210#if 0 /* Simulator does not cope with FP instructions yet. */ 211#ifndef __SOFTFP__ 212 /* Save the floating point registers. */ 213 sfmea f4, 4, [a1] 214#endif 215#endif 216 /* When setting up the jump buffer return 0. */ 217 mov a1, #0 218 219 FUNC_END setjmp 220 221/* -------------------------------------------------------------------- 222 volatile void longjmp (jmp_buf, int); 223 -------------------------------------------------------------------- */ 224 225 FUNC_START longjmp 226 227 /* If we have stack extension code it ought to be handled here. */ 228 229 /* Restore the registers, retrieving the state when setjmp() was called. */ 230#ifdef __thumb2__ 231 ldmfd a1!, { v1-v7, fp, ip, lr } 232 mov sp, ip 233#else 234 ldmfd a1!, { v1-v7, fp, ip, sp, lr } 235#endif 236 237#if 0 /* Simulator does not cope with FP instructions yet. */ 238#ifndef __SOFTFP__ 239 /* Restore floating point registers as well. */ 240 lfmfd f4, 4, [a1] 241#endif 242#endif 243 /* Put the return value into the integer result register. 244 But if it is zero then return 1 instead. */ 245 movs a1, a2 246#ifdef __thumb2__ 247 it eq 248#endif 249 moveq a1, #1 250 251 FUNC_END longjmp 252#endif 253