2 /*--------------------------------------------------------------------*/
3 /*--- The core dispatch loop, for jumping to a code address. ---*/
4 /*--- dispatch-arm64-freebsd.S ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2024 Paul Floyd
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #include "pub_core_basics_asm.h"
32 #if defined(VGP_arm64_freebsd)
34 #include "pub_core_dispatch_asm.h"
35 #include "pub_core_transtab_asm.h"
36 #include "libvex_guest_offsets.h" /* for OFFSET_arm_R* */
39 /*------------------------------------------------------------*/
41 /*--- The dispatch loop. VG_(disp_run_translations) is ---*/
42 /*--- used to run all translations, ---*/
43 /*--- including no-redir ones. ---*/
45 /*------------------------------------------------------------*/
47 /*----------------------------------------------------*/
48 /*--- Entry and preamble (set everything up) ---*/
49 /*----------------------------------------------------*/
52 void VG_(disp_run_translations)( UWord* two_words,
57 .global VG_(disp_run_translations)
58 VG_(disp_run_translations):
63 /* Push the callee-saved registers. Unclear if x19/x20 are
64 callee-saved, but be on the safe side. Note this sequence
65 maintains 16-alignment of sp. Also save x0 since it will
66 be needed in the postamble. */
67 stp x29, x30, [sp, #-16]!
68 stp x27, x28, [sp, #-16]!
69 stp x25, x26, [sp, #-16]!
70 stp x23, x24, [sp, #-16]!
71 stp x21, x22, [sp, #-16]!
72 stp x19, x20, [sp, #-16]!
73 stp x0, xzr, [sp, #-16]!
75 /* set FPSCR to vex-required default value */
80 /* Set up the guest state pointer */
83 /* and jump into the code cache. Chained translations in
84 the code cache run, until for whatever reason, they can't
85 continue. When that happens, the translation in question
86 will jump (or call) to one of the continuation points
91 /*----------------------------------------------------*/
92 /*--- Postamble and exit. ---*/
93 /*----------------------------------------------------*/
96 /* At this point, r1 and r2 contain two
97 words to be returned to the caller. r1
98 holds a TRC value, and r2 optionally may
99 hold another word (for CHAIN_ME exits, the
100 address of the place to patch.) */
102 /* We're leaving. Check that nobody messed with
103 FPSCR in ways we don't expect. */
106 // bic r4, #0xF8000000 /* mask out NZCV and QC */
107 // bic r4, #0x0000009F /* mask out IDC,IXC,UFC,OFC,DZC,IOC */
109 // beq remove_frame /* we're OK */
110 /* otherwise we have an invariant violation */
111 // movw r1, #VG_TRC_INVARIANT_FAILED
116 /* Restore int regs, including importantly x0 (two_words),
118 ldp x0, xzr, [sp], #16
119 ldp x19, x20, [sp], #16
120 ldp x21, x22, [sp], #16
121 ldp x23, x24, [sp], #16
122 ldp x25, x26, [sp], #16
123 ldp x27, x28, [sp], #16
124 ldp x29, x30, [sp], #16
126 /* Stash return values */
131 /*----------------------------------------------------*/
132 /*--- Continuation points ---*/
133 /*----------------------------------------------------*/
135 /* ------ Chain me to slow entry point ------ */
136 .global VG_(disp_cp_chain_me_to_slowEP)
137 VG_(disp_cp_chain_me_to_slowEP):
138 /* We got called. The return address indicates
139 where the patching needs to happen. Collect
140 the return address and, exit back to C land,
141 handing the caller the pair (Chain_me_S, RA) */
142 mov x1, #VG_TRC_CHAIN_ME_TO_SLOW_EP
143 mov x2, x30 // 30 == LR
144 /* 4 = movw x9, disp_cp_chain_me_to_slowEP[15:0]
145 4 = movk x9, disp_cp_chain_me_to_slowEP[31:16], lsl 16
146 4 = movk x9, disp_cp_chain_me_to_slowEP[47:32], lsl 32
147 4 = movk x9, disp_cp_chain_me_to_slowEP[63:48], lsl 48
150 sub x2, x2, #4+4+4+4+4
153 /* ------ Chain me to fast entry point ------ */
154 .global VG_(disp_cp_chain_me_to_fastEP)
155 VG_(disp_cp_chain_me_to_fastEP):
156 /* We got called. The return address indicates
157 where the patching needs to happen. Collect
158 the return address and, exit back to C land,
159 handing the caller the pair (Chain_me_F, RA) */
160 mov x1, #VG_TRC_CHAIN_ME_TO_FAST_EP
161 mov x2, x30 // 30 == LR
162 /* 4 = movw x9, disp_cp_chain_me_to_fastEP[15:0]
163 4 = movk x9, disp_cp_chain_me_to_fastEP[31:16], lsl 16
164 4 = movk x9, disp_cp_chain_me_to_fastEP[47:32], lsl 32
165 4 = movk x9, disp_cp_chain_me_to_fastEP[63:48], lsl 48
168 sub x2, x2, #4+4+4+4+4
171 /* ------ Indirect but boring jump ------ */
172 .global VG_(disp_cp_xindir)
174 // Where are we going?
175 ldr x0, [x21, #OFFSET_arm64_PC]
178 adrp x4, VG_(stats__n_xIndirs_32)
179 add x4, x4, :lo12:VG_(stats__n_xIndirs_32)
184 // LIVE: x21 (guest state ptr), x0 (guest address to go to).
185 // We use 6 temporaries:
186 // x6 (to point at the relevant FastCacheSet),
187 // x1, x2, x3 (scratch, for swapping entries within a set)
188 // x4, x5 (other scratch)
190 /* Try a fast lookup in the translation cache. This is pretty much
191 a handcoded version of VG_(lookupInFastCache). */
193 // Compute x6 = VG_TT_FAST_HASH(guest)
194 lsr x6, x0, #2 // g2 = guest >> 2
195 eor x6, x6, x6, LSR #VG_TT_FAST_BITS // (g2 >> VG_TT_FAST_BITS) ^ g2
196 mov x4, #VG_TT_FAST_MASK // VG_TT_FAST_MASK
197 and x6, x6, x4 // setNo
199 // Compute x6 = &VG_(tt_fast)[x6]
200 adrp x4, VG_(tt_fast)
201 add x4, x4, :lo12:VG_(tt_fast) // &VG_(tt_fast)[0]
202 add x6, x4, x6, LSL #VG_FAST_CACHE_SET_BITS // &VG_(tt_fast)[setNo]
204 // LIVE: x21 (guest state ptr), x0 (guest addr), x6 (cache set)
206 ldp x4, x5, [x6, #FCS_g0] // x4 = .guest0, x5 = .host0
207 cmp x4, x0 // cmp against .guest0
215 ldr x4, [x6, #FCS_g1]
216 cmp x4, x0 // cmp against .guest1
218 // hit at way 1; swap upwards
219 ldr x1, [x6, #FCS_g0] // x1 = old .guest0
220 ldr x2, [x6, #FCS_h0] // x2 = old .host0
221 ldr x3, [x6, #FCS_h1] // x3 = old .host1
222 str x0, [x6, #FCS_g0] // new .guest0 = guest
223 str x3, [x6, #FCS_h0] // new .host0 = old .host1
224 str x1, [x6, #FCS_g1] // new .guest1 = old .guest0
225 str x2, [x6, #FCS_h1] // new .host1 = old .host0
227 adrp x4, VG_(stats__n_xIndir_hits1_32)
228 add x4, x4, :lo12:VG_(stats__n_xIndir_hits1_32)
232 // goto old .host1 a.k.a. new .host0
237 ldr x4, [x6, #FCS_g2]
238 cmp x4, x0 // cmp against .guest2
240 // hit at way 2; swap upwards
241 ldr x1, [x6, #FCS_g1]
242 ldr x2, [x6, #FCS_h1]
243 ldr x3, [x6, #FCS_h2]
244 str x0, [x6, #FCS_g1]
245 str x3, [x6, #FCS_h1]
246 str x1, [x6, #FCS_g2]
247 str x2, [x6, #FCS_h2]
249 adrp x4, VG_(stats__n_xIndir_hits2_32)
250 add x4, x4, :lo12:VG_(stats__n_xIndir_hits2_32)
254 // goto old .host2 a.k.a. new .host1
259 ldr x4, [x6, #FCS_g3]
260 cmp x4, x0 // cmp against .guest3
262 // hit at way 3; swap upwards
263 ldr x1, [x6, #FCS_g2]
264 ldr x2, [x6, #FCS_h2]
265 ldr x3, [x6, #FCS_h3]
266 str x0, [x6, #FCS_g2]
267 str x3, [x6, #FCS_h2]
268 str x1, [x6, #FCS_g3]
269 str x2, [x6, #FCS_h3]
271 adrp x4, VG_(stats__n_xIndir_hits3_32)
272 add x4, x4, :lo12:VG_(stats__n_xIndir_hits3_32)
276 // goto old .host3 a.k.a. new .host2
280 4: // fast lookup failed
281 adrp x4, VG_(stats__n_xIndir_misses_32)
282 add x4, x4, :lo12:VG_(stats__n_xIndir_misses_32)
287 mov x1, #VG_TRC_INNER_FASTMISS
291 /* ------ Assisted jump ------ */
292 .global VG_(disp_cp_xassisted)
293 VG_(disp_cp_xassisted):
294 /* x21 contains the TRC */
299 /* ------ Event check failed ------ */
300 .global VG_(disp_cp_evcheck_fail)
301 VG_(disp_cp_evcheck_fail):
302 mov x1, #VG_TRC_INNER_COUNTERZERO
307 .size VG_(disp_run_translations), .-VG_(disp_run_translations)
309 #endif // defined(VGP_arm64_freebsd)
311 /* Let the linker know we don't need an executable stack */
314 /*--------------------------------------------------------------------*/
315 /*--- end dispatch-arm64-freebsd.S ---*/
316 /*--------------------------------------------------------------------*/