2 /*--------------------------------------------------------------------*/
3 /*--- The core dispatch loop, for jumping to a code address. ---*/
4 /*--- dispatch-arm-linux.S ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2008-2010 Evan Geller
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 The GNU General Public License is contained in the file COPYING.
32 #if defined(VGP_arm_linux)
34 #include "pub_core_basics_asm.h"
35 #include "pub_core_dispatch_asm.h"
36 #include "pub_core_transtab_asm.h"
37 #include "libvex_guest_offsets.h" /* for OFFSET_arm_R* */
40 /*------------------------------------------------------------*/
42 /*--- The dispatch loop. VG_(run_innerloop) is used to ---*/
43 /*--- run all translations except no-redir ones. ---*/
45 /*------------------------------------------------------------*/
47 /*----------------------------------------------------*/
48 /*--- Preamble (set everything up) ---*/
49 /*----------------------------------------------------*/
52 UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
55 .globl VG_(run_innerloop)
57 push {r0, r1, r4, r5, r6, r7, r8, r9, fp, lr}
59 /* set FPSCR to vex-required default value */
63 /* r0 (hence also [sp,#0]) holds guest_state */
64 /* r1 holds do_profiling */
66 ldr r0, [r8, #OFFSET_arm_R15]
68 /* fall into main loop (the right one) */
69 cmp r1, #0 /* do_profiling */
70 beq VG_(run_innerloop__dispatch_unprofiled)
71 b VG_(run_innerloop__dispatch_profiled)
74 /*----------------------------------------------------*/
75 /*--- NO-PROFILING (standard) dispatcher ---*/
76 /*----------------------------------------------------*/
78 .global VG_(run_innerloop__dispatch_unprofiled)
79 VG_(run_innerloop__dispatch_unprofiled):
81 /* AT ENTRY: r0 is next guest addr, r8 is possibly
82 modified guest state ptr */
84 /* Has the guest state pointer been messed with? If yes, exit. */
89 /* save the jump address in the guest state */
90 str r0, [r8, #OFFSET_arm_R15]
92 /* Are we out of timeslice? If yes, defer to scheduler. */
93 ldr r1, =VG_(dispatch_ctr)
99 /* try a fast lookup in the translation cache */
100 // r0 = next guest, r1,r2,r3 scratch
101 ldr r1, =VG_TT_FAST_MASK // r1 = VG_TT_FAST_MASK
102 and r2, r1, r0, LSR #2 // r2 = entry #
103 ldr r1, =VG_(tt_fast) // r1 = &tt_fast[0]
104 add r1, r1, r2, LSL #3 // r1 = &tt_fast[entry#]
105 ldr r3, [r1, #0] /* .guest */
106 ldr r1, [r1, #4] /* .host */
108 bne fast_lookup_failed
109 // r1: live, next-host r8: live, gsp
110 // r2: entry # (but not live)
113 /* Found a match. Jump to .host. */
115 b VG_(run_innerloop__dispatch_unprofiled)
119 /*----------------------------------------------------*/
120 /*--- PROFILING dispatcher (can be much slower) ---*/
121 /*----------------------------------------------------*/
123 .global VG_(run_innerloop__dispatch_profiled)
124 VG_(run_innerloop__dispatch_profiled):
126 /* AT ENTRY: r0 is next guest addr, r8 is possibly
127 modified guest state ptr */
129 /* Has the guest state pointer been messed with? If yes, exit. */
134 /* save the jump address in the guest state */
135 str r0, [r8, #OFFSET_arm_R15]
137 /* Are we out of timeslice? If yes, defer to scheduler. */
138 ldr r1, =VG_(dispatch_ctr)
144 /* try a fast lookup in the translation cache */
145 // r0 = next guest, r1,r2,r3 scratch
146 ldr r1, =VG_TT_FAST_MASK // r1 = VG_TT_FAST_MASK
147 and r2, r1, r0, LSR #2 // r2 = entry #
148 ldr r1, =VG_(tt_fast) // r1 = &tt_fast[0]
149 add r1, r1, r2, LSL #3 // r1 = &tt_fast[entry#]
150 ldr r3, [r1, #0] /* .guest */
151 ldr r1, [r1, #4] /* .host */
153 bne fast_lookup_failed
154 // r1: live, next-host r8: live, gsp
155 // r2: entry # (but not live)
158 /* increment bb profile counter */
159 ldr r0, =VG_(tt_fastN) // r0 = &tt_fastN[0]
160 ldr r0, [r0, r2, LSL #2] // r0 = tt_fast[entry #]
161 ldr r3, [r0] // *r0 ++
165 /* Found a match. Jump to .host. */
167 b VG_(run_innerloop__dispatch_profiled)
170 /*----------------------------------------------------*/
171 /*--- exit points ---*/
172 /*----------------------------------------------------*/
175 // r0 = next guest addr (R15), r8 = modified gsp
176 /* Someone messed with the gsp. Have to
177 defer to scheduler to resolve this. dispatch ctr
178 is not yet decremented, so no need to increment. */
179 /* R15 is NOT up to date here. First, need to write
180 r0 back to R15, but without trashing r8 since
181 that holds the value we want to return to the scheduler.
182 Hence use r1 transiently for the guest state pointer. */
184 str r0, [r1, #OFFSET_arm_R15]
185 mov r0, r8 // "return modified gsp"
190 /* R15 is up to date here */
191 /* Back out increment of the dispatch ctr */
192 ldr r1, =VG_(dispatch_ctr)
196 mov r0, #VG_TRC_INNER_COUNTERZERO
201 /* R15 is up to date here */
202 /* Back out increment of the dispatch ctr */
203 ldr r1, =VG_(dispatch_ctr)
207 mov r0, #VG_TRC_INNER_FASTMISS
211 /* All exits from the dispatcher go through here. %r0 holds
215 /* We're leaving. Check that nobody messed with
216 FPSCR in ways we don't expect. */
218 bic r4, #0xF0000000 /* mask out NZCV */
219 bic r4, #0x0000001F /* mask out IXC,UFC,OFC,DZC,IOC */
221 bne invariant_violation
222 b run_innerloop_exit_REALLY
225 mov r0, #VG_TRC_INVARIANT_FAILED
226 b run_innerloop_exit_REALLY
228 run_innerloop_exit_REALLY:
230 pop {r4, r5, r6, r7, r8, r9, fp, pc}
232 .size VG_(run_innerloop), .-VG_(run_innerloop)
235 /*------------------------------------------------------------*/
237 /*--- A special dispatcher, for running no-redir ---*/
238 /*--- translations. Just runs the given translation once. ---*/
240 /*------------------------------------------------------------*/
243 void VG_(run_a_noredir_translation) ( UWord* argblock );
246 /* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args
247 and 2 to carry results:
248 0: input: ptr to translation
249 1: input: ptr to guest state
250 2: output: next guest PC
251 3: output: guest state pointer afterwards (== thread return code)
253 .global VG_(run_a_noredir_translation)
254 VG_(run_a_noredir_translation):
255 push {r0,r1 /* EABI compliance */, r4-r12, lr}
263 pop {r1/*EABI compliance*/,r4-r12, pc}
265 .size VG_(run_a_noredir_translation), .-VG_(run_a_noredir_translation)
267 /* Let the linker know we don't need an executable stack */
268 .section .note.GNU-stack,"",%progbits
270 #endif // defined(VGP_arm_linux)
272 /*--------------------------------------------------------------------*/
273 /*--- end dispatch-arm-linux.S ---*/
274 /*--------------------------------------------------------------------*/