1/* ARM support code for fibers and multithreading. 2 Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 3, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16Under Section 7 of GPL version 3, you are granted additional 17permissions described in the GCC Runtime Library Exception, version 183.1, as published by the Free Software Foundation. 19 20You should have received a copy of the GNU General Public License and 21a copy of the GCC Runtime Library Exception along with this program; 22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23<http://www.gnu.org/licenses/>. */ 24 25#include "../common/threadasm.S" 26 27#if defined(__ARM_EABI__) 28 29/** 30 * Performs a context switch. 31 * 32 * Parameters: 33 * r0 - void** - ptr to old stack pointer 34 * r1 - void* - new stack pointer 35 * 36 * ARM EABI registers: 37 * r0-r3 : argument/scratch registers 38 * r4-r10 : callee-save registers 39 * r11 : frame pointer (or a callee save register if fp isn't needed) 40 * r12 =ip : inter procedure register. We can treat it like any other scratch 41 * register 42 * r13 =sp : stack pointer 43 * r14 =lr : link register, it contains the return address (belonging to the 44 * function which called us) 45 * r15 =pc : program counter 46 * 47 * For floating point registers: 48 * According to AAPCS (version 2.09, section 5.1.2) only the d8-d15 registers 49 * need to be preserved across method calls. This applies to all ARM FPU 50 * variants, whether they have 16 or 32 double registers NEON support or not, 51 * half-float support or not and so on does not matter. 52 * 53 * Note: If this file was compiled with -mfloat-abi=soft but the code runs on a 54 * softfp system with fpu the d8-d15 registers won't be saved (we do not know 55 * that the system has got a fpu in that case) but the registers might actually 56 * be used by other code if it was compiled with -mfloat-abi=softfp. 57 * 58 * Interworking is only supported on ARMv5+, not on ARM v4T as ARM v4t requires 59 * special stubs when changing from thumb to arm mode or the other way round. 60 */ 61 62 .text 63#if defined(__ARM_PCS_VFP) || (defined(__ARM_PCS) && !defined(__SOFTFP__)) 64 .fpu vfp 65#endif 66 .global CSYM(fiber_switchContext) 67 .type CSYM(fiber_switchContext), %function 68 .align 4 69CSYM(fiber_switchContext): 70 .cfi_sections .debug_frame 71 .cfi_startproc 72 .fnstart 73 push {r4-r11} 74 // update the oldp pointer. Link register and floating point registers 75 // stored later to prevent the GC from scanning them. 76 str sp, [r0] 77 // push r0 (or any other register) as well to keep stack 8byte aligned 78 push {r0, lr} 79 80 // ARM_HardFloat || ARM_SoftFP 81#if defined(__ARM_PCS_VFP) || (defined(__ARM_PCS) && !defined(__SOFTFP__)) 82 vpush {d8-d15} 83 // now switch over to the new stack. 84 // Need to subtract (8*8[d8-d15]+2*4[r0, lr]) to position stack pointer 85 // below the last saved register. Remember we saved the SP before pushing 86 // [r0, lr, d8-d15]. 87 sub sp, r1, #72 88 vpop {d8-d15} 89#else 90 sub sp, r1, #8 91#endif 92 93 // we don't really care about r0, we only used that for padding. 94 // r1 is now what used to be in the link register when saving. 95 pop {r0, r1, r4-r11} 96 /** 97 * The link register for the initial jump to fiber_entryPoint must be zero: 98 * The jump actually looks like a normal method call as we jump to the 99 * start of the fiber_entryPoint function. Although fiber_entryPoint never 100 * returns and therefore never accesses lr, it saves lr to the stack. 101 * ARM unwinding will then look at the stack, find lr and think that 102 * fiber_entryPoint was called by the function in lr! So if we have some 103 * address in lr the unwinder will try to continue stack unwinding, 104 * although it's already at the stack base and crash. 105 * In all other cases the content of lr doesn't matter. 106 * Note: If we simply loaded into lr above and then moved lr into pc, the 107 * initial method call to fiber_entryPoint would look as if it was called 108 * from fiber_entryPoint itself, as the fiber_entryPoint address is in lr 109 * on the initial context switch. 110 */ 111 mov lr, #0 112 // return by writing lr into pc 113 mov pc, r1 114 .fnend 115 .cfi_endproc 116 .size CSYM(fiber_switchContext),.-CSYM(fiber_switchContext) 117 118#endif 119