1 | /* Copyright (C) 2012-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* ??? Needs more rearrangement for the LDM to handle thumb mode. */ |
19 | #define NO_THUMB |
20 | #include <sysdep.h> |
21 | #include <rtld-global-offsets.h> |
22 | |
23 | #include "ucontext_i.h" |
24 | |
25 | .syntax unified |
26 | .text |
27 | |
28 | /* int setcontext (const ucontext_t *ucp) */ |
29 | |
30 | ENTRY(__setcontext) |
31 | mov r4, r0 |
32 | add r0, r0, #UCONTEXT_REGSPACE |
33 | |
34 | /* Restore the VFP registers. Copied from arm/__longjmp.S. */ |
35 | #ifdef SHARED |
36 | ldr r2, 1f |
37 | ldr r1, .Lrtld_global_ro |
38 | 0: add r2, pc, r2 |
39 | ldr r2, [r2, r1] |
40 | ldr r2, [r2, #RTLD_GLOBAL_RO_DL_HWCAP_OFFSET] |
41 | #else |
42 | ldr r2, .Lhwcap |
43 | ldr r2, [r2, #0] |
44 | #endif |
45 | |
46 | #ifdef __SOFTFP__ |
47 | tst r2, #HWCAP_ARM_VFP |
48 | beq .Lno_vfp_sc |
49 | #endif |
50 | |
51 | /* Following instruction is vldmia r0!, {d8-d15}. */ |
52 | ldc p11, cr8, [r0], #64 |
53 | /* Restore the floating-point status register. */ |
54 | ldr r1, [r0], #4 |
55 | /* Following instruction is fmxr fpscr, r1. */ |
56 | mcr p10, 7, r1, cr1, cr0, 0 |
57 | .Lno_vfp_sc: |
58 | tst r2, #HWCAP_ARM_IWMMXT |
59 | beq .Lno_iwmmxt_sc |
60 | |
61 | /* Restore the call-preserved iWMMXt registers. */ |
62 | /* Following instructions are wldrd wr10, [r0], #8 (etc.) */ |
63 | ldcl p1, cr10, [r0], #8 |
64 | ldcl p1, cr11, [r0], #8 |
65 | ldcl p1, cr12, [r0], #8 |
66 | ldcl p1, cr13, [r0], #8 |
67 | ldcl p1, cr14, [r0], #8 |
68 | ldcl p1, cr15, [r0], #8 |
69 | .Lno_iwmmxt_sc: |
70 | |
71 | /* Now bring back the signal status. */ |
72 | mov r0, #SIG_SETMASK |
73 | add r1, r4, #UCONTEXT_SIGMASK |
74 | mov r2, #0 |
75 | bl PLTJMP(__sigprocmask) |
76 | |
77 | /* Loading r0-r3 makes makecontext easier. */ |
78 | add r14, r4, #MCONTEXT_ARM_R0 |
79 | ldmia r14, {r0-r12} |
80 | ldr r13, [r14, #(MCONTEXT_ARM_SP - MCONTEXT_ARM_R0)] |
81 | add r14, r14, #(MCONTEXT_ARM_LR - MCONTEXT_ARM_R0) |
82 | ldmia r14, {r14, pc} |
83 | |
84 | END(setcontext) |
85 | weak_alias(__setcontext, setcontext) |
86 | |
87 | /* Called when a makecontext() context returns. Start the |
88 | context in R4 or fall through to exit(). */ |
89 | /* Unwind descriptors are looked up based on PC - 2, so we have to |
90 | make sure to mark the instruction preceding the __startcontext |
91 | label as .cantunwind. */ |
92 | .fnstart |
93 | .cantunwind |
94 | nop |
95 | ENTRY(__startcontext) |
96 | movs r0, r4 |
97 | bne PLTJMP(__setcontext) |
98 | |
99 | @ New context was 0 - exit |
100 | b PLTJMP(HIDDEN_JUMPTARGET(exit)) |
101 | .fnend |
102 | END(__startcontext) |
103 | |
104 | #ifdef SHARED |
105 | 1: .long _GLOBAL_OFFSET_TABLE_ - 0b - PC_OFS |
106 | .Lrtld_global_ro: |
107 | .long C_SYMBOL_NAME(_rtld_global_ro)(GOT) |
108 | #else |
109 | .Lhwcap: |
110 | .long C_SYMBOL_NAME(_dl_hwcap) |
111 | #endif |
112 | |