91af4b1bb5fc58029930389bbcb23aa8275789b4
[projects/cmucl/cmucl.git] / src / lisp / alpha-arch.c
1 /*
2
3  $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/alpha-arch.c,v 1.11 2008/03/19 09:17:10 cshapiro Rel $
4
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.
7
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12
13 #include "lisp.h"
14 #include "globals.h"
15 #include "validate.h"
16 #include "os.h"
17 #include "internals.h"
18 #include "arch.h"
19 #include "lispregs.h"
20 #include "signal.h"
21 #include "alloc.h"
22 #include "interrupt.h"
23 #include "interr.h"
24 #include "breakpoint.h"
25
26 extern char call_into_lisp_LRA[], call_into_lisp_end[];
27
28 #define BREAKPOINT_INST 0
29
30 char *
31 arch_init(void)
32 {
33     if (mmap((os_vm_address_t) call_into_lisp_LRA_page, OS_VM_DEFAULT_PAGESIZE,
34              OS_VM_PROT_ALL, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0)
35         == (os_vm_address_t) - 1)
36         perror("mmap");
37     memcpy(call_into_lisp_LRA_page, call_into_lisp_LRA, OS_VM_DEFAULT_PAGESIZE);
38     os_flush_icache((os_vm_address_t) call_into_lisp_LRA_page,
39                     OS_VM_DEFAULT_PAGESIZE);
40     return NULL;
41 }
42
43 os_vm_address_t
44 arch_get_bad_addr(int sig, int code, struct sigcontext * scp)
45 {
46     unsigned int badinst;
47
48     if ((scp->sc_pc & 3) != 0)
49         return NULL;
50
51     if ((scp->sc_pc < READ_ONLY_SPACE_START ||
52          scp->sc_pc >= READ_ONLY_SPACE_START + READ_ONLY_SPACE_SIZE) &&
53         ((lispobj *) scp->sc_pc < current_dynamic_space ||
54          (lispobj *) scp->sc_pc >= current_dynamic_space + dynamic_space_size))
55         return NULL;
56
57     badinst = *(unsigned int *) scp->sc_pc;
58
59     if (((badinst >> 27) != 0x16)       /* STL or STQ */
60         &&((badinst >> 27) != 0x13))    /* STS or STT */
61         return NULL;            /* Otherwise forget about address */
62
63     return (os_vm_address_t) (scp->sc_regs[(badinst >> 16) & 0x1f] +
64                               (badinst & 0xffff));
65 }
66
67 void
68 arch_skip_instruction(scp)
69      struct sigcontext *scp;
70 {
71     scp->sc_pc = +4;
72 }
73
74 unsigned char *
75 arch_internal_error_arguments(struct sigcontext *scp)
76 {
77     return (unsigned char *) (scp->sc_pc + 4);
78 }
79
80 boolean
81 arch_pseudo_atomic_atomic(struct sigcontext *scp)
82 {
83     return (scp->sc_regs[reg_ALLOC] & 1);
84 }
85
86 void
87 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
88 {
89 #ifdef __linux__
90     scp->sc_regs[reg_ALLOC] |= (1 << 63);
91 #else
92     scp->sc_regs[reg_ALLOC] |= 2;
93 #endif
94 }
95
96 unsigned long
97 arch_install_breakpoint(void *pc)
98 {
99     unsigned int *ptr = (unsigned int *) pc;
100     unsigned long result = (unsigned long) *ptr;
101
102     *ptr = BREAKPOINT_INST;
103
104     os_flush_icache((os_vm_address_t) ptr, sizeof(unsigned long));
105
106     return result;
107 }
108
109 void
110 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
111 {
112     unsigned int *ptr = (unsigned int) pc;
113
114     *ptr = orig_inst;
115     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
116 }
117
118 static unsigned int *skipped_break_addr, displaced_after_inst, after_breakpoint;
119
120 static sigset_t orig_sigmask;
121
122 unsigned int
123 emulate_branch(struct sigcontext *scp, unsigned long orig_inst)
124 {
125     int op = orig_inst >> 26;
126     int reg_a = (orig_inst >> 21) & 0x1f;
127     int reg_b = (orig_inst >> 16) & 0x1f;
128     int fn = orig_inst & 0xffff;
129     int disp =
130
131         (orig_inst & (1 << 20)) ? orig_inst | (-1 << 21) : orig_inst & 0x1fffff;
132     int next_pc = scp->sc_pc;
133     int branch = NULL;
134
135     switch (op) {
136       case 0x1a:                /* jmp, jsr, jsr_coroutine, ret */
137           scp->sc_regs[reg_a] = scp->sc_pc;
138           scp->sc_pc = scp->sc_regs[reg_b] & ~3;
139           break;
140       case 0x30:                /* br */
141           scp->sc_regs[reg_a] = scp->sc_pc;
142           branch = 1;
143           break;
144       case 0x31:                /* fbeq */
145           if (scp->sc_fpregs[reg_a] == 0)
146               branch = 1;
147           break;
148       case 0x32:                /* fblt */
149           if (scp->sc_fpregs[reg_a] < 0)
150               branch = 1;
151           break;
152       case 0x33:                /* fble */
153           if (scp->sc_fpregs[reg_a] <= 0)
154               branch = 1;
155           break;
156       case 0x34:                /* bsr */
157           scp->sc_regs[reg_a] = scp->sc_pc;
158           branch = 1;
159           break;
160       case 0x35:                /* fbne */
161           if (scp->sc_regs[reg_a] != 0)
162               branch = 1;
163           break;
164       case 0x36:                /* fbge */
165           if (scp->sc_fpregs[reg_a] >= 0)
166               branch = 1;
167           break;
168       case 0x37:                /* fbgt */
169           if (scp->sc_fpregs[reg_a] > 0)
170               branch = 1;
171           break;
172       case 0x38:                /* blbc */
173           if ((scp->sc_regs[reg_a] & 1) == 0)
174               branch = 1;
175           break;
176       case 0x39:                /* beq */
177           if (scp->sc_regs[reg_a] == 0)
178               branch = 1;
179           break;
180       case 0x3a:                /* blt */
181           if (scp->sc_regs[reg_a] < 0)
182               branch = 1;
183           break;
184       case 0x3b:                /* ble */
185           if (scp->sc_regs[reg_a] <= 0)
186               branch = 1;
187           break;
188       case 0x3c:                /* blbs */
189           if ((scp->sc_regs[reg_a] & 1) != 0)
190               branch = 1;
191           break;
192       case 0x3d:                /* bne */
193           if (scp->sc_regs[reg_a] != 0)
194               branch = 1;
195           break;
196       case 0x3e:                /* bge */
197           if (scp->sc_regs[reg_a] >= 0)
198               branch = 1;
199           break;
200       case 0x3f:                /* bgt */
201           if (scp->sc_regs[reg_a] > 0)
202               branch = 1;
203           break;
204     }
205     if (branch)
206         next_pc += disp * 4;
207     return next_pc;
208 }
209
210 void
211 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
212 {
213     unsigned int *pc = scp->sc_pc;
214     unsigned int *next_pc;
215     unsigned int next_inst;
216     int op = orig_inst >> 26;;
217
218 #if !defined(__linux__) || (defined(__linux__) && (__GNU_LIBRARY__ < 6))
219     orig_sigmask = context->uc_sigmask;
220     FILLBLOCKSET(&context->uc_sigmask);
221 #else
222     {
223         sigset_t temp;
224
225         sigemptyset(&temp);
226         orig_sigmask.__val[0] = scp->uc_sigmask;
227         temp.__val[0] = scp->uc_sigmask;
228         FILLBLOCKSET(&temp);
229
230         scp->uc_sigmask = temp.__val[0];
231     }
232 #endif
233
234     /* Figure out where the displaced inst is going */
235     if (op == 0x1a || op & 0xf == 0x30) /* branch...ugh */
236         next_pc = (unsigned int *) emulate_branch(scp, orig_inst);
237     else
238         next_pc = pc + 1;
239
240     /* Put the original instruction back. */
241     *pc = orig_inst;
242     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
243
244     skipped_break_addr = pc;
245
246     /* set the after breakpoint */
247     displaced_after_inst = *next_pc;
248     *next_pc = BREAKPOINT_INST;
249     after_breakpoint = 1;
250     os_flush_icache((os_vm_address_t) next_pc, sizeof(unsigned long));
251
252     sigreturn(scp);
253 }
254
255 #define AfterBreakpoint 100
256
257 static void
258 sigtrap_handler(int signal, int code, struct sigcontext *scp)
259 {
260     /* Don't disallow recursive breakpoint traps.  Otherwise, we can't */
261     /* use debugger breakpoints anywhere in here. */
262     sigsetmask(scp->sc_mask);
263
264     if (*(unsigned int *) (scp->sc_pc - 4) == BREAKPOINT_INST) {
265         if (after_breakpoint)
266             code = AfterBreakpoint;
267         else
268             code = trap_Breakpoint;
269     } else
270         code = *(u32 *) scp->sc_pc;
271
272     switch (code) {
273       case trap_PendingInterrupt:
274           arch_skip_instruction(scp);
275           interrupt_handle_pending(scp);
276           break;
277
278       case trap_Halt:
279           fake_foreign_function_call(scp);
280           lose("%%primitive halt called; the party is over.\n");
281
282       case trap_Error:
283       case trap_Cerror:
284           interrupt_internal_error(signal, code, scp, code == trap_Cerror);
285           break;
286
287       case trap_Breakpoint:
288           scp->sc_pc -= 4;
289           handle_breakpoint(signal, code, scp);
290           break;
291
292       case trap_FunctionEndBreakpoint:
293           scp->sc_pc -= 4;
294           scp->sc_pc = (int) handle_function_end_breakpoint(signal, code, scp);
295           break;
296
297       case AfterBreakpoint:
298           scp->sc_pc -= 4;
299           *skipped_break_addr = BREAKPOINT_INST;
300           os_flush_icache((os_vm_address_t) skipped_break_addr,
301
302                           sizeof(unsigned long));
303           skipped_break_addr = NULL;
304           *(unsigned int *) scp->sc_pc = displaced_after_inst;
305           os_flush_icache((os_vm_address_t) scp->sc_pc, sizeof(unsigned long));
306
307 #if  !defined(__linux__) || (defined(__linux__) && (__GNU_LIBRARY__ < 6))
308           scp->sc_mask = orig_sigmask;
309 #else
310           scp->sc_mask = orig_sigmask.__val[0];
311 #endif
312           after_breakpoint = NULL;
313           break;
314
315       default:
316           interrupt_handle_now(signal, code, scp);
317           break;
318     }
319 }
320
321 static void
322 sigfpe_handler(int signal, int code, struct sigcontext *scp)
323 {
324 }
325
326 void
327 arch_install_interrupt_handlers(void)
328 {
329     interrupt_install_low_level_handler(SIGILL, sigtrap_handler);
330     interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
331     interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
332 }
333
334 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
335
336 lispobj
337 funcall0(lispobj function)
338 {
339     lispobj *args = current_control_stack_pointer;
340
341     return call_into_lisp(function, args, 0);
342 }
343
344 lispobj
345 funcall1(lispobj function, lispobj arg0)
346 {
347     lispobj *args = current_control_stack_pointer;
348
349     current_control_stack_pointer += 1;
350     args[0] = arg0;
351
352     return call_into_lisp(function, args, 1);
353 }
354
355 lispobj
356 funcall2(lispobj function, lispobj arg0, lispobj arg1)
357 {
358     lispobj *args = current_control_stack_pointer;
359
360     current_control_stack_pointer += 2;
361     args[0] = arg0;
362     args[1] = arg1;
363
364     return call_into_lisp(function, args, 2);
365 }
366
367 lispobj
368 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
369 {
370     lispobj *args = current_control_stack_pointer;
371
372     current_control_stack_pointer += 3;
373     args[0] = arg0;
374     args[1] = arg1;
375     args[2] = arg2;
376
377     return call_into_lisp(function, args, 3);
378 }
379
380
381 /* This is apparently called by emulate_branch, but isn't defined.  So */
382 /* just do nothing and hope it works... */
383
384 void
385 cacheflush(void)
386 {
387 }