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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide 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.13: +2 -2 lines
File MIME type: text/plain
Merge in SSE2 changes from sse2-packed-branch (tag
sse2-packed-2008-11-12).
1 pmai 1.1 /*
2    
3 rtoy 1.14 $Header: /tiger/var/lib/cvsroots/cmucl/src/lisp/ppc-arch.c,v 1.14 2008/11/12 15:04:24 rtoy Rel $
4 pmai 1.1
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    
12     #include "arch.h"
13     #include "lisp.h"
14     #include "internals.h"
15     #include "globals.h"
16     #include "validate.h"
17     #include "os.h"
18     #include "lispregs.h"
19     #include "signal.h"
20     #include "interrupt.h"
21     #include "interr.h"
22    
23     /* The header files may not define PT_DAR/PT_DSISR. This definition
24     is correct for all versions of ppc linux >= 2.0.30
25    
26     As of DR2.1u4, MkLinux doesn't pass these registers to signal
27     handlers correctly; a patch is necessary in order to (partially)
28     correct this.
29    
30     Even with the patch, the DSISR may not have its 'write' bit set
31     correctly (it tends not to be set if the fault was caused by
32     something other than a protection violation.)
33 rtoy 1.5
34 pmai 1.1 Caveat callers. */
35    
36     #ifndef PT_DAR
37     #define PT_DAR 41
38     #endif
39    
40     #ifndef PT_DSISR
41     #define PT_DSISR 42
42     #endif
43    
44 rtoy 1.3 /*
45     * A macro to generate the instruction
46     *
47     * twllei r0, code
48     *
49     * This is what the ppc port uses to signal various traps like
50     * breakpoints and stuff.
51     */
52     #define TWLLEI_R0(code) ((3<<26) | (6 << 21) | code)
53    
54 rtoy 1.5 char *
55 rtoy 1.14 arch_init(fpu_mode_t mode)
56 pmai 1.1 {
57 rtoy 1.5 return "lisp.core";
58 pmai 1.1 }
59    
60 rtoy 1.5 os_vm_address_t arch_get_bad_addr(HANDLER_ARGS)
61 pmai 1.1 {
62 rtoy 1.5 os_vm_address_t addr;
63    
64     addr = (os_vm_address_t) SC_REG(context, PT_DAR);
65     return addr;
66 pmai 1.1 }
67    
68 rtoy 1.5
69     void
70     arch_skip_instruction(os_context_t * context)
71 pmai 1.1 {
72 rtoy 1.5 /* Skip the offending instruction */
73     SC_PC(context) += 4;
74 pmai 1.1 }
75    
76     unsigned char *
77 rtoy 1.5 arch_internal_error_arguments(os_context_t * scp)
78 pmai 1.1 {
79 rtoy 1.5 return (unsigned char *) (SC_PC(scp) + 4);
80 pmai 1.1 }
81    
82 rtoy 1.5 boolean arch_pseudo_atomic_atomic(os_context_t * scp)
83 pmai 1.1 {
84 rtoy 1.5 return (SC_REG(scp, reg_ALLOC) & 4);
85 pmai 1.1 }
86    
87     #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
88    
89 rtoy 1.5 void
90     arch_set_pseudo_atomic_interrupted(os_context_t * scp)
91 pmai 1.1 {
92 rtoy 1.4 #if 0
93 rtoy 1.5 SC_REG(scp, reg_NL3) += PSEUDO_ATOMIC_INTERRUPTED_BIAS;
94 rtoy 1.4 #else
95 rtoy 1.5 SC_REG(scp, reg_ALLOC) |= 1;
96 rtoy 1.4 #endif
97 pmai 1.1 }
98    
99 rtoy 1.5 unsigned long
100 pmai 1.1 arch_install_breakpoint(void *pc)
101     {
102 rtoy 1.5 unsigned long *ptr = (unsigned long *) pc;
103     unsigned long result = *ptr;
104    
105     /*
106     * Insert a twllei r0, trap_Breakpoint instruction.
107     */
108     *ptr = TWLLEI_R0(trap_Breakpoint);
109     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
110    
111     return result;
112 pmai 1.1 }
113    
114 rtoy 1.5 void
115 pmai 1.1 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
116     {
117 rtoy 1.5 *(unsigned long *) pc = orig_inst;
118     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
119 pmai 1.1 }
120    
121     static unsigned long *skipped_break_addr, displaced_after_inst;
122     static sigset_t orig_sigmask;
123    
124 rtoy 1.5 void
125     arch_do_displaced_inst(os_context_t * scp, unsigned long orig_inst)
126 pmai 1.1 {
127 rtoy 1.5 unsigned int *pc = (unsigned long *) SC_PC(scp);
128    
129     orig_sigmask = scp->uc_sigmask;
130     sigemptyset(&scp->uc_sigmask);
131     FILLBLOCKSET(&scp->uc_sigmask);
132    
133     /* Put the original instruction back */
134     *pc = orig_inst;
135     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
136    
137     skipped_break_addr = pc;
138 pmai 1.1
139 rtoy 1.5 /*
140     * Replace the next instruction with a
141     * twllei r0, trap_AfterBreakpoint
142     */
143     displaced_after_inst = *++pc;
144     *pc = TWLLEI_R0(trap_AfterBreakpoint);
145     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
146    
147     sigreturn(scp);
148 pmai 1.1 }
149    
150 rtoy 1.7 #ifdef GENCGC
151     /*
152     * Return non-zero if the current instruction is an allocation trap
153     */
154     static int
155     allocation_trap_p(os_context_t * context)
156     {
157     int result;
158     unsigned int *pc;
159     unsigned inst;
160     unsigned opcode;
161     unsigned src;
162     unsigned dst;
163    
164     result = 0;
165    
166     /*
167     * First, the instruction has to be a TWLGE temp, NL3, which as the
168     * format.
169     * | 6| 5| 5 | 5 | 10|1| width
170     * |31|5 |dst|src| 4|0| field
171     */
172     pc = (unsigned int *) SC_PC(context);
173     inst = *pc;
174    
175     #if 0
176     fprintf(stderr, "allocation_trap_p at %p: inst = 0x%08x\n", pc, inst);
177     #endif
178    
179     opcode = inst >> 26;
180     src = (inst >> 11) & 0x1f;
181     dst = (inst >> 16) & 0x1f;
182     if ((opcode == 31) && (src == reg_NL3) && (5 == ((inst >> 21) & 0x1f))
183     && (4 == ((inst >> 1) & 0x3ff))) {
184     /*
185     * We got the instruction. Now, look back to make sure it was
186     * proceeded by what we expected. 2 instructions back should be
187     * an ADD or ADDI instruction.
188     */
189     unsigned int add_inst;
190    
191     add_inst = pc[-2];
192     #if 0
193     fprintf(stderr, " add inst at %p: inst = 0x%08x\n",
194     pc - 2, add_inst);
195     #endif
196     opcode = add_inst >> 26;
197     if ((opcode == 31) && (266 == ((add_inst >> 1) & 0x1ff))) {
198     return 1;
199     } else if ((opcode == 14)) {
200     return 1;
201     } else {
202     fprintf(stderr,
203     "Whoa! Got allocation trap not preceeded by an ADD or ADDI instruction: 0x%08x\n",
204     add_inst);
205     }
206     }
207     return 0;
208     }
209    
210     /*
211     * Use this function to enable the minimum number of signals we need
212     * when our trap handler needs to call Lisp code that might cons. For
213     * consing to work with gencgc, we need to be able to trap the SIGILL
214     * signal to perform allocation.
215     */
216     void
217 cshapiro 1.13 enable_some_signals(void)
218 rtoy 1.7 {
219     sigset_t sigs;
220    
221     #if 0
222     fprintf(stderr, "Enabling some signals\n");
223     #endif
224     #if 0
225     sigprocmask(SIG_SETMASK, &context->uc_sigmask, 0);
226     #else
227     sigemptyset(&sigs);
228     sigaddset(&sigs, SIGILL);
229     sigaddset(&sigs, SIGBUS);
230     sigprocmask(SIG_UNBLOCK, &sigs, NULL);
231     #endif
232     #if 0
233     fprintf(stderr, "Some signals enabled\n");
234     #endif
235     }
236    
237     void
238     handle_allocation_trap(os_context_t * context)
239     {
240     unsigned int *pc;
241     unsigned int inst;
242     unsigned int or_inst;
243     unsigned int target;
244     unsigned int opcode;
245     int size;
246     int immed;
247     boolean were_in_lisp;
248     char *memory;
249     sigset_t block;
250    
251     target = 0;
252     size = 0;
253    
254     #if 0
255     fprintf(stderr, "In handle_allocation_trap\n");
256     #endif
257     /*
258     * I don't think it's possible for us NOT to be in lisp when we get
259     * here. Remove this later?
260     */
261     were_in_lisp = !foreign_function_call_active;
262    
263     if (were_in_lisp) {
264     fake_foreign_function_call(context);
265     } else {
266     fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
267     }
268    
269     /*
270     * Look at current instruction: TWNE temp, NL3. We're here because
271     * temp > NL3 and temp is the end of the allocation, and NL3 is
272     * current-region-end-addr.
273     *
274     * We need to adjust temp and alloc-tn.
275     */
276    
277     pc = (unsigned int *) SC_PC(context);
278     inst = pc[0];
279     target = (inst >> 16) & 0x1f;
280    
281     #if 0
282     fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
283     fprintf(stderr, " trap inst = 0x%08x\n", inst);
284     fprintf(stderr, " target reg = %s\n", lisp_register_names[target]);
285     #endif
286     /*
287     * Go back and look at the add/addi instruction. The second src arg
288     * is the size of the allocation. Get it and call alloc to allocate
289     * new space.
290     */
291     inst = pc[-2];
292     opcode = inst >> 26;
293     #if 0
294     fprintf(stderr, " add inst = 0x%08x, opcode = %d\n", inst, opcode);
295     #endif
296     if (opcode == 14) {
297     /*
298     * ADDI temp-tn, alloc-tn, size
299     *
300     * Extract the size
301     */
302     size = (inst & 0xffff);
303     } else if (opcode == 31) {
304     /*
305     * ADD temp-tn, alloc-tn, size-tn
306     *
307     * Extract the size
308     */
309     int reg;
310    
311     reg = (inst >> 11) & 0x1f;
312     #if 0
313     fprintf(stderr, " add, reg = %s\n", lisp_register_names[reg]);
314     #endif
315     size = SC_REG(context, reg);
316     }
317     #if 0
318     fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
319     #endif
320    
321     /*
322     * Well, maybe not. sigill_handler probably shouldn't be unblocking
323     * all signals. So, let's enable just the signals we need. Since
324     * alloc might call GC, we need to have SIGILL enabled so we can do
325     * allocation. Do we need more?
326     */
327     enable_some_signals();
328    
329     #if 0
330     fprintf(stderr, "Ready to alloc\n");
331     fprintf(stderr, "free_pointer = 0x%08x\n",
332     current_dynamic_space_free_pointer);
333     #endif
334     /*
335     * alloc-tn was incremented by size. Need to decrement it by size to restore it's original value.
336     */
337     current_dynamic_space_free_pointer =
338     (lispobj *) ((long) current_dynamic_space_free_pointer - size);
339     #if 0
340     fprintf(stderr, "free_pointer = 0x%08x new\n",
341     current_dynamic_space_free_pointer);
342     #endif
343    
344     memory = (char *) alloc(size);
345    
346     #if 0
347     fprintf(stderr, "alloc returned %p\n", memory);
348     fprintf(stderr, "free_pointer = 0x%08x\n",
349     current_dynamic_space_free_pointer);
350     #endif
351    
352     /*
353     * The allocation macro wants the result to point to the end of the
354     * object!
355     */
356     memory += size;
357     #if 0
358     fprintf(stderr, "object end at %p\n", memory);
359     #endif
360     SC_REG(context, target) = (unsigned long) memory;
361     SC_REG(context, reg_ALLOC) =
362     (unsigned long) current_dynamic_space_free_pointer;
363    
364     if (were_in_lisp) {
365     undo_fake_foreign_function_call(context);
366     }
367    
368    
369     }
370     #endif
371    
372 rtoy 1.5 static void
373 pmai 1.1 sigill_handler(HANDLER_ARGS)
374     {
375 rtoy 1.5 int badinst;
376     int opcode;
377    
378     sigprocmask(SIG_SETMASK, &context->uc_sigmask, 0);
379     opcode = *((int *) SC_PC(context));
380 pmai 1.1
381 rtoy 1.3 #if 0
382 rtoy 1.5 printf("SIGILL entry: opcode = 0x%08x\n", opcode);
383     fflush(stdout);
384 rtoy 1.3 #endif
385    
386 rtoy 1.5 if (opcode == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))) {
387     /* Got a twnei reg_NL3,0 - check for deferred interrupt */
388 rtoy 1.4 #if 1
389 rtoy 1.5 /* Clear the pseudo-atomic-interrupted bit */
390     SC_REG(context, reg_ALLOC) &= ~1;
391 rtoy 1.4 #else
392 rtoy 1.5 (SC_REG(context, reg_ALLOC) -= PSEUDO_ATOMIC_INTERRUPTED_BIAS);
393 rtoy 1.4 #endif
394 rtoy 1.5 arch_skip_instruction(context);
395     interrupt_handle_pending(context);
396 pmai 1.1 #ifdef DARWIN
397 rtoy 1.5 /* Work around G5 bug; fix courtesy gbyers via chandler */
398     sigreturn(context);
399 pmai 1.1 #endif
400 rtoy 1.5 return;
401     }
402    
403 rtoy 1.8 /* Is this an allocation trap? */
404 rtoy 1.7 #ifdef GENCGC
405     if (allocation_trap_p(context)) {
406 rtoy 1.8 handle_allocation_trap(context);
407     arch_skip_instruction(context);
408 rtoy 1.7 #ifdef DARWIN
409 rtoy 1.8 sigreturn(context);
410 rtoy 1.7 #endif
411 rtoy 1.8 return;
412 rtoy 1.7 }
413     #endif
414    
415 rtoy 1.5 if ((opcode >> 16) == ((3 << 10) | (6 << 5))) {
416     /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
417     int trap = opcode & 0x1f, extra = (opcode >> 5) & 0x1f;
418 pmai 1.1
419 rtoy 1.3 #if 0
420 rtoy 1.5 printf("SIGILL: TWLLEI, code = %d\n", trap);
421     fflush(stdout);
422 rtoy 1.3 #endif
423    
424 rtoy 1.5 switch (trap) {
425     case trap_Halt:
426     fake_foreign_function_call(context);
427     lose("%%primitive halt called; the party is over.\n");
428    
429     case trap_Error:
430     case trap_Cerror:
431     interrupt_internal_error(signal, code, context,
432     trap == trap_Cerror);
433     break;
434    
435     case trap_PendingInterrupt:
436     arch_skip_instruction(context);
437     interrupt_handle_pending(context);
438     break;
439 pmai 1.1
440 rtoy 1.5 case trap_Breakpoint:
441 rtoy 1.3 #if 0
442 rtoy 1.5 printf("trap_Breakpoint\n");
443     fflush(stdout);
444 rtoy 1.3 #endif
445 rtoy 1.5 handle_breakpoint(signal, code, context);
446     break;
447    
448     case trap_FunctionEndBreakpoint:
449 rtoy 1.3 #if 0
450 rtoy 1.5 printf("trap_FunctionEndBreakpoint\n");
451     fflush(stdout);
452     #endif
453     SC_PC(context) =
454     (int) handle_function_end_breakpoint(signal, code, context);
455     break;
456    
457     case trap_AfterBreakpoint:
458 rtoy 1.6 #if 0
459     fprintf(stderr, "trap_AfterBreakpoint: break_addr = %p\n",
460     skipped_break_addr);
461 rtoy 1.8 fprintf(stderr, " CSP = %p\n",
462     (void *) SC_REG(context, reg_CSP));
463     fprintf(stderr, " CFP = %p\n",
464     (void *) SC_REG(context, reg_CFP));
465     fprintf(stderr, " OCFP = %p\n",
466     (void *) SC_REG(context, reg_OCFP));
467     #endif
468 rtoy 1.5 /* Put our breakpoint instruction back in */
469     *skipped_break_addr = TWLLEI_R0(trap_Breakpoint);
470     skipped_break_addr = NULL;
471     *(unsigned long *) SC_PC(context) = displaced_after_inst;
472     context->uc_sigmask = orig_sigmask;
473    
474     os_flush_icache((os_vm_address_t) SC_PC(context),
475     sizeof(unsigned long));
476     break;
477    
478     default:
479     interrupt_handle_now(signal, code, context);
480     break;
481     }
482     #ifdef DARWIN
483     /* Work around G5 bug; fix courtesy gbyers via chandler */
484     sigreturn(context);
485 rtoy 1.3 #endif
486 rtoy 1.5 return;
487 pmai 1.1 }
488 rtoy 1.5 if (((opcode >> 26) == 3) && (((opcode >> 21) & 31) == 24)) {
489     interrupt_internal_error(signal, code, context, 0);
490 pmai 1.1 #ifdef DARWIN
491 rtoy 1.5 /* Work around G5 bug; fix courtesy gbyers via chandler */
492     sigreturn(context);
493 pmai 1.1 #endif
494 rtoy 1.5 return;
495     }
496    
497     interrupt_handle_now(signal, code, context);
498 pmai 1.1 #ifdef DARWIN
499     /* Work around G5 bug; fix courtesy gbyers via chandler */
500     sigreturn(context);
501     #endif
502     }
503    
504    
505 rtoy 1.5 void
506 cshapiro 1.13 arch_install_interrupt_handlers(void)
507 pmai 1.1 {
508 rtoy 1.5 interrupt_install_low_level_handler(SIGILL, sigill_handler);
509     interrupt_install_low_level_handler(SIGTRAP, sigill_handler);
510 pmai 1.1 }
511    
512    
513 rtoy 1.5 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
514 pmai 1.1
515 rtoy 1.5 lispobj
516     funcall0(lispobj function)
517 pmai 1.1 {
518     lispobj *args = current_control_stack_pointer;
519    
520     return call_into_lisp(function, args, 0);
521     }
522    
523 rtoy 1.5 lispobj
524     funcall1(lispobj function, lispobj arg0)
525 pmai 1.1 {
526     lispobj *args = current_control_stack_pointer;
527    
528     current_control_stack_pointer += 1;
529     args[0] = arg0;
530    
531     return call_into_lisp(function, args, 1);
532     }
533    
534 rtoy 1.5 lispobj
535     funcall2(lispobj function, lispobj arg0, lispobj arg1)
536 pmai 1.1 {
537     lispobj *args = current_control_stack_pointer;
538    
539     current_control_stack_pointer += 2;
540     args[0] = arg0;
541     args[1] = arg1;
542    
543     return call_into_lisp(function, args, 2);
544     }
545    
546 rtoy 1.5 lispobj
547     funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
548 pmai 1.1 {
549     lispobj *args = current_control_stack_pointer;
550    
551     current_control_stack_pointer += 3;
552     args[0] = arg0;
553     args[1] = arg1;
554     args[2] = arg2;
555    
556     return call_into_lisp(function, args, 3);
557     }
558    
559     void
560     ppc_flush_icache(os_vm_address_t address, os_vm_size_t length)
561     {
562 rtoy 1.5 os_vm_address_t end =
563     (os_vm_address_t) ((int) (address + length + (32 - 1)) & ~(32 - 1));
564     extern void ppc_flush_cache_line(os_vm_address_t);
565    
566     while (address < end) {
567     ppc_flush_cache_line(address);
568     address += 32;
569     }
570 pmai 1.1 }
571 rtoy 1.2
572     #ifdef LINKAGE_TABLE
573     /* Linkage tables for PowerPC
574     *
575     * Linkage entry size is 16, because we need at least 4 instructions to
576     * implement a jump.
577     */
578    
579     /*
580     * This had better match lisp::target-foreign-linkage-entry-size in
581     * ppco/parms.lisp! Each entry is 6 instructions long, so at least
582     * 24 bytes.
583     */
584     #ifndef LinkageEntrySize
585     #define LinkageEntrySize (8*4)
586     #endif
587    
588     /*
589     * Define the registers to use in the linkage jump table. Can be the
590     * same. Some care must be exercised when choosing these. It has to be
591     * a register that is not otherwise being used. reg_NFP is a good
592     * choice. call_into_c trashes reg_NFP without preserving it, so we can
593     * trash it in the linkage jump table.
594     */
595     #define LINKAGE_TEMP_REG reg_NFP
596     #define LINKAGE_ADDR_REG reg_A0
597    
598     /*
599     * Insert the necessary jump instructions at the given address.
600     */
601     void
602 rtoy 1.5 arch_make_jump_entry(void *reloc_addr, void *target_addr)
603 rtoy 1.2 {
604 rtoy 1.5 /*
605     * Make JMP to function entry.
606     *
607     * The instruction sequence is:
608     *
609     * addis temp, 0, (hi part of reloc)
610     * ori temp, temp, (lo part of reloc)
611     * addis addr, 0, (hi part of addr)
612     * ori addr, addr, (low part of addr)
613     * mtctr addr
614     * bctr
615     *
616     */
617     int *inst_ptr;
618     unsigned long hi; /* Top 16 bits of address */
619     unsigned long lo; /* Low 16 bits of address */
620     unsigned int inst;
621    
622     inst_ptr = (int *) reloc_addr;
623    
624     /*
625     * Split the target address into hi and lo parts for the addis/ori
626     * instructions.
627     */
628     hi = (unsigned long) reloc_addr;
629     lo = hi & 0xffff;
630     hi >>= 16;
631    
632     /*
633     * addis 3, 0, (hi part)
634     */
635     inst = (15 << 26) | (LINKAGE_ADDR_REG << 21) | (0 << 16) | hi;
636     *inst_ptr++ = inst;
637    
638     /*
639     * ori 3, 3, (lo part)
640     */
641    
642     inst =
643     (24 << 26) | (LINKAGE_ADDR_REG << 21) | (LINKAGE_ADDR_REG << 16) | lo;
644     *inst_ptr++ = inst;
645    
646     /*
647     * Split the target address into hi and lo parts for the addis/ori
648     * instructions.
649     */
650    
651     hi = (unsigned long) target_addr;
652     lo = hi & 0xffff;
653     hi >>= 16;
654    
655     /*
656     * addis 13, 0, (hi part)
657     */
658    
659     inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
660     *inst_ptr++ = inst;
661    
662     /*
663     * ori 13, 13, (lo part)
664     */
665    
666     inst =
667     (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
668     *inst_ptr++ = inst;
669    
670     /*
671     * mtctr 13
672     */
673    
674     inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
675     *inst_ptr++ = inst;
676    
677     /*
678     * bctr
679     */
680    
681     inst = (19 << 26) | (20 << 21) | (528 << 1);
682     *inst_ptr++ = inst;
683    
684    
685     *inst_ptr++ = inst;
686    
687     os_flush_icache((os_vm_address_t) reloc_addr,
688     (char *) inst_ptr - (char *) reloc_addr);
689     }
690    
691     void
692     arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
693     {
694     int *reloc_addr = (int *) (FOREIGN_LINKAGE_SPACE_START
695    
696     + linkage_entry * LinkageEntrySize);
697    
698     if (type == 1) { /* code reference */
699     arch_make_jump_entry(reloc_addr, target_addr);
700     } else if (type == 2) {
701     *(unsigned long *) reloc_addr = (unsigned long) target_addr;
702 rtoy 1.2 }
703     }
704    
705     /* Make a the entry a jump to resolve_linkage_tramp. */
706    
707     extern void resolve_linkage_tramp(void);
708    
709 rtoy 1.5 void
710     arch_make_lazy_linkage(long linkage_entry)
711 rtoy 1.2 {
712 rtoy 1.5 arch_make_linkage_entry(linkage_entry, (void *) resolve_linkage_tramp, 1);
713 rtoy 1.2 }
714    
715     /* Get linkage entry. We're given the return address which should be
716     the address of the jmpl instruction (2nd word) of the linkage
717     entry. Figure out which entry this address belong to. */
718    
719 rtoy 1.5 long
720     arch_linkage_entry(unsigned long retaddr)
721 rtoy 1.2 {
722 rtoy 1.5 return (retaddr - (FOREIGN_LINKAGE_SPACE_START))
723     / LinkageEntrySize;
724 rtoy 1.2 }
725     #endif
726 rtoy 1.12
727     int ieee754_rem_pio2(double x, double *y0, double *y1)
728     {
729     extern int __ieee754_rem_pio2(double x, double *y);
730    
731     double y[2];
732     int n;
733    
734     n = __ieee754_rem_pio2(x, y);
735     *y0 = y[0];
736     *y1 = y[1];
737    
738     return n;
739     }

  ViewVC Help
Powered by ViewVC 1.1.5