1 #define LANGUAGE_ASSEMBLY
7 #include "genesis/closure.h"
8 #include "genesis/funcallable-instance.h"
9 #include "genesis/fdefn.h"
10 #include "genesis/static-symbols.h"
11 #include "genesis/simple-fun.h"
12 #include "genesis/symbol.h"
14 #define STATIC_SYMBOL_VALUE(sym) [reg_NULL, #(((sym)-NIL)+SYMBOL_VALUE_OFFSET)]
19 .global call_into_lisp
20 .type call_into_lisp, %function
23 @@ At this point, we have:
25 @@ R1 - pointer to args
26 @@ R2 - number of args (unboxed)
27 @@ There will be no more than three args, so we don't need to
28 @@ worry about parameters to be passed on the stack.
30 @@ All registers other than R0-R3 and R12 are callee-saves.
31 @@ Save R3 to get 8-byte alignemnt.
32 stmfd sp!, {r3-r11, lr}
35 @@ Start by finding NIL.
36 ldr reg_NULL, .known_nil
39 mov reg_NARGS, r2, lsl #2
41 @@ Move args pointer out of the way of the args to be loaded.
44 @@ Move the function to its passing location.
47 @@ Clear the boxed registers that don't already have something
52 @@ Find the lisp stack and frame pointers. We're allocating a
53 @@ new lisp stack frame, so load the stack pointer into CFP.
54 @@ And we need the frame pointer, but OCFP is in use, so use
56 ldr reg_NFP, .frame_pointer_address
57 ldr reg_CFP, .stack_pointer_address
58 ldr reg_NFP, [reg_NFP]
59 ldr reg_CFP, [reg_CFP]
61 @@ Enter PSEUDO-ATOMIC.
62 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
64 #ifndef LISP_FEATURE_GENCGC
65 @@ Copy the current allocation pointer into the symbol.
66 ldr reg_OCFP, =dynamic_space_free_pointer
67 ldr reg_OCFP, [reg_OCFP]
68 str reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
71 @@ Clear FFCA, so the runtime knows that we're "in lisp".
72 ldr reg_OCFP, =foreign_function_call_active
73 str reg_R2, [reg_OCFP]
75 @@ We need to set up the lisp stack pointer and the basics of
76 @@ our stack frame while we're still in P-A. Any sooner and
77 @@ our stack frame can be clobbered by a stray interrupt, any
78 @@ later and we can end up with a half-configured stack frame
79 @@ when we catch a stray interrupt.
81 @@ Allocate our frame and set up the Lisp stack pointer
82 add reg_OCFP, reg_CFP, #8
83 str reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
85 @@ Set up the "frame link"
86 str reg_NFP, [reg_OCFP, #-8]
88 @@ Set up the return address
90 str reg_NL3, [reg_OCFP, #-4]
92 @@ Leave PSEUDO-ATOMIC and check for interrupts.
93 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
94 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
98 @@ Load our function args. Cleverness abounds!
99 rsb reg_NL3, reg_NARGS, #8
101 ldr reg_R2, [reg_R8, #8]
102 ldr reg_R1, [reg_R8, #4]
105 @@ Load the closure-fun (or simple-fun-self), in case we're
106 @@ trying to call a closure.
107 ldr reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
109 @@ And, finally, call into Lisp!
110 add reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
113 .equ .lra, .+OTHER_POINTER_LOWTAG
114 .word RETURN_PC_HEADER_WIDETAG
116 @@ Correct stack pointer for return processing.
117 streq reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
119 @@ Enter PSEUDO-ATOMIC.
120 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
122 @@ Save the lisp stack and frame pointers.
123 ldr reg_NFP, .frame_pointer_address
124 str reg_CFP, [reg_NFP]
125 ldr reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
126 ldr reg_OCFP, .stack_pointer_address
127 str reg_NFP, [reg_OCFP]
129 @@ Set FFCA, so the runtime knows that we're not "in lisp".
130 ldr reg_OCFP, =foreign_function_call_active
133 #ifndef LISP_FEATURE_GENCGC
134 @@ Copy the current allocation pointer out from the symbol.
135 ldr reg_OCFP, =dynamic_space_free_pointer
136 ldr reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
137 str reg_NFP, [reg_OCFP]
140 @@ Leave PSEUDO-ATOMIC and check for interrupts.
141 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
142 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
146 @@ Restore saved registers.
147 fldmfdd sp!, {d8-d15}
148 ldmfd sp!, {r3-r11, lr}
150 .size call_into_lisp, .-call_into_lisp
151 .frame_pointer_address: .word current_control_frame_pointer
152 .stack_pointer_address: .word current_control_stack_pointer
157 .type call_into_c, %function
159 @@ At this point, we have:
160 @@ R8 -- C function to call. This routine doesn't support
161 @@ thumb interworking, but linkage-table does, so we
163 @@ LR -- Return address within the code component.
164 @@ OCFP -- First C register argument.
165 @@ NARGS -- Second C register argument.
166 @@ NL2 -- Third C register argument.
167 @@ NL3 -- Fourth C register argument.
168 @@ All other C arguments are already stashed on the C stack.
170 @@ We need to convert our return address to a GC-safe format,
171 @@ build a stack frame to count for the "foreign" frame,
172 @@ switch to C mode, move the register arguments to the
173 @@ correct locations, call the C function, move the result to
174 @@ the correct location, switch back to Lisp mode, tear down
175 @@ our stack frame, restore the return address, and return to
178 @@ We have ONE unboxed scratch register: NFP. Use it as a
179 @@ temporary while we convert the (unboxed) return address to
180 @@ a (fixnum) offset within the component.
181 sub reg_NFP, reg_LR, reg_CODE
182 add reg_NFP, reg_NFP, #OTHER_POINTER_LOWTAG
184 @@ Build a Lisp stack frame. We need to stash our frame link,
185 @@ the code component, and our return offset. Frame link goes
186 @@ in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in
187 @@ slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2. The
188 @@ debugger knows about this layout (see COMPUTE-CALLING-FRAME
189 @@ in SYS:SRC;CODE;DEBUG-INT.LISP). The stack is aligned, so
190 @@ we can use R0 (a boxed register) as our temporary.
191 ldr reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
192 add reg_R0, reg_R0, #12
193 str reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
194 str reg_CFP, [reg_R0, #-12]
195 str reg_NFP, [reg_R0, #-8]
196 str reg_CODE, [reg_R0, #-4]
198 @@ Enter PSEUDO-ATOMIC.
199 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
201 @@ Save the lisp stack and frame pointers.
202 ldr reg_NFP, .stack_pointer_address
203 str reg_R0, [reg_NFP]
204 sub reg_R0, reg_R0, #12
205 ldr reg_NFP, .frame_pointer_address
206 str reg_R0, [reg_NFP]
208 @@ We're done with R0, and we need to use OCFP when leaving
209 @@ pseudo-atomic, so move the first of the C register
210 @@ arguments to its final resting place now.
213 @@ Set FFCA, so the runtime knows that we're not "in lisp".
214 ldr reg_NFP, =foreign_function_call_active
217 #ifndef LISP_FEATURE_GENCGC
218 @@ Copy the current allocation pointer out from the symbol.
219 ldr reg_OCFP, =dynamic_space_free_pointer
220 ldr reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
221 str reg_NFP, [reg_OCFP]
224 @@ Leave PSEUDO-ATOMIC and check for interrupts.
225 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
226 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
230 @@ Now that we're in C mode, move the remaining register args
236 @@ And call the C function. We don't support interworking
237 @@ here because we have to be able to pass the function
238 @@ pointer in a boxed register, but the linkage-table is quite
239 @@ capable of doing a tail-call to a Thumb routine.
241 @@ R8 is important for undefined_alien_function.
244 @@ We're back. Our main tasks are to move the C return value
245 @@ to where Lisp expects it, and to re-establish the Lisp
248 @@ Stash the return value into NARGS for Lisp.
250 @@ For returning long-long, and doubles with softfp.
254 ldr reg_NULL, .known_nil
256 @@ Blank the boxed registers.
264 @@ Enter PSEUDO-ATOMIC.
265 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
267 @@ Clear FFCA, so the runtime knows that we're "in lisp".
268 ldr reg_OCFP, =foreign_function_call_active
269 str reg_R2, [reg_OCFP]
271 #ifndef LISP_FEATURE_GENCGC
272 @@ Copy the current allocation pointer into the symbol.
273 ldr reg_OCFP, =dynamic_space_free_pointer
274 ldr reg_OCFP, [reg_OCFP]
275 str reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
278 @@ Restore the Lisp stack and frame pointers, but store the
279 @@ control frame pointer in reg_NFP (saving a register move
281 ldr reg_NFP, .stack_pointer_address
282 ldr reg_CFP, [reg_NFP]
283 str reg_CFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
284 ldr reg_NFP, .frame_pointer_address
285 ldr reg_NFP, [reg_NFP]
287 @@ Leave PSEUDO-ATOMIC and check for interrupts.
288 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
289 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
293 @@ Restore our caller state from our stack frame.
294 ldr reg_CODE, [reg_NFP, #8]
295 ldr reg_NL2, [reg_NFP, #4]
296 ldr reg_CFP, [reg_NFP]
297 str reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
299 @@ Restore our return address... into the program counter.
300 sub reg_NL2, reg_NL2, #OTHER_POINTER_LOWTAG
301 add reg_PC, reg_NL2, reg_CODE
303 .size call_into_c, .-call_into_c
305 @@ FIXME-ARM: The following is random garbage, to make
306 @@ code/debug-int compile. To get the debugger working, this
307 @@ needs to be implemented.
309 .global fun_end_breakpoint_guts
310 .type fun_end_breakpoint_guts, %object
311 fun_end_breakpoint_guts:
312 .global fun_end_breakpoint_trap
313 .type fun_end_breakpoint_trap, %function
314 fun_end_breakpoint_trap:
315 b fun_end_breakpoint_trap
316 .global fun_end_breakpoint_end
317 fun_end_breakpoint_end:
319 #ifdef LISP_FEATURE_GENCGC
322 .type alloc_tramp, %function
324 stmfd sp!, {r4, r6, r12, lr}
326 ldr r4, =foreign_function_call_active
329 ldr r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
331 str r6, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
333 @@ Create a new frame and save descriptor regs on the stack
334 @@ for the GC to see.
335 str reg_CFP, [r4, #0]
336 str reg_NULL, [r4, #4]
337 str reg_CODE, [r4, #8]
339 stmea r4, {r0-reg_LEXENV, r8}
349 ldr r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
350 ldmea r4, {r0-reg_LEXENV, r8}
352 str r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
354 ldr r4, =foreign_function_call_active
358 ldmfd sp!, {r4, r6, r12, lr}
362 .global do_pending_interrupt
363 .type do_pending_interrupt, %function
364 do_pending_interrupt:
365 #if defined(LISP_FEATURE_LINUX)
367 #elif defined(LISP_FEATURE_NETBSD)
370 .byte trap_PendingInterrupt