0.8.3.1
[sbcl/lichteblau.git] / src / runtime / mips-arch.c
blob7b68e65f5349c7673f8276596a6de83c4e6a09ec
1 /*
3 $Header$
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.
8 */
10 #include <stdio.h>
12 #include "runtime.h"
13 #include "arch.h"
14 #include "sbcl.h"
15 #include "globals.h"
16 #include "validate.h"
17 #include "os.h"
18 #include "lispregs.h"
19 #include "signal.h"
20 #include "alloc.h"
21 #include "interrupt.h"
22 #include "interr.h"
23 #include "breakpoint.h"
24 #include "monitor.h"
26 void arch_init()
28 return;
31 os_vm_address_t arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
33 /* Classic CMUCL comment:
35 Finding the bad address on the mips is easy. */
36 return (os_vm_address_t) siginfo->si_addr;
39 unsigned long
40 emulate_branch(os_context_t *context, unsigned long inst)
42 long opcode = inst >> 26;
43 long r1 = (inst >> 21) & 0x1f;
44 long r2 = (inst >> 16) & 0x1f;
45 long bdisp = (inst&(1<<15)) ? inst | (-1 << 16) : inst&0xffff;
46 long jdisp = (inst&(1<<25)) ? inst | (-1 << 26) : inst&0xffff;
47 long disp = 0;
49 switch(opcode) {
50 case 0x1: /* bltz, bgez, bltzal, bgezal */
51 switch((inst >> 16) & 0x1f) {
52 case 0x00: /* bltz */
53 if(*os_context_register_addr(context, r1) < 0)
54 disp = bdisp;
55 break;
56 case 0x01: /* bgez */
57 if(*os_context_register_addr(context, r1) >= 0)
58 disp = bdisp;
59 break;
60 case 0x10: /* bltzal */
61 if(*os_context_register_addr(context, r1) < 0)
62 disp = bdisp;
63 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
64 break;
65 case 0x11: /* bgezal */
66 if(*os_context_register_addr(context, r1) >= 0)
67 disp = bdisp;
68 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
69 break;
71 break;
72 case 0x4: /* beq */
73 if(*os_context_register_addr(context, r1)
74 == *os_context_register_addr(context, r2))
75 disp = bdisp;
76 break;
77 case 0x5: /* bne */
78 if(*os_context_register_addr(context, r1)
79 != *os_context_register_addr(context, r2))
80 disp = bdisp;
81 break;
82 case 0x6: /* ble */
83 if(*os_context_register_addr(context, r1)
84 /* FIXME: One has to assume that the CMUCL gods of old have
85 got the sign issues right... but it might be worth
86 checking, someday */
87 <= *os_context_register_addr(context, r2))
88 disp = bdisp;
89 break;
90 case 0x7: /* bgtz */
91 if(*os_context_register_addr(context, r1)
92 >= *os_context_register_addr(context, r2))
93 disp = bdisp;
94 break;
95 case 0x2: /* j */
96 disp = jdisp;
97 break;
98 case 0x3: /* jal */
99 disp = jdisp;
100 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
101 break;
103 return (*os_context_pc_addr(context) + disp * 4);
106 void arch_skip_instruction(os_context_t *context)
108 /* Skip the offending instruction */
109 if (os_context_bd_cause(context)) {
110 /* Currently, we never get here, because Linux' support for
111 bd_cause seems not terribly solid (c.f os_context_bd_cause
112 in mips-linux-os.c). If a port to Irix comes along, this
113 code will be executed, because presumably Irix' support is
114 better (it can hardly be worse). We lose() to remind the
115 porter to review this code. -- CSR, 2002-09-06 */
116 lose("bd_cause branch taken; review code for new OS?\n");
117 *os_context_pc_addr(context) =
118 emulate_branch(context,
119 *(unsigned long *) *os_context_pc_addr(context));
121 else
122 *os_context_pc_addr(context) += 4;
124 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
127 unsigned char *arch_internal_error_arguments(os_context_t *context)
129 if (os_context_bd_cause(context))
130 return (unsigned char *)(*os_context_pc_addr(context) + 8);
131 else
132 return (unsigned char *)(*os_context_pc_addr(context) + 4);
135 boolean arch_pseudo_atomic_atomic(os_context_t *context)
137 return *os_context_register_addr(context, reg_ALLOC) & 1;
140 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
142 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
144 *os_context_register_addr(context, reg_NL4) |= 1<<31;
147 unsigned long arch_install_breakpoint(void *pc)
149 unsigned long *ptr = (unsigned long *)pc;
150 unsigned long result = *ptr;
151 *ptr = (trap_Breakpoint << 16) | 0xd;
153 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
155 return result;
158 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
160 *(unsigned long *)pc = orig_inst;
162 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
165 static unsigned long *skipped_break_addr, displaced_after_inst;
166 static sigset_t orig_sigmask;
168 void arch_do_displaced_inst(os_context_t *context,
169 unsigned int orig_inst)
171 unsigned long *pc = (unsigned long *)*os_context_pc_addr(context);
172 unsigned long *break_pc, *next_pc;
173 unsigned long next_inst;
174 int opcode;
176 orig_sigmask = *os_context_sigmask_addr(context);
177 sigaddset_blockable(os_context_sigmask_addr(context));
179 /* Figure out where the breakpoint is, and what happens next. */
180 if (os_context_bd_cause(context)) {
181 break_pc = pc+1;
182 next_inst = *pc;
184 else {
185 break_pc = pc;
186 next_inst = orig_inst;
189 /* Put the original instruction back. */
190 *break_pc = orig_inst;
191 os_flush_icache((os_vm_address_t)break_pc, sizeof(unsigned long));
192 skipped_break_addr = break_pc;
194 /* Figure out where it goes. */
195 opcode = next_inst >> 26;
196 if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000)) {
198 next_pc = emulate_branch(context, next_inst);
200 else
201 next_pc = pc+1;
203 displaced_after_inst = *next_pc;
204 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
205 os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned long));
208 static void sigtrap_handler(int signal, siginfo_t *info, void *void_context)
210 os_context_t *context = arch_os_get_context(&void_context);
211 sigset_t *mask;
212 int code;
213 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
214 /* use debugger breakpoints anywhere in here. */
215 mask = os_context_sigmask_addr(context);
216 sigsetmask(mask);
217 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
219 switch (code) {
220 case trap_PendingInterrupt:
221 arch_skip_instruction(context);
222 interrupt_handle_pending(context);
223 break;
225 case trap_Halt:
226 fake_foreign_function_call(context);
227 lose("%%primitive halt called; the party is over.\n");
229 case trap_Error:
230 case trap_Cerror:
231 interrupt_internal_error(signal, info, context, code==trap_Cerror);
232 break;
234 case trap_Breakpoint:
235 handle_breakpoint(signal, info, context);
236 break;
238 case trap_FunEndBreakpoint:
239 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
240 break;
242 case trap_AfterBreakpoint:
243 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
244 os_flush_icache((os_vm_address_t)skipped_break_addr,
245 sizeof(unsigned long));
246 skipped_break_addr = NULL;
247 *(unsigned long *)(*os_context_pc_addr(context)) = displaced_after_inst;
248 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
249 *os_context_sigmask_addr(context) = orig_sigmask;
250 break;
252 case 0x10:
253 /* Clear the flag */
254 *os_context_register_addr(context, reg_NL4) &= 0x7fffffff;
255 arch_skip_instruction(context);
256 interrupt_handle_pending(context);
257 return;
259 default:
260 interrupt_handle_now(signal, info, context);
261 break;
265 /* FIXME: We must have one of these somewhere. Also, export
266 N-FIXNUM-TAG-BITS from Lispland and use it rather than 2 here. */
267 #define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
269 void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
271 unsigned long bad_inst;
272 unsigned int op, rs, rt, rd, funct, dest;
273 int immed;
274 long result;
275 os_context_t *context = arch_os_get_context(&void_context);
277 if (os_context_bd_cause(context))
278 bad_inst = *(unsigned long *)(*os_context_pc_addr(context) + 4);
279 else
280 bad_inst = *(unsigned long *)(*os_context_pc_addr(context));
282 op = (bad_inst >> 26) & 0x3f;
283 rs = (bad_inst >> 21) & 0x1f;
284 rt = (bad_inst >> 16) & 0x1f;
285 rd = (bad_inst >> 11) & 0x1f;
286 funct = bad_inst & 0x3f;
287 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
289 switch (op) {
290 case 0x0: /* SPECIAL */
291 switch (funct) {
292 case 0x20: /* ADD */
293 /* FIXME: Hopefully, this whole section can just go away,
294 with the rewrite of pseudo-atomic and the deletion of
295 overflow VOPs */
296 /* Check to see if this is really a pa_interrupted hit */
297 if (rs == reg_ALLOC && rt == reg_NL4) {
298 *os_context_register_addr(context, reg_ALLOC)
299 += (*os_context_register_addr(context, reg_NL4)
300 - PSEUDO_ATOMIC_INTERRUPTED_BIAS);
301 arch_skip_instruction(context);
302 interrupt_handle_pending(context);
303 return;
305 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
306 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
307 dest = rd;
308 break;
310 case 0x22: /* SUB */
311 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
312 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
313 dest = rd;
314 break;
316 default:
317 dest = 32;
318 break;
320 break;
322 case 0x8: /* ADDI */
323 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
324 dest = rt;
325 break;
327 default:
328 dest = 32;
329 break;
332 if (dest < 32) {
333 dynamic_space_free_pointer =
334 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
336 *os_context_register_addr(context,dest) = alloc_number(result);
338 *os_context_register_addr(context, reg_ALLOC) =
339 (unsigned long) dynamic_space_free_pointer;
341 arch_skip_instruction(context);
344 else
345 interrupt_handle_now(signal, info, context);
348 void arch_install_interrupt_handlers()
350 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
351 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_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;
368 args[0] = arg0;
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;
378 args[0] = arg0;
379 args[1] = arg1;
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;
389 args[0] = arg0;
390 args[1] = arg1;
391 args[2] = arg2;
393 return call_into_lisp(function, args, 3);