1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Christian Thalinger
29 Changes: Edwin Steiner
31 $Id: md.c 7848 2007-05-01 21:40:26Z pm $
43 #include "vm/jit/s390/md-abi.h"
45 #if defined(ENABLE_THREADS)
46 # include "threads/threads-common.h"
47 # include "threads/native/threads.h"
50 #include "vm/exceptions.h"
51 #include "vm/signallocal.h"
52 #include "vm/jit/asmpart.h"
53 #include "vm/jit/stacktrace.h"
55 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
56 #include "vmcore/options.h" /* XXX debug */
57 #include "vm/jit/disass.h" /* XXX debug */
60 #include "vm/jit/codegen-common.h"
61 #include "vm/jit/s390/codegen.h"
64 #define OOPS() assert(0);
66 /* prototypes *****************************************************************/
68 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
70 void md_dump_context(u1 *pc, mcontext_t *mc);
72 /* md_init *********************************************************************
74 Do some machine dependent initialization.
76 *******************************************************************************/
82 act.sa_sigaction = md_signal_handler_sigill;
83 act.sa_flags = SA_NODEFER | SA_SIGINFO;
85 if (sigaction(SIGILL, &act, NULL) == -1) {
86 vm_abort("%s: error registering SIGILL signal handler.", __FUNCTION__);
90 /* md_dump_context ************************************************************
92 Logs the machine context
94 *******************************************************************************/
96 void md_dump_context(u1 *pc, mcontext_t *mc) {
104 log_println("Dumping context.");
106 log_println("Program counter: 0x%08X", pc);
108 #if defined(ENABLE_DISASSEMBLER)
109 log_println("Printing instruction at program counter:");
113 log_println("General purpose registers:");
115 for (i = 0; i < 16; i++) {
116 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
119 log_println("Floating point registers:");
121 for (i = 0; i < 16; i++) {
122 freg.fr.d = mc->fpregs.fprs[i].d;
123 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
126 #if defined(ENABLE_THREADS)
127 log_println("Dumping the current stacktrace:");
128 threads_print_stacktrace();
133 /* md_signal_handler_sigsegv ***************************************************
135 NullPointerException signal handler for hardware null pointer
138 *******************************************************************************/
140 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
150 java_objectheader *e;
154 _uc = (ucontext_t *) _p;
155 _mc = &_uc->uc_mcontext;
157 xpc = (u1 *)_mc->psw.addr;
159 /* Check opcodes and verify it is a null pointer exception */
164 base = (xpc[2] >> 4) & 0xF;
167 } else if (_mc->gregs[base] == 0) {
177 md_dump_context(xpc, _mc);
179 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
182 pv = (u1 *)_mc->gregs[REG_PV];
183 sp = (u1 *)_mc->gregs[REG_SP];
185 type = EXCEPTION_HARDWARE_NULLPOINTER;
188 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
190 _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
191 _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
192 _mc->psw.addr = (ptrint) asm_handle_exception;
195 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
204 java_objectheader *e;
207 _uc = (ucontext_t *) _p;
208 _mc = &_uc->uc_mcontext;
209 xpc = ra = siginfo->si_addr;
211 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
213 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
215 /* bits 7-4 contain a register holding a value */
216 reg = (xpc[1] >> 4) & 0xF;
218 /* bits 3-0 designate the exception type */
221 pv = (u1 *)_mc->gregs[REG_PV];
222 sp = (u1 *)_mc->gregs[REG_SP];
223 val = (ptrint)_mc->gregs[reg];
225 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
227 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
228 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
229 _mc->psw.addr = (ptrint) asm_handle_exception;
233 md_dump_context(xpc, _mc);
235 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
239 /* md_signal_handler_sigfpe ****************************************************
241 ArithmeticException signal handler for hardware divide by zero
244 *******************************************************************************/
246 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
258 java_objectheader *e;
260 _uc = (ucontext_t *) _p;
261 _mc = &_uc->uc_mcontext;
263 /* Instruction that raised signal */
264 xpc = siginfo->si_addr;
268 if (xpc[0] == 0x1D) { /* DR */
270 r1 = (xpc[1] >> 4) & 0xF;
274 (_mc->gregs[r1] == 0xFFFFFFFF) &&
275 (_mc->gregs[r1 + 1] == 0x80000000) &&
276 (_mc->gregs[r2] == 0xFFFFFFFF)
278 /* handle special case */
279 /* next instruction */
280 pc = (u1 *)_mc->psw.addr;
284 _mc->gregs[r1 + 1] = 0x80000000;
285 /* continue at next instruction */
286 _mc->psw.addr = (ptrint) pc;
289 } else if (_mc->gregs[r2] == 0) {
292 pv = (u1 *)_mc->gregs[REG_PV];
293 sp = (u1 *)_mc->gregs[REG_SP];
296 type = EXCEPTION_HARDWARE_ARITHMETIC;
299 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
301 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
302 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
303 _mc->psw.addr = (ptrint) asm_handle_exception;
309 /* Could not handle signal */
312 md_dump_context(xpc, _mc);
314 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
318 /* md_signal_handler_sigusr2 ***************************************************
320 Signal handler for profiling sampling.
322 *******************************************************************************/
324 #if defined(ENABLE_THREADS)
325 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
334 _uc = (ucontext_t *) _p;
335 _mc = &_uc->uc_mcontext;
337 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
338 different to the ones in <ucontext.h>. */
340 pc = (u1 *) _mc->psw.addr;
347 #if defined(ENABLE_THREADS)
348 void thread_restartcriticalsection(ucontext_t *_uc)
353 _mc = &_uc->uc_mcontext;
355 pc = critical_find_restart_point((void *) _mc->psw.addr);
358 _mc->psw.addr = (ptrint) pc;
363 /* md_codegen_patch_branch *****************************************************
365 Back-patches a branch instruction.
367 *******************************************************************************/
369 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
373 s4 disp; /* branch displacement */
375 /* calculate the patch position */
377 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
379 /* Calculate the branch displacement. */
381 disp = targetmpc - branchmpc;
382 disp += 4; /* size of branch */
383 disp /= 2; /* specified in halfwords */
385 ASSERT_VALID_BRANCH(disp);
387 /* patch the branch instruction before the mcodeptr */
389 mcodeptr[-1] |= (disp & 0xFFFF);
393 /* md_stacktrace_get_returnaddress *********************************************
395 Returns the return address of the current stackframe, specified by
396 the passed stack pointer and the stack frame size.
398 *******************************************************************************/
400 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
404 /* on S390 the return address is located on the top of the stackframe */
406 ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
412 /* md_get_method_patch_address *************************************************
414 Gets the patch address of the currently compiled method. The offset
415 is extracted from the load instruction(s) before the jump and added
416 to the right base address (PV or REG_METHODPTR).
418 INVOKESTATIC/SPECIAL:
420 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
422 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
424 0x7748d7ba: 0d ed basr %r14,%r13
429 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
431 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
433 0x7748d832: 0d ed basr %r14,%r13
439 last 2 instructions the same as in invokevirtual
441 *******************************************************************************/
443 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
447 u1 *pa; /* patch address */
449 /* go back to the load before the call instruction */
451 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
453 /* get the base register of the load */
457 /* check for the different calls */
459 if (base == 0xd) { /* pv relative */
460 /* INVOKESTATIC/SPECIAL */
462 /* the offset is in the load before the load */
464 offset = *((s2 *) (ra - 2));
466 /* add the offset to the procedure vector */
468 pa = sfi->pv + offset;
470 else if (base == 0xc) { /* mptr relative */
471 /* INVOKEVIRTUAL/INTERFACE */
473 offset = *((u2 *)(ra + 2)) & 0xFFF;
475 /* add offset to method pointer */
480 /* catch any problems */
488 /* md_codegen_get_pv_from_pc ***************************************************
490 On this architecture just a wrapper function to
491 codegen_get_pv_from_pc.
493 *******************************************************************************/
495 u1 *md_codegen_get_pv_from_pc(u1 *ra)
499 /* Get the start address of the function which contains this
500 address from the method table. */
502 pv = codegen_get_pv_from_pc(ra);
508 /* md_cacheflush ***************************************************************
510 Calls the system's function to flush the instruction and data
513 *******************************************************************************/
515 void md_cacheflush(u1 *addr, s4 nbytes)
521 /* md_icacheflush **************************************************************
523 Calls the system's function to flush the instruction cache.
525 *******************************************************************************/
527 void md_icacheflush(u1 *addr, s4 nbytes)
533 /* md_dcacheflush **************************************************************
535 Calls the system's function to flush the data cache.
537 *******************************************************************************/
539 void md_dcacheflush(u1 *addr, s4 nbytes)
545 /* md_patch_replacement_point **************************************************
547 Patch the given replacement point.
549 *******************************************************************************/
551 void md_patch_replacement_point(rplpoint *rp)
555 /* XXX this is probably unsafe! */
557 /* save the current machine code */
558 mcode = *(u8*)rp->pc;
560 /* write spinning instruction */
561 *(u2*)(rp->pc) = 0xebfe;
564 rp->pc[4] = (rp->mcode >> 32);
566 /* write first word */
567 *(u4*)(rp->pc) = (u4) rp->mcode;
569 /* store saved mcode */
572 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
580 /* XXX if required asm_cacheflush(rp->pc,8); */
584 * These are local overrides for various environment variables in Emacs.
585 * Please do not remove this and leave it at the end of the file, where
586 * Emacs will automagically detect them.
587 * ---------------------------------------------------------------------
590 * indent-tabs-mode: t
594 * vim:noexpandtab:sw=4:ts=4: