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/return-pc.h"
23 #include "genesis/simple-fun.h"
24 #include "genesis/static-symbols.h"
60 * LEAF - declare leaf routine
62 #define LEAF(symbol) \
65 .type symbol,@function; \
67 symbol: .frame sp,0,ra
70 * NESTED - declare nested routine entry point
72 #define NESTED(symbol, framesize, rpc) \
75 .type symbol,@function; \
77 symbol: .frame sp, framesize, rpc
80 * END - mark end of function
82 #define END(function) \
84 .size function,.-function
87 * EXPORT - export definition of symbol
89 #define EXPORT(symbol) \
94 * FEXPORT - export definition of a function symbol
96 #define FEXPORT(symbol) \
98 .type symbol,@function; \
105 * Function to transfer control into lisp.
107 #define framesize 16*4
108 NESTED(call_into_lisp, framesize, ra)
114 /* Save all the C regs. */
116 sw ra, framesize-8(sp)
117 sw s8, framesize-12(sp)
118 /* No .cprestore, we don't want automatic gp restauration. */
119 sw gp, framesize-16(sp)
120 sw s7, framesize-20(sp)
121 sw s6, framesize-24(sp)
122 sw s5, framesize-28(sp)
123 sw s4, framesize-32(sp)
124 sw s3, framesize-36(sp)
125 sw s2, framesize-40(sp)
126 sw s1, framesize-44(sp)
127 sw s0, framesize-48(sp)
131 /* Clear unsaved boxed descriptor regs */
135 /* Turn on pseudo-atomic. */
141 /* Load the allocation pointer, preserving the low-bit of alloc */
142 lw reg_BSP, dynamic_space_free_pointer
143 addu reg_ALLOC, reg_BSP
145 /* Load the rest of the LISP state. */
146 lw reg_BSP, current_binding_stack_pointer
147 lw reg_CSP, current_control_stack_pointer
148 lw reg_OCFP, current_control_frame_pointer
150 /* Check for interrupt */
161 lw reg_A0, 0(reg_CFP)
162 lw reg_A1, 4(reg_CFP)
163 lw reg_A2, 8(reg_CFP)
164 lw reg_A3, 12(reg_CFP)
165 lw reg_A4, 16(reg_CFP)
166 lw reg_A5, 20(reg_CFP)
169 la reg_LRA, lra - RETURN_PC_RETURN_POINT_OFFSET
171 /* Indirect closure */
172 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
174 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
176 /* Mark us as in Lisp land. */
177 sw zero, foreign_function_call_active
179 /* Jump into lisp land. */
184 lra: .word RETURN_PC_HEADER_WIDETAG
186 /* Multiple value return spot, clear stack. */
187 move reg_CSP, reg_OCFP
190 /* Single value return spot. */
192 /* Nested lisp -> C calls may have clobbered gp. */
193 lw gp, framesize-16(sp)
195 /* Mark us as in C land. */
196 sw reg_CSP, foreign_function_call_active
198 /* Set the pseudo-atomic flag. */
203 /* Save LISP state. */
204 subu reg_NL0, reg_ALLOC, 1
205 sw reg_NL0, dynamic_space_free_pointer
206 sw reg_BSP, current_binding_stack_pointer
207 sw reg_CSP, current_control_stack_pointer
208 sw reg_CFP, current_control_frame_pointer
210 /* Check for interrupt */
217 /* Pass one return value back to C land. For a 64bit value, we may
218 need to clobber v1 aka reg_NL4. */
219 move v0, reg_A0 # reg_CFUNC
220 move v1, reg_A1 # reg_NL4
223 lw ra, framesize-8(sp)
224 lw s8, framesize-12(sp)
225 lw s7, framesize-20(sp)
226 lw s6, framesize-24(sp)
227 lw s5, framesize-28(sp)
228 lw s4, framesize-32(sp)
229 lw s3, framesize-36(sp)
230 lw s2, framesize-40(sp)
231 lw s1, framesize-44(sp)
232 lw s0, framesize-48(sp)
234 /* Restore C stack. */
243 * Transfering control from Lisp into C
245 NESTED(call_into_c, 0, ra)
246 /* The C stack frame was already set up from lisp, and the
247 argument registers as well. We have to fake the correct
248 gp value for this function, though. */
252 lui gp, %hi(_gp_disp)
253 addiu gp, %lo(_gp_disp)
254 lui reg_NL3, %hi(call_into_c)
255 addiu reg_NL3, %lo(call_into_c)
260 /* Setup the lisp stack. */
261 move reg_OCFP, reg_CFP
262 move reg_CFP, reg_CSP
263 addu reg_CSP, reg_CFP, 32
265 /* Mark us as in C land. */
266 sw reg_CSP, foreign_function_call_active
268 /* Set the pseudo-atomic flag. */
274 /* Convert the return address to an offset and save it on the stack. */
275 subu reg_NFP, reg_LIP, reg_CODE
276 addu reg_NFP, OTHER_POINTER_LOWTAG
277 sw reg_LRA, (reg_CFP)
278 sw reg_CODE, 4(reg_CFP)
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
340 /* Restore LRA & CODE */
341 lw reg_LRA, (reg_CFP)
342 lw reg_CODE, 4(reg_CFP)
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
387 break 0x0, trap_Cerror
388 /* Error data length. */
391 .byte UNDEFINED_FUN_ERROR
392 /* Magic value 254 means a 16bit little endian value follows.
393 See debug-var-io.lisp. */
395 /* reg_FDEFN is #14. */
396 .byte ((14 << 5) + sc_DescriptorReg) % 0x100
397 .byte ((14 << 5) + sc_DescriptorReg) / 0x100
400 1: lw reg_CODE, FDEFN_FUN_OFFSET(reg_FDEFN)
401 lw reg_LIP, SIMPLE_FUN_CODE_OFFSET(reg_CODE)
406 * The closure trampoline.
408 .align 5 /* common MIPS cacheline size */
411 .word SIMPLE_FUN_HEADER_WIDETAG /* header */
412 .word closure_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
415 .word NIL /* arglist */
417 .word NIL /* xrefs */
419 lw reg_LEXENV, FDEFN_FUN_OFFSET(reg_FDEFN)
420 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
421 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
426 * The trampoline for funcallable instances
428 .globl funcallable_instance_tramp
430 .word SIMPLE_FUN_HEADER_WIDETAG
431 funcallable_instance_tramp = . + 1
432 .word funcallable_instance_tramp
439 lw reg_LEXENV, FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(reg_LEXENV)
440 lw reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
441 addu reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
446 * Function-end breakpoint magic. This is truely magic, the code is
447 * copied and has to be relocatable. It also needs a properly aligned
448 * header tag after the fun_end_breakpoint_guts symbol.
450 .align 3 /* minimum alignment for a lisp object */
451 LEAF(fun_end_breakpoint_guts)
453 .word RETURN_PC_HEADER_WIDETAG
454 b multiple_value_return
458 /* single value return */
460 move reg_OCFP, reg_CSP
469 multiple_value_return:
471 FEXPORT(fun_end_breakpoint_trap)
472 break 0x0, trap_FunEndBreakpoint
473 b multiple_value_return
474 EXPORT(fun_end_breakpoint_end)
475 END(fun_end_breakpoint_guts)
478 .align 3 /* minimum alignment for a lisp object */
479 LEAF(do_pending_interrupt)
480 break 0x0, trap_PendingInterrupt
482 END(do_pending_interrupt)