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

  ViewVC Help
Powered by ViewVC 1.1.5