Take pointer, not word count, as upper limit in verify_space()
[sbcl.git] / src / runtime / x86-assem.S
blobb05def49f5ae3c5b4390ef6b104f0bc7592ba674
1 /*
2  * very-low-level utilities for runtime support
3  */
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  */
16 #define LANGUAGE_ASSEMBLY
17 #include "sbcl.h"
18 #include "validate.h"
19 #include "genesis/closure.h"
20 #include "genesis/funcallable-instance.h"
21 #include "genesis/fdefn.h"
22 #include "genesis/static-symbols.h"
23 #include "genesis/symbol.h"
24 #include "genesis/thread.h"
25         
26 /* Minimize conditionalization for different OS naming schemes. 
27  *
28  * (As of sbcl-0.8.10, this seems no longer to be much of an issue, 
29  * since everyone has converged on ELF. If this generality really 
30  * turns out not to matter, perhaps it's just clutter we could get
31  * rid of? -- WHN 2004-04-18)
32  *
33  * (Except Win32, which is unlikely ever to be ELF, sorry. -- AB 2005-12-08)
34  */
35 #if defined __linux__  || defined LISP_FEATURE_FREEBSD || defined __NetBSD__ || defined __OpenBSD__ || \
36         defined __sun || defined __DragonFly__
37 #define GNAME(var) var
38 #else
39 #define GNAME(var) _##var
40 #endif
42 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
43  * want alignment in bytes. 
44  *
45  * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems 
46  * no longer to be much of an issue, since everyone has converged on
47  * the same value. If this generality really turns out not to 
48  * matter any more, perhaps it's just clutter we could get
49  * rid of? -- WHN 2004-04-18)
50  */
51 #if defined(__linux__) || defined(LISP_FEATURE_FREEBSD) || defined(__NetBSD__) || defined(__OpenBSD__) || \
52         defined(__sun) || defined(LISP_FEATURE_WIN32) || defined(__DragonFly__)
53 #define align_4byte     4
54 #define align_8byte     8
55 #define align_16byte    16
56 #define align_page      4096
57 #else
58 #define align_4byte     2
59 #define align_8byte     3
60 #define align_16byte    4       
61 #define align_page      12
62 #endif                  
65  * The assembler used for win32 doesn't like .type or .size directives,
66  * so we want to conditionally kill them out. So let's wrap them in macros
67  * that are defined to be no-ops on win32. Hopefully this still works on
68  * other platforms.
69  */
70 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
71 #define TYPE(name) .type name,@function
72 #define SIZE(name) .size name,.-name
73 #else
74 #define TYPE(name)
75 #define SIZE(name)
76 #endif
78 /* Helper macros for access to thread-locals slots for both OS types:
79  * ------------------------------------------------------------------------
80  *
81  *                          Windows TEB block
82  * ==================        __________
83  * | Win32 %FS base | ---->  |        | 0
84  * ==================        |        | 1
85  *                           z        z
86  *     TLS slots start here> |XXXXXXXX| e10 = TEB_STATIC_TLS_SLOTS_OFFSET
87  *                           |XXXXXXXX| e11
88  *                           z   ...  z
89  *                           |XXXXXXXX| e4e
90  *     TLS ends here>     ,- |XXXXXXXX| e4f = TEB_STATIC_TLS_SLOTS_OFFSET+63
91  *                       /   z        z
92  *                       |   ----------                    "os_address" ----.
93  *                       |                                                   |
94  *                       |   big blob of SBCL-specific thread-local data     |
95  *                       |     |----------------------------------------| <--'
96  *                       |     |   CONTROL, BINDING, ALIEN STACK        |
97  *                       |     z                                        z
98  * ==================    |     |----------------------------------------|
99  * | Linux %FS base | -->|     |   FFI stack pointer                    |
100  * ==================    |     |    (extra page for mprotect)           |
101  *                        \    |----------------------------------------|
102  *   (union p_t_d) ----->  \-> | struct thread {   | dynamic_values[0]  |
103  *   .                         |   ...             |               [1]  |
104  *   .                         z   ...             z               ...  z
105  *   [tls data begins]         | }                 |               ...  | <-
106  *   [declared end of p_t_d]   |----------------------------------------| . |
107  *   .                         |                                   ...  | . |
108  *   .                         |                           [TLS_SIZE-1] | <-|
109  *   [tls data actually ends]  |----------------------------------------|   |
110  *   .                         | ALTSTACK                               |   |
111  *   .                         |----------------------------------------|   |
112  *   .                         | struct nonpointer_thread_data { }      |   |
113  *   .                         ------------------------------------------   |
114  *   [blob actually ends]                                                   |
115  *                                                                         /
116  *                                                                        /
117  *                                                                       /
118  *          ______________________                                      /
119  *          | struct symbol {    |                                     /
120  *          z   ...              z                                    /
121  *          |   fixnum tls_index;  // fixnum value relative to union /
122  *          | }                  |           (< TLS_SIZE = 4096)
123  *          ---------------------|
124  */
125 #ifdef LISP_FEATURE_WIN32
126 # define TEB_STATIC_TLS_SLOTS_OFFSET 0xE10
127 # define TEB_SBCL_THREAD_BASE_OFFSET (TEB_STATIC_TLS_SLOTS_OFFSET+(63*4))
128 # define SBCL_THREAD_BASE_EA %fs:TEB_SBCL_THREAD_BASE_OFFSET
129 # define MAYBE_FS(addr) addr
130 # define LoadTlSymbolValueAddress(symbol,reg) ;         \
131         movl    SBCL_THREAD_BASE_EA, reg ;              \
132         addl    (symbol+SYMBOL_TLS_INDEX_OFFSET), reg ;
133 # define LoadCurrentThreadSlot(offset,reg);     \
134         movl    SBCL_THREAD_BASE_EA, reg ;      \
135         movl    offset(reg), reg ;
136 #elif defined(LISP_FEATURE_LINUX) || defined(LISP_FEATURE_SUNOS) || defined(LISP_FEATURE_FREEBSD) || \
137         defined(LISP_FEATURE_DRAGONFLY)
138     /* %fs:0 refers to the current thread.  Useful!  Less usefully,
139      * Linux/x86 isn't capable of reporting a faulting si_addr on a
140      * segment as defined above (whereas faults on the segment that %gs
141      * usually points are reported just fine...).
142      * But we have the thread's address stored in the THIS slot,
143      * so that within the thread
144      *   movl %fs:THIS_OFFSET,x
145      * stores the absolute address of %fs:0 into x.
146      */
147 # define SBCL_THREAD_BASE_EA %fs:THREAD_THIS_OFFSET
148 # define MAYBE_FS(addr) addr
149 #else
150   /* perhaps there's an OS out there that actually supports %fs without
151    * jumping through hoops, so just in case, here a default definition: */
152 # define SBCL_THREAD_BASE_EA $0
153 # define MAYBE_FS(addr) %fs:addr
154 #endif
156 /* gas can't parse 4096LU; redefine */
157 #if BACKEND_PAGE_BYTES == 4096
158 # undef BACKEND_PAGE_BYTES
159 # define BACKEND_PAGE_BYTES 4096
160 #elif BACKEND_PAGE_BYTES == 32768
161 # undef BACKEND_PAGE_BYTES
162 # define BACKEND_PAGE_BYTES 32768
163 #else
164 # error BACKEND_PAGE_BYTES mismatch
165 #endif
167 /* OAOOM because we don't have the C headers here */
168 #define THREAD_CSP_PAGE_SIZE BACKEND_PAGE_BYTES
170 /* the CSP page sits right before the thread */
171 #define THREAD_SAVED_CSP_OFFSET (-THREAD_CSP_PAGE_SIZE)
174  * x86/darwin (as of MacOS X 10.4.5) doesn't reliably file signal
175  * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have
176  * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or
177  * 0F 0B in low-endian notation, that causes SIGILL to fire. We check
178  * for this instruction in the SIGILL handler and if we see it, we
179  * advance the EIP by two bytes to skip over ud2 instruction and
180  * call sigtrap_handler. */
181 #if defined(LISP_FEATURE_UD2_BREAKPOINTS)
182 #define TRAP ud2
183 #else
184 #define TRAP int3
185 #endif
187         .text
188         .globl  GNAME(all_threads)
191  * A call to call_into_c preserves esi, edi, and ebp.   
192  * (The C function will preserve ebx, esi, edi, and ebp across its
193  * function call, but we trash ebx ourselves by using it to save the
194  * return Lisp address.)
196  * Return values are in eax and maybe edx for quads, or st(0) for
197  * floats.
199  * This should work for Lisp calls C calls Lisp calls C..
201  * FIXME & OAOOM: This duplicates call-out in src/compiler/x86/c-call.lisp,
202  * so if you tweak this, change that too!
203  */
205  * Note on sections specific to LISP_FEATURE_SB_SAFEPOINT:
207  * The code below is essential to safepoint-based garbage collection,
208  * and several details need to be considered for correct implementation.
210  * The stack spilling approach:
211  *   On SB-SAFEPOINT platforms, the CALL-OUT vop is defined to spill all
212  *   live Lisp TNs to the stack to provide information for conservative
213  *   GC cooperatively (avoiding the need to retrieve register values
214  *   from POSIX signal contexts or Windows GetThreadContext()).
216  * Finding the SP at all:
217  *   The main remaining value needed by GC is the stack pointer (SP) at
218  *   the moment of entering the foreign function.  For this purpose, a
219  *   thread-local field for the SP is used.  Two stores to that field
220  *   are done for each C call, one to save the SP before calling out and
221  *   and one to undo that store afterwards.
223  * Stores as synchronization points:
224  *   These two stores delimit the C call: While the SP is set, our
225  *   thread is known not to run Lisp code: During GC, memory protection
226  *   ensures that no thread proceeds across stores.
228  * The return PC issue:
229  *   (Note that CALL-OUT has, in principle, two versions: Inline
230  *   assembly in the VOP -or- alternatively the out-of-line version you
231  *   are currently reading.  In reality, safepoint builds currently
232  *   lack the inline code entirely.)
234  *   Both versions need to take special care with the return PC:
235  *   - In the inline version of the code (if it existed), the two stores
236  *     would be done directly in the CALL-OUT vop.  In that theoretical
237  *     implementation, there is a time interval between return of the
238  *     actual C call and a second SP store during which the return
239  *     address might not be on the stack anymore.
240  *   - In this out-of-line version, the stores are done during
241  *     call_into_c's frame, but an equivalent problem arises: In order
242  *     to present the stack of arguments as our foreign function expects
243  *     them, call_into_c has to pop the Lisp return address into a
244  *     register first; this register has to be preserved by GENCGC
245  *     separately: our return address is not in the stack anymore.
246  *   In both case, stack scanning alone is not sufficient to pin
247  *   the return address, and we communicate it to GC explicitly
248  *   in addition to the SP.
250  * Note on look-alike accessor macros with vastly different behaviour:
251  *   THREAD_PC_AROUND_FOREIGN_CALL_OFFSET is an "ordinary" field of the
252  *   struct thread, whereas THREAD_SAVED_CSP_OFFSET is a synchronization
253  *   point on a potentially write-protected page.
256         .text
257         .align  align_16byte,0x90
258         .globl GNAME(call_into_c)
259         TYPE(GNAME(call_into_c))
260 GNAME(call_into_c):
261 /* Save the return Lisp address in ebx. */
262         popl    %ebx
264 /* Setup the NPX for C */
265         /* The VOP says regarding CLD: "Clear out DF: Darwin, Windows,
266          * and Solaris at least require this, and it should not hurt
267          * others either." call_into_c didn't have it, but better safe than
268          * sorry. */
269         cld
270         fstp    %st(0)
271         fstp    %st(0)
272         fstp    %st(0)
273         fstp    %st(0)
274         fstp    %st(0)
275         fstp    %st(0)
276         fstp    %st(0)
277         fstp    %st(0)
279 #ifdef LISP_FEATURE_SB_SAFEPOINT
280         /* enter safe region: store SP and return PC */
281         movl    SBCL_THREAD_BASE_EA,%edi
282         movl    %esp,MAYBE_FS(THREAD_SAVED_CSP_OFFSET(%edi))
283         movl    %ebx,MAYBE_FS(THREAD_PC_AROUND_FOREIGN_CALL_OFFSET(%edi))
284 #endif
286         /* foreign call, preserving ESI, EDI, and EBX */
287         call    *%eax             # normal callout using Lisp stack
288         /* return values now in eax/edx OR st(0) */
290 #ifdef LISP_FEATURE_SB_SAFEPOINT
291         /* leave region: clear the SP!  (Also unpin the return PC.) */
292         xorl    %ecx,%ecx
293         movl    %ecx,MAYBE_FS(THREAD_SAVED_CSP_OFFSET(%edi))
294         movl    %ecx,MAYBE_FS(THREAD_PC_AROUND_FOREIGN_CALL_OFFSET(%edi))
295 #endif
297         movl    %eax,%ecx         # remember integer return value
299 /* Check for a return FP value. */
300         fxam
301         fnstsw  %ax
302         andl    $0x4500,%eax
303         cmpl    $0x4100,%eax
304         jne     Lfp_rtn_value
306 /* The return value is in eax, or eax,edx? */
307 /* Set up the NPX stack for Lisp. */
308         fldz                    # Ensure no regs are empty.
309         fldz
310         fldz
311         fldz
312         fldz
313         fldz
314         fldz
315         fldz
317 /* Restore the return value. */
318         movl    %ecx,%eax       # maybe return value
320 /* Return. */
321         jmp     *%ebx
323 Lfp_rtn_value:
324 /* The return result is in st(0). */
325 /* Set up the NPX stack for Lisp, placing the result in st(0). */
326         fldz                    # Ensure no regs are empty.
327         fldz
328         fldz
329         fldz
330         fldz
331         fldz
332         fldz
333         fxch    %st(7)          # Move the result back to st(0).
335 /* We don't need to restore eax, because the result is in st(0). */
337 /* Return. FIXME: It would be nice to restructure this to use RET. */
338         jmp     *%ebx
340         SIZE(GNAME(call_into_c))
343         .text   
344         .globl GNAME(call_into_lisp_first_time)
345         TYPE(GNAME(call_into_lisp_first_time))
346                 
347 /* We don't worry too much about saving registers 
348  * here, because we never expect to return from the initial call to lisp 
349  * anyway */
350         
351         .align  align_16byte,0x90
352 GNAME(call_into_lisp_first_time):
353         pushl   %ebp            # Save old frame pointer.
354         movl    %esp,%ebp       # Establish new frame.
355 #ifndef LISP_FEATURE_WIN32
356         movl    GNAME(all_threads),%eax
357         /* pthread machinery takes care of this for other threads */
358         movl    THREAD_CONTROL_STACK_END_OFFSET(%eax) ,%esp
359 #else
360 /* Win32 -really- doesn't like you switching stacks out from under it. */
361         movl    GNAME(all_threads),%eax
362 #endif
363         jmp     Lstack
365         .text   
366         .globl GNAME(call_into_lisp)
367         TYPE(GNAME(call_into_lisp))
368                 
369 /* The C conventions require that ebx, esi, edi, and ebp be preserved
370  * across function calls. */
371         
372         .align  align_16byte,0x90
373 GNAME(call_into_lisp):
374         pushl   %ebp            # Save old frame pointer.
375         movl    %esp,%ebp       # Establish new frame.
377 Lstack:
378 /* Save the NPX state */
379         fwait                   # Catch any pending NPX exceptions.
380         subl    $108,%esp       # Make room for the NPX state.
381         fnsave  (%esp)          # save and reset NPX
383         movl    (%esp),%eax     # Load NPX control word.
384         andl    $0xfffff2ff,%eax        # Set rounding mode to nearest.
385         orl     $0x00000200,%eax        # Set precision to 64 bits.  (53-bit mantissa)
386         pushl   %eax
387         fldcw   (%esp)          # Recover modes.
388         popl    %eax
390         fldz                    # Ensure no FP regs are empty.
391         fldz
392         fldz
393         fldz
394         fldz
395         fldz
396         fldz
397         fldz
398         
399 /* Save C regs: ebx esi edi. */
400         pushl   %ebx
401         pushl   %esi
402         pushl   %edi
403         
404 /* Clear descriptor regs. */
405         xorl    %eax,%eax       # lexenv
406         xorl    %ebx,%ebx       # available
407         xorl    %ecx,%ecx       # arg count
408         xorl    %edx,%edx       # first arg
409         xorl    %edi,%edi       # second arg
410         xorl    %esi,%esi       # third arg
412 /* no longer in function call */
413         movl    %esp,%ebx       # remember current stack
414         pushl   %ebx            # Save entry stack on (maybe) new stack.
416         /* Establish Lisp args. */
417         movl     8(%ebp),%eax   # lexenv?
418         movl    12(%ebp),%ebx   # address of arg vec
419         movl    16(%ebp),%ecx   # num args
420         shll    $2,%ecx         # Make num args into fixnum.
421         cmpl    $0,%ecx
422         je      Ldone
423         movl    (%ebx),%edx     # arg0
424         cmpl    $4,%ecx
425         je      Ldone
426         movl    4(%ebx),%edi    # arg1
427         cmpl    $8,%ecx
428         je      Ldone
429         movl    8(%ebx),%esi    # arg2
430 Ldone:  
431         /* Registers eax, ecx, edx, edi, and esi are now live. */
433 #ifdef LISP_FEATURE_WIN32
434         /* Establish an SEH frame. */
435 #ifdef LISP_FEATURE_SB_THREAD
436         /* Save binding stack pointer */
437         subl $4, %esp
438         pushl %eax
439         movl SBCL_THREAD_BASE_EA, %eax
440         movl THREAD_BINDING_STACK_POINTER_OFFSET(%eax), %eax
441         movl %eax, 4(%esp)
442         popl %eax
443 #else
444         pushl   BINDING_STACK_POINTER + SYMBOL_VALUE_OFFSET
445 #endif
446         pushl   $GNAME(exception_handler_wrapper)
447         pushl   %fs:0
448         movl    %esp, %fs:0
449 #endif
451         /* Alloc new frame. */
452         push    %ebp            # Dummy for return address
453         push    %ebp            # fp in save location S1
454         mov     %esp,%ebp       # The current sp marks start of new frame.
455         sub     $4,%esp         # Ensure 3 slots are allocated, two above.
457         call    *CLOSURE_FUN_OFFSET(%eax)
458         
459         /* If the function returned multiple values, it will return to
460            this point.  Lose them */
461         jnc     LsingleValue
462         mov     %ebx, %esp
463 LsingleValue:
464         /* A singled value function returns here */
466 #ifdef LISP_FEATURE_WIN32
467         /* Remove our SEH frame. */
468         mov     %fs:0,%esp
469         popl    %fs:0
470         add     $8, %esp
471 #endif
473 /* Restore the stack, in case there was a stack change. */
474         popl    %esp            # c-sp
476 /* Restore C regs: ebx esi edi. */
477         popl    %edi
478         popl    %esi
479         popl    %ebx
481 /* Restore the NPX state. */
482         frstor  (%esp)
483         addl    $108, %esp
484         
485         popl    %ebp            # c-sp
486         movl    %edx,%eax       # c-val
487         ret
488         SIZE(GNAME(call_into_lisp))
490 /* support for saving and restoring the NPX state from C */
491         .text
492         .globl  GNAME(fpu_save)
493         TYPE(GNAME(fpu_save))
494         .align  2,0x90
495 GNAME(fpu_save):
496         movl    4(%esp),%eax
497         fnsave  (%eax)          # Save the NPX state. (resets NPX)
498         ret
499         SIZE(GNAME(fpu_save))
501         .globl  GNAME(fpu_restore)
502         TYPE(GNAME(fpu_restore))
503         .align  2,0x90
504 GNAME(fpu_restore):
505         movl    4(%esp),%eax
506         frstor  (%eax)          # Restore the NPX state.
507         ret
508         SIZE(GNAME(fpu_restore))
511  * fun-end breakpoint magic
512  */
515  * For an explanation of the magic involved in function-end
516  * breakpoints, see the implementation in ppc-assem.S.
517  */
519         .text
520         .globl  GNAME(fun_end_breakpoint_guts)
521         .align  align_16byte
522 GNAME(fun_end_breakpoint_guts):
523         /* Multiple Value return */
524         jc      multiple_value_return
525         /* Single value return: The eventual return will now use the
526            multiple values return convention but with a return values
527            count of one. */
528         movl    %esp,%ebx       # Setup ebx - the ofp.
529         subl    $4,%esp         # Allocate one stack slot for the return value
530         movl    $(1 << N_FIXNUM_TAG_BITS),%ecx          # Setup ecx for one return value.
531         movl    $(NIL),%edi     # default second value
532         movl    $(NIL),%esi     # default third value
533                 
534 multiple_value_return:
535         
536         .globl GNAME(fun_end_breakpoint_trap)
537 GNAME(fun_end_breakpoint_trap):
538         TRAP
539         .byte   trap_FunEndBreakpoint
540         hlt                     # We should never return here.
542         .globl GNAME(fun_end_breakpoint_end)
543 GNAME(fun_end_breakpoint_end):
546         .globl  GNAME(do_pending_interrupt)
547         TYPE(GNAME(do_pending_interrupt))
548         .align  align_16byte,0x90
549 GNAME(do_pending_interrupt):
550         TRAP
551         .byte   trap_PendingInterrupt
552         ret
553         SIZE(GNAME(do_pending_interrupt))
555 /* Allocate bytes and return the start of the allocated space
556  * in the specified destination register.
558  * In the general case the size will be in the destination register.
560  * All registers must be preserved except the destination.
561  * The C conventions will preserve ebx, esi, edi, and ebp.
562  * So only eax, ecx, and edx need special care here.
564  * ALLOC factors out the logic of calling alloc(): stack alignment, etc.
566  * DEFINE_ALLOC_TO_FOO defines an alloction routine.
567  */
569 #ifdef LISP_FEATURE_DARWIN
570 #define ALLOC(size)                                             \
571         pushl   %ebp;              /* Save EBP               */ \
572         movl    %esp,%ebp;         /* Save ESP to EBP        */ \
573         pushl   $0;                /* Reserve space for arg  */ \
574         andl    $0xfffffff0,%esp;  /* Align stack to 16bytes */ \
575         movl    size, (%esp);      /* Argument to alloc      */ \
576         call    GNAME(alloc);                                   \
577         movl    %ebp,%esp;         /* Restore ESP from EBP   */ \
578         popl    %ebp;              /* Restore EBP            */
579 #else
580 #define ALLOC(size)                                             \
581         pushl   size;              /* Argument to alloc      */ \
582         call    GNAME(alloc);                                   \
583         addl    $4,%esp;           /* Pop argument           */
584 #endif
586 #define DEFINE_ALLOC_TO_EAX(name,size)                          \
587         .globl  GNAME(name);                                    \
588         TYPE(GNAME(name));                                      \
589         .align  align_16byte,0x90;                              \
590 GNAME(name):                                                    \
591         pushl   %ecx;              /* Save ECX and EDX       */ \
592         pushl   %edx;                                           \
593         ALLOC(size)                                             \
594         popl    %edx;              /* Restore ECX and EDX    */ \
595         popl    %ecx;                                           \
596         ret;                                                    \
597         SIZE(GNAME(name))
599 #define DEFINE_ALLOC_TO_ECX(name,size)                          \
600         .globl  GNAME(name);                                    \
601         TYPE(GNAME(name));                                      \
602         .align  align_16byte,0x90;                              \
603 GNAME(name):                                                    \
604         pushl   %eax;              /* Save EAX and EDX       */ \
605         pushl   %edx;                                           \
606         ALLOC(size)                                             \
607         movl    %eax,%ecx;         /* Result to destination  */ \
608         popl    %edx;                                           \
609         popl    %eax;                                           \
610         ret;                                                    \
611         SIZE(GNAME(name))
612         
613 #define DEFINE_ALLOC_TO_EDX(name,size)                          \
614         .globl  GNAME(name);                                    \
615         TYPE(GNAME(name));                                      \
616         .align  align_16byte,0x90;                              \
617 GNAME(name):                                                    \
618         pushl   %eax;               /* Save EAX and ECX      */ \
619         pushl   %ecx;                                           \
620         ALLOC(size)                                             \
621         movl    %eax,%edx;          /* Restore EAX and ECX   */ \
622         popl    %ecx;                                           \
623         popl    %eax;                                           \
624         ret;                                                    \
625         SIZE(GNAME(name))
627 #define DEFINE_ALLOC_TO_REG(name,reg,size)                      \
628         .globl  GNAME(name);                                    \
629         TYPE(GNAME(name));                                      \
630         .align  align_16byte,0x90;                              \
631 GNAME(name):                                                    \
632         pushl   %eax;              /* Save EAX, ECX, and EDX */ \
633         pushl   %ecx;                                           \
634         pushl   %edx;                                           \
635         ALLOC(size)                                             \
636         movl    %eax,reg;          /* Restore them           */ \
637         popl    %edx;                                           \
638         popl    %ecx;                                           \
639         popl    %eax;                                           \
640         ret;                                                    \
641         SIZE(GNAME(name))
643 DEFINE_ALLOC_TO_EAX(alloc_to_eax,%eax)
644 DEFINE_ALLOC_TO_EAX(alloc_8_to_eax,$8)
645 DEFINE_ALLOC_TO_EAX(alloc_16_to_eax,$16)
647 DEFINE_ALLOC_TO_ECX(alloc_to_ecx,%ecx)
648 DEFINE_ALLOC_TO_ECX(alloc_8_to_ecx,$8)
649 DEFINE_ALLOC_TO_ECX(alloc_16_to_ecx,$16)
651 DEFINE_ALLOC_TO_EDX(alloc_to_edx,%edx)
652 DEFINE_ALLOC_TO_EDX(alloc_8_to_edx,$8)
653 DEFINE_ALLOC_TO_EDX(alloc_16_to_edx,$16)
655 DEFINE_ALLOC_TO_REG(alloc_to_ebx,%ebx,%ebx)
656 DEFINE_ALLOC_TO_REG(alloc_8_to_ebx,%ebx,$8)
657 DEFINE_ALLOC_TO_REG(alloc_16_to_ebx,%ebx,$16)
659 DEFINE_ALLOC_TO_REG(alloc_to_esi,%esi,%esi)
660 DEFINE_ALLOC_TO_REG(alloc_8_to_esi,%esi,$8)
661 DEFINE_ALLOC_TO_REG(alloc_16_to_esi,%esi,$16)
663 DEFINE_ALLOC_TO_REG(alloc_to_edi,%edi,%edi)
664 DEFINE_ALLOC_TO_REG(alloc_8_to_edi,%edi,$8)
665 DEFINE_ALLOC_TO_REG(alloc_16_to_edi,%edi,$16)
667 /* Called from lisp when an inline allocation overflows.
668  * Every register except the result needs to be preserved.
669  * We depend on C to preserve ebx, esi, edi, and ebp.
670  * But where necessary must save eax, ecx, edx. */
672 #ifdef LISP_FEATURE_SB_THREAD
673 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
674 #else
675 #define START_REGION GNAME(boxed_region)
676 #endif
678 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_WIN32)
679 #define ALLOC_OVERFLOW(size,scratch)                            \
680         movl SBCL_THREAD_BASE_EA, scratch;                      \
681         /* Calculate the size for the allocation. */            \
682         subl THREAD_ALLOC_REGION_OFFSET(scratch),size;          \
683         ALLOC(size)
684 #else
685 #define ALLOC_OVERFLOW(size,scratch)                    \
686           /* Calculate the size for the allocation. */  \
687           subl    START_REGION,size;                    \
688           ALLOC(size)
689 #endif
691 /* This routine handles an overflow with eax=crfp+size. So the
692    size=eax-crfp. */
693         .align  align_16byte
694         .globl  GNAME(alloc_overflow_eax)
695         TYPE(GNAME(alloc_overflow_eax))
696 GNAME(alloc_overflow_eax):
697         pushl   %ecx            # Save ecx
698         pushl   %edx            # Save edx
699         ALLOC_OVERFLOW(%eax,%edx)
700         popl    %edx    # Restore edx.
701         popl    %ecx    # Restore ecx.
702         ret
703         SIZE(GNAME(alloc_overflow_eax))
705         .align  align_16byte
706         .globl  GNAME(alloc_overflow_ecx)
707         TYPE(GNAME(alloc_overflow_ecx))
708 GNAME(alloc_overflow_ecx):
709         pushl   %eax            # Save eax
710         pushl   %edx            # Save edx
711         ALLOC_OVERFLOW(%ecx,%edx)
712         movl    %eax,%ecx       # setup the destination.
713         popl    %edx    # Restore edx.
714         popl    %eax    # Restore eax.
715         ret
716         SIZE(GNAME(alloc_overflow_ecx))
718         .align  align_16byte
719         .globl  GNAME(alloc_overflow_edx)
720         TYPE(GNAME(alloc_overflow_edx))
721 GNAME(alloc_overflow_edx):
722         pushl   %eax            # Save eax
723         pushl   %ecx            # Save ecx
724         ALLOC_OVERFLOW(%edx,%ecx)
725         movl    %eax,%edx       # setup the destination.
726         popl    %ecx    # Restore ecx.
727         popl    %eax    # Restore eax.
728         ret
729         SIZE(GNAME(alloc_overflow_edx))
731 /* This routine handles an overflow with ebx=crfp+size. So the
732    size=ebx-crfp. */
733         .align  align_16byte
734         .globl  GNAME(alloc_overflow_ebx)
735         TYPE(GNAME(alloc_overflow_ebx))
736 GNAME(alloc_overflow_ebx):
737         pushl   %eax            # Save eax
738         pushl   %ecx            # Save ecx
739         pushl   %edx            # Save edx
740         ALLOC_OVERFLOW(%ebx,%edx)
741         movl    %eax,%ebx       # setup the destination.
742         popl    %edx    # Restore edx.
743         popl    %ecx    # Restore ecx.
744         popl    %eax    # Restore eax.
745         ret
746         SIZE(GNAME(alloc_overflow_ebx))
748 /* This routine handles an overflow with esi=crfp+size. So the
749    size=esi-crfp. */
750         .align  align_16byte
751         .globl  GNAME(alloc_overflow_esi)
752         TYPE(GNAME(alloc_overflow_esi))
753 GNAME(alloc_overflow_esi):
754         pushl   %eax            # Save eax
755         pushl   %ecx            # Save ecx
756         pushl   %edx            # Save edx
757         ALLOC_OVERFLOW(%esi,%edx)
758         movl    %eax,%esi       # setup the destination.
759         popl    %edx    # Restore edx.
760         popl    %ecx    # Restore ecx.
761         popl    %eax    # Restore eax.
762         ret
763         SIZE(GNAME(alloc_overflow_esi))
765         .align  align_16byte
766         .globl  GNAME(alloc_overflow_edi)
767         TYPE(GNAME(alloc_overflow_edi))
768 GNAME(alloc_overflow_edi):
769         pushl   %eax            # Save eax
770         pushl   %ecx            # Save ecx
771         pushl   %edx            # Save edx
772         ALLOC_OVERFLOW(%edi,%edx)
773         movl    %eax,%edi       # setup the destination.
774         popl    %edx    # Restore edx.
775         popl    %ecx    # Restore ecx.
776         popl    %eax    # Restore eax.
777         ret
778         SIZE(GNAME(alloc_overflow_edi))
781 #ifdef LISP_FEATURE_WIN32
782         /* The guts of the exception-handling system doesn't use
783          * frame pointers, which manages to throw off backtraces
784          * rather badly.  So here we grab the (known-good) EBP
785          * and EIP from the exception context and use it to fake
786          * up a stack frame which will skip over the system SEH
787          * code. */
788         .align  align_16byte
789         .globl  GNAME(exception_handler_wrapper)
790         TYPE(GNAME(exception_handler_wrapper))
791 GNAME(exception_handler_wrapper):
792         /* Context layout is: */
793         /* 7 dwords before FSA. (0x1c) */
794         /* 8 dwords and 0x50 bytes in the FSA. (0x70/0x8c) */
795         /* 4 dwords segregs. (0x10/0x9c) */
796         /* 6 dwords non-stack GPRs. (0x18/0xb4) */
797         /* EBP (at 0xb4) */
798         /* EIP (at 0xb8) */
799 #define CONTEXT_EBP_OFFSET 0xb4
800 #define CONTEXT_EIP_OFFSET 0xb8
801         /* some other stuff we don't care about. */
802         pushl   %ebp
803         movl    0x10(%esp), %ebp        /* context */
804         pushl   CONTEXT_EIP_OFFSET(%ebp)
805         pushl   CONTEXT_EBP_OFFSET(%ebp)
806         movl    %esp, %ebp
807         pushl   0x1c(%esp)
808         pushl   0x1c(%esp)
809         pushl   0x1c(%esp)
810         pushl   0x1c(%esp)
811         call    GNAME(handle_exception)
812         lea     8(%ebp), %esp
813         popl    %ebp
814         ret
815         SIZE(GNAME(exception_handler_wrapper))
816 #endif
818 #ifdef LISP_FEATURE_DARWIN
819         .align align_16byte
820         .globl GNAME(call_into_lisp_tramp)
821         TYPE(GNAME(call_into_lisp_tramp))
822 GNAME(call_into_lisp_tramp):
823         /* 1. build the stack frame from the block that's pointed to by ECX
824            2. free the block
825            3. set ECX to 0
826            4. call the function via call_into_lisp
827         */
828         pushl   0(%ecx)          /* return address */
830         pushl   %ebp
831         movl    %esp, %ebp
833         pushl   32(%ecx)         /* eflags */
834         pushl   28(%ecx)         /* EAX */
835         pushl   20(%ecx)         /* ECX */
836         pushl   16(%ecx)         /* EDX */
837         pushl   24(%ecx)         /* EBX */
838         pushl   $0                /* popal is going to ignore esp */
839         pushl   %ebp              /* is this right?? */
840         pushl   12(%ecx)         /* ESI */
841         pushl   8(%ecx)          /* EDI */
842         pushl   $0                /* args for call_into_lisp */
843         pushl   $0
844         pushl   4(%ecx)          /* function to call */
846         /* free our save block */
847         pushl   %ecx              /* reserve sufficient space on stack for args */
848         pushl   %ecx
849         andl    $0xfffffff0, %esp  /* align stack */
850         movl    $0x40, 4(%esp)
851         movl    %ecx, (%esp)
852         call    GNAME(os_invalidate)
854         /* call call_into_lisp */
855         leal    -48(%ebp), %esp
856         call    GNAME(call_into_lisp)
858         /* Clean up our mess */
859         leal    -36(%ebp), %esp
860         popal
861         popfl
862         leave
863         ret
864         
865         SIZE(call_into_lisp_tramp)
866 #endif
867         
868         .align  align_16byte,0x90
869         .globl  GNAME(post_signal_tramp)
870         TYPE(GNAME(post_signal_tramp))
871 GNAME(post_signal_tramp):
872         /* this is notionally the second half of a function whose first half
873          * doesn't exist.  This is where call_into_lisp returns when called 
874          * using return_to_lisp_function */
875         addl $12,%esp   /* clear call_into_lisp args from stack */
876         popal           /* restore registers */
877         popfl
878 #ifdef LISP_FEATURE_DARWIN
879         /* skip two padding words */
880         addl $8,%esp
881 #endif
882         leave
883         ret
884         SIZE(GNAME(post_signal_tramp))
887         /* fast_bzero implementations and code to detect which implementation
888          * to use.
889          */
891         .globl GNAME(fast_bzero_pointer)
892         .data
893         .align  align_16byte
894 GNAME(fast_bzero_pointer):
895         /* Variable containing a pointer to the bzero function to use.
896          * Initially points to a basic function.  Change this variable
897          * to fast_bzero_detect if OS supports SSE.  */
898         .long GNAME(fast_bzero_base)
900         .text
901         .align  align_16byte,0x90
902         .globl GNAME(fast_bzero)
903         TYPE(GNAME(fast_bzero))
904 GNAME(fast_bzero):        
905         /* Indirect function call */
906         jmp *GNAME(fast_bzero_pointer)
907         SIZE(GNAME(fast_bzero))
908         
909 \f      
910         .text
911         .align  align_16byte,0x90
912         .globl GNAME(fast_bzero_detect)
913         TYPE(GNAME(fast_bzero_detect))
914 GNAME(fast_bzero_detect):
915         /* Decide whether to use SSE, MMX or REP version */
916         push %eax /* CPUID uses EAX-EDX */
917         push %ebx
918         push %ecx
919         push %edx
920         mov $1, %eax
921         cpuid
922         test $0x04000000, %edx    /* SSE2 needed for MOVNTDQ */
923         jnz Lsse2
924         /* Originally there was another case here for using the
925          * MOVNTQ instruction for processors that supported MMX but
926          * not SSE2. This turned out to be a loss especially on
927          * Athlons (where this instruction is apparently microcoded
928          * somewhat slowly). So for simplicity revert to REP STOSL
929          * for all non-SSE2 processors.
930          */
931 Lbase:
932         movl $(GNAME(fast_bzero_base)), GNAME(fast_bzero_pointer)
933         jmp Lrestore
934 Lsse2:
935         movl $(GNAME(fast_bzero_sse)), GNAME(fast_bzero_pointer)
936         jmp Lrestore
937         
938 Lrestore:
939         pop %edx
940         pop %ecx
941         pop %ebx
942         pop %eax
943         jmp *GNAME(fast_bzero_pointer)
944         
945         SIZE(GNAME(fast_bzero_detect))
946         
948         .text
949         .align  align_16byte,0x90
950         .globl GNAME(fast_bzero_sse)
951         TYPE(GNAME(fast_bzero_sse))
952         
953 GNAME(fast_bzero_sse):
954         /* A fast routine for zero-filling blocks of memory that are
955          * guaranteed to start and end at a 4096-byte aligned address.
956          */        
957         push %esi                 /* Save temporary registers */
958         push %edi
959         mov 16(%esp), %esi        /* Parameter: amount of bytes to fill */
960         mov 12(%esp), %edi        /* Parameter: start address */
961         shr $6, %esi              /* Amount of 64-byte blocks to copy */
962         jz Lend_sse               /* If none, stop */
963         movups %xmm7, -16(%esp)   /* Save XMM register */
964         xorps  %xmm7, %xmm7       /* Zero the XMM register */
965         jmp Lloop_sse
966         .align align_16byte
967 Lloop_sse:
969         /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the
970          * non-caching double-quadword moving variant, i.e. the memory areas
971          * we're touching are not fetched into the L1 cache, since we're just
972          * going to overwrite the memory soon anyway.
973          */
974         movntdq %xmm7, 0(%edi)
975         movntdq %xmm7, 16(%edi)
976         movntdq %xmm7, 32(%edi)
977         movntdq %xmm7, 48(%edi)
979         add $64, %edi /* Advance pointer */
980         dec %esi      /* Decrement 64-byte block count */
981         jnz Lloop_sse
982         movups -16(%esp), %xmm7 /* Restore the XMM register */
983         sfence        /* Ensure that weakly ordered writes are flushed. */
984 Lend_sse:
985         mov 12(%esp), %esi      /* Parameter: start address */
986         prefetcht0 0(%esi)      /* Prefetch the start of the block into cache,
987                                  * since it's likely to be used immediately. */
988         pop %edi      /* Restore temp registers */
989         pop %esi
990         ret
991         SIZE(GNAME(fast_bzero_sse))
992                 
994         .text
995         .align  align_16byte,0x90
996         .globl GNAME(fast_bzero_base)
997         TYPE(GNAME(fast_bzero_base))
998         
999 GNAME(fast_bzero_base):
1000         /* A fast routine for zero-filling blocks of memory that are
1001          * guaranteed to start and end at a 4096-byte aligned address.
1002          */        
1003         push %eax                 /* Save temporary registers */
1004         push %ecx
1005         push %edi
1006         mov 20(%esp), %ecx        /* Parameter: amount of bytes to fill */
1007         mov 16(%esp), %edi        /* Parameter: start address */
1008         xor %eax, %eax            /* Zero EAX */
1009         shr $2, %ecx              /* Amount of 4-byte blocks to copy */
1010         jz  Lend_base
1012         rep
1013         stosl                     /* Store EAX to *EDI, ECX times, incrementing
1014                                    * EDI by 4 after each store */
1015         
1016 Lend_base:        
1017         pop %edi                  /* Restore temp registers */
1018         pop %ecx
1019         pop %eax
1020         ret
1021         SIZE(GNAME(fast_bzero_base))
1024 /* When LISP_FEATURE_C_STACK_IS_CONTROL_STACK, we cannot safely scrub
1025  * the control stack from C, largely due to not knowing where the
1026  * active stack frame ends.  On such platforms, we reimplement the
1027  * core scrubbing logic in assembly, in this case here:
1028  */
1029         .text
1030         .align  align_16byte,0x90
1031         .globl GNAME(arch_scrub_control_stack)
1032         TYPE(GNAME(arch_scrub_control_stack))
1033 GNAME(arch_scrub_control_stack):
1034         /* We are passed three parameters:
1035          * A (struct thread *) at [ESP+4],
1036          * the address of the guard page at [ESP+8], and
1037          * the address of the hard guard page at [ESP+12].
1038          * We may trash EAX, ECX, and EDX with impunity.
1039          * [ESP] is our return address, [ESP-4] is the first
1040          * stack slot to scrub. */
1042         /* We start by setting up our scrub pointer in EAX, our
1043          * guard page upper bound in ECX, and our hard guard
1044          * page upper bound in EDX. */
1045         lea     -4(%esp), %eax
1046         mov     GNAME(os_vm_page_size),%edx
1047         mov     %edx, %ecx
1048         add     8(%esp), %ecx
1049         add     12(%esp), %edx
1051         /* We need to do a memory operation relative to the
1052          * thread pointer, so put it in %ecx and our guard
1053          * page upper bound in 4(%esp). */
1054         xchg    4(%esp), %ecx
1056         /* Now we begin our main scrub loop. */
1057 ascs_outer_loop:
1059         /* If we're about to scrub the hard guard page, exit. */
1060         cmp     %edx, %eax
1061         jae     ascs_check_guard_page
1062         cmp     12(%esp), %eax
1063         ja      ascs_finished
1065 ascs_check_guard_page:
1066         /* If we're about to scrub the guard page, and the guard
1067          * page is protected, exit. */
1068         cmp     4(%esp), %eax
1069         jae     ascs_clear_loop
1070         cmp     8(%esp), %eax
1071         jbe     ascs_clear_loop
1072         cmpl    $(NIL), THREAD_CONTROL_STACK_GUARD_PAGE_PROTECTED_OFFSET(%ecx)
1073         jne     ascs_finished
1075         /* Clear memory backwards to the start of the (4KiB) page */
1076 ascs_clear_loop:
1077         movl    $0, (%eax)
1078         test    $0xfff, %eax
1079         lea     -4(%eax), %eax
1080         jnz     ascs_clear_loop
1082         /* If we're about to hit the hard guard page, exit. */
1083         cmp     %edx, %eax
1084         jae     ascs_finished
1086         /* If the next (previous?) 4KiB page contains a non-zero
1087          * word, continue scrubbing. */
1088 ascs_check_loop:
1089         testl   $-1, (%eax)
1090         jnz     ascs_outer_loop
1091         test    $0xfff, %eax
1092         lea     -4(%eax), %eax
1093         jnz     ascs_check_loop
1095 ascs_finished:
1096         ret
1097         SIZE(GNAME(arch_scrub_control_stack))