From c1b4849c95bad4f3535fba2b9307fd37e15bcf6d Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Mon, 18 Mar 2002 17:59:37 +0000 Subject: [PATCH] need these too --- src/runtime/Config.ppc-linux | 22 +++ src/runtime/ppc-arch.c | 266 +++++++++++++++++++++++++++ src/runtime/ppc-arch.h | 6 + src/runtime/ppc-assem.S | 416 ++++++++++++++++++++++++++++++++++++++++++ src/runtime/ppc-linux-os.c | 75 ++++++++ src/runtime/ppc-linux-os.h | 10 + src/runtime/ppc-lispregs.h | 51 ++++++ 7 files changed, 846 insertions(+) create mode 100644 src/runtime/Config.ppc-linux create mode 100644 src/runtime/ppc-arch.c create mode 100644 src/runtime/ppc-arch.h create mode 100644 src/runtime/ppc-assem.S create mode 100644 src/runtime/ppc-linux-os.c create mode 100644 src/runtime/ppc-linux-os.h create mode 100644 src/runtime/ppc-lispregs.h diff --git a/src/runtime/Config.ppc-linux b/src/runtime/Config.ppc-linux new file mode 100644 index 0000000..1dcbc80 --- /dev/null +++ b/src/runtime/Config.ppc-linux @@ -0,0 +1,22 @@ +# This software is part of the SBCL system. See the README file for +# more information. +# +# This software is derived from the CMU CL system, which was +# written at Carnegie Mellon University and released into the +# public domain. The software is in the public domain and is +# provided with absolutely no warranty. See the COPYING and CREDITS +# files for more information. + +CFLAGS += -g -Dppc +LD = ld #-taso +LINKFLAGS = -v -g # -Wl,-T -Wl,ld-script.alpha-linux +NM = nm -p + +ASSEM_SRC = ppc-assem.S ldso-stubs.S +ARCH_SRC = ppc-arch.c + +OS_SRC = linux-os.c ppc-linux-os.c os-common.c +LINKFLAGS+=-rdynamic # -static +OS_LIBS= -ldl + +GC_SRC= gc.c diff --git a/src/runtime/ppc-arch.c b/src/runtime/ppc-arch.c new file mode 100644 index 0000000..eac4013 --- /dev/null +++ b/src/runtime/ppc-arch.c @@ -0,0 +1,266 @@ +/* + + $Header$ + + This code was written as part of the CMU Common Lisp project at + Carnegie Mellon University, and has been placed in the public domain. + +*/ + +#include + +#include "arch.h" +#include "sbcl.h" +#include "globals.h" +#include "validate.h" +#include "os.h" +#include "lispregs.h" +#include "signal.h" +#include "interrupt.h" +#include "interr.h" + + /* The header files may not define PT_DAR/PT_DSISR. This definition + is correct for all versions of ppc linux >= 2.0.30 + + As of DR2.1u4, MkLinux doesn't pass these registers to signal + handlers correctly; a patch is necessary in order to (partially) + correct this. + + Even with the patch, the DSISR may not have its 'write' bit set + correctly (it tends not to be set if the fault was caused by + something other than a protection violation.) + + Caveat callers. */ + +#ifndef PT_DAR +#define PT_DAR 41 +#endif + +#ifndef PT_DSISR +#define PT_DSISR 42 +#endif + +void arch_init() +{ +} + +os_vm_address_t +arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context) +{ + unsigned long badinstr; + unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context)); + int instclass; + os_vm_address_t addr; + + + /* Make sure it's not the pc thats bogus, and that it was lisp code */ + /* that caused the fault. */ + if ((((unsigned long)pc) & 3) != 0 || + ((pc < READ_ONLY_SPACE_START || + pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) && + ((lispobj *)pc < current_dynamic_space && + (lispobj *)pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE))) + return 0; + + + addr = (os_vm_address_t) (*os_context_register_addr(context,PT_DAR)); + return addr; +} + + +void +arch_skip_instruction(os_context_t *context) +{ + ((char*)*os_context_pc_addr(context)) +=4; +} + +unsigned char * +arch_internal_error_arguments(os_context_t *context) +{ + return (unsigned char *)(*os_context_pc_addr(context)+4); +} + + +boolean +arch_pseudo_atomic_atomic(os_context_t *context) +{ + return ((*os_context_register_addr(context,reg_ALLOC)) & 4); +} + +#define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000 + +void +arch_set_pseudo_atomic_interrupted(os_context_t *context) +{ + *os_context_register_addr(context,reg_NL3) + += PSEUDO_ATOMIC_INTERRUPTED_BIAS; +} + +unsigned long +arch_install_breakpoint(void *pc) +{ + unsigned long *ptr = (unsigned long *)pc; + unsigned long result = *ptr; + *ptr = (3<<26) | (5 << 21) | trap_Breakpoint; + os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long)); + return result; +} + +void +arch_remove_breakpoint(void *pc, unsigned long orig_inst) +{ + *(unsigned long *)pc = orig_inst; + os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long)); +} + +static unsigned long *skipped_break_addr, displaced_after_inst; +static sigset_t orig_sigmask; + +void +arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst) +{ + /* not sure how we ensure that we get the breakpoint reinstalled + * after doing this -dan */ + unsigned long *pc = (unsigned long *)(*os_context_pc_addr(context)); + + orig_sigmask = *os_context_sigmask_addr(context); + sigaddset_blockable(os_context_sigmask_addr(context)); + + *pc = orig_inst; + os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long)); + skipped_break_addr = pc; +} + +static void +sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) +{ + int badinst; + u32 code; + sigset_t *mask; + mask=(os_context_sigmask_addr(context)); + sigsetmask(mask); + code=*((u32 *)(*os_context_pc_addr(context))); + if (code == ((3 << 26) | (16 << 21) | (reg_ALLOC << 16))) { + /* twlti reg_ALLOC,0 - check for deferred interrupt */ + *os_context_register_addr(context,reg_ALLOC) + -= PSEUDO_ATOMIC_INTERRUPTED_BIAS; + arch_skip_instruction(context); + /* interrupt or GC was requested in PA; now we're done with the + PA section we may as well get around to it */ + interrupt_handle_pending(context); + return; + + } + if ((code >> 16) == ((3 << 10) | (6 << 5))) { + /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */ + int trap = code & 0x1f, extra = (code >> 5) & 0x1f; + + switch (trap) { + case trap_Halt: + fake_foreign_function_call(context); + lose("%%primitive halt called; the party is over.\n"); + + case trap_Error: + case trap_Cerror: + interrupt_internal_error(signal, code, context, trap == trap_Cerror); + break; + + case trap_PendingInterrupt: + /* when do we run this branch instead of the twlti code above? */ + arch_skip_instruction(context); + interrupt_handle_pending(context); + break; + + case trap_Breakpoint: + handle_breakpoint(signal, code, context); + break; + + case trap_FunEndBreakpoint: + *os_context_pc_addr(context) + =(int)handle_fun_end_breakpoint(signal, code, context); + break; + + case trap_AfterBreakpoint: + *skipped_break_addr = trap_Breakpoint; + skipped_break_addr = NULL; + *(unsigned long *)*os_context_pc_addr(context) + = displaced_after_inst; + *os_context_sigmask_addr(context)= orig_sigmask; + + os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), + sizeof(unsigned long)); + break; + + default: + interrupt_handle_now(signal, code, context); + break; + } + } + if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) { + interrupt_internal_error(signal, code, context, 0); + } + + interrupt_handle_now(signal, code, context); +} + + +void arch_install_interrupt_handlers() +{ + undoably_install_low_level_interrupt_handler(SIGILL,sigtrap_handler); + undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler); +} + + +extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs); + +lispobj funcall0(lispobj function) +{ + lispobj *args = current_control_stack_pointer; + + return call_into_lisp(function, args, 0); +} + +lispobj funcall1(lispobj function, lispobj arg0) +{ + lispobj *args = current_control_stack_pointer; + + current_control_stack_pointer += 1; + args[0] = arg0; + + return call_into_lisp(function, args, 1); +} + +lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1) +{ + lispobj *args = current_control_stack_pointer; + + current_control_stack_pointer += 2; + args[0] = arg0; + args[1] = arg1; + + return call_into_lisp(function, args, 2); +} + +lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2) +{ + lispobj *args = current_control_stack_pointer; + + current_control_stack_pointer += 3; + args[0] = arg0; + args[1] = arg1; + args[2] = arg2; + + return call_into_lisp(function, args, 3); +} + +void +ppc_flush_icache(os_vm_address_t address, os_vm_size_t length) +{ + os_vm_address_t end = (os_vm_address_t) ((int)(address+length+(32-1)) &~(32-1)); + extern void ppc_flush_cache_line(os_vm_address_t); + + while (address < end) { + ppc_flush_cache_line(address); + address += 32; + } +} diff --git a/src/runtime/ppc-arch.h b/src/runtime/ppc-arch.h new file mode 100644 index 0000000..b43e78e --- /dev/null +++ b/src/runtime/ppc-arch.h @@ -0,0 +1,6 @@ +#ifndef _PPC_ARCH_H +#define _PPC_ARCH_H + +#define ARCH_HAS_LINK_REGISTER + +#endif /* _PPC_ARCH_H */ diff --git a/src/runtime/ppc-assem.S b/src/runtime/ppc-assem.S new file mode 100644 index 0000000..dc400f2 --- /dev/null +++ b/src/runtime/ppc-assem.S @@ -0,0 +1,416 @@ +#define LANGUAGE_ASSEMBLY + +#include "sbcl.h" +#include "lispregs.h" +#include "globals.h" + + +#define FUNCDEF(x) .text ; \ + .align 3 ; \ + .type x,@function ; \ +x: +#define GFUNCDEF(x) .globl x ; \ + FUNCDEF(x) + +#define SET_SIZE(x) .size x,.-x + +/* Load a register from a global, using the register as an intermediary */ +/* The register will be a fixnum for one instruction, so this is gc-safe */ + +#define load(reg,global) \ + lis reg,global@ha; lwz reg,global@l(reg) +#define store(reg,temp,global) \ + lis temp,global@ha; stw reg,global@l(temp) + +#define FIRST_SAVE_FPR 14 /* lowest-numbered non-volatile FPR */ +#define FIRST_SAVE_GPR 14 /* lowest-numbered non-volatile GPR */ +#define NFPR_SAVE_BYTES(n) ((32-(n))*8) +#define NGPR_SAVE_BYTES(n) ((32-(~1&((n)+1)))*4) +#define FRAME_ARG_BYTES(n) (((((n)+2)*4)+15)&~15) + +#define FRAME_SIZE(first_g,first_f,out_arg_words,savecr) \ +(NFPR_SAVE_BYTES(first_f)+ NGPR_SAVE_BYTES(first_g)+ FRAME_ARG_BYTES(out_arg_words+savecr)) +#define SAVE_FPR(n) stfd n,-8*(32-(n))(11) +#define SAVE_GPR(n) stw n,-4*(32-(n))(11) +#define FULL_FRAME_SIZE FRAME_SIZE(FIRST_SAVE_GPR,FIRST_SAVE_FPR,0,1) + +#define RESTORE_FPR(n) lfd n,-8*(32-(n))(11) +#define RESTORE_GPR(n) lwz n,-4*(32-(n))(11) +#define C_FULL_PROLOG \ + mflr 0 ; \ + stw 0,4(1) ; \ + mr 11,1 ; \ + stwu 1,-FULL_FRAME_SIZE(1) ; \ + SAVE_FPR(14) ; \ + SAVE_FPR(15) ; \ + SAVE_FPR(16) ; \ + SAVE_FPR(17) ; \ + SAVE_FPR(18) ; \ + SAVE_FPR(19) ; \ + SAVE_FPR(20) ; \ + SAVE_FPR(21) ; \ + SAVE_FPR(22) ; \ + SAVE_FPR(23) ; \ + SAVE_FPR(24) ; \ + SAVE_FPR(25) ; \ + SAVE_FPR(26) ; \ + SAVE_FPR(27) ; \ + SAVE_FPR(28) ; \ + SAVE_FPR(29) ; \ + SAVE_FPR(30) ; \ + SAVE_FPR(31) ; \ + la 11,-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(11) ; \ + SAVE_GPR(14) ; \ + SAVE_GPR(15) ; \ + SAVE_GPR(16) ; \ + SAVE_GPR(17) ; \ + SAVE_GPR(18) ; \ + SAVE_GPR(19) ; \ + SAVE_GPR(20) ; \ + SAVE_GPR(21) ; \ + SAVE_GPR(22) ; \ + SAVE_GPR(23) ; \ + SAVE_GPR(24) ; \ + SAVE_GPR(25) ; \ + SAVE_GPR(26) ; \ + SAVE_GPR(27) ; \ + SAVE_GPR(28) ; \ + SAVE_GPR(29) ; \ + SAVE_GPR(30) ; \ + SAVE_GPR(31) + + +#define C_FULL_EPILOG \ + la 11,FULL_FRAME_SIZE-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(1) ; \ + RESTORE_GPR(14) ; \ + RESTORE_GPR(15) ; \ + RESTORE_GPR(16) ; \ + RESTORE_GPR(17) ; \ + RESTORE_GPR(18) ; \ + RESTORE_GPR(19) ; \ + RESTORE_GPR(20) ; \ + RESTORE_GPR(21) ; \ + RESTORE_GPR(22) ; \ + RESTORE_GPR(23) ; \ + RESTORE_GPR(24) ; \ + RESTORE_GPR(25) ; \ + RESTORE_GPR(26) ; \ + RESTORE_GPR(27) ; \ + RESTORE_GPR(28) ; \ + RESTORE_GPR(29) ; \ + RESTORE_GPR(30) ; \ + RESTORE_GPR(31) ; \ + la 11,NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(11) ; \ + RESTORE_FPR(14) ; \ + RESTORE_FPR(15) ; \ + RESTORE_FPR(16) ; \ + RESTORE_FPR(17) ; \ + RESTORE_FPR(18) ; \ + RESTORE_FPR(19) ; \ + RESTORE_FPR(20) ; \ + RESTORE_FPR(21) ; \ + RESTORE_FPR(22) ; \ + RESTORE_FPR(23) ; \ + RESTORE_FPR(24) ; \ + RESTORE_FPR(25) ; \ + RESTORE_FPR(26) ; \ + RESTORE_FPR(27) ; \ + RESTORE_FPR(28) ; \ + RESTORE_FPR(29) ; \ + RESTORE_FPR(30) ; \ + RESTORE_FPR(31) ; \ + lwz 1,0(1) ; \ + lwz 0,4(1) ; \ + mtlr 0 ; \ + + + + + .text + +/* + * Function to transfer control into lisp. The lisp object to invoke is + * passed as the first argument, which puts it in NL0 + */ + + GFUNCDEF(call_into_lisp) + C_FULL_PROLOG + mfcr 0 + stw 0,8(1) + /* store(reg_POLL,11,saver2) */ + /* Initialize tagged registers */ + li reg_ZERO,0 + li reg_CODE,0 + li reg_CNAME,0 + li reg_LEXENV,0 + li reg_FDEFN,0 + li reg_OCFP,0 + li reg_LRA,0 + li reg_A0,0 + li reg_A1,0 + li reg_A2,0 + li reg_A3,0 + li reg_L0,0 + li reg_L1,0 + li reg_L2,0 + li reg_LIP,0 + lis reg_NULL,NIL@h + ori reg_NULL,reg_NULL,NIL@l + + /* Turn on pseudo-atomic */ + + li reg_NL3,-4 + li reg_ALLOC,4 + store(reg_ZERO,reg_NL4,foreign_function_call_active) + load(reg_NL4,dynamic_space_free_pointer) + add reg_ALLOC,reg_ALLOC,reg_NL4 + load(reg_BSP,current_binding_stack_pointer) + load(reg_CSP,current_control_stack_pointer) + load(reg_OCFP,current_control_frame_pointer) + + /* No longer atomic, and check for interrupt */ + add reg_ALLOC,reg_ALLOC,reg_NL3 + twlti reg_ALLOC,0 + + /* Pass in the arguments */ + + mr reg_CFP,reg_NL1 + mr reg_LEXENV,reg_NL0 + lwz reg_A0,0(reg_CFP) + lwz reg_A1,4(reg_CFP) + lwz reg_A2,8(reg_CFP) + lwz reg_A3,12(reg_CFP) + + /* Calculate LRA */ + lis reg_LRA,lra@ha + addi reg_LRA,reg_LRA,lra@l + addi reg_LRA,reg_LRA,OTHER_POINTER_LOWTAG + + /* Function is an indirect closure */ + lwz reg_CODE,SIMPLE_FUN_SELF_OFFSET(reg_LEXENV) + addi reg_LIP,reg_CODE,6*4-FUN_POINTER_LOWTAG + mtctr reg_LIP + slwi reg_NARGS,reg_NL2,2 + bctr + + .align 3 +lra: + .long RETURN_PC_HEADER_WIDETAG + + /* Blow off any extra values. */ + mr reg_CSP,reg_OCFP + nop + + /* Return the one value. */ + + mr 3,reg_A0 + + /* Turn on pseudo-atomic */ + li reg_NL3,-4 + la reg_ALLOC,4(reg_ALLOC) + + /* Store lisp state */ + clrrwi reg_NL1,reg_ALLOC,3 + store(reg_NL1,reg_NL2,dynamic_space_free_pointer) + /* store(reg_POLL,reg_NL2,poll_flag) */ + /* load(reg_NL2,current_thread) */ + store(reg_BSP,reg_NL2,current_binding_stack_pointer) + store(reg_CSP,reg_NL2,current_control_stack_pointer) + store(reg_CFP,reg_NL2,current_control_frame_pointer) + /* load(reg_POLL,saver2) */ + + /* No longer in Lisp. */ + store(reg_NL1,reg_NL2,foreign_function_call_active) + + /* Check for interrupt */ + add reg_ALLOC,reg_ALLOC,reg_NL3 + twlti reg_ALLOC,0 + + /* Back to C */ + lwz 5,8(1) + mtcrf 255,5 + C_FULL_EPILOG + blr + SET_SIZE(call_into_lisp) + + + GFUNCDEF(call_into_c) + /* We're kind of low on unboxed, non-dedicated registers here: + most of the unboxed registers may have outgoing C args in them. + CFUNC is going to have to go in the CTR in a moment, anyway + so we'll free it up soon. reg_NFP is preserved by lisp if it + has a meaningful value in it, so we can use it. reg_NARGS is + free when it's not holding a copy of the "real" reg_NL3, which + gets tied up by the pseudo-atomic mechanism */ + mtctr reg_CFUNC + mflr reg_LIP + /* Build a lisp stack frame */ + mr reg_OCFP,reg_CFP + mr reg_CFP,reg_CSP + la reg_CSP,32(reg_CSP) + stw reg_OCFP,0(reg_CFP) + stw reg_CODE,8(reg_CFP) + /* The pseudo-atomic mechanism wants to use reg_NL3, but that + may be an outgoing C argument. Copy reg_NL3 to something that's + unboxed and -not- one of the C argument registers */ + mr reg_NARGS,reg_NL3 + + /* Turn on pseudo-atomic */ + li reg_NL3,-4 + la reg_ALLOC,4(reg_ALLOC) + + /* Convert the return address to an offset and save it on the stack. */ + sub reg_NFP,reg_LIP,reg_CODE + la reg_NFP,OTHER_POINTER_LOWTAG(reg_NFP) + stw reg_NFP,4(reg_CFP) + + /* Store Lisp state */ + clrrwi reg_NFP,reg_ALLOC,3 + store(reg_NFP,reg_CFUNC,dynamic_space_free_pointer) + /* load(reg_CFUNC,current_thread) */ + + store(reg_BSP,reg_CFUNC,current_binding_stack_pointer) + store(reg_CSP,reg_CFUNC,current_control_stack_pointer) + store(reg_CFP,reg_CFUNC,current_control_frame_pointer) + + /* No longer in Lisp */ + store(reg_CSP,reg_CFUNC,foreign_function_call_active) + /* load(reg_POLL,saver2) */ + /* Disable pseudo-atomic; check pending interrupt */ + add reg_ALLOC,reg_ALLOC,reg_NL3 + twlti reg_ALLOC,0 + mr reg_NL3,reg_NARGS + + /* Into C we go. */ + bctrl + + /* Re-establish NIL */ + lis reg_NULL,NIL@h + ori reg_NULL,reg_NULL,NIL@l + /* And reg_ZERO */ + li reg_ZERO,0 + + /* If we GC'ed during the FF code (as the result of a callback ?) + the tagged lisp registers may now contain garbage (since the + registers were saved by C and not seen by the GC.) Put something + harmless in all such registers before allowing an interrupt */ + li reg_CODE,0 + li reg_CNAME,0 + li reg_LEXENV,0 + /* reg_OCFP was pointing to a control stack frame & was preserved by C */ + li reg_LRA,0 + li reg_A0,0 + li reg_A1,0 + li reg_A2,0 + li reg_A3,0 + li reg_L0,0 + li reg_L1,0 + li reg_L2,0 + li reg_LIP,0 + + /* Atomic ... */ + li reg_NL3,-4 + li reg_ALLOC,4 + + /* No long in foreign function call. */ + store(reg_ZERO,reg_NL2,foreign_function_call_active) + + /* The free pointer may have moved */ + load(reg_NL4,dynamic_space_free_pointer) + add reg_ALLOC,reg_ALLOC,reg_NL4 + + /* The BSP wasn't preserved by C, so load it */ + load(reg_BSP,current_binding_stack_pointer) + + /* Other lisp stack/frame pointers were preserved by C. + I can't imagine why they'd have moved */ + + /* Get the return address back. */ + lwz reg_LIP,4(reg_CFP) + lwz reg_CODE,8(reg_CFP) + add reg_LIP,reg_CODE,reg_LIP + la reg_LIP,-OTHER_POINTER_LOWTAG(reg_LIP) + + /* No longer atomic */ + add reg_ALLOC,reg_ALLOC,reg_NL3 + twlti reg_ALLOC,0 + mtlr reg_LIP + + /* Reset the lisp stack. */ + mr reg_CSP,reg_CFP + mr reg_CFP,reg_OCFP + + /* And back into Lisp. */ + blr + + SET_SIZE(call_into_c) + + GFUNCDEF(xundefined_tramp) + .globl undefined_tramp + .byte 0,0,0,SIMPLE_FUN_HEADER_WIDETAG /* type_FunctionHeader */ + + .byte 18<<2 +undefined_tramp: + .byte 0,0,24 + .long undefined_tramp + .long NIL + .long NIL + .long NIL + .long NIL + twllei reg_ZERO,trap_Cerror + .byte 4 + .byte UNDEFINED_FUN_ERROR + .byte 254, 140, 2 /* 140? sparc says sc_descriptorReg */ + .align 2 +1: lwz reg_CODE,FDEFN_RAW_ADDR_OFFSET(reg_FDEFN) + la reg_LIP,SIMPLE_FUN_CODE_OFFSET(reg_CODE) + mtctr reg_LIP + bctr + + SET_SIZE(xundefined_tramp) + + GFUNCDEF(xclosure_tramp) + .globl closure_tramp + .byte 0,0,0,SIMPLE_FUN_HEADER_WIDETAG + .byte 18<<2 +closure_tramp: + .byte 0,0,24 + .long closure_tramp + .long NIL + .long NIL + .long NIL + .long NIL + lwz reg_LEXENV,FDEFN_FUN_OFFSET(reg_FDEFN) + lwz reg_CODE,CLOSURE_FUN_OFFSET(reg_LEXENV) + la reg_LIP,SIMPLE_FUN_CODE_OFFSET(reg_CODE) + mtctr reg_LIP + bctr + + SET_SIZE(xclosure_tramp) + + GFUNCDEF(fun_end_breakpoint_trap) + .long 0 + SET_SIZE(fun_end_breakpoint_trap) + + GFUNCDEF(fun_end_breakpoint) + .long 0 + SET_SIZE(fun_end_breakpoint) + + GFUNCDEF(fun_end_breakpoint_guts) + .long 0 + SET_SIZE(fun_end_breakpoint_guts) + + GFUNCDEF(fun_end_breakpoint_end) + .long 0 + SET_SIZE(fun_end_breakpoint_end) + + + GFUNCDEF(ppc_flush_cache_line) + dcbf 0,3 + sync + icbi 0,3 + sync + isync + blr + SET_SIZE(ppc_flush_cache_line) + diff --git a/src/runtime/ppc-linux-os.c b/src/runtime/ppc-linux-os.c new file mode 100644 index 0000000..c5dc7a2 --- /dev/null +++ b/src/runtime/ppc-linux-os.c @@ -0,0 +1,75 @@ +/* + * This is the IBM/Motorola/Apple/whoever Linux incarnation of + * arch-dependent OS-dependent routines. See also "linux-os.c". */ + +/* + * This software is part of the SBCL system. See the README file for + * more information. + * + * This software is derived from the CMU CL system, which was + * written at Carnegie Mellon University and released into the + * public domain. The software is in the public domain and is + * provided with absolutely no warranty. See the COPYING and CREDITS + * files for more information. + */ + +/* These header files were lifted wholesale from linux-os.c, some may + * be redundant. -- Dan Barlow ca. 2001-05-01 */ +#include +#include +#include +#include "./signal.h" +#include "os.h" +#include "arch.h" +#include "globals.h" +#include "interrupt.h" +#include "interr.h" +#include "lispregs.h" +#include "sbcl.h" +#include +#include + +#include +#include +#include +#include +#include + +#include "validate.h" +size_t os_vm_page_size; + +#if defined GENCGC /* unlikely ... */ +#error SBCL PPC does not work with the GENCGC +#include "gencgc.h" +#endif + +os_context_register_t * +os_context_register_addr(os_context_t *context, int offset) +{ + return &((context->uc_mcontext.regs)->gpr[offset]); +} + +os_context_register_t * +os_context_pc_addr(os_context_t *context) +{ + return &((context->uc_mcontext.regs)->nip); +} + +os_context_register_t * +os_context_lr_addr(os_context_t *context) +{ + return &((context->uc_mcontext.regs)->link); +} + +sigset_t * +os_context_sigmask_addr(os_context_t *context) +{ + return &context->uc_sigmask; +} + +void os_flush_icache(os_vm_address_t address, os_vm_size_t length) +{ + /* see ppc-arch.c */ + ppc_flush_icache(address,length); +} + diff --git a/src/runtime/ppc-linux-os.h b/src/runtime/ppc-linux-os.h new file mode 100644 index 0000000..e057ad3 --- /dev/null +++ b/src/runtime/ppc-linux-os.h @@ -0,0 +1,10 @@ +#ifndef _PPC_LINUX_OS_H +#define _PPC_LINUX_OS_H + +typedef struct ucontext os_context_t; + +static inline os_context_t *arch_os_get_context(void **void_context) { + return (os_context_t *) *void_context; +} + +#endif /* _PPC_LINUX_OS_H */ diff --git a/src/runtime/ppc-lispregs.h b/src/runtime/ppc-lispregs.h new file mode 100644 index 0000000..956c11d --- /dev/null +++ b/src/runtime/ppc-lispregs.h @@ -0,0 +1,51 @@ +#define REG(num) num +#define NREGS 32 + +#define reg_ZERO REG(0) /* Should always contain 0 in lisp */ +#define reg_NSP REG(1) /* The number/C stack pointer */ +#define reg_POLL REG(2) /* Lisp preemption/Mystery SVR4 ABI reg */ +#define reg_NL0 REG(3) /* FF param/result 1 */ +#define reg_NL1 REG(4) /* FF param/result 2 */ +#define reg_NL2 REG(5) /* FF param 3 */ +#define reg_NL3 REG(6) +#define reg_NL4 REG(7) +#define reg_NL5 REG(8) +#define reg_NL6 REG(9) /* Last (7th) FF param */ +#define reg_FDEFN REG(10) /* was NL7 until recently -dan */ +#define reg_NARGS REG(11) +#define reg_NFP REG(12) /* Lisp may save around FF-call */ +#define reg_CFUNC REG(13) /* Silly to blow a reg on FF-name */ +#define reg_BSP REG(14) /* Binding stack pointer */ +#define reg_CFP REG(15) /* Control/value stack frame pointer */ +#define reg_CSP REG(16) /* Control/value stack top */ +#define reg_ALLOC REG(17) /* (Global) dynamic free pointer */ +#define reg_NULL REG(18) /* NIL and globals nearby */ +#define reg_CODE REG(19) /* Current function object */ +#define reg_CNAME REG(20) /* Current function name */ +#define reg_LEXENV REG(21) /* And why burn a register for this ? */ +#define reg_OCFP REG(22) /* The caller's reg_CFP */ +#define reg_LRA REG(23) /* Tagged lisp return address */ +#define reg_A0 REG(24) /* First function arg/return value */ +#define reg_A1 REG(25) /* Second. */ +#define reg_A2 REG(26) /* */ +#define reg_A3 REG(27) /* Last of (only) 4 arg regs */ +#define reg_L0 REG(28) /* Tagged temp regs */ +#define reg_L1 REG(29) +#define reg_L2 REG(30) /* Last lisp temp reg */ +#define reg_LIP REG(31) /* Lisp Interior Pointer, e.g., locative */ + +#define REGNAMES \ + "ZERO", "NSP", "???", "NL0", \ + "NL1", "NL2", "NL3P", "NL4", \ + "NL5", "NL6", "FDEFN", "NARGS", \ + "NFP", "CFUNC" "BSP", "CFP", \ + "CSP", "ALLOC", "NULL", "CODE", \ + "CNAME", "LEXENV", "OCFP", "LRA", \ + "A0", "A1", "A2", "A3", \ + "L0", "L1", "L2", "LIP" + +#define BOXED_REGISTERS { \ + reg_FDEFN, reg_CODE, reg_CNAME, reg_LEXENV, reg_OCFP, reg_LRA, \ + reg_A0, reg_A1, reg_A2, reg_A3, \ + reg_L0, reg_L1, reg_L2 \ +} -- 1.7.10.4