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 7839 2007-04-29 22:46:56Z pm $
43 #include "vm/jit/s390/md-abi.h"
45 #if defined(ENABLE_THREADS)
46 # include "threads/native/threads.h"
49 #include "vm/exceptions.h"
50 #include "vm/signallocal.h"
51 #include "vm/jit/asmpart.h"
52 #include "vm/jit/stacktrace.h"
54 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
55 #include "vmcore/options.h" /* XXX debug */
56 #include "vm/jit/disass.h" /* XXX debug */
59 #include "vm/jit/codegen-common.h"
60 #include "vm/jit/s390/codegen.h"
63 #define OOPS() assert(0);
65 /* prototypes *****************************************************************/
67 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
69 /* md_init *********************************************************************
71 Do some machine dependent initialization.
73 *******************************************************************************/
79 act.sa_sigaction = md_signal_handler_sigill;
80 act.sa_flags = SA_NODEFER | SA_SIGINFO;
82 if (sigaction(SIGILL, &act, NULL) == -1) {
83 vm_abort("%s: error registering SIGILL signal handler.", __FUNCTION__);
88 /* md_signal_handler_sigsegv ***************************************************
90 NullPointerException signal handler for hardware null pointer
93 *******************************************************************************/
95 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
105 java_objectheader *e;
109 _uc = (ucontext_t *) _p;
110 _mc = &_uc->uc_mcontext;
112 xpc = (u1 *)_mc->psw.addr;
114 /* Check opcodes and verify it is a null pointer exception */
119 base = (xpc[2] >> 4) & 0xF;
122 } else if (_mc->gregs[base] == 0) {
131 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
134 pv = (u1 *)_mc->gregs[REG_PV];
135 sp = (u1 *)_mc->gregs[REG_SP];
137 type = EXCEPTION_HARDWARE_NULLPOINTER;
140 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
142 _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
143 _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
144 _mc->psw.addr = (ptrint) asm_handle_exception;
147 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
156 java_objectheader *e;
159 _uc = (ucontext_t *) _p;
160 _mc = &_uc->uc_mcontext;
161 xpc = ra = siginfo->si_addr;
163 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
165 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
167 /* bits 7-4 contain a register holding a value */
168 reg = (xpc[1] >> 4) & 0xF;
170 /* bits 3-0 designate the exception type */
173 pv = (u1 *)_mc->gregs[REG_PV];
174 sp = (u1 *)_mc->gregs[REG_SP];
175 val = (ptrint)_mc->gregs[reg];
177 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
179 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
180 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
181 _mc->psw.addr = (ptrint) asm_handle_exception;
184 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
188 /* md_signal_handler_sigfpe ****************************************************
190 ArithmeticException signal handler for hardware divide by zero
193 *******************************************************************************/
195 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
207 java_objectheader *e;
209 _uc = (ucontext_t *) _p;
210 _mc = &_uc->uc_mcontext;
212 /* Instruction that raised signal */
213 xpc = siginfo->si_addr;
217 if (xpc[0] == 0x1D) { /* DR */
219 r1 = (xpc[1] >> 4) & 0xF;
223 (_mc->gregs[r1] == 0xFFFFFFFF) &&
224 (_mc->gregs[r1 + 1] == 0x80000000) &&
225 (_mc->gregs[r2] == 0xFFFFFFFF)
227 /* handle special case */
228 /* next instruction */
229 pc = (u1 *)_mc->psw.addr;
233 _mc->gregs[r1 + 1] = 0x80000000;
234 /* continue at next instruction */
235 _mc->psw.addr = (ptrint) pc;
238 } else if (_mc->gregs[r2] == 0) {
241 pv = (u1 *)_mc->gregs[REG_PV];
242 sp = (u1 *)_mc->gregs[REG_SP];
245 type = EXCEPTION_HARDWARE_ARITHMETIC;
248 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
250 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
251 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
252 _mc->psw.addr = (ptrint) asm_handle_exception;
258 /* Could not handle signal */
260 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
264 /* md_signal_handler_sigusr2 ***************************************************
266 Signal handler for profiling sampling.
268 *******************************************************************************/
270 #if defined(ENABLE_THREADS)
271 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
280 _uc = (ucontext_t *) _p;
281 _mc = &_uc->uc_mcontext;
283 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
284 different to the ones in <ucontext.h>. */
286 pc = (u1 *) _mc->psw.addr;
293 #if defined(ENABLE_THREADS)
294 void thread_restartcriticalsection(ucontext_t *_uc)
299 _mc = &_uc->uc_mcontext;
301 pc = critical_find_restart_point((void *) _mc->psw.addr);
304 _mc->psw.addr = (ptrint) pc;
309 /* md_codegen_patch_branch *****************************************************
311 Back-patches a branch instruction.
313 *******************************************************************************/
315 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
319 s4 disp; /* branch displacement */
321 /* calculate the patch position */
323 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
325 /* Calculate the branch displacement. */
327 disp = targetmpc - branchmpc;
328 disp += 4; /* size of branch */
329 disp /= 2; /* specified in halfwords */
331 ASSERT_VALID_BRANCH(disp);
333 /* patch the branch instruction before the mcodeptr */
335 mcodeptr[-1] |= (disp & 0xFFFF);
339 /* md_stacktrace_get_returnaddress *********************************************
341 Returns the return address of the current stackframe, specified by
342 the passed stack pointer and the stack frame size.
344 *******************************************************************************/
346 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
350 /* on S390 the return address is located on the top of the stackframe */
352 ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
358 /* md_get_method_patch_address *************************************************
360 Gets the patch address of the currently compiled method. The offset
361 is extracted from the load instruction(s) before the jump and added
362 to the right base address (PV or REG_METHODPTR).
364 INVOKESTATIC/SPECIAL:
366 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
368 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
370 0x7748d7ba: 0d ed basr %r14,%r13
375 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
377 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
379 0x7748d832: 0d ed basr %r14,%r13
385 last 2 instructions the same as in invokevirtual
387 *******************************************************************************/
389 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
393 u1 *pa; /* patch address */
395 /* go back to the load before the call instruction */
397 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
399 /* get the base register of the load */
403 /* check for the different calls */
405 if (base == 0xd) { /* pv relative */
406 /* INVOKESTATIC/SPECIAL */
408 /* the offset is in the load before the load */
410 offset = *((s2 *) (ra - 2));
412 /* add the offset to the procedure vector */
414 pa = sfi->pv + offset;
416 else if (base == 0xc) { /* mptr relative */
417 /* INVOKEVIRTUAL/INTERFACE */
419 offset = *((u2 *)(ra + 2)) & 0xFFF;
421 /* add offset to method pointer */
426 /* catch any problems */
434 /* md_codegen_get_pv_from_pc ***************************************************
436 On this architecture just a wrapper function to
437 codegen_get_pv_from_pc.
439 *******************************************************************************/
441 u1 *md_codegen_get_pv_from_pc(u1 *ra)
445 /* Get the start address of the function which contains this
446 address from the method table. */
448 pv = codegen_get_pv_from_pc(ra);
454 /* md_cacheflush ***************************************************************
456 Calls the system's function to flush the instruction and data
459 *******************************************************************************/
461 void md_cacheflush(u1 *addr, s4 nbytes)
467 /* md_icacheflush **************************************************************
469 Calls the system's function to flush the instruction cache.
471 *******************************************************************************/
473 void md_icacheflush(u1 *addr, s4 nbytes)
479 /* md_dcacheflush **************************************************************
481 Calls the system's function to flush the data cache.
483 *******************************************************************************/
485 void md_dcacheflush(u1 *addr, s4 nbytes)
491 /* md_patch_replacement_point **************************************************
493 Patch the given replacement point.
495 *******************************************************************************/
497 void md_patch_replacement_point(rplpoint *rp)
501 /* XXX this is probably unsafe! */
503 /* save the current machine code */
504 mcode = *(u8*)rp->pc;
506 /* write spinning instruction */
507 *(u2*)(rp->pc) = 0xebfe;
510 rp->pc[4] = (rp->mcode >> 32);
512 /* write first word */
513 *(u4*)(rp->pc) = (u4) rp->mcode;
515 /* store saved mcode */
518 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
526 /* XXX if required asm_cacheflush(rp->pc,8); */
530 * These are local overrides for various environment variables in Emacs.
531 * Please do not remove this and leave it at the end of the file, where
532 * Emacs will automagically detect them.
533 * ---------------------------------------------------------------------
536 * indent-tabs-mode: t
540 * vim:noexpandtab:sw=4:ts=4: