/[cmucl]/src/lisp/amd64-arch.c
ViewVC logotype

Contents of /src/lisp/amd64-arch.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations)
Tue May 18 21:53:56 2004 UTC (9 years, 11 months ago) by cwang
Branch: MAIN
CVS Tags: snapshot-2004-06
File MIME type: text/plain
This file is quite similar to x86-arch.c
1 /* x86-arch.c -*- Mode: C; comment-column: 40 -*-
2 *
3 * $Header: /tiger/var/lib/cvsroots/cmucl/src/lisp/amd64-arch.c,v 1.1 2004/05/18 21:53:56 cwang Exp $
4 *
5 */
6
7 #include <stdio.h>
8
9 #include "lisp.h"
10 #include "globals.h"
11 #include "validate.h"
12 #include "os.h"
13 #include "internals.h"
14 #include "arch.h"
15 #include "lispregs.h"
16 #include "signal.h"
17 #include "alloc.h"
18 #include "interrupt.h"
19 #include "interr.h"
20 #include "breakpoint.h"
21
22 #define DPRINTF(test, e) {if(test) fprintf e ;}
23
24 #define BREAKPOINT_INST 0xcc /* INT3 */
25
26 unsigned long fast_random_state = 1;
27
28 char * arch_init(void)
29 {
30 return "lisp.core";
31 }
32
33
34
35 /*
36 * Assuming we get here via an INT3 xxx instruction, the PC now
37 * points to the interrupt code (lisp value) so we just move past
38 * it. Skip the code, then if the code is an error-trap or
39 * Cerror-trap then skip the data bytes that follow.
40 */
41
42 void arch_skip_instruction(struct sigcontext *context)
43 {
44 int vlen,code;
45
46 DPRINTF(0,(stderr,"[arch_skip_inst at %x>]\n", context->sc_pc));
47
48 /* Get and skip the lisp error code. */
49 code = *(char*) context->sc_pc++;
50 switch (code)
51 {
52 case trap_Error:
53 case trap_Cerror:
54 /* Lisp error arg vector length */
55 vlen = *(char*) context->sc_pc++;
56 /* Skip lisp error arg data bytes */
57 while(vlen-- > 0)
58 ((char*) context->sc_pc)++;
59 break;
60
61 case trap_Breakpoint:
62 case trap_FunctionEndBreakpoint:
63 break;
64
65 case trap_PendingInterrupt:
66 case trap_Halt:
67 /* Only needed to skip the Code. */
68 break;
69
70 default:
71 fprintf(stderr, "[arch_skip_inst invalid code %d\n]\n", code);
72 break;
73 }
74
75 DPRINTF(0,(stderr,"[arch_skip_inst resuming at %x>]\n", context->sc_pc));
76 }
77
78 unsigned char * arch_internal_error_arguments(struct sigcontext *context)
79 {
80 return (unsigned char *) (context->sc_pc + 1);
81 }
82
83 boolean arch_pseudo_atomic_atomic(struct sigcontext *context)
84 {
85 return SymbolValue(PSEUDO_ATOMIC_ATOMIC);
86 }
87
88 void arch_set_pseudo_atomic_interrupted(struct sigcontext *context)
89 {
90 SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(1));
91 }
92
93
94
95 unsigned long arch_install_breakpoint(void *pc)
96 {
97 unsigned long result = *(unsigned long*)pc;
98
99 *(char*)pc = BREAKPOINT_INST; /* x86 INT3 */
100 *((char*)pc+1) = trap_Breakpoint; /* Lisp trap code */
101
102 return result;
103 }
104
105 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
106 {
107 *((char *) pc) = orig_inst & 0xff;
108 *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
109 }
110
111
112
113 /*
114 * When single stepping single_stepping holds the original instruction
115 * pc location.
116 */
117
118 unsigned int *single_stepping = NULL;
119 #ifndef __linux__
120 unsigned int single_step_save1;
121 unsigned int single_step_save2;
122 unsigned int single_step_save3;
123 #endif
124
125 void arch_do_displaced_inst(struct sigcontext *context,
126 unsigned long orig_inst)
127 {
128 unsigned int *pc = (unsigned int*) context->sc_pc;
129
130 /*
131 * Put the original instruction back.
132 */
133
134 *((char *) pc) = orig_inst & 0xff;
135 *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
136
137 #ifdef __linux__
138 context->eflags |= 0x100;
139 #else
140
141 /*
142 * Install helper instructions for the single step:
143 * pushf; or [esp],0x100; popf.
144 */
145
146 single_step_save1 = *(pc - 3);
147 single_step_save2 = *(pc - 2);
148 single_step_save3 = *(pc - 1);
149 *(pc - 3) = 0x9c909090;
150 *(pc - 2) = 0x00240c81;
151 *(pc - 1) = 0x9d000001;
152 #endif
153
154 single_stepping = (unsigned int*) pc;
155
156 #ifndef __linux__
157 (unsigned int*) context->sc_pc = (char *) pc - 9;
158 #endif
159 }
160
161
162 void sigtrap_handler(HANDLER_ARGS)
163 {
164 unsigned int trap;
165
166 #ifdef __linux__
167 GET_CONTEXT
168 #endif
169
170 #if 0
171 fprintf(stderr,"x86sigtrap: %8x %x\n",
172 context->sc_pc, *(unsigned char *)(context->sc_pc-1));
173 fprintf(stderr,"sigtrap(%d %d %x)\n",signal,code,context);
174 #endif
175
176 if (single_stepping && (signal == SIGTRAP))
177 {
178 #if 0
179 fprintf(stderr,"* Single step trap %x\n", single_stepping);
180 #endif
181
182 #ifndef __linux__
183 /* Un-install single step helper instructions. */
184 *(single_stepping-3) = single_step_save1;
185 *(single_stepping-2) = single_step_save2;
186 *(single_stepping-1) = single_step_save3;
187 #else
188 context->eflags ^= 0x100;
189 #endif
190
191 /*
192 * Re-install the breakpoint if possible.
193 */
194
195 if ((int) context->sc_pc == (int) single_stepping + 1)
196 fprintf(stderr, "* Breakpoint not re-install\n");
197 else
198 {
199 char *ptr = (char *) single_stepping;
200 ptr[0] = BREAKPOINT_INST; /* x86 INT3 */
201 ptr[1] = trap_Breakpoint;
202 }
203
204 single_stepping = NULL;
205 return;
206 }
207
208 SAVE_CONTEXT();
209
210 /* This is just for info in case monitor wants to print an approx */
211 current_control_stack_pointer = (unsigned long*) context->sc_sp;
212
213 #if defined(__linux__) && (defined(i386) || defined(__x86_64))
214 /*
215 * Restore the FPU control word, setting the rounding mode to nearest.
216 */
217
218 if (contextstruct.fpstate)
219 #if defined(__x86_64)
220 setfpucw(contextstruct.fpstate->cwd & ~0xc00);
221 #else
222 setfpucw(contextstruct.fpstate->cw & ~0xc00);
223 #endif
224 #endif
225
226 /*
227 * On entry %eip points just after the INT3 byte and aims at the
228 * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
229 * number of bytes will follow, the first is the length of the byte
230 * arguments to follow.
231 */
232
233 trap = *(unsigned char *) (context->sc_pc);
234
235 switch (trap)
236 {
237 case trap_PendingInterrupt:
238 DPRINTF(0,(stderr,"<trap Pending Interrupt.>\n"));
239 arch_skip_instruction(context);
240 interrupt_handle_pending(context);
241 break;
242
243 case trap_Halt:
244 {
245 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
246 int fpu_state[27];
247 fpu_save(fpu_state);
248 #endif
249 fake_foreign_function_call(context);
250 lose("%%primitive halt called; the party is over.\n");
251 undo_fake_foreign_function_call(context);
252 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
253 fpu_restore(fpu_state);
254 #endif
255 arch_skip_instruction(context);
256 break;
257 }
258
259 case trap_Error:
260 case trap_Cerror:
261 DPRINTF(0, (stderr, "<trap Error %d>\n",code));
262 #ifdef __linux__
263 interrupt_internal_error(signal, contextstruct, code == trap_Cerror);
264 #else
265 interrupt_internal_error(signal, code, context, code == trap_Cerror);
266 #endif
267 break;
268
269 case trap_Breakpoint:
270 #if 0
271 fprintf(stderr,"*C break\n");
272 #endif
273 (char*) context->sc_pc -= 1;
274 handle_breakpoint(signal, code, context);
275 #if 0
276 fprintf(stderr,"*C break return\n");
277 #endif
278 break;
279
280 case trap_FunctionEndBreakpoint:
281 (char*) context->sc_pc -= 1;
282 context->sc_pc = (int) handle_function_end_breakpoint(signal, code, context);
283 break;
284
285 #ifdef trap_DynamicSpaceOverflowWarning
286 case trap_DynamicSpaceOverflowWarning:
287 interrupt_handle_space_overflow(SymbolFunction(DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
288 context);
289 break;
290 #endif
291 #ifdef trap_DynamicSpaceOverflowError
292 case trap_DynamicSpaceOverflowError:
293 interrupt_handle_space_overflow(SymbolFunction(DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
294 context);
295 break;
296 #endif
297 default:
298 DPRINTF(0,(stderr,"[C--trap default %d %d %x]\n", signal, code,context));
299 #ifdef __linux__
300 interrupt_handle_now(signal, contextstruct);
301 #else
302 interrupt_handle_now(signal, code, context);
303 #endif
304 break;
305 }
306 }
307
308 #define FIXNUM_VALUE(lispobj) (((int) lispobj) >> 2)
309
310 void arch_install_interrupt_handlers()
311 {
312 interrupt_install_low_level_handler(SIGILL, sigtrap_handler);
313 interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
314 }
315
316
317 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
318
319 /* These next four functions are an interface to the
320 * Lisp call-in facility. Since this is C we can know
321 * nothing about the calling environment. The control
322 * stack might be the C stack if called from the monitor
323 * or the Lisp stack if called as a result of an interrupt
324 * or maybe even a separate stack. The args are most likely
325 * on that stack but could be in registers depending on
326 * what the compiler likes. So I try to package up the
327 * args into a portable vector and let the assembly language
328 * call-in function figure it out.
329 */
330
331 lispobj funcall0(lispobj function)
332 {
333 lispobj *args = NULL;
334
335 return call_into_lisp(function, args, 0);
336 }
337
338 lispobj funcall1(lispobj function, lispobj arg0)
339 {
340 lispobj args[1];
341 args[0] = arg0;
342 return call_into_lisp(function, args, 1);
343 }
344
345 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
346 {
347 lispobj args[2];
348 args[0] = arg0;
349 args[1] = arg1;
350 return call_into_lisp(function, args, 2);
351 }
352
353 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
354 {
355 lispobj args[3];
356 args[0] = arg0;
357 args[1] = arg1;
358 args[2] = arg2;
359 return call_into_lisp(function, args, 3);
360 }
361
362 #ifdef LINKAGE_TABLE
363
364 #ifndef LinkageEntrySize
365 #define LinkageEntrySize 16
366 #endif
367
368 void arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
369 {
370 char *reloc_addr = (char *)(FOREIGN_LINKAGE_SPACE_START
371 + linkage_entry * LinkageEntrySize);
372
373 if (type == 1) { /* code reference */
374 /* Make JMP to function entry. */
375 long offset = (char *)target_addr;
376 int i;
377
378 *reloc_addr++ = 0x49; /* opcode for MOV */
379 *reloc_addr++ = 0xbf; /* %r15 */
380 for (i = 0; i < 8; i++) {
381 *reloc_addr++ = offset & 0xff;
382 offset >>= 8;
383 }
384 *reloc_addr++ = 0x41; /* jmpq */
385 *reloc_addr++ = 0xff;
386 *reloc_addr++ = 0xe7; /* %r15 */
387 /* write a nop for good measure. */
388 *reloc_addr = 0x90;
389 } else if (type == 2) {
390 *(unsigned long *)reloc_addr = (unsigned long)target_addr;
391 }
392 }
393
394 /* Make a call to the first function in the linkage table, which is
395 resolve_linkage_tramp. */
396 void arch_make_lazy_linkage(long linkage_entry)
397 {
398 char *reloc_addr = (char *)(FOREIGN_LINKAGE_SPACE_START
399 + linkage_entry * LinkageEntrySize);
400 long offset = (char *)(FOREIGN_LINKAGE_SPACE_START) - (reloc_addr + 5);
401 int i;
402
403 *reloc_addr++ = 0xe8; /* opcode for CALL rel32 */
404 for (i = 0; i < 4; i++) {
405 *reloc_addr++ = offset & 0xff;
406 offset >>= 8;
407 }
408 /* write a nop for good measure. */
409 *reloc_addr = 0x90;
410 }
411
412 /* Get linkage entry. The initial instruction in the linkage
413 entry is a CALL; the return address we're passed points to the next
414 instruction. */
415
416 long arch_linkage_entry(unsigned long retaddr)
417 {
418 return ((retaddr - 5) - FOREIGN_LINKAGE_SPACE_START) / LinkageEntrySize;
419 }
420 #endif /* LINKAGE_TABLE */

  ViewVC Help
Powered by ViewVC 1.1.5