1
2/*--------------------------------------------------------------------*/
3/*--- The core dispatch loop, for jumping to a code address.       ---*/
4/*---                                       dispatch-s390x-linux.S ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8  This file is part of Valgrind, a dynamic binary instrumentation
9  framework.
10
11  Copyright IBM Corp. 2010-2011
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/* Contributed by Florian Krohm and Christian Borntraeger */
32
33#include "pub_core_basics_asm.h"
34#include "pub_core_dispatch_asm.h"
35#include "pub_core_transtab_asm.h"
36#include "libvex_guest_offsets.h"
37#include "libvex_s390x_common.h"
38
39#if defined(VGA_s390x)
40
41/*------------------------------------------------------------*/
42/*---                                                      ---*/
43/*--- The dispatch loop.  VG_(run_innerloop) is used to    ---*/
44/*--- run all translations except no-redir ones.           ---*/
45/*---                                                      ---*/
46/*------------------------------------------------------------*/
47
48/* Convenience definitions for readability */
49#undef  SP
50#define SP S390_REGNO_STACK_POINTER
51
52#undef  LR
53#define LR S390_REGNO_LINK_REGISTER
54
55/* Location of valgrind's saved FPC register */
56#define S390_LOC_SAVED_FPC_V S390_OFFSET_SAVED_FPC_V(SP)
57
58/* Location of saved guest state pointer */
59#define S390_LOC_SAVED_GSP S390_OFFSET_SAVED_GSP(SP)
60
61/* Location of saved R2 register */
62#define S390_LOC_SAVED_R2 S390_OFFSET_SAVED_R2(SP)
63
64/*----------------------------------------------------*/
65/*--- Preamble (set everything up)                 ---*/
66/*----------------------------------------------------*/
67
68/* signature:
69UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
70*/
71
72.text
73.align   4
74.globl VG_(run_innerloop)
75VG_(run_innerloop):
76        /* r2 holds address of guest_state */
77        /* r3 holds do_profiling (a flag) */
78
79        /* Save gprs   ABI: r6...r13 and r15 */
80        stmg %r6,%r15,48(SP)
81
82        /* New stack frame */
83        aghi SP,-S390_INNERLOOP_FRAME_SIZE
84
85        /* Save fprs:   ABI: f8...f15 */
86        std  %f8,160+0(SP)
87        std  %f9,160+8(SP)
88        std  %f10,160+16(SP)
89        std  %f11,160+24(SP)
90        std  %f12,160+32(SP)
91        std  %f13,160+40(SP)
92        std  %f14,160+48(SP)
93        std  %f15,160+56(SP)
94
95        /* Load address of guest state into guest state register (r13) */
96        lgr  %r13,%r2
97
98        /* Store address of guest state pointer on stack.
99           It will be needed later because upon return from a VEX translation
100           r13 may contain a special value. So the old value will be used to
101           determine whether r13 contains a special value. */
102        stg  %r13,S390_LOC_SAVED_GSP
103
104        /* Save valgrind's FPC on stack so run_innerloop_exit can restore
105           it later . */
106        stfpc S390_LOC_SAVED_FPC_V
107
108        /* Load the FPC the way the client code wants it. I.e. pull the
109           value from the guest state.
110        lfpc OFFSET_s390x_fpc(%r13)
111
112        /* Get the IA from the guest state */
113        lg   %r2,OFFSET_s390x_IA(%r13)
114
115        /* Get VG_(dispatch_ctr) -- a 32-bit value -- and store it in a reg */
116        larl %r6,VG_(dispatch_ctr)
117        l    S390_REGNO_DISPATCH_CTR,0(%r6)
118
119        /* Fall into main loop (the right one) */
120
121        /* r3 = 1 --> do_profiling. We may trash r3 later on. That's OK,
122           because it's a volatile register (does not need to be preserved). */
123        ltgr %r3,%r3
124        je   run_innerloop__dispatch_unprofiled
125        j    run_innerloop__dispatch_profiled
126
127/*----------------------------------------------------*/
128/*--- NO-PROFILING (standard) dispatcher           ---*/
129/*----------------------------------------------------*/
130
131run_innerloop__dispatch_unprofiled:
132        /* Load the link register with the address the jitted code will
133           return to when it's done executing. The link register is loaded
134           exactly once per loop. This is safe, because the jitted code
135           cannot possibly modify the LR. How else would it be able to return
136           to the location in the LR otherwise? */
137        basr LR,0
138
139        /* Loop begins here */
140
141        /* This is the story:
142
143           r2  = IA = next guest address
144           r12 = VG_(dispatch_ctr)
145           r13 = guest state pointer or (upon return from guest code) some
146                 special value
147           r15 = stack pointer (as usual)
148        */
149innermost_loop:
150        /* Has the guest state pointer been messed with? If yes, exit.
151           The mess is recognised by r13 containing an odd value. */
152        tmll %r13,1
153        jne  gsp_changed
154
155        /* Save the jump address in the guest state */
156        stg  %r2,OFFSET_s390x_IA(%r13)
157
158
159	/* Try a fast lookup in the translation cache:
160           Compute offset (not index) into VT_(tt_fast):
161
162           offset = VG_TT_FAST_HASH(addr) * sizeof(FastCacheEntry)
163
164           with VG_TT_FAST_HASH(addr) == (addr >> 1) & VG_TT_FAST_MASK
165           and  sizeof(FastCacheEntry) == 16
166
167           offset = ((addr >> 1) & VG_TT_FAST_MASK) << 4
168           which is
169           offset = ((addr & (VG_TT_FAST_MASK << 1) ) << 3
170        */
171        larl  %r8, VG_(tt_fast)
172        llill %r5,( VG_TT_FAST_MASK << 1) & 0xffff
173#if ((( VG_TT_FAST_MASK << 1) & 0xffff0000) >> 16 != 0)
174        iilh %r5,(( VG_TT_FAST_MASK << 1) & 0xffff0000) >> 16
175#endif
176        ngr  %r5,%r2
177        sllg %r7,%r5,3
178
179	/* Are we out of timeslice?  If yes, defer to scheduler. */
180        ahi  S390_REGNO_DISPATCH_CTR,-1
181        jz   counter_is_zero
182
183        lg   %r11, 8(%r8,%r7)      /* .host */
184        cg   %r2,  0(%r8,%r7)      /* next guest address == .guest ? */
185        jne  fast_lookup_failed
186
187        /* Found a match.  Call .host.
188           r11 is an address. There we will find the instrumented client code.
189           That code may modify the guest state register r13. The client code
190           will return to the beginning of this loop start by issuing br LR.
191           We can simply branch to the host code */
192        br %r11
193
194
195/*----------------------------------------------------*/
196/*--- PROFILING dispatcher (can be much slower)    ---*/
197/*----------------------------------------------------*/
198
199run_innerloop__dispatch_profiled:
200        stg  %r2,S390_LOC_SAVED_R2
201
202        /* Load the link register with the address the jitted code will
203           return to when it's done executing. */
204        bras LR,innermost_loop
205
206        /* Jitted code returns here. Update profile counter for previous IA */
207
208        llill %r5,( VG_TT_FAST_MASK << 1) & 0xffff
209#if ((( VG_TT_FAST_MASK << 1) & 0xffff0000) >> 16 != 0)
210        iilh %r5,(( VG_TT_FAST_MASK << 1) & 0xffff0000) >> 16
211#endif
212        ng   %r5,S390_LOC_SAVED_R2
213        sllg %r7,%r5,2
214
215        /* Increment bb profile counter */
216        larl %r8, VG_(tt_fastN)
217        lg   %r9,0(%r8,%r7)
218        l    %r10,0(%r9)
219        ahi  %r10,1
220        st   %r10,0(%r9)
221
222        j    run_innerloop__dispatch_profiled
223
224/*----------------------------------------------------*/
225/*--- exit points                                  ---*/
226/*----------------------------------------------------*/
227
228gsp_changed:
229	/* Someone messed with the gsp (in r13).  Have to
230           defer to scheduler to resolve this.  The register
231           holding VG_(dispatch_ctr) is not yet decremented,
232           so no need to increment. */
233
234        /* Update the IA in the guest state */
235        lg  %r6,S390_LOC_SAVED_GSP       /* r6 = original guest state pointer */
236        stg %r2,OFFSET_s390x_IA(%r6)
237
238        /* Return the special guest state pointer value */
239        lgr %r2, %r13
240	j   run_innerloop_exit
241
242
243counter_is_zero:
244	/* IA is up to date */
245
246	/* Back out decrement of the dispatch counter */
247        ahi S390_REGNO_DISPATCH_CTR,1
248
249        /* Set return value for the scheduler */
250        lghi %r2,VG_TRC_INNER_COUNTERZERO
251        j    run_innerloop_exit
252
253
254fast_lookup_failed:
255	/* IA is up to date */
256
257	/* Back out decrement of the dispatch counter */
258        ahi S390_REGNO_DISPATCH_CTR,1
259
260        /* Set return value for the scheduler */
261        lghi %r2,VG_TRC_INNER_FASTMISS
262        j    run_innerloop_exit
263
264
265        /* All exits from the dispatcher go through here.
266           When we come here r2 holds the return value. */
267run_innerloop_exit:
268
269	/* Restore valgrind's FPC, as client code may have changed it. */
270        lfpc S390_LOC_SAVED_FPC_V
271
272        /* Write ctr to VG_(dispatch_ctr) (=32bit value) */
273        larl %r6,VG_(dispatch_ctr)
274        st   S390_REGNO_DISPATCH_CTR,0(%r6)
275
276        /* Restore callee-saved registers... */
277
278        /* Floating-point regs */
279        ld  %f8,160+0(SP)
280        ld  %f9,160+8(SP)
281        ld  %f10,160+16(SP)
282        ld  %f11,160+24(SP)
283        ld  %f12,160+32(SP)
284        ld  %f13,160+40(SP)
285        ld  %f14,160+48(SP)
286        ld  %f15,160+56(SP)
287
288        /* Remove atack frame */
289        aghi SP,S390_INNERLOOP_FRAME_SIZE
290
291        /* General-purpose regs. This also restores the original link
292           register (r14) and stack pointer (r15). */
293        lmg %r6,%r15,48(SP)
294
295        /* Return */
296        br  LR
297
298/*------------------------------------------------------------*/
299/*---                                                      ---*/
300/*--- A special dispatcher, for running no-redir           ---*/
301/*--- translations.  Just runs the given translation once. ---*/
302/*---                                                      ---*/
303/*------------------------------------------------------------*/
304
305/* signature:
306void VG_(run_a_noredir_translation) ( UWord* argblock );
307*/
308
309/* Run a no-redir translation.  argblock points to 4 UWords, 2 to carry args
310   and 2 to carry results:
311      0: input:  ptr to translation
312      1: input:  ptr to guest state
313      2: output: next guest PC
314      3: output: guest state pointer afterwards (== thread return code)
315*/
316.text
317.align   4
318.globl VG_(run_a_noredir_translation)
319VG_(run_a_noredir_translation):
320        stmg %r6,%r15,48(SP)
321        aghi SP,-S390_INNERLOOP_FRAME_SIZE
322        std  %f8,160+0(SP)
323        std  %f9,160+8(SP)
324        std  %f10,160+16(SP)
325        std  %f11,160+24(SP)
326        std  %f12,160+32(SP)
327        std  %f13,160+40(SP)
328        std  %f14,160+48(SP)
329        std  %f15,160+56(SP)
330
331        /* Load address of guest state into guest state register (r13) */
332        lg   %r13,8(%r2)
333
334        /* Get the IA */
335        lg   %r11,0(%r2)
336
337        /* save r2 (argblock) as it is clobbered */
338	stg  %r2,160+64(SP)
339
340        /* the call itself */
341        basr LR,%r11
342
343        /* restore argblock */
344	lg   %r1,160+64(SP)
345	/* save the next guest PC */
346	stg  %r2,16(%r1)
347
348	/* save the guest state */
349	stg  %r13,24(%r1)
350
351        /* Restore Floating-point regs */
352        ld  %f8,160+0(SP)
353        ld  %f9,160+8(SP)
354        ld  %f10,160+16(SP)
355        ld  %f11,160+24(SP)
356        ld  %f12,160+32(SP)
357        ld  %f13,160+40(SP)
358        ld  %f14,160+48(SP)
359        ld  %f15,160+56(SP)
360
361        aghi SP,S390_INNERLOOP_FRAME_SIZE
362
363        lmg %r6,%r15,48(SP)
364	br  %r14
365
366
367/* Let the linker know we don't need an executable stack */
368.section .note.GNU-stack,"",@progbits
369
370#endif /* VGA_s390x */
371
372/*--------------------------------------------------------------------*/
373/*--- end                                   dispatch-s390x-linux.S ---*/
374/*--------------------------------------------------------------------*/
375