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

  ViewVC Help
Powered by ViewVC 1.1.5