mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-05 11:10:21 +00:00
(Florian Krohm <britzel@acm.org>). #274378. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11787
400 lines
13 KiB
ArmAsm
400 lines
13 KiB
ArmAsm
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- The core dispatch loop, for jumping to a code address. ---*/
|
|
/*--- dispatch-s390x-linux.S ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright IBM Corp. 2010-2011
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
/* Contributed by Florian Krohm and Christian Borntraeger */
|
|
|
|
#include "pub_core_basics_asm.h"
|
|
#include "pub_core_dispatch_asm.h"
|
|
#include "pub_core_transtab_asm.h"
|
|
#include "libvex_guest_offsets.h"
|
|
#include "libvex_s390x_common.h"
|
|
|
|
#if defined(VGA_s390x)
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- The dispatch loop. VG_(run_innerloop) is used to ---*/
|
|
/*--- run all translations except no-redir ones. ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Convenience definitions for readability */
|
|
#undef SP
|
|
#define SP S390_REGNO_STACK_POINTER
|
|
|
|
#undef LR
|
|
#define LR S390_REGNO_LINK_REGISTER
|
|
|
|
/* Location of valgrind's saved FPC register */
|
|
#define S390_LOC_SAVED_FPC_V S390_OFFSET_SAVED_FPC_V(SP)
|
|
|
|
/* Location of saved guest state pointer */
|
|
#define S390_LOC_SAVED_GSP S390_OFFSET_SAVED_GSP(SP)
|
|
|
|
/*----------------------------------------------------*/
|
|
/*--- Preamble (set everything up) ---*/
|
|
/*----------------------------------------------------*/
|
|
|
|
/* signature:
|
|
UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
|
|
*/
|
|
|
|
.text
|
|
.align 4
|
|
.globl VG_(run_innerloop)
|
|
VG_(run_innerloop):
|
|
/* r2 holds address of guest_state */
|
|
/* r3 holds do_profiling (a flag) */
|
|
|
|
/* Save gprs ABI: r6...r13 and r15 */
|
|
stmg %r6,%r15,48(SP)
|
|
|
|
/* New stack frame */
|
|
aghi SP,-S390_INNERLOOP_FRAME_SIZE
|
|
|
|
/* Save fprs: ABI: f8...f15 */
|
|
std %f8,160+0(SP)
|
|
std %f9,160+8(SP)
|
|
std %f10,160+16(SP)
|
|
std %f11,160+24(SP)
|
|
std %f12,160+32(SP)
|
|
std %f13,160+40(SP)
|
|
std %f14,160+48(SP)
|
|
std %f15,160+56(SP)
|
|
|
|
/* Load address of guest state into guest state register (r13) */
|
|
lgr %r13,%r2
|
|
|
|
/* Store address of guest state pointer on stack.
|
|
It will be needed later because upon return from a VEX translation
|
|
r13 may contain a special value. So the old value will be used to
|
|
determine whether r13 contains a special value. */
|
|
stg %r13,S390_LOC_SAVED_GSP
|
|
|
|
/* Save valgrind's FPC on stack so run_innerloop_exit can restore
|
|
it later . */
|
|
stfpc S390_LOC_SAVED_FPC_V
|
|
|
|
/* Load the FPC the way the client code wants it. I.e. pull the
|
|
value from the guest state.
|
|
lfpc OFFSET_s390x_fpc(%r13)
|
|
|
|
/* Get the IA from the guest state */
|
|
lg %r2,OFFSET_s390x_IA(%r13)
|
|
|
|
/* Get VG_(dispatch_ctr) -- a 32-bit value -- and store it in a reg */
|
|
larl %r6,VG_(dispatch_ctr)
|
|
l S390_REGNO_DISPATCH_CTR,0(%r6)
|
|
|
|
/* Fall into main loop (the right one) */
|
|
|
|
/* r3 = 1 --> do_profiling. We may trash r3 later on. That's OK,
|
|
because it's a volatile register (does not need to be preserved). */
|
|
ltgr %r3,%r3
|
|
je run_innerloop__dispatch_unprofiled
|
|
j run_innerloop__dispatch_profiled
|
|
|
|
/*----------------------------------------------------*/
|
|
/*--- NO-PROFILING (standard) dispatcher ---*/
|
|
/*----------------------------------------------------*/
|
|
|
|
run_innerloop__dispatch_unprofiled:
|
|
/* This is the story:
|
|
|
|
r2 = IA = next guest address
|
|
r12 = VG_(dispatch_ctr)
|
|
r13 = guest state pointer or (upon return from guest code) some
|
|
special value
|
|
r15 = stack pointer (as usual)
|
|
*/
|
|
|
|
/* Has the guest state pointer been messed with? If yes, exit.
|
|
The mess is recognised by r13 containing an odd value. */
|
|
tmll %r13,1
|
|
larl %r8, VG_(tt_fast)
|
|
jne gsp_changed
|
|
|
|
/* Save the jump address in the guest state */
|
|
stg %r2,OFFSET_s390x_IA(%r13)
|
|
|
|
|
|
/* Try a fast lookup in the translation cache:
|
|
Compute offset (not index) into VT_(tt_fast):
|
|
|
|
offset = VG_TT_FAST_HASH(addr) * sizeof(FastCacheEntry)
|
|
|
|
with VG_TT_FAST_HASH(addr) == (addr >> 1) & VG_TT_FAST_MASK
|
|
and sizeof(FastCacheEntry) == 16
|
|
|
|
offset = ((addr >> 1) & VG_TT_FAST_MASK) << 4
|
|
*/
|
|
lghi %r5,VG_TT_FAST_MASK
|
|
srlg %r7, %r2,1 /* next guest addr >> 1*/
|
|
ngr %r7,%r5
|
|
sllg %r7,%r7,4
|
|
|
|
/* Set the return address to the beginning of the loop here to
|
|
have some instruction between setting r7 and using it as an
|
|
address */
|
|
larl LR,run_innerloop__dispatch_unprofiled
|
|
|
|
/* Are we out of timeslice? If yes, defer to scheduler. */
|
|
ahi S390_REGNO_DISPATCH_CTR,-1
|
|
jz counter_is_zero
|
|
|
|
|
|
lg %r10, 0(%r8,%r7) /* .guest */
|
|
lg %r11, 8(%r8,%r7) /* .host */
|
|
cgr %r2, %r10
|
|
jne fast_lookup_failed
|
|
|
|
/* Found a match. Call .host.
|
|
r11 is an address. There we will find the instrumented client code.
|
|
That code may modify the guest state register r13. The client code
|
|
will return to the beginning of this loop start by issuing br LR.
|
|
We can simply branch to the host code */
|
|
br %r11
|
|
|
|
|
|
/*----------------------------------------------------*/
|
|
/*--- PROFILING dispatcher (can be much slower) ---*/
|
|
/*----------------------------------------------------*/
|
|
|
|
run_innerloop__dispatch_profiled:
|
|
|
|
/* Has the guest state pointer been messed with? If yes, exit.
|
|
The mess is recognised by r13 containing an odd value. */
|
|
tmll %r13,1
|
|
larl %r8, VG_(tt_fast)
|
|
jne gsp_changed
|
|
|
|
/* Save the jump address in the guest state */
|
|
stg %r2,OFFSET_s390x_IA(%r13)
|
|
|
|
/* Try a fast lookup in the translation cache:
|
|
Compute offset (not index) into VT_(tt_fast):
|
|
|
|
offset = VG_TT_FAST_HASH(addr) * sizeof(FastCacheEntry)
|
|
|
|
with VG_TT_FAST_HASH(addr) == (addr >> 1) & VG_TT_FAST_MASK
|
|
and sizeof(FastCacheEntry) == 16
|
|
|
|
offset = ((addr >> 1) & VG_TT_FAST_MASK) << 4
|
|
*/
|
|
lghi %r5,VG_TT_FAST_MASK
|
|
srlg %r7,%r2,1 /* next guest addr >> 1*/
|
|
ngr %r7,%r5
|
|
sllg %r7,%r7,4
|
|
|
|
/* Set the return address to the beginning of the loop here to
|
|
have some instruction between setting r7 and using it as an
|
|
address */
|
|
larl LR,run_innerloop__dispatch_profiled
|
|
|
|
/* Are we out of timeslice? If yes, defer to scheduler. */
|
|
ahi S390_REGNO_DISPATCH_CTR,-1
|
|
jz counter_is_zero
|
|
|
|
lg %r10, 0(%r8,%r7) /* .guest */
|
|
lg %r11, 8(%r8,%r7) /* .host */
|
|
cgr %r2, %r10
|
|
jne fast_lookup_failed
|
|
|
|
/* sizeof(FastCacheEntry) == 16, sizeof(*UInt)==8 */
|
|
srlg %r7,%r7,1
|
|
|
|
/* we got a hit: VG_(tt_fastN) is guaranteed to point to count */
|
|
larl %r8, VG_(tt_fastN)
|
|
|
|
/* increment bb profile counter */
|
|
lg %r9,0(%r8,%r7)
|
|
l %r10,0(%r9)
|
|
ahi %r10,1
|
|
st %r10,0(%r9)
|
|
|
|
/* Found a match. Call .host.
|
|
r11 is an address. There we will find the instrumented client code.
|
|
That code may modify the guest state register r13. The client code
|
|
will return to the beginning of this loop start by issuing br LR.
|
|
We can simply branch to the host code */
|
|
br %r11
|
|
|
|
/*----------------------------------------------------*/
|
|
/*--- exit points ---*/
|
|
/*----------------------------------------------------*/
|
|
|
|
gsp_changed:
|
|
/* Someone messed with the gsp (in r13). Have to
|
|
defer to scheduler to resolve this. The register
|
|
holding VG_(dispatch_ctr) is not yet decremented,
|
|
so no need to increment. */
|
|
|
|
/* Update the IA in the guest state */
|
|
lg %r6,S390_LOC_SAVED_GSP /* r6 = original guest state pointer */
|
|
stg %r2,OFFSET_s390x_IA(%r6)
|
|
|
|
/* Return the special guest state pointer value */
|
|
lgr %r2, %r13
|
|
j run_innerloop_exit
|
|
|
|
|
|
counter_is_zero:
|
|
/* IA is up to date */
|
|
|
|
/* Back out decrement of the dispatch counter */
|
|
ahi S390_REGNO_DISPATCH_CTR,1
|
|
|
|
/* Set return value for the scheduler */
|
|
lghi %r2,VG_TRC_INNER_COUNTERZERO
|
|
j run_innerloop_exit
|
|
|
|
|
|
fast_lookup_failed:
|
|
/* IA is up to date */
|
|
|
|
/* Back out decrement of the dispatch counter */
|
|
ahi S390_REGNO_DISPATCH_CTR,1
|
|
|
|
/* Set return value for the scheduler */
|
|
lghi %r2,VG_TRC_INNER_FASTMISS
|
|
j run_innerloop_exit
|
|
|
|
|
|
/* All exits from the dispatcher go through here.
|
|
When we come here r2 holds the return value. */
|
|
run_innerloop_exit:
|
|
|
|
/* Restore valgrind's FPC, as client code may have changed it. */
|
|
lfpc S390_LOC_SAVED_FPC_V
|
|
|
|
/* Write ctr to VG_(dispatch_ctr) (=32bit value) */
|
|
larl %r6,VG_(dispatch_ctr)
|
|
st S390_REGNO_DISPATCH_CTR,0(%r6)
|
|
|
|
/* Restore callee-saved registers... */
|
|
|
|
/* Floating-point regs */
|
|
ld %f8,160+0(SP)
|
|
ld %f9,160+8(SP)
|
|
ld %f10,160+16(SP)
|
|
ld %f11,160+24(SP)
|
|
ld %f12,160+32(SP)
|
|
ld %f13,160+40(SP)
|
|
ld %f14,160+48(SP)
|
|
ld %f15,160+56(SP)
|
|
|
|
/* Remove atack frame */
|
|
aghi SP,S390_INNERLOOP_FRAME_SIZE
|
|
|
|
/* General-purpose regs. This also restores the original link
|
|
register (r14) and stack pointer (r15). */
|
|
lmg %r6,%r15,48(SP)
|
|
|
|
/* Return */
|
|
br LR
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- A special dispatcher, for running no-redir ---*/
|
|
/*--- translations. Just runs the given translation once. ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* signature:
|
|
void VG_(run_a_noredir_translation) ( UWord* argblock );
|
|
*/
|
|
|
|
/* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args
|
|
and 2 to carry results:
|
|
0: input: ptr to translation
|
|
1: input: ptr to guest state
|
|
2: output: next guest PC
|
|
3: output: guest state pointer afterwards (== thread return code)
|
|
*/
|
|
.text
|
|
.align 4
|
|
.globl VG_(run_a_noredir_translation)
|
|
VG_(run_a_noredir_translation):
|
|
stmg %r6,%r15,48(SP)
|
|
aghi SP,-S390_INNERLOOP_FRAME_SIZE
|
|
std %f8,160+0(SP)
|
|
std %f9,160+8(SP)
|
|
std %f10,160+16(SP)
|
|
std %f11,160+24(SP)
|
|
std %f12,160+32(SP)
|
|
std %f13,160+40(SP)
|
|
std %f14,160+48(SP)
|
|
std %f15,160+56(SP)
|
|
|
|
/* Load address of guest state into guest state register (r13) */
|
|
lg %r13,8(%r2)
|
|
|
|
/* Get the IA */
|
|
lg %r11,0(%r2)
|
|
|
|
/* save r2 (argblock) as it is clobbered */
|
|
stg %r2,160+64(SP)
|
|
|
|
/* the call itself */
|
|
basr LR,%r11
|
|
|
|
/* restore argblock */
|
|
lg %r1,160+64(SP)
|
|
/* save the next guest PC */
|
|
stg %r2,16(%r1)
|
|
|
|
/* save the guest state */
|
|
stg %r13,24(%r1)
|
|
|
|
/* Restore Floating-point regs */
|
|
ld %f8,160+0(SP)
|
|
ld %f9,160+8(SP)
|
|
ld %f10,160+16(SP)
|
|
ld %f11,160+24(SP)
|
|
ld %f12,160+32(SP)
|
|
ld %f13,160+40(SP)
|
|
ld %f14,160+48(SP)
|
|
ld %f15,160+56(SP)
|
|
|
|
aghi SP,S390_INNERLOOP_FRAME_SIZE
|
|
|
|
lmg %r6,%r15,48(SP)
|
|
br %r14
|
|
|
|
|
|
/* Let the linker know we don't need an executable stack */
|
|
.section .note.GNU-stack,"",@progbits
|
|
|
|
#endif /* VGA_s390x */
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end dispatch-s390x-linux.S ---*/
|
|
/*--------------------------------------------------------------------*/
|