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.
19 #include "genesis/fdefn.h"
20 #include "genesis/closure.h"
21 #include "genesis/funcallable-instance.h"
22 #include "genesis/simple-fun.h"
23 #include "genesis/static-symbols.h"
59 * LEAF - declare leaf routine
61 #define LEAF(symbol) \
64 .type symbol,@function; \
66 symbol: .frame sp,0,ra
69 * NESTED - declare nested routine entry point
71 #define NESTED(symbol, framesize, rpc) \
74 .type symbol,@function; \
76 symbol: .frame sp, framesize, rpc
79 * END - mark end of function
81 #define END(function) \
83 .size function,.-function
86 * EXPORT - export definition of symbol
88 #define EXPORT(symbol) \
93 * FEXPORT - export definition of a function symbol
95 #define FEXPORT(symbol) \
97 .type symbol,@function; \
104 * Function to transfer control into lisp.
106 #define framesize 16*4
107 NESTED(call_into_lisp, framesize, ra)
113 /* Save all the C regs. */
115 sw ra, framesize-8(sp)
116 sw s8, framesize-12(sp)
117 /* No .cprestore, we don't want automatic gp restauration. */
118 sw gp, framesize-16(sp)
119 sw s7, framesize-20(sp)
120 sw s6, framesize-24(sp)
121 sw s5, framesize-28(sp)
122 sw s4, framesize-32(sp)
123 sw s3, framesize-36(sp)
124 sw s2, framesize-40(sp)
125 sw s1, framesize-44(sp)
126 sw s0, framesize-48(sp)
130 /* Clear unsaved boxed descriptor regs */
134 /* Turn on pseudo-atomic. */
140 /* Load the allocation pointer, preserving the low-bit of alloc */
141 lw reg_BSP, dynamic_space_free_pointer
142 addu reg_ALLOC, reg_BSP
144 /* Load the rest of the LISP state. */
145 lw reg_BSP, current_binding_stack_pointer
146 lw reg_CSP, current_control_stack_pointer
147 lw reg_OCFP, current_control_frame_pointer
149 /* Check for interrupt */
160 lw reg_A0, 0(reg_CFP)
161 lw reg_A1, 4(reg_CFP)
162 lw reg_A2, 8(reg_CFP)
163 lw reg_A3, 12(reg_CFP)
164 lw reg_A4, 16(reg_CFP)
165 lw reg_A5, 20(reg_CFP)
168 la reg_LRA, lra + OTHER_POINTER_LOWTAG
170 /* Indirect closure */
171 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
173 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
175 /* Mark us as in Lisp land. */
176 sw zero, foreign_function_call_active
178 /* Jump into lisp land. */
183 lra: .word RETURN_PC_HEADER_WIDETAG
185 /* Multiple value return spot, clear stack. */
186 move reg_CSP, reg_OCFP
189 /* Single value return spot. */
191 /* Nested lisp -> C calls may have clobbered gp. */
192 lw gp, framesize-16(sp)
194 /* Mark us as in C land. */
195 sw reg_CSP, foreign_function_call_active
197 /* Set the pseudo-atomic flag. */
202 /* Save LISP state. */
203 subu reg_NL0, reg_ALLOC, 1
204 sw reg_NL0, dynamic_space_free_pointer
205 sw reg_BSP, current_binding_stack_pointer
206 sw reg_CSP, current_control_stack_pointer
207 sw reg_CFP, current_control_frame_pointer
209 /* Check for interrupt */
216 /* Pass one return value back to C land. For a 64bit value, we may
217 need to clobber v1 aka reg_NL4. */
218 move v0, reg_A0 # reg_CFUNC
219 move v1, reg_A1 # reg_NL4
222 lw ra, framesize-8(sp)
223 lw s8, framesize-12(sp)
224 lw s7, framesize-20(sp)
225 lw s6, framesize-24(sp)
226 lw s5, framesize-28(sp)
227 lw s4, framesize-32(sp)
228 lw s3, framesize-36(sp)
229 lw s2, framesize-40(sp)
230 lw s1, framesize-44(sp)
231 lw s0, framesize-48(sp)
233 /* Restore C stack. */
242 * Transfering control from Lisp into C
244 NESTED(call_into_c, 0, ra)
245 /* The C stack frame was already set up from lisp, and the
246 argument registers as well. We have to fake the correct
247 gp value for this function, though. */
251 lui gp, %hi(_gp_disp)
252 addiu gp, %lo(_gp_disp)
253 lui reg_NL3, %hi(call_into_c)
254 addiu reg_NL3, %lo(call_into_c)
259 /* Setup the lisp stack. */
260 move reg_OCFP, reg_CFP
261 move reg_CFP, reg_CSP
262 addu reg_CSP, reg_CFP, 32
264 /* Mark us as in C land. */
265 sw reg_CSP, foreign_function_call_active
267 /* Set the pseudo-atomic flag. */
273 /* Convert the return address to an offset and save it on the stack. */
274 subu reg_NFP, reg_LIP, reg_CODE
275 addu reg_NFP, OTHER_POINTER_LOWTAG
276 sw reg_OCFP, (reg_CFP)
277 sw reg_NFP, 4(reg_CFP)
278 sw reg_CODE, 8(reg_CFP)
279 sw gp, 12(reg_CFP) // should this be saved? on the control stack?
281 /* Save LISP state. */
282 subu reg_A0, reg_ALLOC, 1
283 sw reg_A0, dynamic_space_free_pointer
284 sw reg_BSP, current_binding_stack_pointer
285 sw reg_CSP, current_control_stack_pointer
286 sw reg_CFP, current_control_frame_pointer
288 /* Check for interrupt */
295 /* Into C land we go. */
296 move t9, reg_CFUNC # reg_ALLOC
301 /* Pass 64bit return value to lisp land. */
302 move reg_NL0, v0 # reg_CFUNC
303 move reg_NL1, v1 # reg_NL4
306 * Clear boxed descriptor registers before allowing an interrupt.
307 * We can't rely on C saving some of those registers, they might
308 * have been GCed in the meanwhile.
317 li reg_LEXENV, 0 # t7
319 * reg_NFP and reg_OCFP are pointing to fixed locations and are
328 /* Turn on pseudo-atomic. */
334 /* Load the allocation pointer, preserving the low-bit of alloc */
335 lw reg_BSP, dynamic_space_free_pointer
336 addu reg_ALLOC, reg_BSP
338 lw reg_BSP, current_binding_stack_pointer
341 lw reg_CODE, 8(reg_CFP)
342 /* Setup the return address */
343 subu reg_LIP, reg_NFP, OTHER_POINTER_LOWTAG
344 addu reg_LIP, reg_CODE
346 /* Check for interrupt */
353 /* Reset the lisp stack. */
354 /* Note: OCFP and CFP are in saved regs. */
355 move reg_CSP, reg_CFP
356 move reg_CFP, reg_OCFP
358 /* Mark us as in Lisp land. */
359 sw zero, foreign_function_call_active
361 /* Return to LISP. */
366 * Trampolines follow the Lisp calling convention.
368 * The undefined-function trampoline.
370 .align 3 /* minimum alignment for a lisp object */
371 .word SIMPLE_FUN_HEADER_WIDETAG /* header */
372 .word undefined_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
375 .word NIL /* arglist */
377 .word NIL /* xrefs */
378 LEAF(undefined_tramp)
379 /* Point reg_CODE to the header and tag it as function, since
380 the debugger regards a function pointer in reg_CODE which
381 doesn't point to a code object as undefined function. */
382 lui reg_CODE, %hi(undefined_tramp)
383 addiu reg_CODE, %lo(undefined_tramp)
384 addiu reg_CODE, -SIMPLE_FUN_CODE_OFFSET
386 /* If we are called with stack arguments (or in a tail-call
387 scenario), we end up with an allocated stack frame, but the
388 frame link information is uninitialized. Fix things by
389 allocating and initializing our stack frame "properly". */
390 addiu reg_NL0,reg_NARGS,-24
392 addu reg_CSP,reg_CFP,reg_NARGS
393 addiu reg_CSP,reg_CFP,24
394 1: sw reg_OCFP,0(reg_CFP)
395 sw reg_LRA,4(reg_CFP)
397 /* Now that the preliminaries are dealt with, actually trap. */
400 break 0x0, trap_Cerror
401 /* Error data length. */
404 .byte UNDEFINED_FUN_ERROR
405 /* Magic value 254 means a 16bit little endian value follows.
406 See debug-var-io.lisp. */
408 /* reg_FDEFN is #14. */
409 .byte ((14 << 6) + sc_DescriptorReg) % 0x100
410 .byte ((14 << 6) + sc_DescriptorReg) / 0x100
413 1: lw reg_CODE, FDEFN_FUN_OFFSET(reg_FDEFN)
414 lw reg_LIP, SIMPLE_FUN_CODE_OFFSET(reg_CODE)
419 * The closure trampoline.
421 .align 5 /* common MIPS cacheline size */
424 .word SIMPLE_FUN_HEADER_WIDETAG /* header */
425 .word closure_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
428 .word NIL /* arglist */
430 .word NIL /* xrefs */
432 lw reg_LEXENV, FDEFN_FUN_OFFSET(reg_FDEFN)
433 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
434 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
439 * The trampoline for funcallable instances
441 .globl funcallable_instance_tramp
443 .word SIMPLE_FUN_HEADER_WIDETAG
444 funcallable_instance_tramp = . + 1
445 .word funcallable_instance_tramp
452 lw reg_LEXENV, FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(reg_LEXENV)
453 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
454 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
459 * Function-end breakpoint magic. This is truely magic, the code is
460 * copied and has to be relocatable. It also needs a properly aligned
461 * header tag after the fun_end_breakpoint_guts symbol.
465 * For an explanation of the magic involved in function-end
466 * breakpoints, see the implementation in ppc-assem.S.
469 .align 3 /* minimum alignment for a lisp object */
470 LEAF(fun_end_breakpoint_guts)
472 .word RETURN_PC_HEADER_WIDETAG + 0x600
473 b multiple_value_return
477 /* single value return */
479 move reg_OCFP, reg_CSP
488 multiple_value_return:
490 FEXPORT(fun_end_breakpoint_trap)
492 b multiple_value_return
493 break 0x0, trap_FunEndBreakpoint
495 EXPORT(fun_end_breakpoint_end)
496 END(fun_end_breakpoint_guts)
499 .align 3 /* minimum alignment for a lisp object */
500 LEAF(do_pending_interrupt)
501 break 0x0, trap_PendingInterrupt
503 END(do_pending_interrupt)