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