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"
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 context->si_regs.npc += 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));
131 unsigned long *npc = &context->si_regs.npc;
133 /* orig_sigmask = context->sigmask;
134 sigemptyset(&context->sigmask); */
136 /* FILLBLOCKSET(&context->uc_sigmask);*/
139 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
140 skipped_break_addr = pc;
141 displaced_after_inst = *npc;
142 *npc = trap_AfterBreakpoint;
143 os_flush_icache((os_vm_address_t) npc, sizeof(unsigned long));
145 /* How much is this not going to work? */
149 static int pseudo_atomic_trap_p(os_context_t *context)
152 unsigned int badinst;
156 pc = (unsigned int*) *os_context_pc_addr(context);
160 /* Check to see if the current instruction is a trap #x40 */
161 /* FIXME: As written, this will not work when someone comes to port
162 this to Solaris. We have chosen trap 0x40 on SPARC Linux because
163 trap 0x10, used in CMUCL/Solaris, generates a sigtrap rather than
164 a sigill. This number should not be hardcoded, but should come,
165 if possible, from src/compiler/target/parms.lisp via sbcl.h --
167 if (((badinst >> 30) == 2) && (((badinst >> 19) & 0x3f) == 0x3a)
168 && (((badinst >> 13) & 1) == 1) && ((badinst & 0x7f) == 0x40))
170 unsigned int previnst;
173 * Check to see if the previous instruction was an andcc alloc-tn,
174 * 3, zero-tn instruction.
176 if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
177 && (((previnst >> 14) & 0x1f) == reg_ALLOC)
178 && (((previnst >> 25) & 0x1f) == reg_ZERO)
179 && (((previnst >> 13) & 1) == 1)
180 && ((previnst & 0x1fff) == 3))
186 /* FIXME: in the light of the comment above, this fprintf is
188 fprintf(stderr, "Oops! Got a trap 16 without a preceeding andcc!\n");
194 static void sigill_handler(int signal, siginfo_t *siginfo, void *void_context)
196 os_context_t *context = arch_os_get_context(&void_context);
198 sigprocmask(SIG_SETMASK, &context->si_mask, 0);
200 if ((siginfo->si_code) == ILL_ILLOPC
202 || (early_kernel && (siginfo->si_code == 2))
207 unsigned int* pc = (unsigned int*) siginfo->si_addr;
210 trap = inst & 0x3fffff;
213 case trap_PendingInterrupt:
214 arch_skip_instruction(context);
215 interrupt_handle_pending(context);
219 fake_foreign_function_call(context);
220 lose("%%primitive halt called; the party is over.\n");
224 interrupt_internal_error(signal, siginfo, context, trap == trap_Cerror);
227 case trap_Breakpoint:
228 handle_breakpoint(signal, siginfo, context);
231 case trap_FunEndBreakpoint:
232 *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(signal, siginfo, context);
233 context->si_regs.npc = *os_context_pc_addr(context) + 4;
236 case trap_AfterBreakpoint:
237 *skipped_break_addr = trap_Breakpoint;
238 skipped_break_addr = NULL;
239 *(unsigned long *) os_context_pc_addr(context) = displaced_after_inst;
240 /* context->sigmask = orig_sigmask; */
241 os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned long));
245 interrupt_handle_now(signal, siginfo, context);
249 else if ((siginfo->si_code) == ILL_ILLTRP
251 || (early_kernel && (siginfo->si_code) == 192)
254 if (pseudo_atomic_trap_p(context)) {
255 /* A trap instruction from a pseudo-atomic. We just need
256 to fixup up alloc-tn to remove the interrupted flag,
257 skip over the trap instruction, and then handle the
258 pending interrupt(s). */
259 *os_context_register_addr(context, reg_ALLOC) &= ~7;
260 arch_skip_instruction(context);
261 interrupt_handle_pending(context);
264 interrupt_internal_error(signal, siginfo, context, 0);
268 interrupt_handle_now(signal, siginfo, context);
272 static void sigemt_handler(int signal, siginfo_t *siginfo, void *void_context)
274 unsigned long badinst;
275 boolean subtract, immed;
276 int rd, rs1, op1, rs2, op2, result;
277 os_context_t *context = arch_os_get_context(&void_context);
279 badinst = *(unsigned long *)os_context_pc_addr(context);
280 if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
281 /* It wasn't a tagged add. Pass the signal into lisp. */
282 interrupt_handle_now(signal, siginfo, context);
286 fprintf(stderr, "SIGEMT trap handler with tagged op instruction!\n");
288 /* Extract the parts of the inst. */
289 subtract = badinst & (1<<19);
290 rs1 = (badinst>>14) & 0x1f;
291 op1 = *os_context_register_addr(context, rs1);
293 /* If the first arg is $ALLOC then it is really a signal-pending note */
294 /* for the pseudo-atomic noise. */
295 if (rs1 == reg_ALLOC) {
296 /* Perform the op anyway. */
297 op2 = badinst & 0x1fff;
304 *os_context_register_addr(context, reg_ALLOC) = result & ~7;
305 arch_skip_instruction(context);
306 interrupt_handle_pending(context);
310 if ((op1 & 3) != 0) {
311 /* The first arg wan't a fixnum. */
312 interrupt_internal_error(signal, siginfo, context, 0);
316 if (immed = badinst & (1<<13)) {
317 op2 = badinst & 0x1fff;
322 rs2 = badinst & 0x1f;
323 op2 = *os_context_register_addr(context, rs2);
326 if ((op2 & 3) != 0) {
327 /* The second arg wan't a fixnum. */
328 interrupt_internal_error(signal, siginfo, context, 0);
332 rd = (badinst>>25) & 0x1f;
334 /* Don't bother computing the result unless we are going to use it. */
336 result = (op1>>2) - (op2>>2);
338 result = (op1>>2) + (op2>>2);
340 dynamic_space_free_pointer =
341 (lispobj *) *os_context_register_addr(context, reg_ALLOC);
343 *os_context_register_addr(context, rd) = alloc_number(result);
345 *os_context_register_addr(context, reg_ALLOC) =
346 (unsigned long) dynamic_space_free_pointer;
349 arch_skip_instruction(context);
352 void arch_install_interrupt_handlers()
354 undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
355 undoably_install_low_level_interrupt_handler(SIGEMT, sigemt_handler);
359 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
361 lispobj funcall0(lispobj function)
363 lispobj *args = current_control_stack_pointer;
365 return call_into_lisp(function, args, 0);
368 lispobj funcall1(lispobj function, lispobj arg0)
370 lispobj *args = current_control_stack_pointer;
372 current_control_stack_pointer += 1;
375 return call_into_lisp(function, args, 1);
378 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
380 lispobj *args = current_control_stack_pointer;
382 current_control_stack_pointer += 2;
386 return call_into_lisp(function, args, 2);
389 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
391 lispobj *args = current_control_stack_pointer;
393 current_control_stack_pointer += 3;
398 return call_into_lisp(function, args, 3);