1//===------------------------ UnwindRegistersSave.S -----------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "assembly.h"
11
12    .text
13
14#if defined(__i386__)
15
16#
17# extern int unw_getcontext(unw_context_t* thread_state)
18#
19# On entry:
20#   +                       +
21#   +-----------------------+
22#   + thread_state pointer  +
23#   +-----------------------+
24#   + return address        +
25#   +-----------------------+   <-- SP
26#   +                       +
27#
28DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
29  push  %eax
30  movl  8(%esp), %eax
31  movl  %ebx,  4(%eax)
32  movl  %ecx,  8(%eax)
33  movl  %edx, 12(%eax)
34  movl  %edi, 16(%eax)
35  movl  %esi, 20(%eax)
36  movl  %ebp, 24(%eax)
37  movl  %esp, %edx
38  addl  $8, %edx
39  movl  %edx, 28(%eax)  # store what sp was at call site as esp
40  # skip ss
41  # skip eflags
42  movl  4(%esp), %edx
43  movl  %edx, 40(%eax)  # store return address as eip
44  # skip cs
45  # skip ds
46  # skip es
47  # skip fs
48  # skip gs
49  movl  (%esp), %edx
50  movl  %edx, (%eax)  # store original eax
51  popl  %eax
52  xorl  %eax, %eax    # return UNW_ESUCCESS
53  ret
54
55#elif defined(__x86_64__)
56
57#
58# extern int unw_getcontext(unw_context_t* thread_state)
59#
60# On entry:
61#  thread_state pointer is in rdi
62#
63DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
64  movq  %rax,   (%rdi)
65  movq  %rbx,  8(%rdi)
66  movq  %rcx, 16(%rdi)
67  movq  %rdx, 24(%rdi)
68  movq  %rdi, 32(%rdi)
69  movq  %rsi, 40(%rdi)
70  movq  %rbp, 48(%rdi)
71  movq  %rsp, 56(%rdi)
72  addq  $8,   56(%rdi)
73  movq  %r8,  64(%rdi)
74  movq  %r9,  72(%rdi)
75  movq  %r10, 80(%rdi)
76  movq  %r11, 88(%rdi)
77  movq  %r12, 96(%rdi)
78  movq  %r13,104(%rdi)
79  movq  %r14,112(%rdi)
80  movq  %r15,120(%rdi)
81  movq  (%rsp),%rsi
82  movq  %rsi,128(%rdi) # store return address as rip
83  # skip rflags
84  # skip cs
85  # skip fs
86  # skip gs
87  xorl  %eax, %eax    # return UNW_ESUCCESS
88  ret
89
90# elif defined(__mips__)
91
92#
93# extern int unw_getcontext(unw_context_t* thread_state)
94#
95# Just trap for the time being.
96DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
97  teq $0, $0
98
99#elif defined(__ppc__)
100
101;
102; extern int unw_getcontext(unw_context_t* thread_state)
103;
104; On entry:
105;  thread_state pointer is in r3
106;
107DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
108  stw    r0,  8(r3)
109  mflr  r0
110  stw    r0,  0(r3)  ; store lr as ssr0
111  stw    r1, 12(r3)
112  stw    r2, 16(r3)
113  stw    r3, 20(r3)
114  stw    r4, 24(r3)
115  stw    r5, 28(r3)
116  stw    r6, 32(r3)
117  stw    r7, 36(r3)
118  stw    r8, 40(r3)
119  stw    r9, 44(r3)
120  stw     r10, 48(r3)
121  stw     r11, 52(r3)
122  stw     r12, 56(r3)
123  stw     r13, 60(r3)
124  stw     r14, 64(r3)
125  stw     r15, 68(r3)
126  stw     r16, 72(r3)
127  stw     r17, 76(r3)
128  stw     r18, 80(r3)
129  stw     r19, 84(r3)
130  stw     r20, 88(r3)
131  stw     r21, 92(r3)
132  stw     r22, 96(r3)
133  stw     r23,100(r3)
134  stw     r24,104(r3)
135  stw     r25,108(r3)
136  stw     r26,112(r3)
137  stw     r27,116(r3)
138  stw     r28,120(r3)
139  stw     r29,124(r3)
140  stw     r30,128(r3)
141  stw     r31,132(r3)
142
143  ; save VRSave register
144  mfspr  r0,256
145  stw    r0,156(r3)
146  ; save CR registers
147  mfcr  r0
148  stw    r0,136(r3)
149  ; save CTR register
150  mfctr  r0
151  stw    r0,148(r3)
152
153  ; save float registers
154  stfd    f0, 160(r3)
155  stfd    f1, 168(r3)
156  stfd    f2, 176(r3)
157  stfd    f3, 184(r3)
158  stfd    f4, 192(r3)
159  stfd    f5, 200(r3)
160  stfd    f6, 208(r3)
161  stfd    f7, 216(r3)
162  stfd    f8, 224(r3)
163  stfd    f9, 232(r3)
164  stfd    f10,240(r3)
165  stfd    f11,248(r3)
166  stfd    f12,256(r3)
167  stfd    f13,264(r3)
168  stfd    f14,272(r3)
169  stfd    f15,280(r3)
170  stfd    f16,288(r3)
171  stfd    f17,296(r3)
172  stfd    f18,304(r3)
173  stfd    f19,312(r3)
174  stfd    f20,320(r3)
175  stfd    f21,328(r3)
176  stfd    f22,336(r3)
177  stfd    f23,344(r3)
178  stfd    f24,352(r3)
179  stfd    f25,360(r3)
180  stfd    f26,368(r3)
181  stfd    f27,376(r3)
182  stfd    f28,384(r3)
183  stfd    f29,392(r3)
184  stfd    f30,400(r3)
185  stfd    f31,408(r3)
186
187
188  ; save vector registers
189
190  subi  r4,r1,16
191  rlwinm  r4,r4,0,0,27  ; mask low 4-bits
192  ; r4 is now a 16-byte aligned pointer into the red zone
193
194#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
195  stvx  _vec,0,r4           @\
196  lwz    r5, 0(r4)          @\
197  stw    r5, _offset(r3)    @\
198  lwz    r5, 4(r4)          @\
199  stw    r5, _offset+4(r3)  @\
200  lwz    r5, 8(r4)          @\
201  stw    r5, _offset+8(r3)  @\
202  lwz    r5, 12(r4)         @\
203  stw    r5, _offset+12(r3)
204
205  SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
206  SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
207  SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
208  SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
209  SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
210  SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
211  SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
212  SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
213  SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
214  SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
215  SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
216  SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
217  SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
218  SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
219  SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
220  SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
221  SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
222  SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
223  SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
224  SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
225  SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
226  SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
227  SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
228  SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
229  SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
230  SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
231  SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
232  SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
233  SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
234  SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
235  SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
236  SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
237
238  li  r3, 0    ; return UNW_ESUCCESS
239  blr
240
241
242#elif defined(__arm64__) || defined(__aarch64__)
243
244//
245// extern int unw_getcontext(unw_context_t* thread_state)
246//
247// On entry:
248//  thread_state pointer is in x0
249//
250  .p2align 2
251DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
252  stp    x0, x1,  [x0, #0x000]
253  stp    x2, x3,  [x0, #0x010]
254  stp    x4, x5,  [x0, #0x020]
255  stp    x6, x7,  [x0, #0x030]
256  stp    x8, x9,  [x0, #0x040]
257  stp    x10,x11, [x0, #0x050]
258  stp    x12,x13, [x0, #0x060]
259  stp    x14,x15, [x0, #0x070]
260  stp    x16,x17, [x0, #0x080]
261  stp    x18,x19, [x0, #0x090]
262  stp    x20,x21, [x0, #0x0A0]
263  stp    x22,x23, [x0, #0x0B0]
264  stp    x24,x25, [x0, #0x0C0]
265  stp    x26,x27, [x0, #0x0D0]
266  stp    x28,fp,  [x0, #0x0E0]
267  str    lr,      [x0, #0x0F0]
268  mov    x1,sp
269  str    x1,      [x0, #0x0F8]
270  str    lr,      [x0, #0x100]    // store return address as pc
271  // skip cpsr
272  stp    d0, d1,  [x0, #0x110]
273  stp    d2, d3,  [x0, #0x120]
274  stp    d4, d5,  [x0, #0x130]
275  stp    d6, d7,  [x0, #0x140]
276  stp    d8, d9,  [x0, #0x150]
277  stp    d10,d11, [x0, #0x160]
278  stp    d12,d13, [x0, #0x170]
279  stp    d14,d15, [x0, #0x180]
280  stp    d16,d17, [x0, #0x190]
281  stp    d18,d19, [x0, #0x1A0]
282  stp    d20,d21, [x0, #0x1B0]
283  stp    d22,d23, [x0, #0x1C0]
284  stp    d24,d25, [x0, #0x1D0]
285  stp    d26,d27, [x0, #0x1E0]
286  stp    d28,d29, [x0, #0x1F0]
287  str    d30,     [x0, #0x200]
288  str    d31,     [x0, #0x208]
289  mov    x0, #0                   // return UNW_ESUCCESS
290  ret
291
292#elif defined(__arm__) && !defined(__APPLE__)
293
294#if !defined(__ARM_ARCH_ISA_ARM)
295  .thumb
296#endif
297
298@
299@ extern int unw_getcontext(unw_context_t* thread_state)
300@
301@ On entry:
302@  thread_state pointer is in r0
303@
304@ Per EHABI #4.7 this only saves the core integer registers.
305@ EHABI #7.4.5 notes that in general all VRS registers should be restored
306@ however this is very hard to do for VFP registers because it is unknown
307@ to the library how many registers are implemented by the architecture.
308@ Instead, VFP registers are demand saved by logic external to unw_getcontext.
309@
310  .p2align 2
311DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
312#if !defined(__ARM_ARCH_ISA_ARM)
313  stm r0, {r0-r7}
314  mov r2, sp
315  mov r3, lr
316  str r2, [r0, #52]
317  str r3, [r0, #56]
318  str r3, [r0, #60]  @ store return address as pc
319#else
320  @ 32bit thumb-2 restrictions for stm:
321  @ . the sp (r13) cannot be in the list
322  @ . the pc (r15) cannot be in the list in an STM instruction
323  stm r0, {r0-r12}
324  str sp, [r0, #52]
325  str lr, [r0, #56]
326  str lr, [r0, #60]  @ store return address as pc
327#endif
328#if __ARM_ARCH_ISA_THUMB == 1
329  @ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
330  @ It is safe to use here though because we are about to return, and cpsr is
331  @ not expected to be preserved.
332  movs r0, #0        @ return UNW_ESUCCESS
333#else
334  mov r0, #0         @ return UNW_ESUCCESS
335#endif
336  JMP(lr)
337
338@
339@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values)
340@
341@ On entry:
342@  values pointer is in r0
343@
344  .p2align 2
345  .fpu vfpv3-d16
346DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy)
347  vstmia r0, {d0-d15}
348  JMP(lr)
349
350@
351@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values)
352@
353@ On entry:
354@  values pointer is in r0
355@
356  .p2align 2
357  .fpu vfpv3-d16
358DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy)
359  vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
360  JMP(lr)
361
362@
363@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values)
364@
365@ On entry:
366@  values pointer is in r0
367@
368  .p2align 2
369  .fpu vfpv3
370DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
371  @ VFP and iwMMX instructions are only available when compiling with the flags
372  @ that enable them. We do not want to do that in the library (because we do not
373  @ want the compiler to generate instructions that access those) but this is
374  @ only accessed if the personality routine needs these registers. Use of
375  @ these registers implies they are, actually, available on the target, so
376  @ it's ok to execute.
377  @ So, generate the instructions using the corresponding coprocessor mnemonic.
378  vstmia r0, {d16-d31}
379  JMP(lr)
380
381@
382@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
383@
384@ On entry:
385@  values pointer is in r0
386@
387  .p2align 2
388DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
389#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
390  stcl p1, cr0, [r0], #8  @ wstrd wR0, [r0], #8
391  stcl p1, cr1, [r0], #8  @ wstrd wR1, [r0], #8
392  stcl p1, cr2, [r0], #8  @ wstrd wR2, [r0], #8
393  stcl p1, cr3, [r0], #8  @ wstrd wR3, [r0], #8
394  stcl p1, cr4, [r0], #8  @ wstrd wR4, [r0], #8
395  stcl p1, cr5, [r0], #8  @ wstrd wR5, [r0], #8
396  stcl p1, cr6, [r0], #8  @ wstrd wR6, [r0], #8
397  stcl p1, cr7, [r0], #8  @ wstrd wR7, [r0], #8
398  stcl p1, cr8, [r0], #8  @ wstrd wR8, [r0], #8
399  stcl p1, cr9, [r0], #8  @ wstrd wR9, [r0], #8
400  stcl p1, cr10, [r0], #8  @ wstrd wR10, [r0], #8
401  stcl p1, cr11, [r0], #8  @ wstrd wR11, [r0], #8
402  stcl p1, cr12, [r0], #8  @ wstrd wR12, [r0], #8
403  stcl p1, cr13, [r0], #8  @ wstrd wR13, [r0], #8
404  stcl p1, cr14, [r0], #8  @ wstrd wR14, [r0], #8
405  stcl p1, cr15, [r0], #8  @ wstrd wR15, [r0], #8
406#endif
407  JMP(lr)
408
409@
410@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values)
411@
412@ On entry:
413@  values pointer is in r0
414@
415  .p2align 2
416DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
417#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
418  stc2 p1, cr8, [r0], #4  @ wstrw wCGR0, [r0], #4
419  stc2 p1, cr9, [r0], #4  @ wstrw wCGR1, [r0], #4
420  stc2 p1, cr10, [r0], #4  @ wstrw wCGR2, [r0], #4
421  stc2 p1, cr11, [r0], #4  @ wstrw wCGR3, [r0], #4
422#endif
423  JMP(lr)
424
425#elif defined(__or1k__)
426
427#
428# extern int unw_getcontext(unw_context_t* thread_state)
429#
430# On entry:
431#  thread_state pointer is in r3
432#
433DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
434  l.sw       0(r3), r0
435  l.sw       4(r3), r1
436  l.sw       8(r3), r2
437  l.sw      12(r3), r3
438  l.sw      16(r3), r4
439  l.sw      20(r3), r5
440  l.sw      24(r3), r6
441  l.sw      28(r3), r7
442  l.sw      32(r3), r8
443  l.sw      36(r3), r9
444  l.sw      40(r3), r10
445  l.sw      44(r3), r11
446  l.sw      48(r3), r12
447  l.sw      52(r3), r13
448  l.sw      56(r3), r14
449  l.sw      60(r3), r15
450  l.sw      64(r3), r16
451  l.sw      68(r3), r17
452  l.sw      72(r3), r18
453  l.sw      76(r3), r19
454  l.sw      80(r3), r20
455  l.sw      84(r3), r21
456  l.sw      88(r3), r22
457  l.sw      92(r3), r23
458  l.sw      96(r3), r24
459  l.sw     100(r3), r25
460  l.sw     104(r3), r26
461  l.sw     108(r3), r27
462  l.sw     112(r3), r28
463  l.sw     116(r3), r29
464  l.sw     120(r3), r30
465  l.sw     124(r3), r31
466#endif
467