10 #include "interrupt.h"
13 /* The header files may not define PT_DAR/PT_DSISR. This definition
14 is correct for all versions of ppc linux >= 2.0.30
16 As of DR2.1u4, MkLinux doesn't pass these registers to signal
17 handlers correctly; a patch is necessary in order to (partially)
20 Even with the patch, the DSISR may not have its 'write' bit set
21 correctly (it tends not to be set if the fault was caused by
22 something other than a protection violation.)
38 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
40 unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
44 /* Make sure it's not the pc thats bogus, and that it was lisp code */
45 /* that caused the fault. */
46 if ((((unsigned long)pc) & 3) != 0 ||
47 ((pc < READ_ONLY_SPACE_START ||
48 pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) &&
49 ((lispobj *)pc < current_dynamic_space ||
50 (lispobj *)pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE)))
54 addr = (os_vm_address_t) (*os_context_register_addr(context,PT_DAR));
60 arch_skip_instruction(os_context_t *context)
63 pcptr = (char**) os_context_pc_addr(context);
68 arch_internal_error_arguments(os_context_t *context)
70 return (unsigned char *)(*os_context_pc_addr(context)+4);
75 arch_pseudo_atomic_atomic(os_context_t *context)
77 return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
80 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
83 arch_set_pseudo_atomic_interrupted(os_context_t *context)
85 *os_context_register_addr(context,reg_NL3)
86 += PSEUDO_ATOMIC_INTERRUPTED_BIAS;
90 arch_install_breakpoint(void *pc)
92 unsigned int *ptr = (unsigned int *)pc;
93 unsigned int result = *ptr;
94 *ptr = (3<<26) | (5 << 21) | trap_Breakpoint;
95 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
100 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
102 *(unsigned int *)pc = orig_inst;
103 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
107 * Perform the instruction that we overwrote with a breakpoint. As we
108 * don't have a single-step facility, this means we have to:
109 * - put the instruction back
110 * - put a second breakpoint at the following instruction,
111 * set after_breakpoint and continue execution.
113 * When the second breakpoint is hit (very shortly thereafter, we hope)
114 * sigtrap_handler gets called again, but follows the AfterBreakpoint
116 * - puts a bpt back in the first breakpoint place (running across a
117 * breakpoint shouldn't cause it to be uninstalled)
118 * - replaces the second bpt with the instruction it was meant to be
123 static unsigned int *skipped_break_addr, displaced_after_inst;
124 static sigset_t orig_sigmask;
127 arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst)
129 /* not sure how we ensure that we get the breakpoint reinstalled
130 * after doing this -dan */
131 unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
133 orig_sigmask = *os_context_sigmask_addr(context);
134 sigaddset_blockable(os_context_sigmask_addr(context));
137 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
138 skipped_break_addr = pc;
142 sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
145 #ifdef LISP_FEATURE_LINUX
146 os_restore_fp_control(context);
148 code=*((u32 *)(*os_context_pc_addr(context)));
149 if (code == ((3 << 26) | (16 << 21) | (reg_ALLOC << 16))) {
150 /* twlti reg_ALLOC,0 - check for deferred interrupt */
151 *os_context_register_addr(context,reg_ALLOC)
152 -= PSEUDO_ATOMIC_INTERRUPTED_BIAS;
153 arch_skip_instruction(context);
154 /* interrupt or GC was requested in PA; now we're done with the
155 PA section we may as well get around to it */
156 interrupt_handle_pending(context);
160 if ((code >> 16) == ((3 << 10) | (6 << 5))) {
161 /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
162 int trap = code & 0x1f;
166 fake_foreign_function_call(context);
167 lose("%%primitive halt called; the party is over.\n");
171 interrupt_internal_error(signal, code, context, trap == trap_Cerror);
174 case trap_PendingInterrupt:
175 /* This is supposed run after WITHOUT-INTERRUPTS if there
176 * were pending signals. */
177 arch_skip_instruction(context);
178 interrupt_handle_pending(context);
181 case trap_Breakpoint:
182 handle_breakpoint(signal, code, context);
185 case trap_FunEndBreakpoint:
186 *os_context_pc_addr(context)
187 =(int)handle_fun_end_breakpoint(signal, code, context);
190 case trap_AfterBreakpoint:
191 *skipped_break_addr = trap_Breakpoint;
192 skipped_break_addr = NULL;
193 *(unsigned int *)*os_context_pc_addr(context)
194 = displaced_after_inst;
195 *os_context_sigmask_addr(context)= orig_sigmask;
197 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context),
198 sizeof(unsigned int));
202 interrupt_handle_now(signal, code, context);
205 #ifdef LISP_FEATURE_DARWIN
206 DARWIN_FIX_CONTEXT(context);
210 if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) {
211 interrupt_internal_error(signal, code, context, 0);
212 #ifdef LISP_FEATURE_DARWIN
213 DARWIN_FIX_CONTEXT(context);
218 interrupt_handle_now(signal, code, context);
219 #ifdef LISP_FEATURE_DARWIN
220 /* Work around G5 bug */
221 DARWIN_FIX_CONTEXT(context);
226 void arch_install_interrupt_handlers()
228 undoably_install_low_level_interrupt_handler(SIGILL,sigtrap_handler);
229 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
233 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
235 lispobj funcall0(lispobj function)
237 lispobj *args = current_control_stack_pointer;
239 return call_into_lisp(function, args, 0);
242 lispobj funcall1(lispobj function, lispobj arg0)
244 lispobj *args = current_control_stack_pointer;
246 current_control_stack_pointer += 1;
249 return call_into_lisp(function, args, 1);
252 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
254 lispobj *args = current_control_stack_pointer;
256 current_control_stack_pointer += 2;
260 return call_into_lisp(function, args, 2);
263 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
265 lispobj *args = current_control_stack_pointer;
267 current_control_stack_pointer += 3;
272 return call_into_lisp(function, args, 3);
276 ppc_flush_icache(os_vm_address_t address, os_vm_size_t length)
278 os_vm_address_t end = (os_vm_address_t) ((int)(address+length+(32-1)) &~(32-1));
279 extern void ppc_flush_cache_line(os_vm_address_t);
281 while (address < end) {
282 ppc_flush_cache_line(address);
287 #ifdef LISP_FEATURE_LINKAGE_TABLE
289 /* Linkage tables for PowerPC
291 * Linkage entry size is 16, because we need at least 4 instructions to
296 * Define the registers to use in the linkage jump table. Can be the
297 * same. Some care must be exercised when choosing these. It has to be
298 * a register that is not otherwise being used. reg_NFP is a good
299 * choice. call_into_c trashes reg_NFP without preserving it, so we can
300 * trash it in the linkage jump table.
302 #define LINKAGE_TEMP_REG reg_NFP
303 #define LINKAGE_ADDR_REG reg_NFP
306 * Insert the necessary jump instructions at the given address.
309 arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
312 * Make JMP to function entry.
314 * The instruction sequence is:
316 * addis 13, 0, (hi part of addr)
317 * ori 13, 13, (low part of addr)
323 unsigned long hi; /* Top 16 bits of address */
324 unsigned long lo; /* Low 16 bits of address */
327 inst_ptr = (int*) reloc_addr;
330 * Split the target address into hi and lo parts for the sethi
331 * instruction. hi is the top 22 bits. lo is the low 10 bits.
333 hi = (unsigned long) target_addr;
338 * addis 13, 0, (hi part)
341 inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
345 * ori 13, 13, (lo part)
348 inst = (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
355 inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
362 inst = (19 << 26) | (20 << 21) | (528 << 1);
368 os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
372 arch_write_linkage_table_ref(void * reloc_addr, void *target_addr)
374 *(unsigned long *)reloc_addr = (unsigned long)target_addr;