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