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 8348 2007-08-19 09:27:03Z pm $
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 m->class->name->text, m->name->text, m->descriptor->text
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) {
185 md_dump_context(xpc, _mc);
187 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
190 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
191 sp = (u1 *)_mc->gregs[REG_SP];
193 type = EXCEPTION_HARDWARE_NULLPOINTER;
196 /* create stackframeinfo */
198 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
200 /* Handle the type. */
202 p = signal_handle(xpc, type, val);
204 /* remove stackframeinfo */
206 stacktrace_remove_stackframeinfo(&sfi);
209 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
210 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
211 _mc->psw.addr = (intptr_t) asm_handle_exception;
214 _mc->psw.addr = (intptr_t) xpc;
218 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
232 _uc = (ucontext_t *) _p;
233 _mc = &_uc->uc_mcontext;
234 xpc = ra = siginfo->si_addr;
236 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
238 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
240 /* bits 7-4 contain a register holding a value */
241 reg = (xpc[1] >> 4) & 0xF;
243 /* bits 3-0 designate the exception type */
246 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
247 sp = (u1 *)_mc->gregs[REG_SP];
248 val = (ptrint)_mc->gregs[reg];
250 /* create stackframeinfo */
252 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
254 /* Handle the type. */
256 p = signal_handle(xpc, type, val);
258 /* remove stackframeinfo */
260 stacktrace_remove_stackframeinfo(&sfi);
263 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
264 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
265 _mc->psw.addr = (intptr_t) asm_handle_exception;
268 _mc->psw.addr = (intptr_t) xpc;
272 md_dump_context(xpc, _mc);
274 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
278 /* md_signal_handler_sigfpe ****************************************************
280 ArithmeticException signal handler for hardware divide by zero
283 *******************************************************************************/
285 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
300 _uc = (ucontext_t *) _p;
301 _mc = &_uc->uc_mcontext;
303 /* Instruction that raised signal */
304 xpc = siginfo->si_addr;
308 if (xpc[0] == 0x1D) { /* DR */
310 r1 = (xpc[1] >> 4) & 0xF;
314 (_mc->gregs[r1] == 0xFFFFFFFF) &&
315 (_mc->gregs[r1 + 1] == 0x80000000) &&
316 (_mc->gregs[r2] == 0xFFFFFFFF)
318 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
319 /* next instruction */
320 pc = (u1 *)_mc->psw.addr;
324 _mc->gregs[r1 + 1] = 0x80000000;
325 /* continue at next instruction */
326 _mc->psw.addr = (ptrint) pc;
330 else if (_mc->gregs[r2] == 0) {
333 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
334 sp = (u1 *)_mc->gregs[REG_SP];
337 type = EXCEPTION_HARDWARE_ARITHMETIC;
340 /* create stackframeinfo */
342 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
344 /* Handle the type. */
346 p = signal_handle(xpc, type, val);
348 /* remove stackframeinfo */
350 stacktrace_remove_stackframeinfo(&sfi);
352 _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
353 _mc->gregs[REG_ITMP2_XPC] = (intptr_t) xpc;
354 _mc->psw.addr = (intptr_t) asm_handle_exception;
360 /* Could not handle signal */
363 md_dump_context(xpc, _mc);
365 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
369 /* md_signal_handler_sigusr2 ***************************************************
371 Signal handler for profiling sampling.
373 *******************************************************************************/
375 #if defined(ENABLE_THREADS)
376 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
385 _uc = (ucontext_t *) _p;
386 _mc = &_uc->uc_mcontext;
388 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
389 different to the ones in <ucontext.h>. */
391 pc = (u1 *) _mc->psw.addr;
398 #if defined(ENABLE_THREADS)
399 void md_critical_section_restart(ucontext_t *_uc)
405 _mc = &_uc->uc_mcontext;
407 pc = (u1 *)_mc->psw.addr;
409 npc = critical_find_restart_point(pc);
412 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
413 _mc->psw.addr = (ptrint) npc;
419 /* md_codegen_patch_branch *****************************************************
421 Back-patches a branch instruction.
423 *******************************************************************************/
425 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
429 s4 disp; /* branch displacement */
431 /* calculate the patch position */
433 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
435 /* Calculate the branch displacement. */
437 disp = targetmpc - branchmpc;
438 disp += 4; /* size of branch */
439 disp /= 2; /* specified in halfwords */
441 ASSERT_VALID_BRANCH(disp);
443 /* patch the branch instruction before the mcodeptr */
445 mcodeptr[-1] |= (disp & 0xFFFF);
449 /* md_stacktrace_get_returnaddress *********************************************
451 Returns the return address of the current stackframe, specified by
452 the passed stack pointer and the stack frame size.
454 *******************************************************************************/
456 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
460 /* on S390 the return address is located on the top of the stackframe */
462 ra = *((u1 **) (sp + framesize - 8));
468 /* md_get_method_patch_address *************************************************
470 Gets the patch address of the currently compiled method. The offset
471 is extracted from the load instruction(s) before the jump and added
472 to the right base address (PV or REG_METHODPTR).
474 INVOKESTATIC/SPECIAL:
476 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
478 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
480 0x7748d7ba: 0d ed basr %r14,%r13
485 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
487 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
489 0x7748d832: 0d ed basr %r14,%r13
495 last 2 instructions the same as in invokevirtual
497 *******************************************************************************/
499 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
503 u1 *pa; /* patch address */
505 /* go back to the load before the call instruction */
507 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
509 /* get the base register of the load */
514 /* check for the different calls */
518 /* INVOKESTATIC/SPECIAL */
523 /* the offset is in the load instruction */
524 offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
527 /* the offset is in the immediate load before the load */
528 offset = *((s2 *) (ra - 2));
534 /* add the offset to the procedure vector */
536 pa = sfi->pv + offset;
542 /* INVOKEVIRTUAL/INTERFACE */
544 offset = *((u2 *)(ra + 2)) & 0xFFF;
546 /* return NULL if no mptr was specified (used for replacement) */
551 /* add offset to method pointer */
556 /* catch any problems */
565 /* md_codegen_get_pv_from_pc ***************************************************
567 On this architecture just a wrapper function to
568 codegen_get_pv_from_pc.
570 *******************************************************************************/
572 u1 *md_codegen_get_pv_from_pc(u1 *ra)
576 /* Get the start address of the function which contains this
577 address from the method table. */
579 pv = codegen_get_pv_from_pc(ra);
585 /* md_cacheflush ***************************************************************
587 Calls the system's function to flush the instruction and data
590 *******************************************************************************/
592 void md_cacheflush(u1 *addr, s4 nbytes)
598 /* md_icacheflush **************************************************************
600 Calls the system's function to flush the instruction cache.
602 *******************************************************************************/
604 void md_icacheflush(u1 *addr, s4 nbytes)
610 /* md_dcacheflush **************************************************************
612 Calls the system's function to flush the data cache.
614 *******************************************************************************/
616 void md_dcacheflush(u1 *addr, s4 nbytes)
622 /* md_patch_replacement_point **************************************************
624 Patch the given replacement point.
626 *******************************************************************************/
627 #if defined(ENABLE_REPLACEMENT)
628 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
634 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
652 xptr = *(uint8_t **)(regs + REG_ITMP1_XPTR);
653 xpc = *(uint8_t **)(regs + REG_ITMP2_XPC);
654 sp = *(uint8_t **)(regs + REG_SP);
657 /* initialize number of calle saved int regs to restore to 0 */
660 /* initialize number of calle saved flt regs to restore to 0 */
667 pv = codegen_get_pv_from_pc(xpc);
669 handler = exceptions_handle_exception(xptr, xpc, pv, sp);
671 if (handler == NULL) {
673 /* exception was not handled
674 * get values of calee saved registers and remove stack frame
677 /* read stuff from data segment */
679 framesize = *(int32_t *)(pv + FrameSize);
681 intsave = *(int32_t *)(pv + IntSave);
682 if (intsave > out[0]) {
686 fltsave = *(int32_t *)(pv + FltSave);
687 if (fltsave > out[1]) {
691 /* pointer to register save area */
693 savearea = (int64_t *)(sp + framesize - 8);
697 ra = *(uint8_t **)(sp + framesize - 8);
699 /* restore saved registers */
701 for (i = 0; i < intsave; ++i) {
703 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
704 regs[reg] = *(int32_t *)(savearea);
707 for (i = 0; i < fltsave; ++i) {
709 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
710 fregs[reg] = *savearea;
713 /* remove stack frame */
717 /* new xpc is call before return address */
724 } while (handler == NULL);
726 /* write new values for registers */
728 *(uint8_t **)(regs + REG_ITMP1_XPTR) = xptr;
729 *(uint8_t **)(regs + REG_ITMP2_XPC) = xpc;
730 *(uint8_t **)(regs + REG_SP) = sp;
731 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
733 /* maybe leaf flag */
735 out[2] = (loops == 1);
739 * These are local overrides for various environment variables in Emacs.
740 * Please do not remove this and leave it at the end of the file, where
741 * Emacs will automagically detect them.
742 * ---------------------------------------------------------------------
745 * indent-tabs-mode: t
749 * vim:noexpandtab:sw=4:ts=4: