Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / sparc-arch.c
CommitLineData
82a2bc67 1/*
2
82a2bc67 3 This code was written as part of the CMU Common Lisp project at
4 Carnegie Mellon University, and has been placed in the public domain.
5
6*/
7
36232b68 8#include <stdio.h>
571df509 9#ifdef SOLARIS
10#include <sys/trap.h>
11#else
36232b68 12#include <machine/trap.h>
571df509 13#endif
36232b68 14
571df509 15#include "arch.h"
36232b68 16#include "lisp.h"
17#include "internals.h"
18#include "globals.h"
19#include "validate.h"
20#include "os.h"
36232b68 21#include "lispregs.h"
22#include "signal.h"
23#include "interrupt.h"
015a25b6 24#include "gencgc.h"
25#include "breakpoint.h"
26#include "interr.h"
36232b68 27
9a8c1c2f 28char *
cb786538 29arch_init(fpu_mode_t mode)
36232b68 30{
571df509 31 return 0;
36232b68 32}
33
9a8c1c2f 34os_vm_address_t
35arch_get_bad_addr(HANDLER_ARGS)
36232b68 36{
015a25b6 37 unsigned int badinst;
36232b68 38 int rs1;
cba6f60b
RT
39 os_context_t *os_context = (os_context_t *) context;
40
36232b68 41 /* On the sparc, we have to decode the instruction. */
42
43 /* Make sure it's not the pc thats bogus, and that it was lisp code */
44 /* that caused the fault. */
cba6f60b
RT
45 if ((SC_PC(os_context) & 3) != 0 ||
46 ((SC_PC(os_context) < READ_ONLY_SPACE_START ||
47 SC_PC(os_context) >= READ_ONLY_SPACE_START + read_only_space_size) &&
48 ((lispobj *) SC_PC(os_context) < current_dynamic_space &&
49 (lispobj *) SC_PC(os_context) >=
9a8c1c2f 50 current_dynamic_space + dynamic_space_size))) return 0;
36232b68 51
cba6f60b 52 badinst = *(unsigned int *) SC_PC(os_context);
36232b68 53
54 if ((badinst >> 30) != 3)
55 /* All load/store instructions have op = 11 (binary) */
571df509 56 return 0;
36232b68 57
9a8c1c2f 58 rs1 = (badinst >> 14) & 0x1f;
36232b68 59
9a8c1c2f 60 if (badinst & (1 << 13)) {
36232b68 61 /* r[rs1] + simm(13) */
62 int simm13 = badinst & 0x1fff;
63
9a8c1c2f 64 if (simm13 & (1 << 12))
65 simm13 |= -1 << 13;
36232b68 66
cba6f60b 67 return (os_vm_address_t) (SC_REG(os_context, rs1) + simm13);
9a8c1c2f 68 } else {
36232b68 69 /* r[rs1] + r[rs2] */
70 int rs2 = badinst & 0x1f;
71
cba6f60b 72 return (os_vm_address_t) (SC_REG(os_context, rs1) + SC_REG(os_context, rs2));
36232b68 73 }
74
75}
76
9a8c1c2f 77void
cba6f60b 78arch_skip_instruction(os_context_t *context)
36232b68 79{
80 /* Skip the offending instruction */
571df509 81 SC_PC(context) = SC_NPC(context);
82 SC_NPC(context) += 4;
36232b68 83}
84
9a8c1c2f 85unsigned char *
86arch_internal_error_arguments(struct sigcontext *scp)
36232b68 87{
9a8c1c2f 88 return (unsigned char *) (SC_PC(scp) + 4);
36232b68 89}
90
9a8c1c2f 91boolean
92arch_pseudo_atomic_atomic(struct sigcontext *scp)
36232b68 93{
263f0353 94 return (SC_REG(scp, reg_ALLOC) & pseudo_atomic_Value);
36232b68 95}
96
9a8c1c2f 97void
98arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
36232b68 99{
263f0353 100 SC_REG(scp, reg_ALLOC) |= pseudo_atomic_InterruptedValue;
36232b68 101}
102
9a8c1c2f 103unsigned long
104arch_install_breakpoint(void *pc)
36232b68 105{
9a8c1c2f 106 unsigned int *ptr = (unsigned int *) pc;
015a25b6 107 unsigned int result = *ptr;
9a8c1c2f 108
36232b68 109 *ptr = trap_Breakpoint;
015a25b6 110 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
9a8c1c2f 111
36232b68 112 return result;
113}
114
9a8c1c2f 115void
116arch_remove_breakpoint(void *pc, unsigned long orig_inst)
36232b68 117{
9a8c1c2f 118 *(unsigned int *) pc = (unsigned int) orig_inst;
119 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
36232b68 120}
121
015a25b6 122static unsigned int *skipped_break_addr, displaced_after_inst;
9a8c1c2f 123
571df509 124static sigset_t orig_sigmask;
36232b68 125
9a8c1c2f 126void
127arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
36232b68 128{
9a8c1c2f 129 unsigned int *pc = (unsigned int *) SC_PC(scp);
130 unsigned int *npc = (unsigned int *) SC_NPC(scp);
571df509 131
571df509 132 orig_sigmask = scp->uc_sigmask;
133 sigemptyset(&scp->uc_sigmask);
134 FILLBLOCKSET(&scp->uc_sigmask);
36232b68 135
136 *pc = orig_inst;
015a25b6 137 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
9a8c1c2f 138
36232b68 139 skipped_break_addr = pc;
140 displaced_after_inst = *npc;
141 *npc = trap_AfterBreakpoint;
015a25b6 142 os_flush_icache((os_vm_address_t) npc, sizeof(unsigned int));
36232b68 143
571df509 144#ifdef SOLARIS
145 /* XXX never tested */
146 setcontext(scp);
147#else
36232b68 148 sigreturn(scp);
571df509 149#endif
36232b68 150}
151
af867264 152/*
153 * Look at the instruction at address PC and see if it's a trap
154 * instruction with an immediate value. If so, set trapno to the trap
155 * number, and return non-zero. If it's not a trap instruction,
156 * return 0.
157 */
9a8c1c2f 158boolean
159trap_inst_p(unsigned int *pc, int *trapno)
af867264 160{
9a8c1c2f 161 unsigned int trap_inst;
162
163 trap_inst = *pc;
164
165 if (((trap_inst >> 30) == 2)
166 && (((trap_inst >> 19) & 0x3f) == 0x3a)
167 && (((trap_inst >> 14) & 0x1f) == reg_ZERO)
168 && (((trap_inst >> 13) & 1) == 1)) {
169 /*
170 * Got a trap instruction with immediate trap value.
171 * Get the value and return.
172 */
173 *trapno = (trap_inst & 0x3f);
174
175 return 1;
176 } else {
177 *trapno = -1;
178 return 0;
af867264 179 }
180}
181
182
9a8c1c2f 183static int
184pseudo_atomic_trap_p(struct sigcontext *context)
36232b68 185{
9a8c1c2f 186 unsigned int *pc;
187 unsigned int badinst;
188 int trapno;
189 int result;
190
191
192 pc = (unsigned int *) SC_PC(context);
193 badinst = *pc;
194 result = 0;
195
196 /*
197 * Check to see if the current instruction is a trap #16. We check
198 * to make sure this instruction was a trap instruction with rs1 = 0
199 * and a software trap number (immediate value) of 16.
200 */
201 if (trap_inst_p(pc, &trapno) && (trapno == trap_PseudoAtomic)) {
202 unsigned int previnst;
203
204 previnst = pc[-1];
205 /*
206 * Check to see if the previous instruction was an andcc alloc-tn,
207 * pseudo_atomic_InterruptedValue, zero-tn instruction.
208 */
209 if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
210 && (((previnst >> 14) & 0x1f) == reg_ALLOC)
211 && (((previnst >> 25) & 0x1f) == reg_ZERO)
212 && (((previnst >> 13) & 1) == 1)
213 && ((previnst & 0x1fff) == pseudo_atomic_InterruptedValue)) {
214 result = 1;
215 } else {
216 fprintf(stderr,
217 "Oops! Got a pseudo atomic trap without a preceeding andcc!\n");
218 }
cbc96305 219 }
9a8c1c2f 220 return result;
cbc96305 221}
222
af867264 223#ifdef GENCGC
224/*
225 * Return non-zero if the instruction is a trap 31 instruction
226 */
227
9a8c1c2f 228boolean
229allocation_trap_p(struct sigcontext * context)
af867264 230{
9a8c1c2f 231 int result;
232 unsigned int *pc;
233 unsigned int or_inst;
234 int trapno;
235
236 result = 0;
237
238 /*
239 * Make sure this is a trap 31 instruction preceeded by an OR
240 * instruction.
241 */
242
243 pc = (unsigned int *) SC_PC(context);
244
245 if (trap_inst_p(pc, &trapno) && (trapno == trap_Allocation)) {
246 /* Got the trap. Is it preceeded by an OR instruction or SUB
247 instruction? */
248 or_inst = pc[-1];
249 if ((((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) ||
250 (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4))) {
251 result = 1;
252 } else {
253 fprintf(stderr,
254 "Whoa!!! Got an allocation trap not preceeded by an OR inst: 0x%08x!\n",
255 or_inst);
256 }
af867264 257 }
258
9a8c1c2f 259 return result;
af867264 260}
261#endif
262
263#if 0
264/* Pop the stack frame that build_fake_control_stack_frame makes */
9a8c1c2f 265static void
266pop_fake_control_stack_frame(struct sigcontext *context)
af867264 267{
9a8c1c2f 268 current_control_frame_pointer = (lispobj *) SC_REG(context, reg_CFP);
269 SC_REG(context, reg_OCFP) = current_control_frame_pointer[0];
270 SC_REG(context, reg_CODE) = current_control_frame_pointer[1];
271 SC_REG(context, reg_CSP) = SC_REG(context, reg_CFP);
272 SC_REG(context, reg_CFP) = SC_REG(context, reg_OCFP);
af867264 273}
274#endif
275
ba62ca95 276/*
277 * Use this function to enable the minimum number of signals we need
278 * when our trap handler needs to call Lisp code that might cons. For
279 * consing to work with gencgc, we need to be able to trap the SIGILL
280 * signal to perform allocation.
281 */
9a8c1c2f 282void
b8d0dfaf 283enable_some_signals(void)
ba62ca95 284{
285#ifdef GENCGC
9a8c1c2f 286 sigset_t sigs;
287
288 sigemptyset(&sigs);
289 sigaddset(&sigs, SIGILL);
290 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
ba62ca95 291#endif
292}
293
af867264 294#ifdef GENCGC
9a8c1c2f 295void
296handle_allocation_trap(struct sigcontext *context)
af867264 297{
9a8c1c2f 298 unsigned int *pc;
299 unsigned int or_inst;
300 int target;
301 int size;
302 int immed;
303 boolean were_in_lisp;
304 char *memory;
305 sigset_t block;
306
307 target = 0;
308 size = 0;
309
6779af26 310#if 0
9a8c1c2f 311 /*
312 * Block all blockable signals. Need to do this because
313 * sigill_handler enables the signals. When the handler returns,
314 * signals should be enabled again, automatically.
315 */
316
317 sigemptyset(&block);
318 FILLBLOCKSET(&block);
319 sigprocmask(SIG_BLOCK, &block, 0);
6779af26 320#else
9a8c1c2f 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();
6779af26 328#endif
9a8c1c2f 329
330 pc = (unsigned int *) SC_PC(context);
331 or_inst = pc[-1];
332
333 /*
334 * The instruction before this trap instruction had better be an OR
335 * instruction or SUB instruction!
336 */
337
338 if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) {
339 /*
340 * An OR instruction. RS1 is the register we want to allocate
341 * to. RS2 (or an immediate) is the size.
342 */
343
344 target = (or_inst >> 14) & 0x1f;
345
346 immed = (or_inst >> 13) & 1;
347
348 if (immed == 1) {
349 size = or_inst & 0x1fff;
350 } else {
351 size = or_inst & 0x1f;
352 size = SC_REG(context, size);
353 }
354 } else if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4)) {
355 /*
356 * A SUB instruction. RD is the register to allocate to, RS2
357 * (or an immediate) is the size.
358 */
359
360 target = (or_inst >> 25) & 0x1f;
361 immed = (or_inst >> 13) & 1;
362 if (immed == 1) {
363 size = or_inst & 0x1fff;
364 } else {
365 size = or_inst & 0x1f;
366 size = SC_REG(context, size);
367 }
af867264 368 }
9a8c1c2f 369
370
371 /*
372 * I don't think it's possible for us NOT to be in lisp when we get
373 * here. Remove this later?
374 */
375 were_in_lisp = !foreign_function_call_active;
376
377 if (were_in_lisp) {
378 fake_foreign_function_call(context);
379 } else {
380 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
af867264 381 }
723055bb 382
9a8c1c2f 383 /*
384 * alloc-tn was incremented by size. If we get here, we need to
385 * decrement it by size to restore it's original value.
386 */
387 /* current_dynamic_space_free_pointer = (lispobj *) SC_REG(context, reg_ALLOC); */
388 current_dynamic_space_free_pointer =
389 (lispobj *) ((long) current_dynamic_space_free_pointer - size);
390
391 /*
392 * Allocate some memory, store the memory address in target.
393 */
af867264 394
395#if 0
9a8c1c2f 396 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
af867264 397#endif
55c3e8e3 398
9a8c1c2f 399 memory = (char *) alloc(size);
400 SC_REG(context, target) = (unsigned long) memory;
401 SC_REG(context, reg_ALLOC) =
402 (unsigned long) current_dynamic_space_free_pointer;
af867264 403
9a8c1c2f 404 if (were_in_lisp) {
405 undo_fake_foreign_function_call(context);
af867264 406 }
9a8c1c2f 407
af867264 408}
409#endif
36232b68 410
887ae1dd 411/*
412 * How to identify an illegal instruction trap and a trap instruction
413 * trap.
414 */
415#ifdef SOLARIS
416#define ILLTRAP_INST ILL_ILLOPC
417#define TRAP_INST(code) (CODE(code) == ILL_ILLTRP)
418#else
419#define ILLTRAP_INST T_UNIMP_INSTR
420#define TRAP_INST(code) ((CODE(code) >= T_SOFTWARE_TRAP + 16) && (CODE(code) < T_SOFTWARE_TRAP + 32))
421#endif
cbc96305 422
9a8c1c2f 423static void
424sigill_handler(HANDLER_ARGS)
cbc96305 425{
cba6f60b
RT
426 os_context_t *os_context = (os_context_t *) context;
427
571df509 428 SAVE_CONTEXT();
429
6779af26 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
cba6f60b 444 sigprocmask(SIG_SETMASK, &os_context->uc_sigmask, 0);
6779af26 445#endif
36232b68 446
9a8c1c2f 447 if (CODE(code) == ILLTRAP_INST) {
887ae1dd 448 int illtrap_code;
cbc96305 449 unsigned int inst;
cba6f60b 450 unsigned int *pc = (unsigned int *) (SC_PC(os_context));
36232b68 451
686f8394 452 inst = *pc;
36232b68 453
887ae1dd 454 illtrap_code = inst & 0x3fffff;
455
456 switch (illtrap_code) {
36232b68 457 case trap_PendingInterrupt:
cba6f60b
RT
458 arch_skip_instruction(os_context);
459 interrupt_handle_pending(os_context);
9a8c1c2f 460 break;
36232b68 461
462 case trap_Halt:
cba6f60b 463 fake_foreign_function_call(os_context);
9a8c1c2f 464 lose("%%primitive halt called; the party is over.\n");
36232b68 465
466 case trap_Error:
467 case trap_Cerror:
cba6f60b 468 interrupt_internal_error(signal, code, os_context,
9a8c1c2f 469 illtrap_code == trap_Cerror);
470 break;
36232b68 471
472 case trap_Breakpoint:
9a8c1c2f 473 enable_some_signals();
cba6f60b 474 handle_breakpoint(signal, CODE(code), os_context);
9a8c1c2f 475 break;
36232b68 476
477 case trap_FunctionEndBreakpoint:
9a8c1c2f 478 enable_some_signals();
cba6f60b 479 SC_PC(os_context) =
9a8c1c2f 480 (long) handle_function_end_breakpoint(signal, CODE(code),
cba6f60b
RT
481 os_context);
482 SC_NPC(os_context) = SC_PC(os_context) + 4;
9a8c1c2f 483 break;
36232b68 484
485 case trap_AfterBreakpoint:
9a8c1c2f 486 *skipped_break_addr = trap_Breakpoint;
487 skipped_break_addr = NULL;
cba6f60b
RT
488 *(unsigned long *) SC_PC(os_context) = displaced_after_inst;
489 os_context->uc_sigmask = orig_sigmask;
490 os_flush_icache((os_vm_address_t) SC_PC(os_context),
9a8c1c2f 491
492 sizeof(unsigned long));
493 break;
36232b68 494
3e309c44 495#ifdef trap_DynamicSpaceOverflowWarning
9a8c1c2f 496 case trap_DynamicSpaceOverflowWarning:
cba6f60b 497 arch_skip_instruction(os_context);
9a8c1c2f 498 enable_some_signals();
499 interrupt_handle_space_overflow(SymbolFunction
500 (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
cba6f60b 501 os_context);
9a8c1c2f 502 break;
3e309c44 503#endif
504#ifdef trap_DynamicSpaceOverflowError
9a8c1c2f 505 case trap_DynamicSpaceOverflowError:
cba6f60b 506 arch_skip_instruction(os_context);
9a8c1c2f 507 enable_some_signals();
508 interrupt_handle_space_overflow(SymbolFunction
509 (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
cba6f60b 510 os_context);
9a8c1c2f 511 break;
3e309c44 512#endif
36232b68 513 default:
cba6f60b 514 interrupt_handle_now(signal, code, os_context);
9a8c1c2f 515 break;
516 }
517 } else if (TRAP_INST(code)) {
cba6f60b 518 if (pseudo_atomic_trap_p(os_context)) {
9a8c1c2f 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). */
cba6f60b
RT
523 SC_REG(os_context, reg_ALLOC) &= ~lowtag_Mask;
524 arch_skip_instruction(os_context);
525 interrupt_handle_pending(os_context);
36232b68 526 }
af867264 527#ifdef GENCGC
cba6f60b 528 else if (allocation_trap_p(os_context)) {
9a8c1c2f 529 /* An allocation trap. Call the trap handler and then skip
530 this instruction */
cba6f60b
RT
531 handle_allocation_trap(os_context);
532 arch_skip_instruction(os_context);
9a8c1c2f 533 }
af867264 534#endif
9a8c1c2f 535 else {
cba6f60b 536 interrupt_internal_error(signal, code, os_context, FALSE);
9a8c1c2f 537 }
538 } else {
cba6f60b 539 interrupt_handle_now(signal, code, os_context);
9a8c1c2f 540 }
36232b68 541}
542
9a8c1c2f 543void
b8d0dfaf 544arch_install_interrupt_handlers(void)
36232b68 545{
9a8c1c2f 546 interrupt_install_low_level_handler(SIGILL, sigill_handler);
36232b68 547}
548
549
9a8c1c2f 550extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
36232b68 551
9a8c1c2f 552lispobj
553funcall0(lispobj function)
36232b68 554{
555 lispobj *args = current_control_stack_pointer;
556
557 return call_into_lisp(function, args, 0);
558}
559
9a8c1c2f 560lispobj
561funcall1(lispobj function, lispobj arg0)
36232b68 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
9a8c1c2f 571lispobj
572funcall2(lispobj function, lispobj arg0, lispobj arg1)
36232b68 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
9a8c1c2f 583lispobj
584funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
36232b68 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}
49fdb025 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.)
eb6ce575 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.
49fdb025 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 */
9a8c1c2f 646void *
647arch_make_jump_entry(void *reloc_addr, void *target_addr)
49fdb025 648{
9a8c1c2f 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;
49fdb025 701}
702
9a8c1c2f 703void
704arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
49fdb025 705{
9a8c1c2f 706 int *reloc_addr = (int *) (FOREIGN_LINKAGE_SPACE_START
49fdb025 707
9a8c1c2f 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;
49fdb025 714 }
715}
716
717/* Make a the entry a jump to resolve_linkage_tramp. */
718
719extern void resolve_linkage_tramp(void);
720
9a8c1c2f 721void
722arch_make_lazy_linkage(long linkage_entry)
49fdb025 723{
9a8c1c2f 724 arch_make_linkage_entry(linkage_entry, (void *) resolve_linkage_tramp, 1);
49fdb025 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
9a8c1c2f 731long
732arch_linkage_entry(unsigned long retaddr)
49fdb025 733{
9a8c1c2f 734 return (retaddr - (FOREIGN_LINKAGE_SPACE_START))
735 / LinkageEntrySize;
49fdb025 736}
737#endif /* LINKAGE_TABLE */