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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.30 - (show annotations)
Wed Nov 12 15:04:24 2008 UTC (5 years, 5 months ago) by rtoy
Branch: MAIN
CVS Tags: sparc-tramp-assem-base, post-merge-intl-branch, merged-unicode-utf16-extfmt-2009-06-11, intl-branch-working-2010-02-19-1000, unicode-string-buffer-impl-base, release-20b-pre1, release-20b-pre2, unicode-string-buffer-base, sparc-tramp-assem-2010-07-19, amd64-dd-start, release-19f-pre1, snapshot-2008-12, intl-2-branch-base, GIT-CONVERSION, cross-sol-x86-merged, label-2009-03-16, release-19f-base, merge-sse2-packed, merge-with-19f, intl-branch-working-2010-02-11-1000, RELEASE_20b, RELEASE_19f, release-20a-base, cross-sol-x86-base, snapshot-2010-12, snapshot-2010-11, snapshot-2011-09, snapshot-2011-06, snapshot-2011-07, snapshot-2011-04, snapshot-2011-02, snapshot-2011-03, snapshot-2011-01, pre-merge-intl-branch, snapshot-2010-05, snapshot-2010-04, snapshot-2010-07, snapshot-2010-06, snapshot-2010-01, snapshot-2010-03, snapshot-2010-02, snapshot-2010-08, label-2009-03-25, cross-sol-x86-2010-12-20, intl-branch-2010-03-18-1300, RELEASE_20a, release-20a-pre1, snapshot-2009-11, snapshot-2009-12, portable-clx-import-2009-06-16, cross-sparc-branch-base, intl-branch-base, portable-clx-base, snapshot-2009-08, snapshot-2009-02, snapshot-2009-01, snapshot-2009-07, snapshot-2009-05, snapshot-2009-04, HEAD
Branch point for: RELEASE-19F-BRANCH, portable-clx-branch, cross-sparc-branch, RELEASE-20B-BRANCH, unicode-string-buffer-branch, sparc-tramp-assem-branch, RELEASE-20A-BRANCH, amd64-dd-branch, unicode-string-buffer-impl-branch, intl-branch, cross-sol-x86-branch, intl-2-branch
Changes since 1.29: +2 -2 lines
File MIME type: text/plain
Merge in SSE2 changes from sse2-packed-branch (tag
sse2-packed-2008-11-12).
1 /*
2
3 $Header: /tiger/var/lib/cvsroots/cmucl/src/lisp/sparc-arch.c,v 1.30 2008/11/12 15:04:24 rtoy 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 #ifdef SOLARIS
12 #include <sys/trap.h>
13 #else
14 #include <machine/trap.h>
15 #endif
16
17 #include "arch.h"
18 #include "lisp.h"
19 #include "internals.h"
20 #include "globals.h"
21 #include "validate.h"
22 #include "os.h"
23 #include "lispregs.h"
24 #include "signal.h"
25 #include "interrupt.h"
26 #include "gencgc.h"
27 #include "breakpoint.h"
28 #include "interr.h"
29
30 char *
31 arch_init(fpu_mode_t mode)
32 {
33 return 0;
34 }
35
36 os_vm_address_t
37 arch_get_bad_addr(HANDLER_ARGS)
38 {
39 unsigned int badinst;
40 int rs1;
41
42 /* On the sparc, we have to decode the instruction. */
43
44 /* Make sure it's not the pc thats bogus, and that it was lisp code */
45 /* that caused the fault. */
46 if ((SC_PC(context) & 3) != 0 ||
47 ((SC_PC(context) < READ_ONLY_SPACE_START ||
48 SC_PC(context) >= READ_ONLY_SPACE_START + READ_ONLY_SPACE_SIZE) &&
49 ((lispobj *) SC_PC(context) < current_dynamic_space &&
50 (lispobj *) SC_PC(context) >=
51 current_dynamic_space + dynamic_space_size))) return 0;
52
53 badinst = *(unsigned int *) SC_PC(context);
54
55 if ((badinst >> 30) != 3)
56 /* All load/store instructions have op = 11 (binary) */
57 return 0;
58
59 rs1 = (badinst >> 14) & 0x1f;
60
61 if (badinst & (1 << 13)) {
62 /* r[rs1] + simm(13) */
63 int simm13 = badinst & 0x1fff;
64
65 if (simm13 & (1 << 12))
66 simm13 |= -1 << 13;
67
68 return (os_vm_address_t) (SC_REG(context, rs1) + simm13);
69 } else {
70 /* r[rs1] + r[rs2] */
71 int rs2 = badinst & 0x1f;
72
73 return (os_vm_address_t) (SC_REG(context, rs1) + SC_REG(context, rs2));
74 }
75
76 }
77
78 void
79 arch_skip_instruction(context)
80 struct sigcontext *context;
81 {
82 /* Skip the offending instruction */
83 SC_PC(context) = SC_NPC(context);
84 SC_NPC(context) += 4;
85 }
86
87 unsigned char *
88 arch_internal_error_arguments(struct sigcontext *scp)
89 {
90 return (unsigned char *) (SC_PC(scp) + 4);
91 }
92
93 boolean
94 arch_pseudo_atomic_atomic(struct sigcontext *scp)
95 {
96 return (SC_REG(scp, reg_ALLOC) & pseudo_atomic_Value);
97 }
98
99 void
100 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
101 {
102 SC_REG(scp, reg_ALLOC) |= pseudo_atomic_InterruptedValue;
103 }
104
105 unsigned long
106 arch_install_breakpoint(void *pc)
107 {
108 unsigned int *ptr = (unsigned int *) pc;
109 unsigned int result = *ptr;
110
111 *ptr = trap_Breakpoint;
112 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
113
114 return result;
115 }
116
117 void
118 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
119 {
120 *(unsigned int *) pc = (unsigned int) orig_inst;
121 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
122 }
123
124 static unsigned int *skipped_break_addr, displaced_after_inst;
125
126 static sigset_t orig_sigmask;
127
128 void
129 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
130 {
131 unsigned int *pc = (unsigned int *) SC_PC(scp);
132 unsigned int *npc = (unsigned int *) SC_NPC(scp);
133
134 orig_sigmask = scp->uc_sigmask;
135 sigemptyset(&scp->uc_sigmask);
136 FILLBLOCKSET(&scp->uc_sigmask);
137
138 *pc = orig_inst;
139 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
140
141 skipped_break_addr = pc;
142 displaced_after_inst = *npc;
143 *npc = trap_AfterBreakpoint;
144 os_flush_icache((os_vm_address_t) npc, sizeof(unsigned int));
145
146 #ifdef SOLARIS
147 /* XXX never tested */
148 setcontext(scp);
149 #else
150 sigreturn(scp);
151 #endif
152 }
153
154 /*
155 * Look at the instruction at address PC and see if it's a trap
156 * instruction with an immediate value. If so, set trapno to the trap
157 * number, and return non-zero. If it's not a trap instruction,
158 * return 0.
159 */
160 boolean
161 trap_inst_p(unsigned int *pc, int *trapno)
162 {
163 unsigned int trap_inst;
164
165 trap_inst = *pc;
166
167 if (((trap_inst >> 30) == 2)
168 && (((trap_inst >> 19) & 0x3f) == 0x3a)
169 && (((trap_inst >> 14) & 0x1f) == reg_ZERO)
170 && (((trap_inst >> 13) & 1) == 1)) {
171 /*
172 * Got a trap instruction with immediate trap value.
173 * Get the value and return.
174 */
175 *trapno = (trap_inst & 0x3f);
176
177 return 1;
178 } else {
179 *trapno = -1;
180 return 0;
181 }
182 }
183
184
185 static int
186 pseudo_atomic_trap_p(struct sigcontext *context)
187 {
188 unsigned int *pc;
189 unsigned int badinst;
190 int trapno;
191 int result;
192
193
194 pc = (unsigned int *) SC_PC(context);
195 badinst = *pc;
196 result = 0;
197
198 /*
199 * Check to see if the current instruction is a trap #16. We check
200 * to make sure this instruction was a trap instruction with rs1 = 0
201 * and a software trap number (immediate value) of 16.
202 */
203 if (trap_inst_p(pc, &trapno) && (trapno == trap_PseudoAtomic)) {
204 unsigned int previnst;
205
206 previnst = pc[-1];
207 /*
208 * Check to see if the previous instruction was an andcc alloc-tn,
209 * pseudo_atomic_InterruptedValue, zero-tn instruction.
210 */
211 if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
212 && (((previnst >> 14) & 0x1f) == reg_ALLOC)
213 && (((previnst >> 25) & 0x1f) == reg_ZERO)
214 && (((previnst >> 13) & 1) == 1)
215 && ((previnst & 0x1fff) == pseudo_atomic_InterruptedValue)) {
216 result = 1;
217 } else {
218 fprintf(stderr,
219 "Oops! Got a pseudo atomic trap without a preceeding andcc!\n");
220 }
221 }
222 return result;
223 }
224
225 #ifdef GENCGC
226 /*
227 * Return non-zero if the instruction is a trap 31 instruction
228 */
229
230 boolean
231 allocation_trap_p(struct sigcontext * context)
232 {
233 int result;
234 unsigned int *pc;
235 unsigned int or_inst;
236 int trapno;
237
238 result = 0;
239
240 /*
241 * Make sure this is a trap 31 instruction preceeded by an OR
242 * instruction.
243 */
244
245 pc = (unsigned int *) SC_PC(context);
246
247 if (trap_inst_p(pc, &trapno) && (trapno == trap_Allocation)) {
248 /* Got the trap. Is it preceeded by an OR instruction or SUB
249 instruction? */
250 or_inst = pc[-1];
251 if ((((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) ||
252 (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4))) {
253 result = 1;
254 } else {
255 fprintf(stderr,
256 "Whoa!!! Got an allocation trap not preceeded by an OR inst: 0x%08x!\n",
257 or_inst);
258 }
259 }
260
261 return result;
262 }
263 #endif
264
265 #if 0
266 /* Pop the stack frame that build_fake_control_stack_frame makes */
267 static void
268 pop_fake_control_stack_frame(struct sigcontext *context)
269 {
270 current_control_frame_pointer = (lispobj *) SC_REG(context, reg_CFP);
271 SC_REG(context, reg_OCFP) = current_control_frame_pointer[0];
272 SC_REG(context, reg_CODE) = current_control_frame_pointer[1];
273 SC_REG(context, reg_CSP) = SC_REG(context, reg_CFP);
274 SC_REG(context, reg_CFP) = SC_REG(context, reg_OCFP);
275 }
276 #endif
277
278 /*
279 * Use this function to enable the minimum number of signals we need
280 * when our trap handler needs to call Lisp code that might cons. For
281 * consing to work with gencgc, we need to be able to trap the SIGILL
282 * signal to perform allocation.
283 */
284 void
285 enable_some_signals(void)
286 {
287 #ifdef GENCGC
288 sigset_t sigs;
289
290 sigemptyset(&sigs);
291 sigaddset(&sigs, SIGILL);
292 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
293 #endif
294 }
295
296 #ifdef GENCGC
297 void
298 handle_allocation_trap(struct sigcontext *context)
299 {
300 unsigned int *pc;
301 unsigned int or_inst;
302 int target;
303 int size;
304 int immed;
305 boolean were_in_lisp;
306 char *memory;
307 sigset_t block;
308
309 target = 0;
310 size = 0;
311
312 #if 0
313 /*
314 * Block all blockable signals. Need to do this because
315 * sigill_handler enables the signals. When the handler returns,
316 * signals should be enabled again, automatically.
317 */
318
319 sigemptyset(&block);
320 FILLBLOCKSET(&block);
321 sigprocmask(SIG_BLOCK, &block, 0);
322 #else
323 /*
324 * Well, maybe not. sigill_handler probably shouldn't be unblocking
325 * all signals. So, let's enable just the signals we need. Since
326 * alloc might call GC, we need to have SIGILL enabled so we can do
327 * allocation. Do we need more?
328 */
329 enable_some_signals();
330 #endif
331
332 pc = (unsigned int *) SC_PC(context);
333 or_inst = pc[-1];
334
335 /*
336 * The instruction before this trap instruction had better be an OR
337 * instruction or SUB instruction!
338 */
339
340 if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) {
341 /*
342 * An OR instruction. RS1 is the register we want to allocate
343 * to. RS2 (or an immediate) is the size.
344 */
345
346 target = (or_inst >> 14) & 0x1f;
347
348 immed = (or_inst >> 13) & 1;
349
350 if (immed == 1) {
351 size = or_inst & 0x1fff;
352 } else {
353 size = or_inst & 0x1f;
354 size = SC_REG(context, size);
355 }
356 } else if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4)) {
357 /*
358 * A SUB instruction. RD is the register to allocate to, RS2
359 * (or an immediate) is the size.
360 */
361
362 target = (or_inst >> 25) & 0x1f;
363 immed = (or_inst >> 13) & 1;
364 if (immed == 1) {
365 size = or_inst & 0x1fff;
366 } else {
367 size = or_inst & 0x1f;
368 size = SC_REG(context, size);
369 }
370 }
371
372
373 /*
374 * I don't think it's possible for us NOT to be in lisp when we get
375 * here. Remove this later?
376 */
377 were_in_lisp = !foreign_function_call_active;
378
379 if (were_in_lisp) {
380 fake_foreign_function_call(context);
381 } else {
382 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
383 }
384
385 /*
386 * alloc-tn was incremented by size. If we get here, we need to
387 * decrement it by size to restore it's original value.
388 */
389 /* current_dynamic_space_free_pointer = (lispobj *) SC_REG(context, reg_ALLOC); */
390 current_dynamic_space_free_pointer =
391 (lispobj *) ((long) current_dynamic_space_free_pointer - size);
392
393 /*
394 * Allocate some memory, store the memory address in target.
395 */
396
397 #if 0
398 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
399 #endif
400
401 memory = (char *) alloc(size);
402 SC_REG(context, target) = (unsigned long) memory;
403 SC_REG(context, reg_ALLOC) =
404 (unsigned long) current_dynamic_space_free_pointer;
405
406 if (were_in_lisp) {
407 undo_fake_foreign_function_call(context);
408 }
409
410 }
411 #endif
412
413 /*
414 * How to identify an illegal instruction trap and a trap instruction
415 * trap.
416 */
417 #ifdef SOLARIS
418 #define ILLTRAP_INST ILL_ILLOPC
419 #define TRAP_INST(code) (CODE(code) == ILL_ILLTRP)
420 #else
421 #define ILLTRAP_INST T_UNIMP_INSTR
422 #define TRAP_INST(code) ((CODE(code) >= T_SOFTWARE_TRAP + 16) && (CODE(code) < T_SOFTWARE_TRAP + 32))
423 #endif
424
425 static void
426 sigill_handler(HANDLER_ARGS)
427 {
428 SAVE_CONTEXT();
429
430 /*
431 * Do we really want to have the same signals as in the context?
432 * This would typically enable all signals, I think. But there
433 * are comments in interrupt_handle_now that says we want to
434 * alloc_sap while interrupts are disabled. The interrupt
435 * handlers that eventually get called from here will re-enable
436 * interrupts at the appropriate time, so we don't do anything
437 * here.
438 *
439 * (I'm guessing here. I don't really know if this is right or
440 * not, but it doesn't seem to cause harm, and it does seem to be
441 * a bad idea to have interrupts enabled here.)
442 */
443 #if 0
444 sigprocmask(SIG_SETMASK, &context->uc_sigmask, 0);
445 #endif
446
447 if (CODE(code) == ILLTRAP_INST) {
448 int illtrap_code;
449 unsigned int inst;
450 unsigned int *pc = (unsigned int *) (SC_PC(context));
451
452 inst = *pc;
453
454 illtrap_code = inst & 0x3fffff;
455
456 switch (illtrap_code) {
457 case trap_PendingInterrupt:
458 arch_skip_instruction(context);
459 interrupt_handle_pending(context);
460 break;
461
462 case trap_Halt:
463 fake_foreign_function_call(context);
464 lose("%%primitive halt called; the party is over.\n");
465
466 case trap_Error:
467 case trap_Cerror:
468 interrupt_internal_error(signal, code, context,
469 illtrap_code == trap_Cerror);
470 break;
471
472 case trap_Breakpoint:
473 enable_some_signals();
474 handle_breakpoint(signal, CODE(code), context);
475 break;
476
477 case trap_FunctionEndBreakpoint:
478 enable_some_signals();
479 SC_PC(context) =
480 (long) handle_function_end_breakpoint(signal, CODE(code),
481 context);
482 SC_NPC(context) = SC_PC(context) + 4;
483 break;
484
485 case trap_AfterBreakpoint:
486 *skipped_break_addr = trap_Breakpoint;
487 skipped_break_addr = NULL;
488 *(unsigned long *) SC_PC(context) = displaced_after_inst;
489 context->uc_sigmask = orig_sigmask;
490 os_flush_icache((os_vm_address_t) SC_PC(context),
491
492 sizeof(unsigned long));
493 break;
494
495 #ifdef trap_DynamicSpaceOverflowWarning
496 case trap_DynamicSpaceOverflowWarning:
497 arch_skip_instruction(context);
498 enable_some_signals();
499 interrupt_handle_space_overflow(SymbolFunction
500 (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
501 context);
502 break;
503 #endif
504 #ifdef trap_DynamicSpaceOverflowError
505 case trap_DynamicSpaceOverflowError:
506 arch_skip_instruction(context);
507 enable_some_signals();
508 interrupt_handle_space_overflow(SymbolFunction
509 (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
510 context);
511 break;
512 #endif
513 default:
514 interrupt_handle_now(signal, code, context);
515 break;
516 }
517 } else if (TRAP_INST(code)) {
518 if (pseudo_atomic_trap_p(context)) {
519 /* A trap instruction from a pseudo-atomic. We just need
520 to fixup up alloc-tn to remove the interrupted flag,
521 skip over the trap instruction, and then handle the
522 pending interrupt(s). */
523 SC_REG(context, reg_ALLOC) &= ~lowtag_Mask;
524 arch_skip_instruction(context);
525 interrupt_handle_pending(context);
526 }
527 #ifdef GENCGC
528 else if (allocation_trap_p(context)) {
529 /* An allocation trap. Call the trap handler and then skip
530 this instruction */
531 handle_allocation_trap(context);
532 arch_skip_instruction(context);
533 }
534 #endif
535 else {
536 interrupt_internal_error(signal, code, context, FALSE);
537 }
538 } else {
539 interrupt_handle_now(signal, code, context);
540 }
541 }
542
543 void
544 arch_install_interrupt_handlers(void)
545 {
546 interrupt_install_low_level_handler(SIGILL, sigill_handler);
547 }
548
549
550 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
551
552 lispobj
553 funcall0(lispobj function)
554 {
555 lispobj *args = current_control_stack_pointer;
556
557 return call_into_lisp(function, args, 0);
558 }
559
560 lispobj
561 funcall1(lispobj function, lispobj arg0)
562 {
563 lispobj *args = current_control_stack_pointer;
564
565 current_control_stack_pointer += 1;
566 args[0] = arg0;
567
568 return call_into_lisp(function, args, 1);
569 }
570
571 lispobj
572 funcall2(lispobj function, lispobj arg0, lispobj arg1)
573 {
574 lispobj *args = current_control_stack_pointer;
575
576 current_control_stack_pointer += 2;
577 args[0] = arg0;
578 args[1] = arg1;
579
580 return call_into_lisp(function, args, 2);
581 }
582
583 lispobj
584 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
585 {
586 lispobj *args = current_control_stack_pointer;
587
588 current_control_stack_pointer += 3;
589 args[0] = arg0;
590 args[1] = arg1;
591 args[2] = arg2;
592
593 return call_into_lisp(function, args, 3);
594 }
595
596 #ifdef LINKAGE_TABLE
597
598 /* This is mostly stolen from the x86 version, with adjustments for sparc */
599
600 /*
601 * Linkage entry size is 16, because we need at least 3 instruction to
602 * implement a jump:
603 *
604 * sethi %hi(addr), %g4
605 * jmpl [%g4 + %lo(addr)], %g5
606 * nop
607 *
608 * The Sparc V9 ABI seems to use 8 words for its jump tables. Maybe
609 * we should do the same?
610 */
611
612 /*
613 * This had better match lisp::target-foreign-linkage-entry-size in
614 * sparc/parms.lisp! Each entry is 4 instructions long, so 16 bytes.
615 */
616 #ifndef LinkageEntrySize
617 #define LinkageEntrySize (4*4)
618 #endif
619
620
621 /*
622 * Define the registers to use in the linkage jump table. Can be the
623 * same. This MUST be coordinated with resolve_linkage_tramp which
624 * needs to know the register used for LINKAGE_ADDR_REG.
625 *
626 * Some care must be exercised when choosing these. It has to be a
627 * register that is not otherwise being used. reg_L0 is a good
628 * choice. call_into_c trashes reg_L0 without preserving it, so we
629 * can trash it in the linkage jump table. For the linkage entries
630 * that call resolve_linkage_tramp, we can use reg_L0 too because
631 * resolve_linkage_tramp is always called from call_into_c. (This is
632 * enforced by having new-genesis create an entry for call_into_c, so
633 * we never have to do a lookup for call_into_c.)
634 *
635 * The LINKAGE_ADDR_REG is important! resolve_linkage_tramp needs to
636 * be coordinated with this because that's how resolve_linkage_tramp
637 * figures out what linkage entry it's being called from.
638 */
639 #define LINKAGE_TEMP_REG reg_L0
640 #define LINKAGE_ADDR_REG reg_L0
641
642 /*
643 * Insert the necessary jump instructions at the given address.
644 * Return the address of the next word
645 */
646 void *
647 arch_make_jump_entry(void *reloc_addr, void *target_addr)
648 {
649
650 /*
651 * Make JMP to function entry.
652 *
653 * The instruction sequence is:
654 *
655 * sethi %hi(addr), temp_reg
656 * jmpl %temp_reg + %lo(addr), %addr_reg
657 * nop
658 * nop
659 *
660 */
661 int *inst_ptr;
662 unsigned long hi; /* Top 22 bits of address */
663 unsigned long lo; /* Low 10 bits of address */
664 unsigned int inst;
665
666 inst_ptr = (int *) reloc_addr;
667
668 /*
669 * Split the target address into hi and lo parts for the sethi
670 * instruction. hi is the top 22 bits. lo is the low 10 bits.
671 */
672 hi = (unsigned long) target_addr;
673 lo = hi & 0x3ff;
674 hi >>= 10;
675
676 /*
677 * sethi %hi(addr), temp_reg
678 */
679
680 inst = (0 << 30) | (LINKAGE_TEMP_REG << 25) | (4 << 22) | hi;
681 *inst_ptr++ = inst;
682
683 /*
684 * jmpl [temp_reg + %lo(addr)], addr_reg
685 */
686
687 inst = (2U << 30) | (LINKAGE_ADDR_REG << 25) | (0x38 << 19)
688 | (LINKAGE_TEMP_REG << 14) | (1 << 13) | lo;
689 *inst_ptr++ = inst;
690
691 /* nop (really sethi 0, %g0) */
692
693 inst = (0 << 30) | (0 << 25) | (4 << 22) | 0;
694
695 *inst_ptr++ = inst;
696 *inst_ptr++ = inst;
697
698 os_flush_icache((os_vm_address_t) reloc_addr,
699 (char *) inst_ptr - (char *) reloc_addr);
700 return reloc_addr;
701 }
702
703 void
704 arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
705 {
706 int *reloc_addr = (int *) (FOREIGN_LINKAGE_SPACE_START
707
708 + linkage_entry * LinkageEntrySize);
709
710 if (type == 1) { /* code reference */
711 arch_make_jump_entry(reloc_addr, target_addr);
712 } else if (type == 2) {
713 *(unsigned long *) reloc_addr = (unsigned long) target_addr;
714 }
715 }
716
717 /* Make a the entry a jump to resolve_linkage_tramp. */
718
719 extern void resolve_linkage_tramp(void);
720
721 void
722 arch_make_lazy_linkage(long linkage_entry)
723 {
724 arch_make_linkage_entry(linkage_entry, (void *) resolve_linkage_tramp, 1);
725 }
726
727 /* Get linkage entry. We're given the return address which should be
728 the address of the jmpl instruction (2nd word) of the linkage
729 entry. Figure out which entry this address belong to. */
730
731 long
732 arch_linkage_entry(unsigned long retaddr)
733 {
734 return (retaddr - (FOREIGN_LINKAGE_SPACE_START))
735 / LinkageEntrySize;
736 }
737 #endif /* LINKAGE_TABLE */

  ViewVC Help
Powered by ViewVC 1.1.5