-/*
-
- $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 <stdio.h>
-#include "arch.h"
#include "sbcl.h"
+#include "arch.h"
#include "globals.h"
#include "validate.h"
#include "os.h"
#define PT_DSISR 42
#endif
-void arch_init()
-{
+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;
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 ||
(lispobj *)pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE)))
return 0;
void
arch_skip_instruction(os_context_t *context)
{
- ((char*)*os_context_pc_addr(context)) +=4;
+ char** pcptr;
+ pcptr = (char**) os_context_pc_addr(context);
+ *pcptr += 4;
}
unsigned char *
static void
sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
{
- int badinst;
u32 code;
- sigset_t *mask;
#ifdef LISP_FEATURE_LINUX
os_restore_fp_control(context);
#endif
- 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 */
}
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;
+ int trap = code & 0x1f;
switch (trap) {
case trap_Halt:
break;
case trap_PendingInterrupt:
- /* when do we run this branch instead of the twlti code above? */
+ /* This is supposed run after WITHOUT-INTERRUPTS if there
+ * were pending signals. */
arch_skip_instruction(context);
interrupt_handle_pending(context);
break;
interrupt_handle_now(signal, code, context);
break;
}
+#ifdef LISP_FEATURE_DARWIN
+ DARWIN_FIX_CONTEXT(context);
+#endif
+ return;
}
if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) {
interrupt_internal_error(signal, code, context, 0);
+#ifdef LISP_FEATURE_DARWIN
+ DARWIN_FIX_CONTEXT(context);
+#endif
+ return;
}
interrupt_handle_now(signal, code, context);
+#ifdef LISP_FEATURE_DARWIN
+ /* Work around G5 bug */
+ DARWIN_FIX_CONTEXT(context);
+#endif
}
address += 32;
}
}
+
+#ifdef LISP_FEATURE_LINKAGE_TABLE
+
+/* Linkage tables for PowerPC
+ *
+ * Linkage entry size is 16, because we need at least 4 instructions to
+ * implement a jump.
+ */
+
+/*
+ * Define the registers to use in the linkage jump table. Can be the
+ * same. Some care must be exercised when choosing these. It has to be
+ * a register that is not otherwise being used. reg_NFP is a good
+ * choice. call_into_c trashes reg_NFP without preserving it, so we can
+ * trash it in the linkage jump table.
+ */
+#define LINKAGE_TEMP_REG reg_NFP
+#define LINKAGE_ADDR_REG reg_NFP
+
+/*
+ * Insert the necessary jump instructions at the given address.
+ */
+void
+arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
+{
+ /*
+ * Make JMP to function entry.
+ *
+ * The instruction sequence is:
+ *
+ * addis 13, 0, (hi part of addr)
+ * ori 13, 13, (low part of addr)
+ * mtctr 13
+ * bctr
+ *
+ */
+ int* inst_ptr;
+ unsigned long hi; /* Top 16 bits of address */
+ unsigned long lo; /* Low 16 bits of address */
+ unsigned int inst;
+
+ inst_ptr = (int*) reloc_addr;
+
+ /*
+ * Split the target address into hi and lo parts for the sethi
+ * instruction. hi is the top 22 bits. lo is the low 10 bits.
+ */
+ hi = (unsigned long) target_addr;
+ lo = hi & 0xffff;
+ hi >>= 16;
+
+ /*
+ * addis 13, 0, (hi part)
+ */
+
+ inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
+ *inst_ptr++ = inst;
+
+ /*
+ * ori 13, 13, (lo part)
+ */
+
+ inst = (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
+ *inst_ptr++ = inst;
+
+ /*
+ * mtctr 13
+ */
+
+ inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
+ *inst_ptr++ = inst;
+
+ /*
+ * bctr
+ */
+
+ inst = (19 << 26) | (20 << 21) | (528 << 1);
+ *inst_ptr++ = inst;
+
+
+ *inst_ptr++ = inst;
+
+ os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
+}
+
+void
+arch_write_linkage_table_ref(void * reloc_addr, void *target_addr)
+{
+ *(unsigned long *)reloc_addr = (unsigned long)target_addr;
+}
+
+#endif