5 This code was written as part of the CMU Common Lisp project at
6 Carnegie Mellon University, and has been placed in the public domain.
21 #include "interrupt.h"
23 #include "breakpoint.h"
26 #ifdef LISP_FEATURE_LINUX
27 extern int early_kernel;
35 os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
37 unsigned long badinst;
41 pc = (unsigned long *)(*os_context_pc_addr(context));
43 /* On the sparc, we have to decode the instruction. */
45 /* Make sure it's not the pc thats bogus, and that it was lisp code */
46 /* that caused the fault. */
47 if ((unsigned long) pc & 3) {
51 if ((pc < READ_ONLY_SPACE_START ||
52 pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) &&
53 (pc < current_dynamic_space ||
54 pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE)) {
60 if ((badinst >> 30) != 3)
61 /* All load/store instructions have op = 11 (binary) */
64 rs1 = (badinst>>14)&0x1f;
66 if (badinst & (1<<13)) {
67 /* r[rs1] + simm(13) */
68 int simm13 = badinst & 0x1fff;
73 return (os_vm_address_t)
74 (*os_context_register_addr(context, rs1)+simm13);
78 int rs2 = badinst & 0x1f;
80 return (os_vm_address_t)
81 (*os_context_register_addr(context, rs1) +
82 *os_context_register_addr(context, rs2));
86 void arch_skip_instruction(os_context_t *context)
88 ((char *) *os_context_pc_addr(context)) = ((char *) *os_context_npc_addr(context));
89 ((char *) *os_context_npc_addr(context)) += 4;
92 unsigned char *arch_internal_error_arguments(os_context_t *context)
94 return (unsigned char *)(*os_context_pc_addr(context) + 4);
97 boolean arch_pseudo_atomic_atomic(os_context_t *context)
99 return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
102 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
104 *os_context_register_addr(context,reg_ALLOC) |= 1;
107 unsigned long arch_install_breakpoint(void *pc)
109 unsigned long *ptr = (unsigned long *)pc;
110 unsigned long result = *ptr;
111 *ptr = trap_Breakpoint;
113 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
118 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
120 *(unsigned long *)pc = orig_inst;
121 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
124 static unsigned long *skipped_break_addr, displaced_after_inst;
125 static sigset_t orig_sigmask;
127 void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
129 unsigned long *pc = (unsigned long *)(*os_context_pc_addr(context));
130 unsigned long *npc = (unsigned long *)(*os_context_npc_addr(context));
132 /* orig_sigmask = context->sigmask;
133 sigemptyset(&context->sigmask); */
135 /* FILLBLOCKSET(&context->uc_sigmask);*/
138 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
139 skipped_break_addr = pc;
140 displaced_after_inst = *npc;
141 *npc = trap_AfterBreakpoint;
142 os_flush_icache((os_vm_address_t) npc, sizeof(unsigned long));
146 static int pseudo_atomic_trap_p(os_context_t *context)
149 unsigned int badinst;
153 pc = (unsigned int*) *os_context_pc_addr(context);
157 /* Check to see if the current instruction is a pseudo-atomic-trap */
158 if (((badinst >> 30) == 2) && (((badinst >> 19) & 0x3f) == 0x3a)
159 && (((badinst >> 13) & 1) == 1) && ((badinst & 0x7f) == PSEUDO_ATOMIC_TRAP))
161 unsigned int previnst;
164 * Check to see if the previous instruction was an andcc alloc-tn,
165 * 3, zero-tn instruction.
167 if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
168 && (((previnst >> 14) & 0x1f) == reg_ALLOC)
169 && (((previnst >> 25) & 0x1f) == reg_ZERO)
170 && (((previnst >> 13) & 1) == 1)
171 && ((previnst & 0x1fff) == 3))
177 fprintf(stderr, "Oops! Got a PSEUDO-ATOMIC-TRAP without a preceeding andcc!\n");
183 static void sigill_handler(int signal, siginfo_t *siginfo, void *void_context)
185 os_context_t *context = arch_os_get_context(&void_context);
186 #ifdef LISP_FEATURE_LINUX
187 /* FIXME: Check that this is necessary -- CSR, 2002-07-15 */
188 os_restore_fp_control(context);
190 sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
192 if ((siginfo->si_code) == ILL_ILLOPC
193 #ifdef LISP_FEATURE_LINUX
194 || (early_kernel && (siginfo->si_code == 2))
199 unsigned int* pc = (unsigned int*) siginfo->si_addr;
202 trap = inst & 0x3fffff;
205 case trap_PendingInterrupt:
206 arch_skip_instruction(context);
207 interrupt_handle_pending(context);
211 fake_foreign_function_call(context);
212 lose("%%primitive halt called; the party is over.\n");
216 interrupt_internal_error(signal, siginfo, context, trap == trap_Cerror);
219 case trap_Breakpoint:
220 handle_breakpoint(signal, siginfo, context);
223 case trap_FunEndBreakpoint:
224 *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(signal, siginfo, context);
225 *os_context_npc_addr(context) = *os_context_pc_addr(context) + 4;
228 case trap_AfterBreakpoint:
229 *skipped_break_addr = trap_Breakpoint;
230 skipped_break_addr = NULL;
231 *(unsigned long *) os_context_pc_addr(context) = displaced_after_inst;
232 /* context->sigmask = orig_sigmask; */
233 os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned long));
237 interrupt_handle_now(signal, siginfo, context);
241 else if ((siginfo->si_code) == ILL_ILLTRP
242 #ifdef LISP_FEATURE_LINUX
243 || (early_kernel && (siginfo->si_code) == 192)
246 if (pseudo_atomic_trap_p(context)) {
247 /* A trap instruction from a pseudo-atomic. We just need
248 to fixup up alloc-tn to remove the interrupted flag,
249 skip over the trap instruction, and then handle the
250 pending interrupt(s). */
251 *os_context_register_addr(context, reg_ALLOC) &= ~7;
252 arch_skip_instruction(context);
253 interrupt_handle_pending(context);
256 interrupt_internal_error(signal, siginfo, context, 0);
260 interrupt_handle_now(signal, siginfo, context);
264 static void sigemt_handler(int signal, siginfo_t *siginfo, void *void_context)
266 unsigned long badinst;
267 boolean subtract, immed;
268 int rd, rs1, op1, rs2, op2, result;
269 os_context_t *context = arch_os_get_context(&void_context);
270 #ifdef LISP_FEATURE_LINUX
271 os_restore_fp_control(context);
274 badinst = *(unsigned long *)os_context_pc_addr(context);
275 if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
276 /* It wasn't a tagged add. Pass the signal into lisp. */
277 interrupt_handle_now(signal, siginfo, context);
281 fprintf(stderr, "SIGEMT trap handler with tagged op instruction!\n");
283 /* Extract the parts of the inst. */
284 subtract = badinst & (1<<19);
285 rs1 = (badinst>>14) & 0x1f;
286 op1 = *os_context_register_addr(context, rs1);
288 /* If the first arg is $ALLOC then it is really a signal-pending note */
289 /* for the pseudo-atomic noise. */
290 if (rs1 == reg_ALLOC) {
291 /* Perform the op anyway. */
292 op2 = badinst & 0x1fff;
299 *os_context_register_addr(context, reg_ALLOC) = result & ~7;
300 arch_skip_instruction(context);
301 interrupt_handle_pending(context);
305 if ((op1 & 3) != 0) {
306 /* The first arg wan't a fixnum. */
307 interrupt_internal_error(signal, siginfo, context, 0);
311 if (immed = badinst & (1<<13)) {
312 op2 = badinst & 0x1fff;
317 rs2 = badinst & 0x1f;
318 op2 = *os_context_register_addr(context, rs2);
321 if ((op2 & 3) != 0) {
322 /* The second arg wan't a fixnum. */
323 interrupt_internal_error(signal, siginfo, context, 0);
327 rd = (badinst>>25) & 0x1f;
329 /* Don't bother computing the result unless we are going to use it. */
331 result = (op1>>2) - (op2>>2);
333 result = (op1>>2) + (op2>>2);
335 dynamic_space_free_pointer =
336 (lispobj *) *os_context_register_addr(context, reg_ALLOC);
338 *os_context_register_addr(context, rd) = alloc_number(result);
340 *os_context_register_addr(context, reg_ALLOC) =
341 (unsigned long) dynamic_space_free_pointer;
344 arch_skip_instruction(context);
347 void arch_install_interrupt_handlers()
349 undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
350 undoably_install_low_level_interrupt_handler(SIGEMT, sigemt_handler);
354 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
356 lispobj funcall0(lispobj function)
358 lispobj *args = current_control_stack_pointer;
360 return call_into_lisp(function, args, 0);
363 lispobj funcall1(lispobj function, lispobj arg0)
365 lispobj *args = current_control_stack_pointer;
367 current_control_stack_pointer += 1;
370 return call_into_lisp(function, args, 1);
373 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
375 lispobj *args = current_control_stack_pointer;
377 current_control_stack_pointer += 2;
381 return call_into_lisp(function, args, 2);
384 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
386 lispobj *args = current_control_stack_pointer;
388 current_control_stack_pointer += 3;
393 return call_into_lisp(function, args, 3);