1 /* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
3 Copyright (C) 2006, 2007 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 $Id: md.c 8299 2007-08-13 08:41:18Z michi $
39 #include "vm/jit/s390/md-abi.h"
41 #if defined(ENABLE_THREADS)
42 # include "threads/threads-common.h"
43 # include "threads/native/threads.h"
46 #include "vm/exceptions.h"
47 #include "vm/signallocal.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/abi.h"
50 #include "vm/jit/methodheader.h"
51 #include "vm/jit/stacktrace.h"
53 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
54 #include "vmcore/options.h" /* XXX debug */
55 #include "vm/jit/disass.h" /* XXX debug */
58 #include "vm/jit/codegen-common.h"
59 #include "vm/jit/s390/codegen.h"
62 #define OOPS() assert(0);
64 /* prototypes *****************************************************************/
66 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
68 void md_dump_context(u1 *pc, mcontext_t *mc);
70 /* md_init *********************************************************************
72 Do some machine dependent initialization.
74 *******************************************************************************/
80 /* md_dump_context ************************************************************
82 Logs the machine context
84 *******************************************************************************/
86 void md_dump_context(u1 *pc, mcontext_t *mc) {
96 log_println("Dumping context.");
98 log_println("Program counter: 0x%08X", pc);
100 pv = codegen_get_pv_from_pc_nocheck(pc);
102 log_println("No java method found at location.");
104 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
106 "Java method: class %s, method %s, descriptor %s.",
107 utf_bytes(m->class->name), utf_bytes(m->name), utf_bytes(m->descriptor)
111 #if defined(ENABLE_DISASSEMBLER)
112 log_println("Printing instruction at program counter:");
116 log_println("General purpose registers:");
118 for (i = 0; i < 16; i++) {
119 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
122 log_println("Floating point registers:");
124 for (i = 0; i < 16; i++) {
125 freg.fr.d = mc->fpregs.fprs[i].d;
126 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
129 #if defined(ENABLE_THREADS)
130 log_println("Dumping the current stacktrace:");
131 threads_print_stacktrace();
136 /* md_signal_handler_sigsegv ***************************************************
138 NullPointerException signal handler for hardware null pointer
141 *******************************************************************************/
143 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
158 _uc = (ucontext_t *) _p;
159 _mc = &_uc->uc_mcontext;
161 xpc = (u1 *)_mc->psw.addr;
163 /* Check opcodes and verify it is a null pointer exception */
168 case 0x55: /* CL (array size check on NULL array) */
169 base = (xpc[2] >> 4) & 0xF;
172 } else if (_mc->gregs[base] == 0) {
182 md_dump_context(xpc, _mc);
184 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
187 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
188 sp = (u1 *)_mc->gregs[REG_SP];
190 type = EXCEPTION_HARDWARE_NULLPOINTER;
193 /* create stackframeinfo */
195 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
197 /* Handle the type. */
199 p = signal_handle(xpc, type, val);
201 /* remove stackframeinfo */
203 stacktrace_remove_stackframeinfo(&sfi);
206 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
207 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
208 _mc->psw.addr = (intptr_t) asm_handle_exception;
211 _mc->psw.addr = (intptr_t) xpc;
215 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
229 _uc = (ucontext_t *) _p;
230 _mc = &_uc->uc_mcontext;
231 xpc = ra = siginfo->si_addr;
233 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
235 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
237 /* bits 7-4 contain a register holding a value */
238 reg = (xpc[1] >> 4) & 0xF;
240 /* bits 3-0 designate the exception type */
243 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
244 sp = (u1 *)_mc->gregs[REG_SP];
245 val = (ptrint)_mc->gregs[reg];
247 /* create stackframeinfo */
249 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
251 /* Handle the type. */
253 p = signal_handle(xpc, type, val);
255 /* remove stackframeinfo */
257 stacktrace_remove_stackframeinfo(&sfi);
260 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
261 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
262 _mc->psw.addr = (intptr_t) asm_handle_exception;
265 _mc->psw.addr = (intptr_t) xpc;
269 md_dump_context(xpc, _mc);
271 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
275 /* md_signal_handler_sigfpe ****************************************************
277 ArithmeticException signal handler for hardware divide by zero
280 *******************************************************************************/
282 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
297 _uc = (ucontext_t *) _p;
298 _mc = &_uc->uc_mcontext;
300 /* Instruction that raised signal */
301 xpc = siginfo->si_addr;
305 if (xpc[0] == 0x1D) { /* DR */
307 r1 = (xpc[1] >> 4) & 0xF;
311 (_mc->gregs[r1] == 0xFFFFFFFF) &&
312 (_mc->gregs[r1 + 1] == 0x80000000) &&
313 (_mc->gregs[r2] == 0xFFFFFFFF)
315 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
316 /* next instruction */
317 pc = (u1 *)_mc->psw.addr;
321 _mc->gregs[r1 + 1] = 0x80000000;
322 /* continue at next instruction */
323 _mc->psw.addr = (ptrint) pc;
327 else if (_mc->gregs[r2] == 0) {
330 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
331 sp = (u1 *)_mc->gregs[REG_SP];
334 type = EXCEPTION_HARDWARE_ARITHMETIC;
337 /* create stackframeinfo */
339 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
341 /* Handle the type. */
343 p = signal_handle(xpc, type, val);
345 /* remove stackframeinfo */
347 stacktrace_remove_stackframeinfo(&sfi);
349 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
350 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
351 _mc->psw.addr = (intptr_t) asm_handle_exception;
357 /* Could not handle signal */
360 md_dump_context(xpc, _mc);
362 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
366 /* md_signal_handler_sigusr2 ***************************************************
368 Signal handler for profiling sampling.
370 *******************************************************************************/
372 #if defined(ENABLE_THREADS)
373 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
382 _uc = (ucontext_t *) _p;
383 _mc = &_uc->uc_mcontext;
385 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
386 different to the ones in <ucontext.h>. */
388 pc = (u1 *) _mc->psw.addr;
395 #if defined(ENABLE_THREADS)
396 void md_critical_section_restart(ucontext_t *_uc)
402 _mc = &_uc->uc_mcontext;
404 pc = (u1 *)_mc->psw.addr;
406 npc = critical_find_restart_point(pc);
409 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
410 _mc->psw.addr = (ptrint) npc;
416 /* md_codegen_patch_branch *****************************************************
418 Back-patches a branch instruction.
420 *******************************************************************************/
422 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
426 s4 disp; /* branch displacement */
428 /* calculate the patch position */
430 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
432 /* Calculate the branch displacement. */
434 disp = targetmpc - branchmpc;
435 disp += 4; /* size of branch */
436 disp /= 2; /* specified in halfwords */
438 ASSERT_VALID_BRANCH(disp);
440 /* patch the branch instruction before the mcodeptr */
442 mcodeptr[-1] |= (disp & 0xFFFF);
446 /* md_stacktrace_get_returnaddress *********************************************
448 Returns the return address of the current stackframe, specified by
449 the passed stack pointer and the stack frame size.
451 *******************************************************************************/
453 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
457 /* on S390 the return address is located on the top of the stackframe */
459 ra = *((u1 **) (sp + framesize - 8));
465 /* md_get_method_patch_address *************************************************
467 Gets the patch address of the currently compiled method. The offset
468 is extracted from the load instruction(s) before the jump and added
469 to the right base address (PV or REG_METHODPTR).
471 INVOKESTATIC/SPECIAL:
473 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
475 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
477 0x7748d7ba: 0d ed basr %r14,%r13
482 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
484 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
486 0x7748d832: 0d ed basr %r14,%r13
492 last 2 instructions the same as in invokevirtual
494 *******************************************************************************/
496 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
500 u1 *pa; /* patch address */
502 /* go back to the load before the call instruction */
504 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
506 /* get the base register of the load */
511 /* check for the different calls */
515 /* INVOKESTATIC/SPECIAL */
520 /* the offset is in the load instruction */
521 offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
524 /* the offset is in the immediate load before the load */
525 offset = *((s2 *) (ra - 2));
531 /* add the offset to the procedure vector */
533 pa = sfi->pv + offset;
539 /* INVOKEVIRTUAL/INTERFACE */
541 offset = *((u2 *)(ra + 2)) & 0xFFF;
543 /* return NULL if no mptr was specified (used for replacement) */
548 /* add offset to method pointer */
553 /* catch any problems */
562 /* md_codegen_get_pv_from_pc ***************************************************
564 On this architecture just a wrapper function to
565 codegen_get_pv_from_pc.
567 *******************************************************************************/
569 u1 *md_codegen_get_pv_from_pc(u1 *ra)
573 /* Get the start address of the function which contains this
574 address from the method table. */
576 pv = codegen_get_pv_from_pc(ra);
582 /* md_cacheflush ***************************************************************
584 Calls the system's function to flush the instruction and data
587 *******************************************************************************/
589 void md_cacheflush(u1 *addr, s4 nbytes)
595 /* md_icacheflush **************************************************************
597 Calls the system's function to flush the instruction cache.
599 *******************************************************************************/
601 void md_icacheflush(u1 *addr, s4 nbytes)
607 /* md_dcacheflush **************************************************************
609 Calls the system's function to flush the data cache.
611 *******************************************************************************/
613 void md_dcacheflush(u1 *addr, s4 nbytes)
619 /* md_patch_replacement_point **************************************************
621 Patch the given replacement point.
623 *******************************************************************************/
624 #if defined(ENABLE_REPLACEMENT)
625 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
631 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
649 xptr = *(uint8_t **)(regs + REG_ITMP1_XPTR);
650 xpc = *(uint8_t **)(regs + REG_ITMP2_XPC);
651 sp = *(uint8_t **)(regs + REG_SP);
654 /* initialize number of calle saved int regs to restore to 0 */
657 /* initialize number of calle saved flt regs to restore to 0 */
664 pv = codegen_get_pv_from_pc(xpc);
666 handler = exceptions_handle_exception(xptr, xpc, pv, sp);
668 if (handler == NULL) {
670 /* exception was not handled
671 * get values of calee saved registers and remove stack frame
674 /* read stuff from data segment */
676 framesize = *(int32_t *)(pv + FrameSize);
678 intsave = *(int32_t *)(pv + IntSave);
679 if (intsave > out[0]) {
683 fltsave = *(int32_t *)(pv + FltSave);
684 if (fltsave > out[1]) {
688 /* pointer to register save area */
690 savearea = (int64_t *)(sp + framesize - 8);
694 ra = *(uint8_t **)(sp + framesize - 8);
696 /* restore saved registers */
698 for (i = 0; i < intsave; ++i) {
700 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
701 regs[reg] = *(int32_t *)(savearea);
704 for (i = 0; i < fltsave; ++i) {
706 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
707 fregs[reg] = *savearea;
710 /* remove stack frame */
714 /* new xpc is call before return address */
721 } while (handler == NULL);
723 /* write new values for registers */
725 *(uint8_t **)(regs + REG_ITMP1_XPTR) = xptr;
726 *(uint8_t **)(regs + REG_ITMP2_XPC) = xpc;
727 *(uint8_t **)(regs + REG_SP) = sp;
728 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
730 /* maybe leaf flag */
732 out[2] = (loops == 1);
736 * These are local overrides for various environment variables in Emacs.
737 * Please do not remove this and leave it at the end of the file, where
738 * Emacs will automagically detect them.
739 * ---------------------------------------------------------------------
742 * indent-tabs-mode: t
746 * vim:noexpandtab:sw=4:ts=4: