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