sb-bsd-sockets: More robust inet-socket-bind test on Windows.
[sbcl.git] / src / runtime / mips-arch.c
1 /*
2
3  This code was written as part of the CMU Common Lisp project at
4  Carnegie Mellon University, and has been placed in the public domain.
5
6 */
7
8 #include <stdio.h>
9
10 #include "sbcl.h"
11 #include "runtime.h"
12 #include "arch.h"
13 #include "globals.h"
14 #include "validate.h"
15 #include "os.h"
16 #include "lispregs.h"
17 #include "signal.h"
18 #include "alloc.h"
19 #include "interrupt.h"
20 #include "interr.h"
21 #include "breakpoint.h"
22
23 #include "genesis/constants.h"
24
25 #define INSN_LEN sizeof(unsigned int)
26
27 void
28 arch_init(void)
29 {
30     return;
31 }
32
33 os_vm_address_t
34 arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
35 {
36     /* Classic CMUCL comment:
37
38        Finding the bad address on the mips is easy. */
39     return (os_vm_address_t)siginfo->si_addr;
40 }
41
42 static inline unsigned int
43 os_context_register(os_context_t *context, int offset)
44 {
45     return (unsigned int)(*os_context_register_addr(context, offset));
46 }
47
48 static inline unsigned int
49 os_context_pc(os_context_t *context)
50 {
51     return (unsigned int)(*os_context_pc_addr(context));
52 }
53
54 static inline unsigned int
55 os_context_insn(os_context_t *context)
56 {
57     if (os_context_bd_cause(context))
58         return *(unsigned int *)(os_context_pc(context) + INSN_LEN);
59     else
60         return *(unsigned int *)(os_context_pc(context));
61 }
62
63 boolean
64 arch_insn_with_bdelay_p(unsigned int insn)
65 {
66     switch (insn >> 26) {
67     case 0x0:
68         switch (insn & 0x3f) {
69         /* register jumps */
70         case 0x08:
71         case 0x09:
72             return 1;
73         }
74         break;
75     /* branches and immediate jumps */
76     case 0x1:
77         switch ((insn >> 16) & 0x1f) {
78         case 0x00:
79         case 0x01:
80         case 0x02:
81         case 0x03:
82         case 0x10:
83         case 0x11:
84         case 0x12:
85         case 0x13:
86             return 1;
87         }
88         break;
89     case 0x2:
90     case 0x3:
91     case 0x4:
92     case 0x5:
93     case 0x6:
94     case 0x7:
95         return 1;
96     case 0x10:
97     case 0x11:
98     case 0x12:
99         switch ((insn >> 21) & 0x1f) {
100          /* CP0/CP1/CP2 branches */
101         case 0x08:
102             return 1;
103         }
104         break;
105     /* branch likely (MIPS II) */
106     case 0x14:
107     case 0x15:
108     case 0x16:
109     case 0x17:
110         return 1;
111     }
112     return 0;
113 }
114
115 /* Find the next instruction in the control flow. For a instruction
116    with branch delay slot, this is the branch/jump target if the branch
117    is taken, and PC + 8 if it is not taken. For other instructions it
118    is PC + 4. */
119 static unsigned int
120 next_insn_addr(os_context_t *context, unsigned int inst)
121 {
122     unsigned int opcode = inst >> 26;
123     unsigned int r1 = (inst >> 21) & 0x1f;
124     unsigned int r2 = (inst >> 16) & 0x1f;
125     unsigned int r3 = (inst >> 11) & 0x1f;
126     unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
127     unsigned int jtgt = (os_context_pc(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2;
128     unsigned int tgt = os_context_pc(context);
129
130     switch(opcode) {
131     case 0x0: /* jr, jalr */
132         switch(inst & 0x3f) {
133         case 0x08: /* jr */
134             tgt = os_context_register(context, r1);
135             break;
136         case 0x09: /* jalr */
137             tgt = os_context_register(context, r1);
138             *os_context_register_addr(context, r3)
139                 = os_context_pc(context) + INSN_LEN;
140             break;
141         default:
142             tgt += INSN_LEN;
143             break;
144         }
145         break;
146     case 0x1: /* bltz, bgez, bltzal, bgezal, ... */
147         switch(r2) {
148         case 0x00: /* bltz */
149         case 0x02: /* bltzl */
150             if(os_context_register(context, r1) < 0)
151                 tgt += disp;
152             else
153                 tgt += INSN_LEN;
154             break;
155         case 0x01: /* bgez */
156         case 0x03: /* bgezl */
157             if(os_context_register(context, r1) >= 0)
158                 tgt += disp;
159             else
160                 tgt += INSN_LEN;
161             break;
162         case 0x10: /* bltzal */
163         case 0x12: /* bltzall */
164             if(os_context_register(context, r1) < 0) {
165                 tgt += disp;
166                 *os_context_register_addr(context, 31)
167                     = os_context_pc(context) + INSN_LEN;
168             } else
169                 tgt += INSN_LEN;
170             break;
171         case 0x11: /* bgezal */
172         case 0x13: /* bgezall */
173             if(os_context_register(context, r1) >= 0) {
174                 tgt += disp;
175                 *os_context_register_addr(context, 31)
176                     = os_context_pc(context) + INSN_LEN;
177             } else
178                 tgt += INSN_LEN;
179             break;
180         default:
181             tgt += INSN_LEN;
182             break;
183         }
184         break;
185     case 0x2: /* j */
186         tgt = jtgt;
187         break;
188     case 0x3: /* jal */
189         tgt = jtgt;
190         *os_context_register_addr(context, 31)
191             = os_context_pc(context) + INSN_LEN;
192         break;
193     case 0x4: /* beq */
194     case 0x14: /* beql */
195         if(os_context_register(context, r1)
196            == os_context_register(context, r2))
197             tgt += disp;
198         else
199             tgt += INSN_LEN;
200         break;
201     case 0x5: /* bne */
202     case 0x15: /* bnel */
203         if(os_context_register(context, r1)
204            != os_context_register(context, r2))
205             tgt += disp;
206         else
207             tgt += INSN_LEN;
208         break;
209     case 0x6: /* blez */
210     case 0x16: /* blezl */
211         if(os_context_register(context, r1)
212            <= os_context_register(context, r2))
213             tgt += disp;
214         else
215             tgt += INSN_LEN;
216         break;
217     case 0x7: /* bgtz */
218     case 0x17: /* bgtzl */
219         if(os_context_register(context, r1)
220            > os_context_register(context, r2))
221             tgt += disp;
222         else
223             tgt += INSN_LEN;
224         break;
225     case 0x10:
226     case 0x11:
227     case 0x12:
228         switch (r1) {
229          /* CP0/CP1/CP2 branches */
230         case 0x08:
231             /* FIXME */
232             tgt += INSN_LEN;
233             break;
234         }
235         break;
236     default:
237         tgt += INSN_LEN;
238         break;
239     }
240     return tgt;
241 }
242
243 void
244 arch_skip_instruction(os_context_t *context)
245 {
246     /* Skip the offending instruction. Don't use os_context_insn here,
247        since in case of a branch we want the branch insn, not the delay
248        slot. */
249     *os_context_pc_addr(context)
250         = (os_context_register_t)
251             next_insn_addr(context,
252                 *(unsigned int *)(os_context_pc(context)));
253 }
254
255 unsigned char *
256 arch_internal_error_arguments(os_context_t *context)
257 {
258     if (os_context_bd_cause(context))
259         return (unsigned char *)(os_context_pc(context) + (INSN_LEN * 2));
260     else
261         return (unsigned char *)(os_context_pc(context) + INSN_LEN);
262 }
263
264 boolean
265 arch_pseudo_atomic_atomic(os_context_t *context)
266 {
267     return os_context_register(context, reg_ALLOC) & 1;
268 }
269
270 void
271 arch_set_pseudo_atomic_interrupted(os_context_t *context)
272 {
273     *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
274 }
275
276 void
277 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
278 {
279     *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
280 }
281
282 unsigned int
283 arch_install_breakpoint(void *pc)
284 {
285     unsigned int *ptr = (unsigned int *)pc;
286     unsigned int insn;
287
288     /* Don't install over a branch/jump with delay slot. */
289     if (arch_insn_with_bdelay_p(*ptr))
290         ptr++;
291
292     insn = *ptr;
293     *ptr = (trap_Breakpoint << 6) | 0xd;
294     os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
295
296     return insn;
297 }
298
299 static inline unsigned int
300 arch_install_after_breakpoint(void *pc)
301 {
302     unsigned int *ptr = (unsigned int *)pc;
303     unsigned int insn;
304
305     /* Don't install over a branch/jump with delay slot. */
306     if (arch_insn_with_bdelay_p(*ptr))
307         ptr++;
308
309     insn = *ptr;
310     *ptr = (trap_AfterBreakpoint << 6) | 0xd;
311     os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
312
313     return insn;
314 }
315
316 void
317 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
318 {
319     unsigned int *ptr = (unsigned int *)pc;
320
321     /* We may remove from a branch delay slot. */
322     if (arch_insn_with_bdelay_p(*ptr))
323         ptr++;
324
325     *ptr = orig_inst;
326     os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
327 }
328
329 /* Perform the instruction that we overwrote with a breakpoint. As we
330    don't have a single-step facility, this means we have to:
331    - put the instruction back
332    - put a second breakpoint at the following instruction,
333      set after_breakpoint and continue execution.
334
335    When the second breakpoint is hit (very shortly thereafter, we hope)
336    sigtrap_handler gets called again, but follows the AfterBreakpoint
337    arm, which
338    - puts a bpt back in the first breakpoint place (running across a
339      breakpoint shouldn't cause it to be uninstalled)
340    - replaces the second bpt with the instruction it was meant to be
341    - carries on
342
343    Clear? */
344
345 static unsigned int *skipped_break_addr, displaced_after_inst;
346 static sigset_t orig_sigmask;
347
348 void
349 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
350 {
351     unsigned int *pc = (unsigned int *)os_context_pc(context);
352     unsigned int *next_pc;
353
354     orig_sigmask = *os_context_sigmask_addr(context);
355     sigaddset_blockable(os_context_sigmask_addr(context));
356
357     /* Put the original instruction back. */
358     arch_remove_breakpoint(pc, orig_inst);
359     skipped_break_addr = pc;
360
361     /* Figure out where it goes. */
362     next_pc = (unsigned int *)next_insn_addr(context, *pc);
363     displaced_after_inst = arch_install_after_breakpoint(next_pc);
364 }
365
366 void
367 arch_handle_breakpoint(os_context_t *context)
368 {
369     handle_breakpoint(context);
370 }
371
372 void
373 arch_handle_fun_end_breakpoint(os_context_t *context)
374 {
375     *os_context_pc_addr(context)
376         = (os_context_register_t)(unsigned int)
377         handle_fun_end_breakpoint(context);
378 }
379
380 void
381 arch_handle_after_breakpoint(os_context_t *context)
382 {
383     arch_install_breakpoint(skipped_break_addr);
384     arch_remove_breakpoint((unsigned int *)os_context_pc(context),
385                            displaced_after_inst);
386     *os_context_sigmask_addr(context) = orig_sigmask;
387 }
388
389 void
390 arch_handle_single_step_trap(os_context_t *context, int trap)
391 {
392     unsigned int code = *((u32 *)(os_context_pc(context)));
393     int register_offset = code >> 11 & 0x1f;
394     handle_single_step_trap(context, trap, register_offset);
395     arch_skip_instruction(context);
396 }
397
398 static void
399 sigtrap_handler(int signal, siginfo_t *info, os_context_t *context)
400 {
401     unsigned int code = (os_context_insn(context) >> 6) & 0xfffff;
402     /* FIXME: This magic number is pseudo-atomic-trap from parms.lisp.
403      * Genesis should provide the proper #define, but it specialcases
404      * pseudo-atomic-trap to work around some oddity on SPARC.
405      * Eventually this should go into handle_trap. */
406     if (code==0x10) {
407         arch_clear_pseudo_atomic_interrupted(context);
408         arch_skip_instruction(context);
409         interrupt_handle_pending(context);
410     } else
411         handle_trap(context,code & 0x1f);
412 }
413
414 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
415
416 static void
417 sigfpe_handler(int signal, siginfo_t *info, os_context_t *context)
418 {
419     unsigned int bad_inst = os_context_insn(context);
420     unsigned int op, rs, rt, rd, funct, dest = 32;
421     int immed;
422     int result;
423
424     op = (bad_inst >> 26) & 0x3f;
425     rs = (bad_inst >> 21) & 0x1f;
426     rt = (bad_inst >> 16) & 0x1f;
427     rd = (bad_inst >> 11) & 0x1f;
428     funct = bad_inst & 0x3f;
429     immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
430
431     switch (op) {
432     case 0x0: /* SPECIAL */
433         switch (funct) {
434         case 0x20: /* ADD */
435             result = FIXNUM_VALUE(os_context_register(context, rs))
436                 + FIXNUM_VALUE(os_context_register(context, rt));
437             dest = rd;
438             break;
439
440         case 0x22: /* SUB */
441             result = FIXNUM_VALUE(os_context_register(context, rs))
442                 - FIXNUM_VALUE(os_context_register(context, rt));
443             dest = rd;
444             break;
445
446         default:
447             interrupt_handle_now(signal, info, context);
448             return;
449         }
450         break;
451
452     case 0x8: /* ADDI */
453         result = FIXNUM_VALUE(os_context_register(context,rs))
454                     + (immed >> N_FIXNUM_TAG_BITS);
455         dest = rt;
456         break;
457
458     default:
459         interrupt_handle_now(signal, info, context);
460         return;
461     }
462
463     dynamic_space_free_pointer =
464         (lispobj *)(unsigned int)*os_context_register_addr(context,reg_ALLOC);
465
466     *os_context_register_addr(context,dest) = alloc_number(result);
467
468     *os_context_register_addr(context, reg_ALLOC) =
469         (unsigned int) dynamic_space_free_pointer;
470
471     arch_skip_instruction(context);
472 }
473
474 unsigned int
475 arch_get_fp_control(void)
476 {
477     register unsigned int ret asm("$2");
478
479     __asm__ __volatile__ ("cfc1 %0, $31" : "=r" (ret));
480
481     return ret;
482 }
483
484 void
485 arch_set_fp_control(unsigned int fp)
486 {
487     __asm__ __volatile__ ("ctc1 %0, $31" :: "r" (fp));
488 }
489
490 void
491 arch_install_interrupt_handlers(void)
492 {
493     undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
494     undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
495 }
496
497 #ifdef LISP_FEATURE_LINKAGE_TABLE
498
499 /* Linkage tables for MIPS
500
501    Linkage entry size is 16, because we need 4 instructions to implement
502    a jump. The entry size constant is defined in parms.lisp.
503
504    Define the register to use in the linkage jump table. For MIPS this
505    has to be the PIC call register $25 aka t9 aka reg_ALLOC. */
506 #define LINKAGE_TEMP_REG        reg_ALLOC
507
508 /* Insert the necessary jump instructions at the given address. */
509 void
510 arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
511 {
512   /* Make JMP to function entry. The instruction sequence is:
513        lui    $25, 0, %hi(addr)
514        addiu  $25, $25, %lo(addr)
515        jr     $25
516         nop */
517   unsigned int *insn = (unsigned int *)reloc_addr;
518   unsigned int addr = (unsigned int)target_addr;
519   unsigned int hi = ((addr + 0x8000) >> 16) & 0xffff;
520   unsigned int lo = addr & 0xffff;
521
522   *insn++ = (15 << 26) | (LINKAGE_TEMP_REG << 16) | hi;
523   *insn++ = ((9 << 26) | (LINKAGE_TEMP_REG << 21)
524                  | (LINKAGE_TEMP_REG << 16) | lo);
525   *insn++ = (LINKAGE_TEMP_REG << 21) | 8;
526   *insn = 0;
527
528   os_flush_icache((os_vm_address_t)reloc_addr, LINKAGE_TABLE_ENTRY_SIZE);
529 }
530
531 void
532 arch_write_linkage_table_ref(void *reloc_addr, void *target_addr)
533 {
534     *(unsigned int *)reloc_addr = (unsigned int)target_addr;
535 }
536
537 #endif