blob: 20b13facdebcb6a11d205c9576d1f03aa8fa7d0a [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- The core dispatch loop, for jumping to a code address. ---*/
/*--- dispatch-arm-linux.S ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2008-2010 Evan Geller
gaze@bea.ms
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.
*/
#if defined(VGP_arm_linux)
.fpu vfp
#include "pub_core_basics_asm.h"
#include "pub_core_dispatch_asm.h"
#include "pub_core_transtab_asm.h"
#include "libvex_guest_offsets.h" /* for OFFSET_arm_R* */
/*------------------------------------------------------------*/
/*--- ---*/
/*--- The dispatch loop. VG_(run_innerloop) is used to ---*/
/*--- run all translations except no-redir ones. ---*/
/*--- ---*/
/*------------------------------------------------------------*/
/*----------------------------------------------------*/
/*--- Preamble (set everything up) ---*/
/*----------------------------------------------------*/
/* signature:
UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
*/
.text
.globl VG_(run_innerloop)
VG_(run_innerloop):
push {r0, r1, r4, r5, r6, r7, r8, r9, fp, lr}
/* set FPSCR to vex-required default value */
mov r4, #0
fmxr fpscr, r4
/* r0 (hence also [sp,#0]) holds guest_state */
/* r1 holds do_profiling */
mov r8, r0
ldr r0, [r8, #OFFSET_arm_R15T]
/* fall into main loop (the right one) */
cmp r1, #0 /* do_profiling */
beq VG_(run_innerloop__dispatch_unprofiled)
b VG_(run_innerloop__dispatch_profiled)
/*----------------------------------------------------*/
/*--- NO-PROFILING (standard) dispatcher ---*/
/*----------------------------------------------------*/
/* Pairing of insns below is my guesstimate of how dual dispatch would
work on an A8. JRS, 2011-May-28 */
.global VG_(run_innerloop__dispatch_unprofiled)
VG_(run_innerloop__dispatch_unprofiled):
/* AT ENTRY: r0 is next guest addr, r8 is possibly
modified guest state ptr */
/* Has the guest state pointer been messed with? If yes, exit. */
ldr r1, [sp, #0]
movw r3, #:lower16:VG_(dispatch_ctr)
cmp r8, r1
movt r3, #:upper16:VG_(dispatch_ctr)
bne gsp_changed
/* save the jump address in the guest state */
str r0, [r8, #OFFSET_arm_R15T]
/* Are we out of timeslice? If yes, defer to scheduler. */
ldr r2, [r3]
subs r2, r2, #1
str r2, [r3]
beq counter_is_zero
/* try a fast lookup in the translation cache */
// r0 = next guest, r1,r2,r3,r4 scratch
movw r1, #VG_TT_FAST_MASK // r1 = VG_TT_FAST_MASK
movw r4, #:lower16:VG_(tt_fast)
and r2, r1, r0, LSR #1 // r2 = entry #
movt r4, #:upper16:VG_(tt_fast) // r4 = &VG_(tt_fast)
add r1, r4, r2, LSL #3 // r1 = &tt_fast[entry#]
ldrd r4, r5, [r1, #0] // r4 = .guest, r5 = .host
cmp r4, r0
bne fast_lookup_failed
// r5: next-host r8: live, gsp
// r4: next-guest
// r2: entry #
// LIVE: r5, r8; all others dead
/* Found a match. Jump to .host. */
blx r5
b VG_(run_innerloop__dispatch_unprofiled)
.ltorg
/*NOTREACHED*/
/*----------------------------------------------------*/
/*--- PROFILING dispatcher (can be much slower) ---*/
/*----------------------------------------------------*/
.global VG_(run_innerloop__dispatch_profiled)
VG_(run_innerloop__dispatch_profiled):
/* AT ENTRY: r0 is next guest addr, r8 is possibly
modified guest state ptr */
/* Has the guest state pointer been messed with? If yes, exit. */
ldr r1, [sp, #0]
movw r3, #:lower16:VG_(dispatch_ctr)
cmp r8, r1
movt r3, #:upper16:VG_(dispatch_ctr)
bne gsp_changed
/* save the jump address in the guest state */
str r0, [r8, #OFFSET_arm_R15T]
/* Are we out of timeslice? If yes, defer to scheduler. */
ldr r2, [r3]
subs r2, r2, #1
str r2, [r3]
beq counter_is_zero
/* try a fast lookup in the translation cache */
// r0 = next guest, r1,r2,r3,r4 scratch
movw r1, #VG_TT_FAST_MASK // r1 = VG_TT_FAST_MASK
movw r4, #:lower16:VG_(tt_fast)
and r2, r1, r0, LSR #1 // r2 = entry #
movt r4, #:upper16:VG_(tt_fast) // r4 = &VG_(tt_fast)
add r1, r4, r2, LSL #3 // r1 = &tt_fast[entry#]
ldrd r4, r5, [r1, #0] // r4 = .guest, r5 = .host
cmp r4, r0
bne fast_lookup_failed
// r5: next-host r8: live, gsp
// r4: next-guest
// r2: entry #
// LIVE: r5, r8; all others dead
/* increment bb profile counter */
movw r0, #:lower16:VG_(tt_fastN)
movt r0, #:upper16:VG_(tt_fastN) // r0 = &tt_fastN[0]
ldr r0, [r0, r2, LSL #2] // r0 = tt_fast[entry #]
ldr r3, [r0] // *r0 ++
add r3, r3, #1
str r3, [r0]
/* Found a match. Jump to .host. */
blx r5
b VG_(run_innerloop__dispatch_profiled)
/*NOTREACHED*/
/*----------------------------------------------------*/
/*--- exit points ---*/
/*----------------------------------------------------*/
gsp_changed:
// r0 = next guest addr (R15T), r8 = modified gsp
/* Someone messed with the gsp. Have to
defer to scheduler to resolve this. dispatch ctr
is not yet decremented, so no need to increment. */
/* R15T is NOT up to date here. First, need to write
r0 back to R15T, but without trashing r8 since
that holds the value we want to return to the scheduler.
Hence use r1 transiently for the guest state pointer. */
ldr r1, [sp, #0]
str r0, [r1, #OFFSET_arm_R15T]
mov r0, r8 // "return modified gsp"
b run_innerloop_exit
/*NOTREACHED*/
counter_is_zero:
/* R15T is up to date here */
/* Back out increment of the dispatch ctr */
ldr r1, =VG_(dispatch_ctr)
ldr r2, [r1]
add r2, r2, #1
str r2, [r1]
mov r0, #VG_TRC_INNER_COUNTERZERO
b run_innerloop_exit
/*NOTREACHED*/
fast_lookup_failed:
/* R15T is up to date here */
/* Back out increment of the dispatch ctr */
ldr r1, =VG_(dispatch_ctr)
ldr r2, [r1]
add r2, r2, #1
str r2, [r1]
mov r0, #VG_TRC_INNER_FASTMISS
b run_innerloop_exit
/*NOTREACHED*/
/* All exits from the dispatcher go through here. %r0 holds
the return value.
*/
run_innerloop_exit:
/* We're leaving. Check that nobody messed with
FPSCR in ways we don't expect. */
fmrx r4, fpscr
bic r4, #0xF8000000 /* mask out NZCV and QC */
bic r4, #0x0000009F /* mask out IDC,IXC,UFC,OFC,DZC,IOC */
cmp r4, #0
bne invariant_violation
b run_innerloop_exit_REALLY
invariant_violation:
mov r0, #VG_TRC_INVARIANT_FAILED
b run_innerloop_exit_REALLY
run_innerloop_exit_REALLY:
add sp, sp, #8
pop {r4, r5, r6, r7, r8, r9, fp, pc}
.size VG_(run_innerloop), .-VG_(run_innerloop)
/*------------------------------------------------------------*/
/*--- ---*/
/*--- 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)
*/
.global VG_(run_a_noredir_translation)
VG_(run_a_noredir_translation):
push {r0,r1 /* EABI compliance */, r4-r12, lr}
ldr r8, [r0, #4]
mov lr, pc
ldr pc, [r0, #0]
pop {r1}
str r0, [r1, #8]
str r8, [r1, #12]
pop {r1/*EABI compliance*/,r4-r12, pc}
.size VG_(run_a_noredir_translation), .-VG_(run_a_noredir_translation)
/* Let the linker know we don't need an executable stack */
.section .note.GNU-stack,"",%progbits
#endif // defined(VGP_arm_linux)
/*--------------------------------------------------------------------*/
/*--- end dispatch-arm-linux.S ---*/
/*--------------------------------------------------------------------*/