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
37 #include "vm/jit/s390/md-abi.h"
39 #if defined(ENABLE_THREADS)
40 # include "threads/threads-common.h"
41 # include "threads/native/threads.h"
44 #include "vm/exceptions.h"
45 #include "vm/signallocal.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/methodheader.h"
49 #include "vm/jit/stacktrace.h"
51 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
52 #include "vmcore/options.h" /* XXX debug */
53 #include "vm/jit/disass.h" /* XXX debug */
56 #include "vm/jit/codegen-common.h"
57 #include "vm/jit/s390/codegen.h"
60 #define OOPS() assert(0);
62 /* prototypes *****************************************************************/
64 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
66 void md_dump_context(u1 *pc, mcontext_t *mc);
68 /* md_init *********************************************************************
70 Do some machine dependent initialization.
72 *******************************************************************************/
78 /* md_dump_context ************************************************************
80 Logs the machine context
82 *******************************************************************************/
84 void md_dump_context(u1 *pc, mcontext_t *mc) {
94 log_println("Dumping context.");
96 log_println("Program counter: 0x%08X", pc);
98 pv = codegen_get_pv_from_pc_nocheck(pc);
100 log_println("No java method found at location.");
102 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
104 "Java method: class %s, method %s, descriptor %s.",
105 m->class->name->text, m->name->text, m->descriptor->text
109 #if defined(ENABLE_DISASSEMBLER)
110 log_println("Printing instruction at program counter:");
114 log_println("General purpose registers:");
116 for (i = 0; i < 16; i++) {
117 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
120 log_println("Floating point registers:");
122 for (i = 0; i < 16; i++) {
123 freg.fr.d = mc->fpregs.fprs[i].d;
124 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
127 #if defined(ENABLE_THREADS)
128 log_println("Dumping the current stacktrace:");
129 threads_print_stacktrace();
134 /* md_signal_handler_sigsegv ***************************************************
136 NullPointerException signal handler for hardware null pointer
139 *******************************************************************************/
141 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
156 _uc = (ucontext_t *) _p;
157 _mc = &_uc->uc_mcontext;
159 xpc = (u1 *)_mc->psw.addr;
161 /* Check opcodes and verify it is a null pointer exception */
166 case 0x55: /* CL (array size check on NULL array) */
167 base = (xpc[2] >> 4) & 0xF;
170 } else if (_mc->gregs[base] == 0) {
183 md_dump_context(xpc, _mc);
185 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
188 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
189 sp = (u1 *)_mc->gregs[REG_SP];
191 type = EXCEPTION_HARDWARE_NULLPOINTER;
194 /* create stackframeinfo */
196 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
198 /* Handle the type. */
200 p = signal_handle(xpc, type, val);
202 /* remove stackframeinfo */
204 stacktrace_remove_stackframeinfo(&sfi);
207 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
208 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
209 _mc->psw.addr = (intptr_t) asm_handle_exception;
212 _mc->psw.addr = (intptr_t) xpc;
216 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
230 _uc = (ucontext_t *) _p;
231 _mc = &_uc->uc_mcontext;
232 xpc = ra = siginfo->si_addr;
234 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
236 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
238 /* bits 7-4 contain a register holding a value */
239 reg = (xpc[1] >> 4) & 0xF;
241 /* bits 3-0 designate the exception type */
244 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
245 sp = (u1 *)_mc->gregs[REG_SP];
246 val = (ptrint)_mc->gregs[reg];
248 /* create stackframeinfo */
250 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
252 /* Handle the type. */
254 p = signal_handle(xpc, type, val);
256 /* remove stackframeinfo */
258 stacktrace_remove_stackframeinfo(&sfi);
261 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
262 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
263 _mc->psw.addr = (intptr_t) asm_handle_exception;
266 _mc->psw.addr = (intptr_t) xpc;
270 md_dump_context(xpc, _mc);
272 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
276 /* md_signal_handler_sigfpe ****************************************************
278 ArithmeticException signal handler for hardware divide by zero
281 *******************************************************************************/
283 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
298 _uc = (ucontext_t *) _p;
299 _mc = &_uc->uc_mcontext;
301 /* Instruction that raised signal */
302 xpc = siginfo->si_addr;
306 if (xpc[0] == 0x1D) { /* DR */
308 r1 = (xpc[1] >> 4) & 0xF;
312 (_mc->gregs[r1] == 0xFFFFFFFF) &&
313 (_mc->gregs[r1 + 1] == 0x80000000) &&
314 (_mc->gregs[r2] == 0xFFFFFFFF)
316 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
317 /* next instruction */
318 pc = (u1 *)_mc->psw.addr;
322 _mc->gregs[r1 + 1] = 0x80000000;
323 /* continue at next instruction */
324 _mc->psw.addr = (ptrint) pc;
328 else if (_mc->gregs[r2] == 0) {
331 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
332 sp = (u1 *)_mc->gregs[REG_SP];
335 type = EXCEPTION_HARDWARE_ARITHMETIC;
338 /* create stackframeinfo */
340 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
342 /* Handle the type. */
344 p = signal_handle(xpc, type, val);
346 /* remove stackframeinfo */
348 stacktrace_remove_stackframeinfo(&sfi);
350 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
351 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
352 _mc->psw.addr = (intptr_t) asm_handle_exception;
358 /* Could not handle signal */
361 md_dump_context(xpc, _mc);
363 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
367 /* md_signal_handler_sigusr2 ***************************************************
369 Signal handler for profiling sampling.
371 *******************************************************************************/
373 #if defined(ENABLE_THREADS)
374 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
383 _uc = (ucontext_t *) _p;
384 _mc = &_uc->uc_mcontext;
386 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
387 different to the ones in <ucontext.h>. */
389 pc = (u1 *) _mc->psw.addr;
396 #if defined(ENABLE_THREADS)
397 void md_critical_section_restart(ucontext_t *_uc)
403 _mc = &_uc->uc_mcontext;
405 pc = (u1 *)_mc->psw.addr;
407 npc = critical_find_restart_point(pc);
410 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
411 _mc->psw.addr = (ptrint) npc;
417 /* md_codegen_patch_branch *****************************************************
419 Back-patches a branch instruction.
421 *******************************************************************************/
423 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
427 s4 disp; /* branch displacement */
429 /* calculate the patch position */
431 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
433 /* Calculate the branch displacement. */
435 disp = targetmpc - branchmpc;
436 disp += 4; /* size of branch */
437 disp /= 2; /* specified in halfwords */
439 ASSERT_VALID_BRANCH(disp);
441 /* patch the branch instruction before the mcodeptr */
443 mcodeptr[-1] |= (disp & 0xFFFF);
447 /* md_stacktrace_get_returnaddress *********************************************
449 Returns the return address of the current stackframe, specified by
450 the passed stack pointer and the stack frame size.
452 *******************************************************************************/
454 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
458 /* on S390 the return address is located on the top of the stackframe */
460 ra = *((u1 **) (sp + framesize - 8));
466 /* md_get_method_patch_address *************************************************
468 Gets the patch address of the currently compiled method. The offset
469 is extracted from the load instruction(s) before the jump and added
470 to the right base address (PV or REG_METHODPTR).
472 INVOKESTATIC/SPECIAL:
474 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
476 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
478 0x7748d7ba: 0d ed basr %r14,%r13
483 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
485 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
487 0x7748d832: 0d ed basr %r14,%r13
493 last 2 instructions the same as in invokevirtual
495 *******************************************************************************/
497 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
501 u1 *pa; /* patch address */
503 /* go back to the load before the call instruction */
505 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
507 /* get the base register of the load */
512 /* check for the different calls */
516 /* INVOKESTATIC/SPECIAL */
521 /* the offset is in the load instruction */
522 offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
525 /* the offset is in the immediate load before the load */
526 offset = *((s2 *) (ra - 2));
532 /* add the offset to the procedure vector */
534 pa = sfi->pv + offset;
540 /* INVOKEVIRTUAL/INTERFACE */
542 offset = *((u2 *)(ra + 2)) & 0xFFF;
544 /* return NULL if no mptr was specified (used for replacement) */
549 /* add offset to method pointer */
554 /* catch any problems */
563 /* md_codegen_get_pv_from_pc ***************************************************
565 On this architecture just a wrapper function to
566 codegen_get_pv_from_pc.
568 *******************************************************************************/
570 u1 *md_codegen_get_pv_from_pc(u1 *ra)
574 /* Get the start address of the function which contains this
575 address from the method table. */
577 pv = codegen_get_pv_from_pc(ra);
583 /* md_cacheflush ***************************************************************
585 Calls the system's function to flush the instruction and data
588 *******************************************************************************/
590 void md_cacheflush(u1 *addr, s4 nbytes)
596 /* md_icacheflush **************************************************************
598 Calls the system's function to flush the instruction cache.
600 *******************************************************************************/
602 void md_icacheflush(u1 *addr, s4 nbytes)
608 /* md_dcacheflush **************************************************************
610 Calls the system's function to flush the data cache.
612 *******************************************************************************/
614 void md_dcacheflush(u1 *addr, s4 nbytes)
620 /* md_patch_replacement_point **************************************************
622 Patch the given replacement point.
624 *******************************************************************************/
625 #if defined(ENABLE_REPLACEMENT)
626 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
632 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
650 xptr = *(uint8_t **)(regs + REG_ITMP1_XPTR);
651 xpc = *(uint8_t **)(regs + REG_ITMP2_XPC);
652 sp = *(uint8_t **)(regs + REG_SP);
655 /* initialize number of calle saved int regs to restore to 0 */
658 /* initialize number of calle saved flt regs to restore to 0 */
665 pv = codegen_get_pv_from_pc(xpc);
667 handler = exceptions_handle_exception(xptr, xpc, pv, sp);
669 if (handler == NULL) {
671 /* exception was not handled
672 * get values of calee saved registers and remove stack frame
675 /* read stuff from data segment */
677 framesize = *(int32_t *)(pv + FrameSize);
679 intsave = *(int32_t *)(pv + IntSave);
680 if (intsave > out[0]) {
684 fltsave = *(int32_t *)(pv + FltSave);
685 if (fltsave > out[1]) {
689 /* pointer to register save area */
691 savearea = (int64_t *)(sp + framesize - 8);
695 ra = *(uint8_t **)(sp + framesize - 8);
697 /* restore saved registers */
699 for (i = 0; i < intsave; ++i) {
701 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
702 regs[reg] = *(int32_t *)(savearea);
705 for (i = 0; i < fltsave; ++i) {
707 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
708 fregs[reg] = *savearea;
711 /* remove stack frame */
715 /* new xpc is call before return address */
722 } while (handler == NULL);
724 /* write new values for registers */
726 *(uint8_t **)(regs + REG_ITMP1_XPTR) = xptr;
727 *(uint8_t **)(regs + REG_ITMP2_XPC) = xpc;
728 *(uint8_t **)(regs + REG_SP) = sp;
729 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
731 /* maybe leaf flag */
733 out[2] = (loops == 1);
737 * These are local overrides for various environment variables in Emacs.
738 * Please do not remove this and leave it at the end of the file, where
739 * Emacs will automagically detect them.
740 * ---------------------------------------------------------------------
743 * indent-tabs-mode: t
747 * vim:noexpandtab:sw=4:ts=4: