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 ((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));
131 unsigned long *npc = (unsigned long *)(*os_context_npc_addr(context));
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));
147 static int pseudo_atomic_trap_p(os_context_t *context)
150 unsigned int badinst;
154 pc = (unsigned int*) *os_context_pc_addr(context);
158 /* Check to see if the current instruction is a pseudo-atomic-trap */
159 if (((badinst >> 30) == 2) && (((badinst >> 19) & 0x3f) == 0x3a)
160 && (((badinst >> 13) & 1) == 1) && ((badinst & 0x7f) == PSEUDO_ATOMIC_TRAP))
162 unsigned int previnst;
165 * Check to see if the previous instruction was an andcc alloc-tn,
166 * 3, zero-tn instruction.
168 if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
169 && (((previnst >> 14) & 0x1f) == reg_ALLOC)
170 && (((previnst >> 25) & 0x1f) == reg_ZERO)
171 && (((previnst >> 13) & 1) == 1)
172 && ((previnst & 0x1fff) == 3))
178 fprintf(stderr, "Oops! Got a PSEUDO-ATOMIC-TRAP without a preceeding andcc!\n");
184 static void sigill_handler(int signal, siginfo_t *siginfo, void *void_context)
186 os_context_t *context = arch_os_get_context(&void_context);
188 sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
190 if ((siginfo->si_code) == ILL_ILLOPC
192 || (early_kernel && (siginfo->si_code == 2))
197 unsigned int* pc = (unsigned int*) siginfo->si_addr;
200 trap = inst & 0x3fffff;
203 case trap_PendingInterrupt:
204 arch_skip_instruction(context);
205 interrupt_handle_pending(context);
209 fake_foreign_function_call(context);
210 lose("%%primitive halt called; the party is over.\n");
214 interrupt_internal_error(signal, siginfo, context, trap == trap_Cerror);
217 case trap_Breakpoint:
218 handle_breakpoint(signal, siginfo, context);
221 case trap_FunEndBreakpoint:
222 *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(signal, siginfo, context);
223 *os_context_npc_addr(context) = *os_context_pc_addr(context) + 4;
226 case trap_AfterBreakpoint:
227 *skipped_break_addr = trap_Breakpoint;
228 skipped_break_addr = NULL;
229 *(unsigned long *) os_context_pc_addr(context) = displaced_after_inst;
230 /* context->sigmask = orig_sigmask; */
231 os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned long));
235 interrupt_handle_now(signal, siginfo, context);
239 else if ((siginfo->si_code) == ILL_ILLTRP
241 || (early_kernel && (siginfo->si_code) == 192)
244 if (pseudo_atomic_trap_p(context)) {
245 /* A trap instruction from a pseudo-atomic. We just need
246 to fixup up alloc-tn to remove the interrupted flag,
247 skip over the trap instruction, and then handle the
248 pending interrupt(s). */
249 *os_context_register_addr(context, reg_ALLOC) &= ~7;
250 arch_skip_instruction(context);
251 interrupt_handle_pending(context);
254 interrupt_internal_error(signal, siginfo, context, 0);
258 interrupt_handle_now(signal, siginfo, context);
262 static void sigemt_handler(int signal, siginfo_t *siginfo, void *void_context)
264 unsigned long badinst;
265 boolean subtract, immed;
266 int rd, rs1, op1, rs2, op2, result;
267 os_context_t *context = arch_os_get_context(&void_context);
269 badinst = *(unsigned long *)os_context_pc_addr(context);
270 if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
271 /* It wasn't a tagged add. Pass the signal into lisp. */
272 interrupt_handle_now(signal, siginfo, context);
276 fprintf(stderr, "SIGEMT trap handler with tagged op instruction!\n");
278 /* Extract the parts of the inst. */
279 subtract = badinst & (1<<19);
280 rs1 = (badinst>>14) & 0x1f;
281 op1 = *os_context_register_addr(context, rs1);
283 /* If the first arg is $ALLOC then it is really a signal-pending note */
284 /* for the pseudo-atomic noise. */
285 if (rs1 == reg_ALLOC) {
286 /* Perform the op anyway. */
287 op2 = badinst & 0x1fff;
294 *os_context_register_addr(context, reg_ALLOC) = result & ~7;
295 arch_skip_instruction(context);
296 interrupt_handle_pending(context);
300 if ((op1 & 3) != 0) {
301 /* The first arg wan't a fixnum. */
302 interrupt_internal_error(signal, siginfo, context, 0);
306 if (immed = badinst & (1<<13)) {
307 op2 = badinst & 0x1fff;
312 rs2 = badinst & 0x1f;
313 op2 = *os_context_register_addr(context, rs2);
316 if ((op2 & 3) != 0) {
317 /* The second arg wan't a fixnum. */
318 interrupt_internal_error(signal, siginfo, context, 0);
322 rd = (badinst>>25) & 0x1f;
324 /* Don't bother computing the result unless we are going to use it. */
326 result = (op1>>2) - (op2>>2);
328 result = (op1>>2) + (op2>>2);
330 dynamic_space_free_pointer =
331 (lispobj *) *os_context_register_addr(context, reg_ALLOC);
333 *os_context_register_addr(context, rd) = alloc_number(result);
335 *os_context_register_addr(context, reg_ALLOC) =
336 (unsigned long) dynamic_space_free_pointer;
339 arch_skip_instruction(context);
342 void arch_install_interrupt_handlers()
344 undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
345 undoably_install_low_level_interrupt_handler(SIGEMT, sigemt_handler);
349 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
351 lispobj funcall0(lispobj function)
353 lispobj *args = current_control_stack_pointer;
355 return call_into_lisp(function, args, 0);
358 lispobj funcall1(lispobj function, lispobj arg0)
360 lispobj *args = current_control_stack_pointer;
362 current_control_stack_pointer += 1;
365 return call_into_lisp(function, args, 1);
368 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
370 lispobj *args = current_control_stack_pointer;
372 current_control_stack_pointer += 2;
376 return call_into_lisp(function, args, 2);
379 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
381 lispobj *args = current_control_stack_pointer;
383 current_control_stack_pointer += 3;
388 return call_into_lisp(function, args, 3);