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