dispatch-arm-linux.S revision ec062e8d96a361af9905b5447027819dfbfee01a
1/*--------------------------------------------------------------------*/
2/*--- The core dispatch loop, for jumping to a code address.       ---*/
3/*---                                         dispatch-arm-linux.S ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7  This file is part of Valgrind, a dynamic binary instrumentation
8  framework.
9
10  Copyright (C) 2008-2011 Evan Geller
11     gaze@bea.ms
12
13  This program is free software; you can redistribute it and/or
14  modify it under the terms of the GNU General Public License as
15  published by the Free Software Foundation; either version 2 of the
16  License, or (at your option) any later version.
17
18  This program is distributed in the hope that it will be useful, but
19  WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  General Public License for more details.
22
23  You should have received a copy of the GNU General Public License
24  along with this program; if not, write to the Free Software
25  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26  02111-1307, USA.
27
28  The GNU General Public License is contained in the file COPYING.
29*/
30
31#if defined(VGP_arm_linux)
32	.fpu vfp
33
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* */
38
39
40/*------------------------------------------------------------*/
41/*---                                                      ---*/
42/*--- The dispatch loop.  VG_(run_innerloop) is used to    ---*/
43/*--- run all translations except no-redir ones.           ---*/
44/*---                                                      ---*/
45/*------------------------------------------------------------*/
46
47/*----------------------------------------------------*/
48/*--- Preamble (set everything up)                 ---*/
49/*----------------------------------------------------*/
50
51/* signature:
52UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
53*/
54.text
55.globl VG_(run_innerloop)
56VG_(run_innerloop):
57	push {r0, r1, r4, r5, r6, r7, r8, r9, fp, lr}
58
59        /* set FPSCR to vex-required default value */
60        mov  r4, #0
61        fmxr fpscr, r4
62
63        /* r0 (hence also [sp,#0]) holds guest_state */
64        /* r1 holds do_profiling */
65	mov r8, r0
66	ldr r0, [r8, #OFFSET_arm_R15T]
67
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)
72
73
74/*----------------------------------------------------*/
75/*--- NO-PROFILING (standard) dispatcher           ---*/
76/*----------------------------------------------------*/
77
78/* Pairing of insns below is my guesstimate of how dual dispatch would
79   work on an A8.  JRS, 2011-May-28 */
80
81.global	VG_(run_innerloop__dispatch_unprofiled)
82VG_(run_innerloop__dispatch_unprofiled):
83
84	/* AT ENTRY: r0 is next guest addr, r8 is possibly
85        modified guest state ptr */
86
87        /* Has the guest state pointer been messed with?  If yes, exit. */
88        movw r3, #:lower16:VG_(dispatch_ctr)
89        tst  r8, #1
90
91        movt r3, #:upper16:VG_(dispatch_ctr)
92
93	bne  gsp_changed
94
95	/* save the jump address in the guest state */
96        str  r0, [r8, #OFFSET_arm_R15T]
97
98        /* Are we out of timeslice?  If yes, defer to scheduler. */
99        ldr  r2, [r3]
100
101        subs r2, r2, #1
102
103        str  r2, [r3]
104
105        beq  counter_is_zero
106
107        /* try a fast lookup in the translation cache */
108        // r0 = next guest, r1,r2,r3,r4 scratch
109        movw r1, #VG_TT_FAST_MASK       // r1 = VG_TT_FAST_MASK
110        movw r4, #:lower16:VG_(tt_fast)
111
112	and  r2, r1, r0, LSR #1         // r2 = entry #
113        movt r4, #:upper16:VG_(tt_fast) // r4 = &VG_(tt_fast)
114
115	add  r1, r4, r2, LSL #3         // r1 = &tt_fast[entry#]
116
117        ldrd r4, r5, [r1, #0]           // r4 = .guest, r5 = .host
118
119	cmp  r4, r0
120
121	bne  fast_lookup_failed
122        // r5: next-host    r8: live, gsp
123        // r4: next-guest
124        // r2: entry #
125        // LIVE: r5, r8; all others dead
126
127        /* Found a match.  Jump to .host. */
128	blx  r5
129	b    VG_(run_innerloop__dispatch_unprofiled)
130.ltorg
131	/*NOTREACHED*/
132
133/*----------------------------------------------------*/
134/*--- PROFILING dispatcher (can be much slower)    ---*/
135/*----------------------------------------------------*/
136
137.global	VG_(run_innerloop__dispatch_profiled)
138VG_(run_innerloop__dispatch_profiled):
139
140	/* AT ENTRY: r0 is next guest addr, r8 is possibly
141        modified guest state ptr */
142
143        /* Has the guest state pointer been messed with?  If yes, exit. */
144        movw r3, #:lower16:VG_(dispatch_ctr)
145	tst  r8, #1
146
147        movt r3, #:upper16:VG_(dispatch_ctr)
148
149	bne  gsp_changed
150
151	/* save the jump address in the guest state */
152        str  r0, [r8, #OFFSET_arm_R15T]
153
154        /* Are we out of timeslice?  If yes, defer to scheduler. */
155        ldr  r2, [r3]
156
157        subs r2, r2, #1
158
159        str  r2, [r3]
160
161        beq  counter_is_zero
162
163        /* try a fast lookup in the translation cache */
164        // r0 = next guest, r1,r2,r3,r4 scratch
165        movw r1, #VG_TT_FAST_MASK       // r1 = VG_TT_FAST_MASK
166        movw r4, #:lower16:VG_(tt_fast)
167
168	and  r2, r1, r0, LSR #1         // r2 = entry #
169        movt r4, #:upper16:VG_(tt_fast) // r4 = &VG_(tt_fast)
170
171	add  r1, r4, r2, LSL #3         // r1 = &tt_fast[entry#]
172
173        ldrd r4, r5, [r1, #0]           // r4 = .guest, r5 = .host
174
175	cmp  r4, r0
176
177	bne  fast_lookup_failed
178        // r5: next-host    r8: live, gsp
179        // r4: next-guest
180        // r2: entry #
181        // LIVE: r5, r8; all others dead
182
183        /* increment bb profile counter */
184        movw r0, #:lower16:VG_(tt_fastN)
185        movt r0, #:upper16:VG_(tt_fastN) // r0 = &tt_fastN[0]
186        ldr  r0, [r0, r2, LSL #2]        // r0 = tt_fast[entry #]
187        ldr  r3, [r0]                    // *r0 ++
188        add  r3, r3, #1
189        str  r3, [r0]
190
191        /* Found a match.  Jump to .host. */
192	blx  r5
193	b    VG_(run_innerloop__dispatch_profiled)
194	/*NOTREACHED*/
195
196/*----------------------------------------------------*/
197/*--- exit points                                  ---*/
198/*----------------------------------------------------*/
199
200gsp_changed:
201        // r0 = next guest addr (R15T), r8 = modified gsp
202        /* Someone messed with the gsp.  Have to
203           defer to scheduler to resolve this.  dispatch ctr
204           is not yet decremented, so no need to increment. */
205        /* R15T is NOT up to date here.  First, need to write
206           r0 back to R15T, but without trashing r8 since
207           that holds the value we want to return to the scheduler.
208           Hence use r1 transiently for the guest state pointer. */
209	ldr r1, [sp, #0]
210	str r0, [r1, #OFFSET_arm_R15T]
211	mov r0, r8      // "return modified gsp"
212	b run_innerloop_exit
213        /*NOTREACHED*/
214
215counter_is_zero:
216        /* R15T is up to date here */
217        /* Back out increment of the dispatch ctr */
218        ldr  r1, =VG_(dispatch_ctr)
219        ldr  r2, [r1]
220        add  r2, r2, #1
221        str  r2, [r1]
222        mov  r0, #VG_TRC_INNER_COUNTERZERO
223        b    run_innerloop_exit
224        /*NOTREACHED*/
225
226fast_lookup_failed:
227        /* R15T is up to date here */
228        /* Back out increment of the dispatch ctr */
229        ldr  r1, =VG_(dispatch_ctr)
230        ldr  r2, [r1]
231        add  r2, r2, #1
232        str  r2, [r1]
233	mov  r0, #VG_TRC_INNER_FASTMISS
234	b    run_innerloop_exit
235        /*NOTREACHED*/
236
237/* All exits from the dispatcher go through here.  %r0 holds
238   the return value.
239*/
240run_innerloop_exit:
241        /* We're leaving.  Check that nobody messed with
242           FPSCR in ways we don't expect. */
243        fmrx r4, fpscr
244        bic  r4, #0xF8000000 /* mask out NZCV and QC */
245        bic  r4, #0x0000009F /* mask out IDC,IXC,UFC,OFC,DZC,IOC */
246        cmp  r4, #0
247        bne  invariant_violation
248        b    run_innerloop_exit_REALLY
249
250invariant_violation:
251        mov  r0, #VG_TRC_INVARIANT_FAILED
252        b    run_innerloop_exit_REALLY
253
254run_innerloop_exit_REALLY:
255	add sp, sp, #8
256	pop {r4, r5, r6, r7, r8, r9, fp, pc}
257
258.size VG_(run_innerloop), .-VG_(run_innerloop)
259
260
261/*------------------------------------------------------------*/
262/*---                                                      ---*/
263/*--- A special dispatcher, for running no-redir           ---*/
264/*--- translations.  Just runs the given translation once. ---*/
265/*---                                                      ---*/
266/*------------------------------------------------------------*/
267
268/* signature:
269void VG_(run_a_noredir_translation) ( UWord* argblock );
270*/
271
272/* Run a no-redir translation.  argblock points to 4 UWords, 2 to carry args
273   and 2 to carry results:
274      0: input:  ptr to translation
275      1: input:  ptr to guest state
276      2: output: next guest PC
277      3: output: guest state pointer afterwards (== thread return code)
278*/
279.global VG_(run_a_noredir_translation)
280VG_(run_a_noredir_translation):
281	push {r0,r1 /* EABI compliance */, r4-r12, lr}
282	ldr r8, [r0, #4]
283	mov lr, pc
284	ldr pc, [r0, #0]
285
286	pop {r1}
287	str r0, [r1, #8]
288	str r8, [r1, #12]
289	pop {r1/*EABI compliance*/,r4-r12, pc}
290
291.size VG_(run_a_noredir_translation), .-VG_(run_a_noredir_translation)
292
293/* Let the linker know we don't need an executable stack */
294.section .note.GNU-stack,"",%progbits
295
296#endif // defined(VGP_arm_linux)
297
298/*--------------------------------------------------------------------*/
299/*--- end                                     dispatch-arm-linux.S ---*/
300/*--------------------------------------------------------------------*/
301