2 * very-low-level utilities for runtime support
6 * This software is part of the SBCL system. See the README file for
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.
16 #define LANGUAGE_ASSEMBLY
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"
25 /* Minimize conditionalization for different OS naming schemes. */
26 #if defined __linux__ || defined __FreeBSD__ /* (but *not* OpenBSD) */
27 #define GNAME(var) var
29 #define GNAME(var) _##var
32 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
33 * want alignment in bytes. */
34 #if defined(__linux__) || defined(__FreeBSD__)
37 #define align_16byte 16
38 #define align_32byte 32
42 #define align_16byte 4
46 .global GNAME(foreign_function_call_active)
47 .global GNAME(all_threads)
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)
59 .align align_16byte,0x90
60 .global GNAME(call_into_c)
61 .type GNAME(call_into_c),@function
63 push %rbp # Save old frame pointer.
64 mov %rsp,%rbp # Establish new frame.
66 push %rsi # args are going in here
79 .size GNAME(call_into_c), . - GNAME(call_into_c)
83 .global GNAME(call_into_lisp_first_time)
84 .type GNAME(call_into_lisp_first_time),@function
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
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
100 add $THREAD_CONTROL_STACK_SIZE-8,%rsp
104 .global GNAME(call_into_lisp)
105 .type GNAME(call_into_lisp),@function
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
114 .align align_16byte,0x90
115 GNAME(call_into_lisp):
116 push %rbp # Save old frame pointer.
117 mov %rsp,%rbp # Establish new frame.
119 /* FIXME x86 saves FPU state here */
127 mov %rsp,%rbx # remember current stack
128 push %rbx # Save entry stack on (maybe) new stack.
130 /* Establish Lisp args. */
131 mov %rdi,%rax # lexenv?
132 mov %rsi,%rbx # address of arg vec
133 mov %rdx,%rcx # num args
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)
141 mov 0(%rbx),%rdx # arg0
144 mov 8(%rbx),%rdi # arg1
147 mov 16(%rbx),%rsi # arg2
149 /* Registers rax, rcx, rdx, rdi, and rsi are now live. */
150 xor %rbx,%rbx # available
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.
159 call *CLOSURE_FUN_OFFSET(%rax)
161 /* If the function returned multiple values, it will return to
162 this point. Lose them */
164 /* A singled value function returns here */
166 /* Restore the stack, in case there was a stack change. */
176 /* FIXME Restore the NPX state. */
178 /* return value is already in rax where lisp expects it */
180 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
182 /* support for saving and restoring the NPX state from C */
184 .global GNAME(fpu_save)
185 .type GNAME(fpu_save),@function
189 fnsave (%rax) # Save the NPX state. (resets NPX)
191 .size GNAME(fpu_save),.-GNAME(fpu_save)
193 .global GNAME(fpu_restore)
194 .type GNAME(fpu_restore),@function
198 frstor (%rax) # Restore the NPX state.
200 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
203 * the undefined-function trampoline
206 .align align_4byte,0x90
207 .global GNAME(undefined_tramp)
208 .type GNAME(undefined_tramp),@function
209 GNAME(undefined_tramp):
213 .byte UNDEFINED_FUN_ERROR
214 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
216 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
220 .align align_4byte,0x90
221 .global GNAME(alloc_tramp)
222 .type GNAME(alooc_tramp),@function
224 push %rbp # Save old frame pointer.
225 mov %rsp,%rbp # Establish new frame.
249 .size GNAME(alloc_tramp),.-GNAME(alloc_tramp)
253 * the closure trampoline
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)
271 * fun-end breakpoint magic
274 .global GNAME(fun_end_breakpoint_guts)
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
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
288 multiple_value_return:
290 .global GNAME(fun_end_breakpoint_trap)
291 GNAME(fun_end_breakpoint_trap):
293 .byte trap_FunEndBreakpoint
294 hlt # We should never return here.
296 .global GNAME(fun_end_breakpoint_end)
297 GNAME(fun_end_breakpoint_end):
300 .global GNAME(do_pending_interrupt)
301 .type GNAME(do_pending_interrupt),@function
302 .align align_4byte,0x90
303 GNAME(do_pending_interrupt):
305 .byte trap_PendingInterrupt
307 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
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 */
335 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)