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 8027 2007-06-07 10:30:33Z michi $
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 /* md_dump_context ************************************************************
84 Logs the machine context
86 *******************************************************************************/
88 void md_dump_context(u1 *pc, mcontext_t *mc) {
96 log_println("Dumping context.");
98 log_println("Program counter: 0x%08X", pc);
100 #if defined(ENABLE_DISASSEMBLER)
101 log_println("Printing instruction at program counter:");
105 log_println("General purpose registers:");
107 for (i = 0; i < 16; i++) {
108 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
111 log_println("Floating point registers:");
113 for (i = 0; i < 16; i++) {
114 freg.fr.d = mc->fpregs.fprs[i].d;
115 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
118 #if defined(ENABLE_THREADS)
119 log_println("Dumping the current stacktrace:");
120 threads_print_stacktrace();
125 /* md_signal_handler_sigsegv ***************************************************
127 NullPointerException signal handler for hardware null pointer
130 *******************************************************************************/
132 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
142 java_objectheader *e;
146 _uc = (ucontext_t *) _p;
147 _mc = &_uc->uc_mcontext;
149 xpc = (u1 *)_mc->psw.addr;
151 /* Check opcodes and verify it is a null pointer exception */
156 base = (xpc[2] >> 4) & 0xF;
159 } else if (_mc->gregs[base] == 0) {
169 md_dump_context(xpc, _mc);
171 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
174 pv = (u1 *)_mc->gregs[REG_PV];
175 sp = (u1 *)_mc->gregs[REG_SP];
177 type = EXCEPTION_HARDWARE_NULLPOINTER;
180 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
182 _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
183 _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
184 _mc->psw.addr = (ptrint) asm_handle_exception;
187 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
196 java_objectheader *e;
199 _uc = (ucontext_t *) _p;
200 _mc = &_uc->uc_mcontext;
201 xpc = ra = siginfo->si_addr;
203 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
205 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
207 /* bits 7-4 contain a register holding a value */
208 reg = (xpc[1] >> 4) & 0xF;
210 /* bits 3-0 designate the exception type */
213 pv = (u1 *)_mc->gregs[REG_PV];
214 sp = (u1 *)_mc->gregs[REG_SP];
215 val = (ptrint)_mc->gregs[reg];
217 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
219 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
220 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
221 _mc->psw.addr = (ptrint) asm_handle_exception;
225 md_dump_context(xpc, _mc);
227 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
231 /* md_signal_handler_sigfpe ****************************************************
233 ArithmeticException signal handler for hardware divide by zero
236 *******************************************************************************/
238 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
250 java_objectheader *e;
252 _uc = (ucontext_t *) _p;
253 _mc = &_uc->uc_mcontext;
255 /* Instruction that raised signal */
256 xpc = siginfo->si_addr;
260 if (xpc[0] == 0x1D) { /* DR */
262 r1 = (xpc[1] >> 4) & 0xF;
266 (_mc->gregs[r1] == 0xFFFFFFFF) &&
267 (_mc->gregs[r1 + 1] == 0x80000000) &&
268 (_mc->gregs[r2] == 0xFFFFFFFF)
270 /* handle special case */
271 /* next instruction */
272 pc = (u1 *)_mc->psw.addr;
276 _mc->gregs[r1 + 1] = 0x80000000;
277 /* continue at next instruction */
278 _mc->psw.addr = (ptrint) pc;
281 } else if (_mc->gregs[r2] == 0) {
284 pv = (u1 *)_mc->gregs[REG_PV];
285 sp = (u1 *)_mc->gregs[REG_SP];
288 type = EXCEPTION_HARDWARE_ARITHMETIC;
291 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
293 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
294 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
295 _mc->psw.addr = (ptrint) asm_handle_exception;
301 /* Could not handle signal */
304 md_dump_context(xpc, _mc);
306 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
310 /* md_signal_handler_sigusr2 ***************************************************
312 Signal handler for profiling sampling.
314 *******************************************************************************/
316 #if defined(ENABLE_THREADS)
317 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
326 _uc = (ucontext_t *) _p;
327 _mc = &_uc->uc_mcontext;
329 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
330 different to the ones in <ucontext.h>. */
332 pc = (u1 *) _mc->psw.addr;
339 #if defined(ENABLE_THREADS)
340 void md_critical_section_restart(ucontext_t *_uc)
346 _mc = &_uc->uc_mcontext;
348 pc = (u1 *)_mc->psw.addr;
350 npc = critical_find_restart_point(pc);
353 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
354 _mc->psw.addr = (ptrint) npc;
360 /* md_codegen_patch_branch *****************************************************
362 Back-patches a branch instruction.
364 *******************************************************************************/
366 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
370 s4 disp; /* branch displacement */
372 /* calculate the patch position */
374 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
376 /* Calculate the branch displacement. */
378 disp = targetmpc - branchmpc;
379 disp += 4; /* size of branch */
380 disp /= 2; /* specified in halfwords */
382 ASSERT_VALID_BRANCH(disp);
384 /* patch the branch instruction before the mcodeptr */
386 mcodeptr[-1] |= (disp & 0xFFFF);
390 /* md_stacktrace_get_returnaddress *********************************************
392 Returns the return address of the current stackframe, specified by
393 the passed stack pointer and the stack frame size.
395 *******************************************************************************/
397 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
401 /* on S390 the return address is located on the top of the stackframe */
403 ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
409 /* md_get_method_patch_address *************************************************
411 Gets the patch address of the currently compiled method. The offset
412 is extracted from the load instruction(s) before the jump and added
413 to the right base address (PV or REG_METHODPTR).
415 INVOKESTATIC/SPECIAL:
417 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
419 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
421 0x7748d7ba: 0d ed basr %r14,%r13
426 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
428 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
430 0x7748d832: 0d ed basr %r14,%r13
436 last 2 instructions the same as in invokevirtual
438 *******************************************************************************/
440 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
444 u1 *pa; /* patch address */
446 /* go back to the load before the call instruction */
448 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
450 /* get the base register of the load */
454 /* check for the different calls */
456 if (base == 0xd) { /* pv relative */
457 /* INVOKESTATIC/SPECIAL */
459 /* the offset is in the load before the load */
461 offset = *((s2 *) (ra - 2));
463 /* add the offset to the procedure vector */
465 pa = sfi->pv + offset;
467 else if (base == 0xc) { /* mptr relative */
468 /* INVOKEVIRTUAL/INTERFACE */
470 offset = *((u2 *)(ra + 2)) & 0xFFF;
472 /* add offset to method pointer */
477 /* catch any problems */
485 /* md_codegen_get_pv_from_pc ***************************************************
487 On this architecture just a wrapper function to
488 codegen_get_pv_from_pc.
490 *******************************************************************************/
492 u1 *md_codegen_get_pv_from_pc(u1 *ra)
496 /* Get the start address of the function which contains this
497 address from the method table. */
499 pv = codegen_get_pv_from_pc(ra);
505 /* md_cacheflush ***************************************************************
507 Calls the system's function to flush the instruction and data
510 *******************************************************************************/
512 void md_cacheflush(u1 *addr, s4 nbytes)
518 /* md_icacheflush **************************************************************
520 Calls the system's function to flush the instruction cache.
522 *******************************************************************************/
524 void md_icacheflush(u1 *addr, s4 nbytes)
530 /* md_dcacheflush **************************************************************
532 Calls the system's function to flush the data cache.
534 *******************************************************************************/
536 void md_dcacheflush(u1 *addr, s4 nbytes)
542 /* md_patch_replacement_point **************************************************
544 Patch the given replacement point.
546 *******************************************************************************/
548 void md_patch_replacement_point(rplpoint *rp)
552 /* XXX this is probably unsafe! */
554 /* save the current machine code */
555 mcode = *(u8*)rp->pc;
557 /* write spinning instruction */
558 *(u2*)(rp->pc) = 0xebfe;
561 rp->pc[4] = (rp->mcode >> 32);
563 /* write first word */
564 *(u4*)(rp->pc) = (u4) rp->mcode;
566 /* store saved mcode */
569 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
577 /* XXX if required asm_cacheflush(rp->pc,8); */
581 * These are local overrides for various environment variables in Emacs.
582 * Please do not remove this and leave it at the end of the file, where
583 * Emacs will automagically detect them.
584 * ---------------------------------------------------------------------
587 * indent-tabs-mode: t
591 * vim:noexpandtab:sw=4:ts=4: