cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 1 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- The core dispatch loop, for jumping to a code address. ---*/ |
sewardj | 0ddf76c | 2006-10-17 02:08:26 +0000 | [diff] [blame] | 4 | /*--- dispatch-ppc32-linux.S ---*/ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 5 | /*--------------------------------------------------------------------*/ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 6 | |
| 7 | /* |
| 8 | This file is part of Valgrind, a dynamic binary instrumentation |
| 9 | framework. |
| 10 | |
sewardj | 4d474d0 | 2008-02-11 11:34:59 +0000 | [diff] [blame^] | 11 | Copyright (C) 2005-2008 Cerion Armour-Brown <cerion@open-works.co.uk> |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 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 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 31 | #include "pub_core_basics_asm.h" |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 32 | #include "pub_core_dispatch_asm.h" |
| 33 | #include "pub_core_transtab_asm.h" |
| 34 | #include "libvex_guest_offsets.h" /* for OFFSET_ppc32_CIA */ |
| 35 | |
| 36 | |
| 37 | /*------------------------------------------------------------*/ |
sewardj | a591a05 | 2006-01-12 14:04:46 +0000 | [diff] [blame] | 38 | /*--- ---*/ |
| 39 | /*--- The dispatch loop. VG_(run_innerloop) is used to ---*/ |
| 40 | /*--- run all translations except no-redir ones. ---*/ |
| 41 | /*--- ---*/ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 42 | /*------------------------------------------------------------*/ |
| 43 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 44 | /*----------------------------------------------------*/ |
| 45 | /*--- Preamble (set everything up) ---*/ |
| 46 | /*----------------------------------------------------*/ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 47 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 48 | /* signature: |
| 49 | UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling ); |
| 50 | */ |
| 51 | .text |
| 52 | .globl VG_(run_innerloop) |
tom | 63c8de5 | 2006-05-01 09:28:39 +0000 | [diff] [blame] | 53 | .type VG_(run_innerloop), @function |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 54 | VG_(run_innerloop): |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 55 | /* r3 holds guest_state */ |
| 56 | /* r4 holds do_profiling */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 57 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 58 | /* ----- entry point to VG_(run_innerloop) ----- */ |
cerion | 51ce791 | 2005-11-11 01:00:36 +0000 | [diff] [blame] | 59 | /* For Linux/ppc32 we need the SysV ABI, which uses |
| 60 | LR->4(parent_sp), CR->anywhere. |
cerion | 1ade697 | 2005-12-20 20:48:50 +0000 | [diff] [blame] | 61 | (The AIX ABI, used on Darwin, |
cerion | 51ce791 | 2005-11-11 01:00:36 +0000 | [diff] [blame] | 62 | uses LR->8(prt_sp), CR->4(prt_sp)) |
| 63 | */ |
| 64 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 65 | /* Save lr */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 66 | mflr 0 |
| 67 | stw 0,4(1) |
| 68 | |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 69 | /* New stack frame */ |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 70 | stwu 1,-496(1) /* sp should maintain 16-byte alignment */ |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 71 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 72 | /* Save callee-saved registers... */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 73 | /* r3, r4 are live here, so use r5 */ |
| 74 | lis 5,VG_(machine_ppc32_has_FP)@ha |
| 75 | lwz 5,VG_(machine_ppc32_has_FP)@l(5) |
| 76 | cmplwi 5,0 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 77 | beq LafterFP1 |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 78 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 79 | /* Floating-point reg save area : 144 bytes */ |
| 80 | stfd 31,488(1) |
| 81 | stfd 30,480(1) |
| 82 | stfd 29,472(1) |
| 83 | stfd 28,464(1) |
| 84 | stfd 27,456(1) |
| 85 | stfd 26,448(1) |
| 86 | stfd 25,440(1) |
| 87 | stfd 24,432(1) |
| 88 | stfd 23,424(1) |
| 89 | stfd 22,416(1) |
| 90 | stfd 21,408(1) |
| 91 | stfd 20,400(1) |
| 92 | stfd 19,392(1) |
| 93 | stfd 18,384(1) |
| 94 | stfd 17,376(1) |
| 95 | stfd 16,368(1) |
| 96 | stfd 15,360(1) |
| 97 | stfd 14,352(1) |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 98 | LafterFP1: |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 99 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 100 | /* General reg save area : 72 bytes */ |
| 101 | stw 31,348(1) |
| 102 | stw 30,344(1) |
| 103 | stw 29,340(1) |
| 104 | stw 28,336(1) |
| 105 | stw 27,332(1) |
| 106 | stw 26,328(1) |
| 107 | stw 25,324(1) |
| 108 | stw 24,320(1) |
| 109 | stw 23,316(1) |
| 110 | stw 22,312(1) |
| 111 | stw 21,308(1) |
| 112 | stw 20,304(1) |
| 113 | stw 19,300(1) |
| 114 | stw 18,296(1) |
| 115 | stw 17,292(1) |
| 116 | stw 16,288(1) |
| 117 | stw 15,284(1) |
| 118 | stw 14,280(1) |
cerion | 51ce791 | 2005-11-11 01:00:36 +0000 | [diff] [blame] | 119 | /* Probably not necessary to save r13 (thread-specific ptr), |
| 120 | as VEX stays clear of it... but what the hey. */ |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 121 | stw 13,276(1) |
| 122 | |
cerion | 51ce791 | 2005-11-11 01:00:36 +0000 | [diff] [blame] | 123 | /* It's necessary to save/restore VRSAVE in the AIX / Darwin ABI. |
| 124 | The Linux kernel might not actually use VRSAVE for its intended |
| 125 | purpose, but it should be harmless to preserve anyway. */ |
cerion | 1ade697 | 2005-12-20 20:48:50 +0000 | [diff] [blame] | 126 | /* r3, r4 are live here, so use r5 */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 127 | lis 5,VG_(machine_ppc32_has_VMX)@ha |
| 128 | lwz 5,VG_(machine_ppc32_has_VMX)@l(5) |
| 129 | cmplwi 5,0 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 130 | beq LafterVMX1 |
cerion | 51ce791 | 2005-11-11 01:00:36 +0000 | [diff] [blame] | 131 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 132 | /* VRSAVE save word : 32 bytes */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 133 | mfspr 5,256 /* vrsave reg is spr number 256 */ |
| 134 | stw 5,244(1) |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 135 | |
| 136 | /* Alignment padding : 4 bytes */ |
| 137 | |
| 138 | /* Vector reg save area (quadword aligned) : 192 bytes */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 139 | li 5,224 |
| 140 | stvx 31,5,1 |
| 141 | li 5,208 |
| 142 | stvx 30,5,1 |
| 143 | li 5,192 |
| 144 | stvx 29,5,1 |
| 145 | li 5,176 |
| 146 | stvx 28,5,1 |
| 147 | li 5,160 |
| 148 | stvx 27,5,1 |
| 149 | li 5,144 |
| 150 | stvx 26,5,1 |
| 151 | li 5,128 |
| 152 | stvx 25,5,1 |
| 153 | li 5,112 |
| 154 | stvx 25,5,1 |
| 155 | li 5,96 |
| 156 | stvx 23,5,1 |
| 157 | li 5,80 |
| 158 | stvx 22,5,1 |
| 159 | li 5,64 |
| 160 | stvx 21,5,1 |
| 161 | li 5,48 |
| 162 | stvx 20,5,1 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 163 | LafterVMX1: |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 164 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 165 | /* Save cr */ |
| 166 | mfcr 0 |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 167 | stw 0,44(1) |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 168 | |
cerion | 51ce791 | 2005-11-11 01:00:36 +0000 | [diff] [blame] | 169 | /* Local variable space... */ |
| 170 | |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 171 | /* 32(sp) used later to check FPSCR[RM] */ |
| 172 | |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 173 | /* r3 holds guest_state */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 174 | /* r4 holds do_profiling */ |
| 175 | mr 31,3 /* r31 (generated code gsp) = r3 */ |
| 176 | stw 3,28(1) /* spill orig guest_state ptr */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 177 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 178 | /* 24(sp) used later to stop ctr reg being clobbered */ |
cerion | a5422db | 2005-12-01 19:05:41 +0000 | [diff] [blame] | 179 | /* 20(sp) used later to load fpscr with zero */ |
| 180 | /* 8:16(sp) free */ |
cerion | 1b6b2b3 | 2005-11-18 20:45:18 +0000 | [diff] [blame] | 181 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 182 | /* Linkage Area (reserved) |
cerion | 1b6b2b3 | 2005-11-18 20:45:18 +0000 | [diff] [blame] | 183 | 4(sp) : LR |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 184 | 0(sp) : back-chain |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 185 | */ |
| 186 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 187 | /* CAB TODO: Use a caller-saved reg for orig guest_state ptr |
| 188 | - rem to set non-allocateable in isel.c */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 189 | |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 190 | /* hold dispatch_ctr in r29 */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 191 | lis 5,VG_(dispatch_ctr)@ha |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 192 | lwz 29,VG_(dispatch_ctr)@l(5) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 193 | |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 194 | /* set host FPU control word to the default mode expected |
cerion | 1936d8d | 2005-07-05 18:24:22 +0000 | [diff] [blame] | 195 | by VEX-generated code. See comments in libvex.h for |
| 196 | more info. */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 197 | lis 5,VG_(machine_ppc32_has_FP)@ha |
| 198 | lwz 5,VG_(machine_ppc32_has_FP)@l(5) |
| 199 | cmplwi 5,0 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 200 | beq LafterFP2 |
cerion | 1b6b2b3 | 2005-11-18 20:45:18 +0000 | [diff] [blame] | 201 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 202 | /* get zero into f3 (tedious) */ |
| 203 | /* note: fsub 3,3,3 is not a reliable way to do this, |
| 204 | since if f3 holds a NaN or similar then we don't necessarily |
| 205 | wind up with zero. */ |
| 206 | li 5,0 |
| 207 | stw 5,20(1) |
cerion | a5422db | 2005-12-01 19:05:41 +0000 | [diff] [blame] | 208 | lfs 3,20(1) |
cerion | 2108204 | 2005-12-06 19:07:08 +0000 | [diff] [blame] | 209 | mtfsf 0xFF,3 /* fpscr = f3 */ |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 210 | LafterFP2: |
cerion | 1936d8d | 2005-07-05 18:24:22 +0000 | [diff] [blame] | 211 | |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 212 | /* set host AltiVec control word to the default mode expected |
| 213 | by VEX-generated code. */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 214 | lis 5,VG_(machine_ppc32_has_VMX)@ha |
| 215 | lwz 5,VG_(machine_ppc32_has_VMX)@l(5) |
| 216 | cmplwi 5,0 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 217 | beq LafterVMX2 |
cerion | 1b6b2b3 | 2005-11-18 20:45:18 +0000 | [diff] [blame] | 218 | |
| 219 | vspltisw 3,0x0 /* generate zero */ |
cerion | 1936d8d | 2005-07-05 18:24:22 +0000 | [diff] [blame] | 220 | mtvscr 3 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 221 | LafterVMX2: |
| 222 | |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 223 | /* make a stack frame for the code we are calling */ |
| 224 | stwu 1,-16(1) |
| 225 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 226 | /* fetch %CIA into r3 */ |
| 227 | lwz 3,OFFSET_ppc32_CIA(31) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 228 | |
cerion | 1ade697 | 2005-12-20 20:48:50 +0000 | [diff] [blame] | 229 | /* fall into main loop (the right one) */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 230 | /* r4 = do_profiling. It's probably trashed after here, |
| 231 | but that's OK: we don't need it after here. */ |
| 232 | cmplwi 4,0 |
| 233 | beq VG_(run_innerloop__dispatch_unprofiled) |
| 234 | b VG_(run_innerloop__dispatch_profiled) |
| 235 | /*NOTREACHED*/ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 236 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 237 | /*----------------------------------------------------*/ |
| 238 | /*--- NO-PROFILING (standard) dispatcher ---*/ |
| 239 | /*----------------------------------------------------*/ |
| 240 | |
| 241 | .global VG_(run_innerloop__dispatch_unprofiled) |
| 242 | VG_(run_innerloop__dispatch_unprofiled): |
| 243 | /* At entry: Live regs: |
cerion | 1ade697 | 2005-12-20 20:48:50 +0000 | [diff] [blame] | 244 | r1 (=sp) |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 245 | r3 (=CIA = next guest address) |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 246 | r29 (=dispatch_ctr) |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 247 | r31 (=guest_state) |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 248 | Stack state: |
| 249 | 44(r1) (=orig guest_state) |
| 250 | */ |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 251 | /* Has the guest state pointer been messed with? If yes, exit. |
sewardj | 4994cc2 | 2007-02-11 09:09:20 +0000 | [diff] [blame] | 252 | Also set up & VG_(tt_fast) early in an attempt at better |
| 253 | scheduling. */ |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 254 | lwz 9,44(1) /* original guest_state ptr */ |
| 255 | lis 5,VG_(tt_fast)@ha |
| 256 | addi 5,5,VG_(tt_fast)@l /* & VG_(tt_fast) */ |
| 257 | cmpw 9,31 |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 258 | bne gsp_changed |
| 259 | |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 260 | /* save the jump address in the guest state */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 261 | stw 3,OFFSET_ppc32_CIA(31) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 262 | |
| 263 | /* Are we out of timeslice? If yes, defer to scheduler. */ |
cerion | 1ade697 | 2005-12-20 20:48:50 +0000 | [diff] [blame] | 264 | subi 29,29,1 |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 265 | cmplwi 29,0 |
| 266 | beq counter_is_zero |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 267 | |
| 268 | /* try a fast lookup in the translation cache */ |
sewardj | 4994cc2 | 2007-02-11 09:09:20 +0000 | [diff] [blame] | 269 | /* r4 = VG_TT_FAST_HASH(addr) * sizeof(FastCacheEntry) |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 270 | = ((r3 >>u 2) & VG_TT_FAST_MASK) << 3 */ |
| 271 | rlwinm 4,3,1, 29-VG_TT_FAST_BITS, 28 /* entry# * 8 */ |
| 272 | add 5,5,4 /* & VG_(tt_fast)[entry#] */ |
| 273 | lwz 6,0(5) /* .guest */ |
| 274 | lwz 7,4(5) /* .host */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 275 | cmpw 3,6 |
| 276 | bne fast_lookup_failed |
| 277 | |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 278 | /* Found a match. Call .host. */ |
| 279 | mtctr 7 |
sewardj | 0ddf76c | 2006-10-17 02:08:26 +0000 | [diff] [blame] | 280 | bctrl |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 281 | |
cerion | 1ade697 | 2005-12-20 20:48:50 +0000 | [diff] [blame] | 282 | /* On return from guest code: |
| 283 | r3 holds destination (original) address. |
| 284 | r31 may be unchanged (guest_state), or may indicate further |
| 285 | details of the control transfer requested to *r3. |
| 286 | */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 287 | /* start over */ |
| 288 | b VG_(run_innerloop__dispatch_unprofiled) |
| 289 | /*NOTREACHED*/ |
| 290 | |
| 291 | /*----------------------------------------------------*/ |
| 292 | /*--- PROFILING dispatcher (can be much slower) ---*/ |
| 293 | /*----------------------------------------------------*/ |
| 294 | |
| 295 | .global VG_(run_innerloop__dispatch_profiled) |
| 296 | VG_(run_innerloop__dispatch_profiled): |
| 297 | /* At entry: Live regs: |
| 298 | r1 (=sp) |
| 299 | r3 (=CIA = next guest address) |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 300 | r29 (=dispatch_ctr) |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 301 | r31 (=guest_state) |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 302 | Stack state: |
| 303 | 44(r1) (=orig guest_state) |
| 304 | */ |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 305 | /* Has the guest state pointer been messed with? If yes, exit. |
sewardj | 4994cc2 | 2007-02-11 09:09:20 +0000 | [diff] [blame] | 306 | Also set up & VG_(tt_fast) early in an attempt at better |
| 307 | scheduling. */ |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 308 | lwz 9,44(1) /* original guest_state ptr */ |
| 309 | lis 5,VG_(tt_fast)@ha |
| 310 | addi 5,5,VG_(tt_fast)@l /* & VG_(tt_fast) */ |
| 311 | cmpw 9,31 |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 312 | bne gsp_changed |
| 313 | |
| 314 | /* save the jump address in the guest state */ |
| 315 | stw 3,OFFSET_ppc32_CIA(31) |
| 316 | |
| 317 | /* Are we out of timeslice? If yes, defer to scheduler. */ |
sewardj | 3387dda | 2005-12-26 17:58:58 +0000 | [diff] [blame] | 318 | subi 29,29,1 |
| 319 | cmplwi 29,0 |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 320 | beq counter_is_zero |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 321 | |
| 322 | /* try a fast lookup in the translation cache */ |
sewardj | 4994cc2 | 2007-02-11 09:09:20 +0000 | [diff] [blame] | 323 | /* r4 = VG_TT_FAST_HASH(addr) * sizeof(FastCacheEntry) |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 324 | = ((r3 >>u 2) & VG_TT_FAST_MASK) << 3 */ |
| 325 | rlwinm 4,3,1, 29-VG_TT_FAST_BITS, 28 /* entry# * 8 */ |
| 326 | add 5,5,4 /* & VG_(tt_fast)[entry#] */ |
| 327 | lwz 6,0(5) /* .guest */ |
| 328 | lwz 7,4(5) /* .host */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 329 | cmpw 3,6 |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 330 | bne fast_lookup_failed |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 331 | |
| 332 | /* increment bb profile counter */ |
sewardj | 4994cc2 | 2007-02-11 09:09:20 +0000 | [diff] [blame] | 333 | srwi 4,4,1 /* entry# * sizeof(UInt*) */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 334 | addis 6,4,VG_(tt_fastN)@ha |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 335 | lwz 9,VG_(tt_fastN)@l(6) |
| 336 | lwz 8,0(9) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 337 | addi 8,8,1 |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 338 | stw 8,0(9) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 339 | |
sewardj | 5f76de0 | 2007-02-11 05:08:06 +0000 | [diff] [blame] | 340 | /* Found a match. Call .host. */ |
| 341 | mtctr 7 |
sewardj | 0ddf76c | 2006-10-17 02:08:26 +0000 | [diff] [blame] | 342 | bctrl |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 343 | |
cerion | 1ade697 | 2005-12-20 20:48:50 +0000 | [diff] [blame] | 344 | /* On return from guest code: |
| 345 | r3 holds destination (original) address. |
| 346 | r31 may be unchanged (guest_state), or may indicate further |
| 347 | details of the control transfer requested to *r3. |
| 348 | */ |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 349 | /* start over */ |
| 350 | b VG_(run_innerloop__dispatch_profiled) |
| 351 | /*NOTREACHED*/ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 352 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 353 | /*----------------------------------------------------*/ |
| 354 | /*--- exit points ---*/ |
| 355 | /*----------------------------------------------------*/ |
| 356 | |
| 357 | gsp_changed: |
| 358 | /* Someone messed with the gsp (in r31). Have to |
| 359 | defer to scheduler to resolve this. dispatch ctr |
| 360 | is not yet decremented, so no need to increment. */ |
| 361 | /* %CIA is NOT up to date here. First, need to write |
| 362 | %r3 back to %CIA, but without trashing %r31 since |
| 363 | that holds the value we want to return to the scheduler. |
| 364 | Hence use %r5 transiently for the guest state pointer. */ |
| 365 | lwz 5,44(1) /* original guest_state ptr */ |
| 366 | stw 3,OFFSET_ppc32_CIA(5) |
| 367 | mr 3,31 /* r3 = new gsp value */ |
| 368 | b run_innerloop_exit |
| 369 | /*NOTREACHED*/ |
| 370 | |
| 371 | counter_is_zero: |
| 372 | /* %CIA is up to date */ |
| 373 | /* back out decrement of the dispatch counter */ |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 374 | addi 29,29,1 |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 375 | li 3,VG_TRC_INNER_COUNTERZERO |
| 376 | b run_innerloop_exit |
| 377 | |
| 378 | fast_lookup_failed: |
| 379 | /* %CIA is up to date */ |
| 380 | /* back out decrement of the dispatch counter */ |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 381 | addi 29,29,1 |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 382 | li 3,VG_TRC_INNER_FASTMISS |
| 383 | b run_innerloop_exit |
| 384 | |
| 385 | |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 386 | |
| 387 | /* All exits from the dispatcher go through here. |
| 388 | r3 holds the return value. |
| 389 | */ |
| 390 | run_innerloop_exit: |
| 391 | /* We're leaving. Check that nobody messed with |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 392 | VSCR or FPSCR. */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 393 | |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 394 | /* Using r10 - value used again further on, so don't trash! */ |
| 395 | lis 10,VG_(machine_ppc32_has_FP)@ha |
| 396 | lwz 10,VG_(machine_ppc32_has_FP)@l(10) |
| 397 | cmplwi 10,0 |
| 398 | beq LafterFP8 |
| 399 | |
sewardj | e68ddf7 | 2006-02-06 05:14:31 +0000 | [diff] [blame] | 400 | /* Set fpscr back to a known state, since vex-generated code |
| 401 | may have messed with fpscr[rm]. */ |
| 402 | li 5,0 |
| 403 | addi 1,1,-16 |
| 404 | stw 5,0(1) |
| 405 | lfs 3,0(1) |
| 406 | addi 1,1,16 |
| 407 | mtfsf 0xFF,3 /* fpscr = f3 */ |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 408 | LafterFP8: |
| 409 | |
| 410 | /* Using r11 - value used again further on, so don't trash! */ |
| 411 | lis 11,VG_(machine_ppc32_has_VMX)@ha |
| 412 | lwz 11,VG_(machine_ppc32_has_VMX)@l(11) |
| 413 | cmplwi 11,0 |
| 414 | beq LafterVMX8 |
| 415 | |
| 416 | /* Check VSCR[NJ] == 1 */ |
| 417 | /* first generate 4x 0x00010000 */ |
| 418 | vspltisw 4,0x1 /* 4x 0x00000001 */ |
| 419 | vspltisw 5,0x0 /* zero */ |
cerion | 1b6b2b3 | 2005-11-18 20:45:18 +0000 | [diff] [blame] | 420 | vsldoi 6,4,5,0x2 /* <<2*8 => 4x 0x00010000 */ |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 421 | /* retrieve VSCR and mask wanted bits */ |
| 422 | mfvscr 7 |
cerion | 1b6b2b3 | 2005-11-18 20:45:18 +0000 | [diff] [blame] | 423 | vand 7,7,6 /* gives NJ flag */ |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 424 | vspltw 7,7,0x3 /* flags-word to all lanes */ |
cerion | 1b6b2b3 | 2005-11-18 20:45:18 +0000 | [diff] [blame] | 425 | vcmpequw. 8,6,7 /* CR[24] = 1 if v6 == v7 */ |
| 426 | bt 24,invariant_violation /* branch if all_equal */ |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 427 | LafterVMX8: |
| 428 | |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 429 | /* otherwise we're OK */ |
| 430 | b run_innerloop_exit_REALLY |
| 431 | |
| 432 | |
| 433 | invariant_violation: |
| 434 | li 3,VG_TRC_INVARIANT_FAILED |
| 435 | b run_innerloop_exit_REALLY |
| 436 | |
| 437 | run_innerloop_exit_REALLY: |
| 438 | /* r3 holds VG_TRC_* value to return */ |
| 439 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 440 | /* Return to parent stack */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 441 | addi 1,1,16 |
| 442 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 443 | /* Write ctr to VG(dispatch_ctr) */ |
sewardj | 5ee4948 | 2005-12-16 01:08:22 +0000 | [diff] [blame] | 444 | lis 5,VG_(dispatch_ctr)@ha |
| 445 | stw 29,VG_(dispatch_ctr)@l(5) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 446 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 447 | /* Restore cr */ |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 448 | lwz 0,44(1) |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 449 | mtcr 0 |
| 450 | |
| 451 | /* Restore callee-saved registers... */ |
| 452 | |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 453 | /* r10 already holds VG_(machine_ppc32_has_FP) value */ |
| 454 | cmplwi 10,0 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 455 | beq LafterFP9 |
| 456 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 457 | /* Floating-point regs */ |
| 458 | lfd 31,488(1) |
| 459 | lfd 30,480(1) |
| 460 | lfd 29,472(1) |
| 461 | lfd 28,464(1) |
| 462 | lfd 27,456(1) |
| 463 | lfd 26,448(1) |
| 464 | lfd 25,440(1) |
| 465 | lfd 24,432(1) |
| 466 | lfd 23,424(1) |
| 467 | lfd 22,416(1) |
| 468 | lfd 21,408(1) |
| 469 | lfd 20,400(1) |
| 470 | lfd 19,392(1) |
| 471 | lfd 18,384(1) |
| 472 | lfd 17,376(1) |
| 473 | lfd 16,368(1) |
| 474 | lfd 15,360(1) |
| 475 | lfd 14,352(1) |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 476 | LafterFP9: |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 477 | |
| 478 | /* General regs */ |
| 479 | lwz 31,348(1) |
| 480 | lwz 30,344(1) |
| 481 | lwz 29,340(1) |
| 482 | lwz 28,336(1) |
| 483 | lwz 27,332(1) |
| 484 | lwz 26,328(1) |
| 485 | lwz 25,324(1) |
| 486 | lwz 24,320(1) |
| 487 | lwz 23,316(1) |
| 488 | lwz 22,312(1) |
| 489 | lwz 21,308(1) |
| 490 | lwz 20,304(1) |
| 491 | lwz 19,300(1) |
| 492 | lwz 18,296(1) |
| 493 | lwz 17,292(1) |
| 494 | lwz 16,288(1) |
| 495 | lwz 15,284(1) |
| 496 | lwz 14,280(1) |
| 497 | lwz 13,276(1) |
| 498 | |
cerion | 3d11e0e | 2005-11-16 20:22:11 +0000 | [diff] [blame] | 499 | /* r11 already holds VG_(machine_ppc32_has_VMX) value */ |
| 500 | cmplwi 11,0 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 501 | beq LafterVMX9 |
| 502 | |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 503 | /* VRSAVE */ |
| 504 | lwz 4,244(1) |
| 505 | mfspr 4,256 /* VRSAVE reg is spr number 256 */ |
| 506 | |
| 507 | /* Vector regs */ |
| 508 | li 4,224 |
| 509 | lvx 31,4,1 |
| 510 | li 4,208 |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 511 | lvx 30,4,1 |
| 512 | li 4,192 |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 513 | lvx 29,4,1 |
| 514 | li 4,176 |
| 515 | lvx 28,4,1 |
| 516 | li 4,160 |
| 517 | lvx 27,4,1 |
| 518 | li 4,144 |
| 519 | lvx 26,4,1 |
| 520 | li 4,128 |
| 521 | lvx 25,4,1 |
| 522 | li 4,112 |
| 523 | lvx 24,4,1 |
| 524 | li 4,96 |
| 525 | lvx 23,4,1 |
| 526 | li 4,80 |
| 527 | lvx 22,4,1 |
| 528 | li 4,64 |
| 529 | lvx 21,4,1 |
| 530 | li 4,48 |
| 531 | lvx 20,4,1 |
sewardj | 2c36d42 | 2005-11-13 01:59:22 +0000 | [diff] [blame] | 532 | LafterVMX9: |
cerion | e51a42c | 2005-11-08 22:03:07 +0000 | [diff] [blame] | 533 | |
| 534 | /* reset lr & sp */ |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 535 | lwz 0,500(1) /* stack_size + 4 */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 536 | mtlr 0 |
cerion | 3e35756 | 2005-11-09 14:13:08 +0000 | [diff] [blame] | 537 | addi 1,1,496 /* stack_size */ |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 538 | blr |
tom | 63c8de5 | 2006-05-01 09:28:39 +0000 | [diff] [blame] | 539 | .size VG_(run_innerloop), .-VG_(run_innerloop) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 540 | |
sewardj | a591a05 | 2006-01-12 14:04:46 +0000 | [diff] [blame] | 541 | |
| 542 | /*------------------------------------------------------------*/ |
| 543 | /*--- ---*/ |
| 544 | /*--- A special dispatcher, for running no-redir ---*/ |
| 545 | /*--- translations. Just runs the given translation once. ---*/ |
| 546 | /*--- ---*/ |
| 547 | /*------------------------------------------------------------*/ |
| 548 | |
| 549 | /* signature: |
| 550 | void VG_(run_a_noredir_translation) ( UWord* argblock ); |
| 551 | */ |
| 552 | |
| 553 | /* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args |
| 554 | and 2 to carry results: |
| 555 | 0: input: ptr to translation |
| 556 | 1: input: ptr to guest state |
| 557 | 2: output: next guest PC |
| 558 | 3: output: guest state pointer afterwards (== thread return code) |
| 559 | */ |
sewardj | a591a05 | 2006-01-12 14:04:46 +0000 | [diff] [blame] | 560 | .global VG_(run_a_noredir_translation) |
tom | 63c8de5 | 2006-05-01 09:28:39 +0000 | [diff] [blame] | 561 | .type VG_(run_a_noredir_translation), @function |
sewardj | a591a05 | 2006-01-12 14:04:46 +0000 | [diff] [blame] | 562 | VG_(run_a_noredir_translation): |
| 563 | /* save callee-save int regs, & lr */ |
| 564 | stwu 1,-256(1) |
| 565 | stw 14,128(1) |
| 566 | stw 15,132(1) |
| 567 | stw 16,136(1) |
| 568 | stw 17,140(1) |
| 569 | stw 18,144(1) |
| 570 | stw 19,148(1) |
| 571 | stw 20,152(1) |
| 572 | stw 21,156(1) |
| 573 | stw 22,160(1) |
| 574 | stw 23,164(1) |
| 575 | stw 24,168(1) |
| 576 | stw 25,172(1) |
| 577 | stw 26,176(1) |
| 578 | stw 27,180(1) |
| 579 | stw 28,184(1) |
| 580 | stw 29,188(1) |
| 581 | stw 30,192(1) |
| 582 | stw 31,196(1) |
| 583 | mflr 31 |
| 584 | stw 31,200(1) |
| 585 | |
| 586 | stw 3,204(1) |
| 587 | lwz 31,4(3) |
| 588 | lwz 30,0(3) |
| 589 | mtlr 30 |
| 590 | blrl |
| 591 | |
| 592 | lwz 4,204(1) |
| 593 | stw 3, 8(4) |
| 594 | stw 31,12(4) |
| 595 | |
| 596 | lwz 14,128(1) |
| 597 | lwz 15,132(1) |
| 598 | lwz 16,136(1) |
| 599 | lwz 17,140(1) |
| 600 | lwz 18,144(1) |
| 601 | lwz 19,148(1) |
| 602 | lwz 20,152(1) |
| 603 | lwz 21,156(1) |
| 604 | lwz 22,160(1) |
| 605 | lwz 23,164(1) |
| 606 | lwz 24,168(1) |
| 607 | lwz 25,172(1) |
| 608 | lwz 26,176(1) |
| 609 | lwz 27,180(1) |
| 610 | lwz 28,184(1) |
| 611 | lwz 29,188(1) |
| 612 | lwz 30,192(1) |
| 613 | lwz 31,200(1) |
| 614 | mtlr 31 |
| 615 | lwz 31,196(1) |
| 616 | addi 1,1,256 |
| 617 | blr |
tom | 63c8de5 | 2006-05-01 09:28:39 +0000 | [diff] [blame] | 618 | .size VG_(run_a_noredir_translation), .-VG_(run_a_noredir_translation) |
sewardj | a591a05 | 2006-01-12 14:04:46 +0000 | [diff] [blame] | 619 | |
| 620 | |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 621 | /* Let the linker know we don't need an executable stack */ |
| 622 | .section .note.GNU-stack,"",@progbits |
| 623 | |
sewardj | 5d3a1c9 | 2005-12-15 21:40:34 +0000 | [diff] [blame] | 624 | /*--------------------------------------------------------------------*/ |
| 625 | /*--- end ---*/ |
| 626 | /*--------------------------------------------------------------------*/ |