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