0.8.19.25:
[sbcl.git] / src / runtime / x86-64-assem.S
1 /*
2  * very-low-level utilities for runtime support
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15 \f
16 #define LANGUAGE_ASSEMBLY
17 #include "validate.h"
18 #include "sbcl.h"
19 #include "genesis/closure.h"
20 #include "genesis/fdefn.h"
21 #include "genesis/static-symbols.h"
22 #include "genesis/symbol.h"
23 #include "genesis/thread.h"
24         
25 /* Minimize conditionalization for different OS naming schemes. */
26 #if defined __linux__  || defined __FreeBSD__ /* (but *not* OpenBSD) */
27 #define GNAME(var) var
28 #else
29 #define GNAME(var) _##var
30 #endif
31
32 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
33  * want alignment in bytes. */
34 #if defined(__linux__) || defined(__FreeBSD__)
35 #define align_4byte     4
36 #define align_8byte     8
37 #define align_16byte    16
38 #define align_32byte    32
39 #else
40 #define align_4byte     2
41 #define align_8byte     3
42 #define align_16byte    4       
43 #endif                  
44
45         .text
46         .global GNAME(foreign_function_call_active)
47         .global GNAME(all_threads)
48         
49 \f
50 /* From lower to higher-numbered addresses, the stack contains 
51  * return address, arg 0, arg 1, arg 2 ...
52  * rax contains the address of the function to call
53  * Lisp expects return value in rax, whic is already consistent with C
54  * XXXX correct floating point handling is unimplemented so far
55  * Based on comments cleaned from x86-assem.S, we believe that 
56  * Lisp is expecting us to preserve rsi, rdi, rsp (no idea about r8-15)
57  */
58         .text
59         .align  align_16byte,0x90
60         .global GNAME(call_into_c)
61         .type   GNAME(call_into_c),@function
62 GNAME(call_into_c):
63         push    %rbp            # Save old frame pointer.
64         mov     %rsp,%rbp       # Establish new frame.
65
66         push    %rsi            # args are going in here
67         push    %rdi
68         mov     16(%rbp),%rdi
69         mov     24(%rbp),%rsi
70         mov     32(%rbp),%rdx
71         mov     40(%rbp),%rcx
72         mov     48(%rbp),%rcx
73         mov     56(%rbp),%r8
74         mov     64(%rbp),%r9
75         call    *%rax
76         mov     %rbp,%rsp
77         pop     %rbp
78         ret
79         .size   GNAME(call_into_c), . - GNAME(call_into_c)
80
81 \f
82         .text   
83         .global GNAME(call_into_lisp_first_time)
84         .type  GNAME(call_into_lisp_first_time),@function
85                 
86 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
87  * the stack changes.  We don't worry too much about saving registers 
88  * here, because we never expect to return from the initial call to lisp 
89  * anyway */
90         
91         .align  align_16byte,0x90
92 GNAME(call_into_lisp_first_time):
93         push    %rbp            # Save old frame pointer.
94         mov     %rsp,%rbp       # Establish new frame.
95         mov    %rsp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
96         mov    GNAME(all_threads),%rax
97         mov    THREAD_CONTROL_STACK_START_OFFSET(%rax) ,%rsp
98         /* don't think too hard about what happens if we get interrupted
99         * here */
100         add     $THREAD_CONTROL_STACK_SIZE-8,%rsp
101         jmp     Lstack
102 \f
103         .text   
104         .global GNAME(call_into_lisp)
105         .type  GNAME(call_into_lisp),@function
106                 
107 /*
108  * amd64 calling convention: C expects that
109  * arguments go in rdi rsi rdx rcx r8 r9
110  * return values in rax rdx
111  * callee saves rbp rbx r12-15 if it uses them
112  */
113         
114         .align  align_16byte,0x90
115 GNAME(call_into_lisp):
116         push    %rbp            # Save old frame pointer.
117         mov     %rsp,%rbp       # Establish new frame.
118 Lstack:
119         /* FIXME x86 saves FPU state here */
120         push    %rbx
121         push    %r12
122         push    %r13
123         push    %r14
124         push    %r15
125
126
127         mov     %rsp,%rbx       # remember current stack
128         push    %rbx            # Save entry stack on (maybe) new stack.
129
130         /* Establish Lisp args. */
131         mov     %rdi,%rax       # lexenv?
132         mov     %rsi,%rbx       # address of arg vec
133         mov     %rdx,%rcx       # num args
134
135         xor     %rdx,%rdx       # clear any descriptor registers 
136         xor     %rdi,%rdi       # that we can't be sure we'll 
137         xor     %rsi,%rsi       # initialise properly.  XX do r8-r15 too?
138         shl     $3,%rcx         # (fixnumize num-args)
139         cmp     $0,%rcx
140         je      Ldone
141         mov     0(%rbx),%rdx    # arg0
142         cmp     $8,%rcx
143         je      Ldone
144         mov     8(%rbx),%rdi    # arg1
145         cmp     $16,%rcx
146         je      Ldone
147         mov     16(%rbx),%rsi   # arg2
148 Ldone:  
149         /* Registers rax, rcx, rdx, rdi, and rsi are now live. */
150         xor     %rbx,%rbx       # available
151
152         /* Alloc new frame. */
153         mov     %rsp,%rbx       # The current sp marks start of new frame.
154         push    %rbp            # fp in save location S0
155         sub     $16,%rsp        # Ensure 3 slots are allocated, one above.
156         mov     %rbx,%rbp       # Switch to new frame.
157
158 Lcall:
159         call    *CLOSURE_FUN_OFFSET(%rax)
160         
161         /* If the function returned multiple values, it will return to
162            this point.  Lose them */
163         mov     %rbx, %rsp
164         /* A singled value function returns here */
165
166 /* Restore the stack, in case there was a stack change. */
167         pop     %rsp            # c-sp
168
169 /* Restore C regs */
170         pop     %r15
171         pop     %r14
172         pop     %r13
173         pop     %r12
174         pop     %rbx
175
176 /* FIXME Restore the NPX state. */
177         pop     %rbp            # c-sp
178         /* return value is already in rax where lisp expects it */
179         ret
180         .size   GNAME(call_into_lisp), . - GNAME(call_into_lisp)
181 \f
182 /* support for saving and restoring the NPX state from C */
183         .text
184         .global GNAME(fpu_save)
185         .type   GNAME(fpu_save),@function
186         .align  2,0x90
187 GNAME(fpu_save):
188         mov     4(%rsp),%rax
189         fnsave  (%rax)          # Save the NPX state. (resets NPX)
190         ret
191         .size   GNAME(fpu_save),.-GNAME(fpu_save)
192
193         .global GNAME(fpu_restore)
194         .type   GNAME(fpu_restore),@function
195         .align  2,0x90
196 GNAME(fpu_restore):
197         mov     4(%rsp),%rax
198         frstor  (%rax)          # Restore the NPX state.
199         ret
200         .size   GNAME(fpu_restore),.-GNAME(fpu_restore)
201 \f
202 /*
203  * the undefined-function trampoline
204  */
205         .text
206         .align  align_4byte,0x90
207         .global GNAME(undefined_tramp)
208         .type   GNAME(undefined_tramp),@function
209 GNAME(undefined_tramp):
210         int3
211         .byte   trap_Error
212         .byte   2
213         .byte   UNDEFINED_FUN_ERROR
214         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
215         ret
216         .size   GNAME(undefined_tramp), .-GNAME(undefined_tramp)
217
218
219         .text
220         .align  align_4byte,0x90
221         .global GNAME(alloc_tramp)
222         .type   GNAME(alooc_tramp),@function
223 GNAME(alloc_tramp):
224         push    %rbp            # Save old frame pointer.
225         mov     %rsp,%rbp       # Establish new frame.
226         push    %rax
227         push    %rcx
228         push    %rdx
229         push    %rsi
230         push    %rdi
231         push    %r8
232         push    %r9
233         push    %r10
234         push    %r11
235         mov     16(%rbp),%rdi   
236         call    alloc
237         mov     %rax,16(%rbp)
238         pop     %r11
239         pop     %r10
240         pop     %r9
241         pop     %r8
242         pop     %rdi
243         pop     %rsi
244         pop     %rdx
245         pop     %rcx
246         pop     %rax
247         pop     %rbp
248         ret
249         .size   GNAME(alloc_tramp),.-GNAME(alloc_tramp)
250
251                 
252 /*
253  * the closure trampoline
254  */
255         .text
256         .align  align_4byte,0x90
257         .global GNAME(closure_tramp)
258         .type   GNAME(closure_tramp),@function
259 GNAME(closure_tramp):
260         mov     FDEFN_FUN_OFFSET(%rax),%rax
261         /* FIXME: The '*' after "jmp" in the next line is from PVE's
262          * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
263          * reasonable, and it certainly seems as though if CMU CL needs it,
264          * SBCL needs it too, but I haven't actually verified that it's
265          * right. It would be good to find a way to force the flow of
266          * control through here to test it. */
267         jmp     *CLOSURE_FUN_OFFSET(%rax)
268         .size   GNAME(closure_tramp), .-GNAME(closure_tramp)
269
270 /*
271  * fun-end breakpoint magic
272  */
273         .text
274         .global GNAME(fun_end_breakpoint_guts)
275         .align  align_4byte
276 GNAME(fun_end_breakpoint_guts):
277         /* Multiple Value return */
278         jmp     multiple_value_return
279         /* Single value return: The eventual return will now use the
280            multiple values return convention but with a return values
281            count of one. */
282         mov     %rsp,%rbx       # Setup ebx - the ofp.
283         sub     $4,%rsp         # Allocate one stack slot for the return value
284         mov     $4,%rcx         # Setup ecx for one return value.
285         mov     $NIL,%rdi       # default second value
286         mov     $NIL,%rsi       # default third value
287                 
288 multiple_value_return:
289         
290         .global GNAME(fun_end_breakpoint_trap)
291 GNAME(fun_end_breakpoint_trap):
292         int3
293         .byte   trap_FunEndBreakpoint
294         hlt                     # We should never return here.
295
296         .global GNAME(fun_end_breakpoint_end)
297 GNAME(fun_end_breakpoint_end):
298
299 \f
300         .global GNAME(do_pending_interrupt)
301         .type   GNAME(do_pending_interrupt),@function
302         .align  align_4byte,0x90
303 GNAME(do_pending_interrupt):
304         int3
305         .byte   trap_PendingInterrupt
306         ret
307         .size   GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
308 \f
309         .globl  GNAME(post_signal_tramp)
310         .type   GNAME(post_signal_tramp),@function
311         .align  align_4byte,0x90
312 GNAME(post_signal_tramp):
313         /* this is notionally the second half of a function whose first half
314          * doesn't exist.  This is where call_into_lisp returns when called 
315          * using return_to_lisp_function */
316         addq $24,%rsp   /* clear call_into_lisp args from stack */
317         popq %r15
318         popq %r14
319         popq %r13
320         popq %r12
321         popq %r11
322         popq %r10
323         popq %r9
324         popq %r8
325         popq %rdi
326         popq %rsi
327         popq %rbp
328         popq %rsp
329         popq %rdx
330         popq %rbx
331         popq %rcx
332         popq %rax
333         leave
334         ret
335         .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)
336 \f
337         .end