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_LRA, (reg_CFP)
277 sw reg_CODE, 4(reg_CFP)
280 /* Save LISP state. */
281 subu reg_A0, reg_ALLOC, 1
282 sw reg_A0, dynamic_space_free_pointer
283 sw reg_BSP, current_binding_stack_pointer
284 sw reg_CSP, current_control_stack_pointer
285 sw reg_CFP, current_control_frame_pointer
287 /* Check for interrupt */
294 /* Into C land we go. */
295 move t9, reg_CFUNC # reg_ALLOC
300 /* Pass 64bit return value to lisp land. */
301 move reg_NL0, v0 # reg_CFUNC
302 move reg_NL1, v1 # reg_NL4
305 * Clear boxed descriptor registers before allowing an interrupt.
306 * We can't rely on C saving some of those registers, they might
307 * have been GCed in the meanwhile.
316 li reg_LEXENV, 0 # t7
318 * reg_NFP and reg_OCFP are pointing to fixed locations and are
327 /* Turn on pseudo-atomic. */
333 /* Load the allocation pointer, preserving the low-bit of alloc */
334 lw reg_BSP, dynamic_space_free_pointer
335 addu reg_ALLOC, reg_BSP
337 lw reg_BSP, current_binding_stack_pointer
339 /* Restore LRA & CODE */
340 lw reg_LRA, (reg_CFP)
341 lw reg_CODE, 4(reg_CFP)
342 subu reg_LIP, reg_NFP, OTHER_POINTER_LOWTAG
343 addu reg_LIP, reg_CODE
345 /* Check for interrupt */
352 /* Reset the lisp stack. */
353 /* Note: OCFP and CFP are in saved regs. */
354 move reg_CSP, reg_CFP
355 move reg_CFP, reg_OCFP
357 /* Mark us as in Lisp land. */
358 sw zero, foreign_function_call_active
360 /* Return to LISP. */
365 * Trampolines follow the Lisp calling convention.
367 * The undefined-function trampoline.
369 .align 3 /* minimum alignment for a lisp object */
370 .word SIMPLE_FUN_HEADER_WIDETAG /* header */
371 .word undefined_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
374 .word NIL /* arglist */
376 .word NIL /* xrefs */
377 LEAF(undefined_tramp)
378 /* Point reg_CODE to the header and tag it as function, since
379 the debugger regards a function pointer in reg_CODE which
380 doesn't point to a code object as undefined function. */
381 lui reg_CODE, %hi(undefined_tramp)
382 addiu reg_CODE, %lo(undefined_tramp)
383 addiu reg_CODE, -SIMPLE_FUN_CODE_OFFSET
386 break 0x0, trap_Cerror
387 /* Error data length. */
390 .byte UNDEFINED_FUN_ERROR
391 /* Magic value 254 means a 16bit little endian value follows.
392 See debug-var-io.lisp. */
394 /* reg_FDEFN is #14. */
395 .byte ((14 << 5) + sc_DescriptorReg) % 0x100
396 .byte ((14 << 5) + sc_DescriptorReg) / 0x100
399 1: lw reg_CODE, FDEFN_FUN_OFFSET(reg_FDEFN)
400 lw reg_LIP, SIMPLE_FUN_CODE_OFFSET(reg_CODE)
405 * The closure trampoline.
407 .align 5 /* common MIPS cacheline size */
410 .word SIMPLE_FUN_HEADER_WIDETAG /* header */
411 .word closure_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
414 .word NIL /* arglist */
416 .word NIL /* xrefs */
418 lw reg_LEXENV, FDEFN_FUN_OFFSET(reg_FDEFN)
419 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
420 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
425 * The trampoline for funcallable instances
427 .globl funcallable_instance_tramp
429 .word SIMPLE_FUN_HEADER_WIDETAG
430 funcallable_instance_tramp = . + 1
431 .word funcallable_instance_tramp
438 lw reg_LEXENV, FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(reg_LEXENV)
439 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
440 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
445 * Function-end breakpoint magic. This is truely magic, the code is
446 * copied and has to be relocatable. It also needs a properly aligned
447 * header tag after the fun_end_breakpoint_guts symbol.
451 * For an explanation of the magic involved in function-end
452 * breakpoints, see the implementation in ppc-assem.S.
455 .align 3 /* minimum alignment for a lisp object */
456 LEAF(fun_end_breakpoint_guts)
458 .word RETURN_PC_HEADER_WIDETAG + 0x800
459 b multiple_value_return
463 /* single value return */
465 move reg_OCFP, reg_CSP
474 multiple_value_return:
476 FEXPORT(fun_end_breakpoint_trap)
478 b multiple_value_return
479 break 0x0, trap_FunEndBreakpoint
481 EXPORT(fun_end_breakpoint_end)
482 END(fun_end_breakpoint_guts)
485 .align 3 /* minimum alignment for a lisp object */
486 LEAF(do_pending_interrupt)
487 break 0x0, trap_PendingInterrupt
489 END(do_pending_interrupt)