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-16,%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 */
181 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
183 /* support for saving and restoring the NPX state from C */
185 .global GNAME(fpu_save)
186 .type GNAME(fpu_save),@function
190 fnsave (%rax) # Save the NPX state. (resets NPX)
192 .size GNAME(fpu_save),.-GNAME(fpu_save)
194 .global GNAME(fpu_restore)
195 .type GNAME(fpu_restore),@function
199 frstor (%rax) # Restore the NPX state.
201 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
204 * the undefined-function trampoline
207 .align align_8byte,0x90
208 .global GNAME(undefined_tramp)
209 .type GNAME(undefined_tramp),@function
210 GNAME(undefined_tramp):
214 .byte UNDEFINED_FUN_ERROR
215 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
217 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
221 .align align_8byte,0x90
222 .global GNAME(alloc_tramp)
223 .type GNAME(alloc_tramp),@function
225 push %rbp # Save old frame pointer.
226 mov %rsp,%rbp # Establish new frame.
250 .size GNAME(alloc_tramp),.-GNAME(alloc_tramp)
254 * the closure trampoline
257 .align align_8byte,0x90
258 .global GNAME(closure_tramp)
259 .type GNAME(closure_tramp),@function
260 GNAME(closure_tramp):
261 mov FDEFN_FUN_OFFSET(%rax),%rax
262 /* FIXME: The '*' after "jmp" in the next line is from PVE's
263 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
264 * reasonable, and it certainly seems as though if CMU CL needs it,
265 * SBCL needs it too, but I haven't actually verified that it's
266 * right. It would be good to find a way to force the flow of
267 * control through here to test it. */
268 jmp *CLOSURE_FUN_OFFSET(%rax)
269 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
272 * fun-end breakpoint magic
275 .global GNAME(fun_end_breakpoint_guts)
277 GNAME(fun_end_breakpoint_guts):
278 /* Multiple Value return */
279 jmp multiple_value_return
280 /* the above jmp is only 2 bytes long, we need to add a nop for
281 * padding since the single value return convention jumps to original
282 * return address + 3 bytes */
284 /* Single value return: The eventual return will now use the
285 multiple values return convention but with a return values
287 mov %rsp,%rbx # Setup ebx - the ofp.
288 sub $8,%rsp # Allocate one stack slot for the return value
289 mov $8,%rcx # Setup ecx for one return value.
290 mov $NIL,%rdi # default second value
291 mov $NIL,%rsi # default third value
293 multiple_value_return:
295 .global GNAME(fun_end_breakpoint_trap)
296 GNAME(fun_end_breakpoint_trap):
298 .byte trap_FunEndBreakpoint
299 hlt # We should never return here.
301 .global GNAME(fun_end_breakpoint_end)
302 GNAME(fun_end_breakpoint_end):
305 .global GNAME(do_pending_interrupt)
306 .type GNAME(do_pending_interrupt),@function
307 .align align_8byte,0x90
308 GNAME(do_pending_interrupt):
310 .byte trap_PendingInterrupt
312 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
314 .globl GNAME(post_signal_tramp)
315 .type GNAME(post_signal_tramp),@function
316 .align align_8byte,0x90
317 GNAME(post_signal_tramp):
318 /* this is notionally the second half of a function whose first half
319 * doesn't exist. This is where call_into_lisp returns when called
320 * using return_to_lisp_function */
339 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)