blob: 00a92c3ac73bc6ece73305ca3d54d3803cabc421 [file] [log] [blame]
sewardj362cf842012-06-07 08:59:53 +00001
2/*---------------------------------------------------------------*/
3/*--- begin guest_mips_helpers.c ---*/
4/*---------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
Elliott Hughesed398002017-06-21 14:41:24 -070010 Copyright (C) 2010-2017 RT-RK
sewardj362cf842012-06-07 08:59:53 +000011 mips-valgrind@rt-rk.com
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#include "libvex_basictypes.h"
florian33b02432012-08-25 21:48:04 +000032#include "libvex_emnote.h"
sewardj362cf842012-06-07 08:59:53 +000033#include "libvex_guest_mips32.h"
petarjb92a9542013-02-27 22:57:17 +000034#include "libvex_guest_mips64.h"
sewardj362cf842012-06-07 08:59:53 +000035#include "libvex_ir.h"
36#include "libvex.h"
37
38#include "main_util.h"
philippe6c46bef2012-08-14 22:29:01 +000039#include "main_globals.h"
sewardj362cf842012-06-07 08:59:53 +000040#include "guest_generic_bb_to_IR.h"
41#include "guest_mips_defs.h"
42
43/* This file contains helper functions for mips guest code. Calls to
44 these functions are generated by the back end.
45*/
46
dejanj0e006f22014-02-19 11:56:29 +000047#define ALWAYSDEFD32(field) \
sewardj362cf842012-06-07 08:59:53 +000048 { offsetof(VexGuestMIPS32State, field), \
49 (sizeof ((VexGuestMIPS32State*)0)->field) }
50
petarjb92a9542013-02-27 22:57:17 +000051#define ALWAYSDEFD64(field) \
52 { offsetof(VexGuestMIPS64State, field), \
53 (sizeof ((VexGuestMIPS64State*)0)->field) }
54
florian1ff47562012-10-21 02:09:51 +000055IRExpr *guest_mips32_spechelper(const HChar * function_name, IRExpr ** args,
sewardj362cf842012-06-07 08:59:53 +000056 IRStmt ** precedingStmts, Int n_precedingStmts)
57{
58 return NULL;
59}
60
petarjb92a9542013-02-27 22:57:17 +000061IRExpr *guest_mips64_spechelper ( const HChar * function_name, IRExpr ** args,
62 IRStmt ** precedingStmts,
63 Int n_precedingStmts )
64{
65 return NULL;
66}
67
sewardj362cf842012-06-07 08:59:53 +000068/* VISIBLE TO LIBVEX CLIENT */
69void LibVEX_GuestMIPS32_initialise( /*OUT*/ VexGuestMIPS32State * vex_state)
70{
71 vex_state->guest_r0 = 0; /* Hardwired to 0 */
72 vex_state->guest_r1 = 0; /* Assembler temporary */
73 vex_state->guest_r2 = 0; /* Values for function returns ... */
74 vex_state->guest_r3 = 0; /* ...and expression evaluation */
75 vex_state->guest_r4 = 0; /* Function arguments */
76 vex_state->guest_r5 = 0;
77 vex_state->guest_r6 = 0;
78 vex_state->guest_r7 = 0;
79 vex_state->guest_r8 = 0; /* Temporaries */
80 vex_state->guest_r9 = 0;
81 vex_state->guest_r10 = 0;
82 vex_state->guest_r11 = 0;
83 vex_state->guest_r12 = 0;
84 vex_state->guest_r13 = 0;
85 vex_state->guest_r14 = 0;
86 vex_state->guest_r15 = 0;
87 vex_state->guest_r16 = 0; /* Saved temporaries */
88 vex_state->guest_r17 = 0;
89 vex_state->guest_r18 = 0;
90 vex_state->guest_r19 = 0;
91 vex_state->guest_r20 = 0;
92 vex_state->guest_r21 = 0;
93 vex_state->guest_r22 = 0;
94 vex_state->guest_r23 = 0;
95 vex_state->guest_r24 = 0; /* Temporaries */
96 vex_state->guest_r25 = 0;
97 vex_state->guest_r26 = 0; /* Reserved for OS kernel */
98 vex_state->guest_r27 = 0;
99 vex_state->guest_r28 = 0; /* Global pointer */
100 vex_state->guest_r29 = 0; /* Stack pointer */
101 vex_state->guest_r30 = 0; /* Frame pointer */
102 vex_state->guest_r31 = 0; /* Return address */
103 vex_state->guest_PC = 0; /* Program counter */
104 vex_state->guest_HI = 0; /* Multiply and divide register higher result */
105 vex_state->guest_LO = 0; /* Multiply and divide register lower result */
106
107 /* FPU Registers */
dejanj14360e92014-03-19 11:10:51 +0000108 vex_state->guest_f0 = 0x7ff800007ff80000ULL; /* Floting point GP registers */
109 vex_state->guest_f1 = 0x7ff800007ff80000ULL;
110 vex_state->guest_f2 = 0x7ff800007ff80000ULL;
111 vex_state->guest_f3 = 0x7ff800007ff80000ULL;
112 vex_state->guest_f4 = 0x7ff800007ff80000ULL;
113 vex_state->guest_f5 = 0x7ff800007ff80000ULL;
114 vex_state->guest_f6 = 0x7ff800007ff80000ULL;
115 vex_state->guest_f7 = 0x7ff800007ff80000ULL;
116 vex_state->guest_f8 = 0x7ff800007ff80000ULL;
117 vex_state->guest_f9 = 0x7ff800007ff80000ULL;
118 vex_state->guest_f10 = 0x7ff800007ff80000ULL;
119 vex_state->guest_f11 = 0x7ff800007ff80000ULL;
120 vex_state->guest_f12 = 0x7ff800007ff80000ULL;
121 vex_state->guest_f13 = 0x7ff800007ff80000ULL;
122 vex_state->guest_f14 = 0x7ff800007ff80000ULL;
123 vex_state->guest_f15 = 0x7ff800007ff80000ULL;
124 vex_state->guest_f16 = 0x7ff800007ff80000ULL;
125 vex_state->guest_f17 = 0x7ff800007ff80000ULL;
126 vex_state->guest_f18 = 0x7ff800007ff80000ULL;
127 vex_state->guest_f19 = 0x7ff800007ff80000ULL;
128 vex_state->guest_f20 = 0x7ff800007ff80000ULL;
129 vex_state->guest_f21 = 0x7ff800007ff80000ULL;
130 vex_state->guest_f22 = 0x7ff800007ff80000ULL;
131 vex_state->guest_f23 = 0x7ff800007ff80000ULL;
132 vex_state->guest_f24 = 0x7ff800007ff80000ULL;
133 vex_state->guest_f25 = 0x7ff800007ff80000ULL;
134 vex_state->guest_f26 = 0x7ff800007ff80000ULL;
135 vex_state->guest_f27 = 0x7ff800007ff80000ULL;
136 vex_state->guest_f28 = 0x7ff800007ff80000ULL;
137 vex_state->guest_f29 = 0x7ff800007ff80000ULL;
138 vex_state->guest_f30 = 0x7ff800007ff80000ULL;
139 vex_state->guest_f31 = 0x7ff800007ff80000ULL;
sewardj362cf842012-06-07 08:59:53 +0000140
141 vex_state->guest_FIR = 0; /* FP implementation and revision register */
142 vex_state->guest_FCCR = 0; /* FP condition codes register */
143 vex_state->guest_FEXR = 0; /* FP exceptions register */
144 vex_state->guest_FENR = 0; /* FP enables register */
145 vex_state->guest_FCSR = 0; /* FP control/status register */
146 vex_state->guest_ULR = 0; /* TLS */
147
148 /* Various pseudo-regs mandated by Vex or Valgrind. */
florian6ef84be2012-08-26 03:20:07 +0000149 /* Emulation notes */
150 vex_state->guest_EMNOTE = 0;
sewardj362cf842012-06-07 08:59:53 +0000151
152 /* For clflush: record start and length of area to invalidate */
sewardj05f5e012014-05-04 10:52:11 +0000153 vex_state->guest_CMSTART = 0;
154 vex_state->guest_CMLEN = 0;
sewardj362cf842012-06-07 08:59:53 +0000155 vex_state->host_EvC_COUNTER = 0;
156 vex_state->host_EvC_FAILADDR = 0;
157
158 /* Used to record the unredirected guest address at the start of
petarjb92a9542013-02-27 22:57:17 +0000159 a translation whose start has been redirected. By reading
160 this pseudo-register shortly afterwards, the translation can
161 find out what the corresponding no-redirection address was.
162 Note, this is only set for wrap-style redirects, not for
163 replace-style ones. */
164 vex_state->guest_NRADDR = 0;
165
166 vex_state->guest_COND = 0;
dejanjc3fee0d2013-07-25 09:08:03 +0000167
Elliott Hughesa0664b92017-04-18 17:46:52 -0700168 vex_state->guest_CP0_status = 0;
169
Elliott Hughesed398002017-06-21 14:41:24 -0700170 vex_state->guest_LLaddr = 0xFFFFFFFF;
171 vex_state->guest_LLdata = 0;
172
dejanjc3fee0d2013-07-25 09:08:03 +0000173 /* MIPS32 DSP ASE(r2) specific registers */
174 vex_state->guest_DSPControl = 0; /* DSPControl register */
175 vex_state->guest_ac0 = 0; /* Accumulator 0 */
176 vex_state->guest_ac1 = 0; /* Accumulator 1 */
177 vex_state->guest_ac2 = 0; /* Accumulator 2 */
178 vex_state->guest_ac3 = 0; /* Accumulator 3 */
petarjb92a9542013-02-27 22:57:17 +0000179}
180
181void LibVEX_GuestMIPS64_initialise ( /*OUT*/ VexGuestMIPS64State * vex_state )
182{
183 vex_state->guest_r0 = 0; /* Hardwired to 0 */
184 vex_state->guest_r1 = 0; /* Assembler temporary */
185 vex_state->guest_r2 = 0; /* Values for function returns ... */
186 vex_state->guest_r3 = 0;
187 vex_state->guest_r4 = 0; /* Function arguments */
188 vex_state->guest_r5 = 0;
189 vex_state->guest_r6 = 0;
190 vex_state->guest_r7 = 0;
191 vex_state->guest_r8 = 0;
192 vex_state->guest_r9 = 0;
193 vex_state->guest_r10 = 0;
194 vex_state->guest_r11 = 0;
195 vex_state->guest_r12 = 0; /* Temporaries */
196 vex_state->guest_r13 = 0;
197 vex_state->guest_r14 = 0;
198 vex_state->guest_r15 = 0;
199 vex_state->guest_r16 = 0; /* Saved temporaries */
200 vex_state->guest_r17 = 0;
201 vex_state->guest_r18 = 0;
202 vex_state->guest_r19 = 0;
203 vex_state->guest_r20 = 0;
204 vex_state->guest_r21 = 0;
205 vex_state->guest_r22 = 0;
206 vex_state->guest_r23 = 0;
207 vex_state->guest_r24 = 0; /* Temporaries */
208 vex_state->guest_r25 = 0;
209 vex_state->guest_r26 = 0; /* Reserved for OS kernel */
210 vex_state->guest_r27 = 0;
211 vex_state->guest_r28 = 0; /* Global pointer */
212 vex_state->guest_r29 = 0; /* Stack pointer */
213 vex_state->guest_r30 = 0; /* Frame pointer */
214 vex_state->guest_r31 = 0; /* Return address */
215 vex_state->guest_PC = 0; /* Program counter */
216 vex_state->guest_HI = 0; /* Multiply and divide register higher result */
217 vex_state->guest_LO = 0; /* Multiply and divide register lower result */
218
219 /* FPU Registers */
dejanj1df406c2014-01-15 16:26:31 +0000220 vex_state->guest_f0 = 0x7ff800007ff80000ULL; /* Floting point registers */
221 vex_state->guest_f1 = 0x7ff800007ff80000ULL;
222 vex_state->guest_f2 = 0x7ff800007ff80000ULL;
223 vex_state->guest_f3 = 0x7ff800007ff80000ULL;
224 vex_state->guest_f4 = 0x7ff800007ff80000ULL;
225 vex_state->guest_f5 = 0x7ff800007ff80000ULL;
226 vex_state->guest_f6 = 0x7ff800007ff80000ULL;
227 vex_state->guest_f7 = 0x7ff800007ff80000ULL;
228 vex_state->guest_f8 = 0x7ff800007ff80000ULL;
229 vex_state->guest_f9 = 0x7ff800007ff80000ULL;
230 vex_state->guest_f10 = 0x7ff800007ff80000ULL;
231 vex_state->guest_f11 = 0x7ff800007ff80000ULL;
232 vex_state->guest_f12 = 0x7ff800007ff80000ULL;
233 vex_state->guest_f13 = 0x7ff800007ff80000ULL;
234 vex_state->guest_f14 = 0x7ff800007ff80000ULL;
235 vex_state->guest_f15 = 0x7ff800007ff80000ULL;
236 vex_state->guest_f16 = 0x7ff800007ff80000ULL;
237 vex_state->guest_f17 = 0x7ff800007ff80000ULL;
238 vex_state->guest_f18 = 0x7ff800007ff80000ULL;
239 vex_state->guest_f19 = 0x7ff800007ff80000ULL;
240 vex_state->guest_f20 = 0x7ff800007ff80000ULL;
241 vex_state->guest_f21 = 0x7ff800007ff80000ULL;
242 vex_state->guest_f22 = 0x7ff800007ff80000ULL;
243 vex_state->guest_f23 = 0x7ff800007ff80000ULL;
244 vex_state->guest_f24 = 0x7ff800007ff80000ULL;
245 vex_state->guest_f25 = 0x7ff800007ff80000ULL;
246 vex_state->guest_f26 = 0x7ff800007ff80000ULL;
247 vex_state->guest_f27 = 0x7ff800007ff80000ULL;
248 vex_state->guest_f28 = 0x7ff800007ff80000ULL;
249 vex_state->guest_f29 = 0x7ff800007ff80000ULL;
250 vex_state->guest_f30 = 0x7ff800007ff80000ULL;
251 vex_state->guest_f31 = 0x7ff800007ff80000ULL;
petarjb92a9542013-02-27 22:57:17 +0000252
253 vex_state->guest_FIR = 0; /* FP implementation and revision register */
254 vex_state->guest_FCCR = 0; /* FP condition codes register */
255 vex_state->guest_FEXR = 0; /* FP exceptions register */
256 vex_state->guest_FENR = 0; /* FP enables register */
257 vex_state->guest_FCSR = 0; /* FP control/status register */
258
259 vex_state->guest_ULR = 0;
260
261 /* Various pseudo-regs mandated by Vex or Valgrind. */
262 /* Emulation notes */
263 vex_state->guest_EMNOTE = 0;
264
265 /* For clflush: record start and length of area to invalidate */
sewardj05f5e012014-05-04 10:52:11 +0000266 vex_state->guest_CMSTART = 0;
267 vex_state->guest_CMLEN = 0;
petarjb92a9542013-02-27 22:57:17 +0000268 vex_state->host_EvC_COUNTER = 0;
269 vex_state->host_EvC_FAILADDR = 0;
270
271 /* Used to record the unredirected guest address at the start of
272 a translation whose start has been redirected. By reading
sewardj362cf842012-06-07 08:59:53 +0000273 this pseudo-register shortly afterwards, the translation can
274 find out what the corresponding no-redirection address was.
275 Note, this is only set for wrap-style redirects, not for
276 replace-style ones. */
277 vex_state->guest_NRADDR = 0;
278
279 vex_state->guest_COND = 0;
Elliott Hughesa0664b92017-04-18 17:46:52 -0700280
281 vex_state->guest_CP0_status = MIPS_CP0_STATUS_FR;
Elliott Hughesed398002017-06-21 14:41:24 -0700282
283 vex_state->guest_LLaddr = 0xFFFFFFFFFFFFFFFFULL;
284 vex_state->guest_LLdata = 0;
sewardj362cf842012-06-07 08:59:53 +0000285}
286
287/*-----------------------------------------------------------*/
288/*--- Describing the mips guest state, for the benefit ---*/
289/*--- of iropt and instrumenters. ---*/
290/*-----------------------------------------------------------*/
291
292/* Figure out if any part of the guest state contained in minoff
293 .. maxoff requires precise memory exceptions. If in doubt return
dejanjc3fee0d2013-07-25 09:08:03 +0000294 True (but this generates significantly slower code).
sewardj362cf842012-06-07 08:59:53 +0000295
296 We enforce precise exns for guest SP, PC.
philippe6c46bef2012-08-14 22:29:01 +0000297
dejanjc3fee0d2013-07-25 09:08:03 +0000298 Only SP is needed in mode VexRegUpdSpAtMemAccess.
sewardj362cf842012-06-07 08:59:53 +0000299*/
sewardjca2c3c72015-02-05 12:53:20 +0000300Bool guest_mips32_state_requires_precise_mem_exns (
301 Int minoff, Int maxoff, VexRegisterUpdates pxControl
302 )
sewardj362cf842012-06-07 08:59:53 +0000303{
304 Int sp_min = offsetof(VexGuestMIPS32State, guest_r29);
305 Int sp_max = sp_min + 4 - 1;
306 Int pc_min = offsetof(VexGuestMIPS32State, guest_PC);
307 Int pc_max = pc_min + 4 - 1;
308
309 if (maxoff < sp_min || minoff > sp_max) {
310 /* no overlap with sp */
sewardjca2c3c72015-02-05 12:53:20 +0000311 if (pxControl == VexRegUpdSpAtMemAccess)
petarjb92a9542013-02-27 22:57:17 +0000312 return False; /* We only need to check stack pointer. */
sewardj362cf842012-06-07 08:59:53 +0000313 } else {
314 return True;
315 }
316
317 if (maxoff < pc_min || minoff > pc_max) {
318 /* no overlap with pc */
319 } else {
320 return True;
321 }
322
323 /* We appear to need precise updates of R11 in order to get proper
324 stacktraces from non-optimised code. */
325 Int fp_min = offsetof(VexGuestMIPS32State, guest_r30);
326 Int fp_max = fp_min + 4 - 1;
327
328 if (maxoff < fp_min || minoff > fp_max) {
329 /* no overlap with fp */
330 } else {
331 return True;
332 }
333
334 return False;
335}
336
sewardjca2c3c72015-02-05 12:53:20 +0000337Bool guest_mips64_state_requires_precise_mem_exns (
338 Int minoff, Int maxoff, VexRegisterUpdates pxControl
339 )
petarjb92a9542013-02-27 22:57:17 +0000340{
341 Int sp_min = offsetof(VexGuestMIPS64State, guest_r29);
342 Int sp_max = sp_min + 8 - 1;
343 Int pc_min = offsetof(VexGuestMIPS64State, guest_PC);
344 Int pc_max = pc_min + 8 - 1;
345
346 if ( maxoff < sp_min || minoff > sp_max ) {
347 /* no overlap with sp */
sewardjca2c3c72015-02-05 12:53:20 +0000348 if (pxControl == VexRegUpdSpAtMemAccess)
petarjb92a9542013-02-27 22:57:17 +0000349 return False; /* We only need to check stack pointer. */
350 } else {
351 return True;
352 }
353
354 if ( maxoff < pc_min || minoff > pc_max ) {
355 /* no overlap with pc */
356 } else {
357 return True;
358 }
359
360 Int fp_min = offsetof(VexGuestMIPS64State, guest_r30);
361 Int fp_max = fp_min + 8 - 1;
362
363 if ( maxoff < fp_min || minoff > fp_max ) {
364 /* no overlap with fp */
365 } else {
366 return True;
367 }
368
369 return False;
370}
371
sewardj362cf842012-06-07 08:59:53 +0000372VexGuestLayout mips32Guest_layout = {
373 /* Total size of the guest state, in bytes. */
374 .total_sizeB = sizeof(VexGuestMIPS32State),
375 /* Describe the stack pointer. */
376 .offset_SP = offsetof(VexGuestMIPS32State, guest_r29),
377 .sizeof_SP = 4,
378 /* Describe the frame pointer. */
379 .offset_FP = offsetof(VexGuestMIPS32State, guest_r30),
380 .sizeof_FP = 4,
381 /* Describe the instruction pointer. */
382 .offset_IP = offsetof(VexGuestMIPS32State, guest_PC),
383 .sizeof_IP = 4,
384 /* Describe any sections to be regarded by Memcheck as
385 'always-defined'. */
386 .n_alwaysDefd = 8,
387 /* ? :( */
388 .alwaysDefd = {
389 /* 0 */ ALWAYSDEFD32(guest_r0),
390 /* 1 */ ALWAYSDEFD32(guest_r1),
florian6ef84be2012-08-26 03:20:07 +0000391 /* 2 */ ALWAYSDEFD32(guest_EMNOTE),
sewardj05f5e012014-05-04 10:52:11 +0000392 /* 3 */ ALWAYSDEFD32(guest_CMSTART),
393 /* 4 */ ALWAYSDEFD32(guest_CMLEN),
sewardj362cf842012-06-07 08:59:53 +0000394 /* 5 */ ALWAYSDEFD32(guest_r29),
395 /* 6 */ ALWAYSDEFD32(guest_r31),
396 /* 7 */ ALWAYSDEFD32(guest_ULR)
397 }
398};
399
petarjb92a9542013-02-27 22:57:17 +0000400VexGuestLayout mips64Guest_layout = {
401 /* Total size of the guest state, in bytes. */
402 .total_sizeB = sizeof(VexGuestMIPS64State),
403 /* Describe the stack pointer. */
404 .offset_SP = offsetof(VexGuestMIPS64State, guest_r29),
405 .sizeof_SP = 8,
406 /* Describe the frame pointer. */
407 .offset_FP = offsetof(VexGuestMIPS64State, guest_r30),
408 .sizeof_FP = 8,
409 /* Describe the instruction pointer. */
410 .offset_IP = offsetof(VexGuestMIPS64State, guest_PC),
411 .sizeof_IP = 8,
412 /* Describe any sections to be regarded by Memcheck as
413 'always-defined'. */
414 .n_alwaysDefd = 7,
415 /* ? :( */
416 .alwaysDefd = {
417 /* 0 */ ALWAYSDEFD64 (guest_r0),
418 /* 1 */ ALWAYSDEFD64 (guest_EMNOTE),
sewardj05f5e012014-05-04 10:52:11 +0000419 /* 2 */ ALWAYSDEFD64 (guest_CMSTART),
420 /* 3 */ ALWAYSDEFD64 (guest_CMLEN),
petarjb92a9542013-02-27 22:57:17 +0000421 /* 4 */ ALWAYSDEFD64 (guest_r29),
422 /* 5 */ ALWAYSDEFD64 (guest_r31),
423 /* 6 */ ALWAYSDEFD64 (guest_ULR)
424 }
425};
426
Elliott Hughesed398002017-06-21 14:41:24 -0700427#define ASM_VOLATILE_RDHWR(opcode) \
428 __asm__ __volatile__(".word 0x7C02003B | "#opcode" << 11 \n\t" \
429 : "+r" (x) : : \
430 )
431
432HWord mips_dirtyhelper_rdhwr ( UInt rd )
dejanja445f1b2013-10-22 08:52:46 +0000433{
Elliott Hughesed398002017-06-21 14:41:24 -0700434#if defined(__mips__)
435 register HWord x __asm__("v0") = 0;
436
dejanja445f1b2013-10-22 08:52:46 +0000437 switch (rd) {
Elliott Hughesed398002017-06-21 14:41:24 -0700438 case 0: /* x = CPUNum() */
439 ASM_VOLATILE_RDHWR(0); /* rdhwr v0, $0 */
440 break;
441
442 case 1: /* x = SYNCI_Step() */
443 ASM_VOLATILE_RDHWR(1); /* rdhwr v0, $1 */
444 break;
445
446 case 2: /* x = CC() */
447 ASM_VOLATILE_RDHWR(2); /* rdhwr v0, $2 */
448 break;
449
450 case 3: /* x = CCRes() */
451 ASM_VOLATILE_RDHWR(3); /* rdhwr v0, $3 */
dejanja445f1b2013-10-22 08:52:46 +0000452 break;
453
petarj1f47ae22015-07-21 22:27:19 +0000454 case 31: /* x = CVMX_get_cycles() */
Elliott Hughesed398002017-06-21 14:41:24 -0700455 ASM_VOLATILE_RDHWR(31); /* rdhwr v0, $31 */
petarj1f47ae22015-07-21 22:27:19 +0000456 break;
457
dejanja445f1b2013-10-22 08:52:46 +0000458 default:
459 vassert(0);
460 break;
461 }
462 return x;
Elliott Hughesed398002017-06-21 14:41:24 -0700463#else
464 return 0;
petarjb92a9542013-02-27 22:57:17 +0000465#endif
Elliott Hughesed398002017-06-21 14:41:24 -0700466}
petarjb92a9542013-02-27 22:57:17 +0000467
dejanj41833222013-11-14 15:44:42 +0000468#define ASM_VOLATILE_UNARY32(inst) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700469 __asm__ volatile(".set push" "\n\t" \
470 ".set hardfloat" "\n\t" \
471 "cfc1 $t0, $31" "\n\t" \
dejanj41833222013-11-14 15:44:42 +0000472 "ctc1 %2, $31" "\n\t" \
473 "mtc1 %1, $f20" "\n\t" \
474 #inst" $f20, $f20" "\n\t" \
475 "cfc1 %0, $31" "\n\t" \
476 "ctc1 $t0, $31" "\n\t" \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700477 ".set pop" "\n\t" \
dejanja445f1b2013-10-22 08:52:46 +0000478 : "=r" (ret) \
dejanj41833222013-11-14 15:44:42 +0000479 : "r" (loFsVal), "r" (fcsr) \
480 : "t0", "$f20" \
dejanja445f1b2013-10-22 08:52:46 +0000481 );
482
dejanj41833222013-11-14 15:44:42 +0000483#define ASM_VOLATILE_UNARY32_DOUBLE(inst) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700484 __asm__ volatile(".set push" "\n\t" \
485 ".set hardfloat" "\n\t" \
486 "cfc1 $t0, $31" "\n\t" \
487 "ctc1 %2, $31" "\n\t" \
488 "ldc1 $f20, 0(%1)" "\n\t" \
dejanj41833222013-11-14 15:44:42 +0000489 #inst" $f20, $f20" "\n\t" \
490 "cfc1 %0, $31" "\n\t" \
491 "ctc1 $t0, $31" "\n\t" \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700492 ".set pop" "\n\t" \
dejanj8007ea62013-09-18 10:06:13 +0000493 : "=r" (ret) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700494 : "r" (&fsVal), "r" (fcsr) \
dejanj41833222013-11-14 15:44:42 +0000495 : "t0", "$f20", "$f21" \
dejanj8007ea62013-09-18 10:06:13 +0000496 );
497
dejanj41833222013-11-14 15:44:42 +0000498#define ASM_VOLATILE_UNARY64(inst) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700499 __asm__ volatile(".set push" "\n\t" \
500 ".set hardfloat" "\n\t" \
Elliott Hughesed398002017-06-21 14:41:24 -0700501 ".set fp=64" "\n\t" \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700502 "cfc1 $t0, $31" "\n\t" \
dejanj0e006f22014-02-19 11:56:29 +0000503 "ctc1 %2, $31" "\n\t" \
504 "ldc1 $f24, 0(%1)" "\n\t" \
505 #inst" $f24, $f24" "\n\t" \
506 "cfc1 %0, $31" "\n\t" \
507 "ctc1 $t0, $31" "\n\t" \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700508 ".set pop" "\n\t" \
dejanj8007ea62013-09-18 10:06:13 +0000509 : "=r" (ret) \
dejanj0e006f22014-02-19 11:56:29 +0000510 : "r" (&(addr[fs])), "r" (fcsr) \
dejanj41833222013-11-14 15:44:42 +0000511 : "t0", "$f24" \
512 );
513
514#define ASM_VOLATILE_BINARY32(inst) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700515 __asm__ volatile(".set push" "\n\t" \
516 ".set hardfloat" "\n\t" \
517 "cfc1 $t0, $31" "\n\t" \
dejanj41833222013-11-14 15:44:42 +0000518 "ctc1 %3, $31" "\n\t" \
519 "mtc1 %1, $f20" "\n\t" \
520 "mtc1 %2, $f22" "\n\t" \
521 #inst" $f20, $f20, $f22" "\n\t" \
522 "cfc1 %0, $31" "\n\t" \
523 "ctc1 $t0, $31" "\n\t" \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700524 ".set pop" "\n\t" \
dejanj41833222013-11-14 15:44:42 +0000525 : "=r" (ret) \
526 : "r" (loFsVal), "r" (loFtVal), "r" (fcsr) \
527 : "t0", "$f20", "$f22" \
528 );
529
530#define ASM_VOLATILE_BINARY32_DOUBLE(inst) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700531 __asm__ volatile(".set push" "\n\t" \
532 ".set hardfloat" "\n\t" \
533 "cfc1 $t0, $31" "\n\t" \
534 "ctc1 %3, $31" "\n\t" \
535 "ldc1 $f20, 0(%1)" "\n\t" \
536 "ldc1 $f22, 0(%2)" "\n\t" \
dejanj41833222013-11-14 15:44:42 +0000537 #inst" $f20, $f20, $f22" "\n\t" \
538 "cfc1 %0, $31" "\n\t" \
539 "ctc1 $t0, $31" "\n\t" \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700540 ".set pop" "\n\t" \
dejanj41833222013-11-14 15:44:42 +0000541 : "=r" (ret) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700542 : "r" (&fsVal), "r" (&ftVal), "r" (fcsr) \
dejanj41833222013-11-14 15:44:42 +0000543 : "t0", "$f20", "$f21", "$f22", "$f23" \
544 );
545
dejanj0e006f22014-02-19 11:56:29 +0000546#define ASM_VOLATILE_BINARY64(inst) \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700547 __asm__ volatile(".set push" "\n\t" \
548 ".set hardfloat" "\n\t" \
549 "cfc1 $t0, $31" "\n\t" \
dejanj0e006f22014-02-19 11:56:29 +0000550 "ctc1 %3, $31" "\n\t" \
551 "ldc1 $f24, 0(%1)" "\n\t" \
552 "ldc1 $f26, 0(%2)" "\n\t" \
553 #inst" $f24, $f24, $f26" "\n\t" \
554 "cfc1 %0, $31" "\n\t" \
555 "ctc1 $t0, $31" "\n\t" \
Elliott Hughesa0664b92017-04-18 17:46:52 -0700556 ".set pop" "\n\t" \
dejanj0e006f22014-02-19 11:56:29 +0000557 : "=r" (ret) \
558 : "r" (&(addr[fs])), "r" (&(addr[ft])), "r" (fcsr) \
559 : "t0", "$f24", "$f26" \
dejanj8007ea62013-09-18 10:06:13 +0000560 );
561
562/* TODO: Add cases for all fpu instructions because all fpu instructions are
563 change the value of FCSR register. */
dejanj0e006f22014-02-19 11:56:29 +0000564extern UInt mips_dirtyhelper_calculate_FCSR_fp32 ( void* gs, UInt fs, UInt ft,
565 flt_op inst )
566{
567 UInt ret = 0;
568#if defined(__mips__)
569 VexGuestMIPS32State* guest_state = (VexGuestMIPS32State*)gs;
570 UInt loFsVal, hiFsVal, loFtVal, hiFtVal;
571#if defined (_MIPSEL)
572 ULong *addr = (ULong *)&guest_state->guest_f0;
573 loFsVal = (UInt)addr[fs];
574 hiFsVal = (UInt)addr[fs+1];
575 loFtVal = (UInt)addr[ft];
576 hiFtVal = (UInt)addr[ft+1];
577#elif defined (_MIPSEB)
578 UInt *addr = (UInt *)&guest_state->guest_f0;
579 loFsVal = (UInt)addr[fs*2];
580 hiFsVal = (UInt)addr[fs*2+2];
581 loFtVal = (UInt)addr[ft*2];
582 hiFtVal = (UInt)addr[ft*2+2];
583#endif
Elliott Hughesa0664b92017-04-18 17:46:52 -0700584 ULong fsVal = ((ULong) hiFsVal) << 32 | loFsVal;
585 ULong ftVal = ((ULong) hiFtVal) << 32 | loFtVal;
dejanj0e006f22014-02-19 11:56:29 +0000586 UInt fcsr = guest_state->guest_FCSR;
587 switch (inst) {
588 case ROUNDWD:
589 ASM_VOLATILE_UNARY32_DOUBLE(round.w.d)
590 break;
591 case FLOORWS:
592 ASM_VOLATILE_UNARY32(floor.w.s)
593 break;
594 case FLOORWD:
595 ASM_VOLATILE_UNARY32_DOUBLE(floor.w.d)
596 break;
597 case TRUNCWS:
598 ASM_VOLATILE_UNARY32(trunc.w.s)
599 break;
600 case TRUNCWD:
601 ASM_VOLATILE_UNARY32_DOUBLE(trunc.w.d)
602 break;
603 case CEILWS:
604 ASM_VOLATILE_UNARY32(ceil.w.s)
605 break;
606 case CEILWD:
607 ASM_VOLATILE_UNARY32_DOUBLE(ceil.w.d)
608 break;
609 case CVTDS:
610 ASM_VOLATILE_UNARY32(cvt.d.s)
611 break;
612 case CVTDW:
613 ASM_VOLATILE_UNARY32(cvt.d.w)
614 break;
615 case CVTSW:
616 ASM_VOLATILE_UNARY32(cvt.s.w)
617 break;
618 case CVTSD:
619 ASM_VOLATILE_UNARY32_DOUBLE(cvt.s.d)
620 break;
621 case CVTWS:
622 ASM_VOLATILE_UNARY32(cvt.w.s)
623 break;
624 case CVTWD:
625 ASM_VOLATILE_UNARY32_DOUBLE(cvt.w.d)
626 break;
627 case ROUNDWS:
628 ASM_VOLATILE_UNARY32(round.w.s)
629 break;
dejanj0e006f22014-02-19 11:56:29 +0000630 case ADDS:
631 ASM_VOLATILE_BINARY32(add.s)
632 break;
633 case ADDD:
634 ASM_VOLATILE_BINARY32_DOUBLE(add.d)
635 break;
636 case SUBS:
637 ASM_VOLATILE_BINARY32(sub.s)
638 break;
639 case SUBD:
640 ASM_VOLATILE_BINARY32_DOUBLE(sub.d)
641 break;
642 case DIVS:
643 ASM_VOLATILE_BINARY32(div.s)
644 break;
645 default:
646 vassert(0);
647 break;
648 }
649#endif
650 return ret;
651}
652
653/* TODO: Add cases for all fpu instructions because all fpu instructions are
654 change the value of FCSR register. */
655extern UInt mips_dirtyhelper_calculate_FCSR_fp64 ( void* gs, UInt fs, UInt ft,
656 flt_op inst )
dejanj8007ea62013-09-18 10:06:13 +0000657{
658 UInt ret = 0;
Elliott Hughesed398002017-06-21 14:41:24 -0700659#if defined(__mips__) && ((__mips == 64) || \
660 (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)))
dejanj8007ea62013-09-18 10:06:13 +0000661#if defined(VGA_mips32)
662 VexGuestMIPS32State* guest_state = (VexGuestMIPS32State*)gs;
dejanj8007ea62013-09-18 10:06:13 +0000663#else
664 VexGuestMIPS64State* guest_state = (VexGuestMIPS64State*)gs;
dejanj8007ea62013-09-18 10:06:13 +0000665#endif
dejanj0e006f22014-02-19 11:56:29 +0000666 ULong *addr = (ULong *)&guest_state->guest_f0;
667 UInt fcsr = guest_state->guest_FCSR;
dejanj8007ea62013-09-18 10:06:13 +0000668 switch (inst) {
669 case ROUNDWD:
dejanj0e006f22014-02-19 11:56:29 +0000670 ASM_VOLATILE_UNARY64(round.w.d)
dejanj8007ea62013-09-18 10:06:13 +0000671 break;
672 case FLOORWS:
dejanj0e006f22014-02-19 11:56:29 +0000673 ASM_VOLATILE_UNARY64(floor.w.s)
dejanj8007ea62013-09-18 10:06:13 +0000674 break;
675 case FLOORWD:
dejanj0e006f22014-02-19 11:56:29 +0000676 ASM_VOLATILE_UNARY64(floor.w.d)
dejanj8007ea62013-09-18 10:06:13 +0000677 break;
678 case TRUNCWS:
dejanj0e006f22014-02-19 11:56:29 +0000679 ASM_VOLATILE_UNARY64(trunc.w.s)
dejanj8007ea62013-09-18 10:06:13 +0000680 break;
681 case TRUNCWD:
dejanj0e006f22014-02-19 11:56:29 +0000682 ASM_VOLATILE_UNARY64(trunc.w.d)
dejanj8007ea62013-09-18 10:06:13 +0000683 break;
684 case CEILWS:
dejanj0e006f22014-02-19 11:56:29 +0000685 ASM_VOLATILE_UNARY64(ceil.w.s)
dejanj8007ea62013-09-18 10:06:13 +0000686 break;
687 case CEILWD:
dejanj0e006f22014-02-19 11:56:29 +0000688 ASM_VOLATILE_UNARY64(ceil.w.d)
dejanj8007ea62013-09-18 10:06:13 +0000689 break;
petarj8e70cdc2013-09-21 01:47:18 +0000690 case CVTDS:
dejanj0e006f22014-02-19 11:56:29 +0000691 ASM_VOLATILE_UNARY64(cvt.d.s)
petarj8e70cdc2013-09-21 01:47:18 +0000692 break;
693 case CVTDW:
dejanj0e006f22014-02-19 11:56:29 +0000694 ASM_VOLATILE_UNARY64(cvt.d.w)
petarj8e70cdc2013-09-21 01:47:18 +0000695 break;
696 case CVTSW:
dejanj0e006f22014-02-19 11:56:29 +0000697 ASM_VOLATILE_UNARY64(cvt.s.w)
petarj8e70cdc2013-09-21 01:47:18 +0000698 break;
699 case CVTSD:
dejanj0e006f22014-02-19 11:56:29 +0000700 ASM_VOLATILE_UNARY64(cvt.s.d)
petarj8e70cdc2013-09-21 01:47:18 +0000701 break;
702 case CVTWS:
dejanj0e006f22014-02-19 11:56:29 +0000703 ASM_VOLATILE_UNARY64(cvt.w.s)
petarj8e70cdc2013-09-21 01:47:18 +0000704 break;
705 case CVTWD:
dejanj0e006f22014-02-19 11:56:29 +0000706 ASM_VOLATILE_UNARY64(cvt.w.d)
petarj8e70cdc2013-09-21 01:47:18 +0000707 break;
708 case ROUNDWS:
dejanj0e006f22014-02-19 11:56:29 +0000709 ASM_VOLATILE_UNARY64(round.w.s)
petarj8e70cdc2013-09-21 01:47:18 +0000710 break;
dejanj8007ea62013-09-18 10:06:13 +0000711 case CEILLS:
dejanj0e006f22014-02-19 11:56:29 +0000712 ASM_VOLATILE_UNARY64(ceil.l.s)
dejanj8007ea62013-09-18 10:06:13 +0000713 break;
714 case CEILLD:
dejanj0e006f22014-02-19 11:56:29 +0000715 ASM_VOLATILE_UNARY64(ceil.l.d)
dejanj8007ea62013-09-18 10:06:13 +0000716 break;
petarj8e70cdc2013-09-21 01:47:18 +0000717 case CVTDL:
dejanj0e006f22014-02-19 11:56:29 +0000718 ASM_VOLATILE_UNARY64(cvt.d.l)
petarj8e70cdc2013-09-21 01:47:18 +0000719 break;
720 case CVTLS:
dejanj0e006f22014-02-19 11:56:29 +0000721 ASM_VOLATILE_UNARY64(cvt.l.s)
petarj8e70cdc2013-09-21 01:47:18 +0000722 break;
723 case CVTLD:
dejanj0e006f22014-02-19 11:56:29 +0000724 ASM_VOLATILE_UNARY64(cvt.l.d)
petarj8e70cdc2013-09-21 01:47:18 +0000725 break;
726 case CVTSL:
dejanj0e006f22014-02-19 11:56:29 +0000727 ASM_VOLATILE_UNARY64(cvt.s.l)
petarj8e70cdc2013-09-21 01:47:18 +0000728 break;
729 case FLOORLS:
dejanj0e006f22014-02-19 11:56:29 +0000730 ASM_VOLATILE_UNARY64(floor.l.s)
petarj8e70cdc2013-09-21 01:47:18 +0000731 break;
732 case FLOORLD:
dejanj0e006f22014-02-19 11:56:29 +0000733 ASM_VOLATILE_UNARY64(floor.l.d)
petarj8e70cdc2013-09-21 01:47:18 +0000734 break;
dejanj8007ea62013-09-18 10:06:13 +0000735 case ROUNDLS:
dejanj0e006f22014-02-19 11:56:29 +0000736 ASM_VOLATILE_UNARY64(round.l.s)
dejanj8007ea62013-09-18 10:06:13 +0000737 break;
738 case ROUNDLD:
dejanj0e006f22014-02-19 11:56:29 +0000739 ASM_VOLATILE_UNARY64(round.l.d)
dejanj8007ea62013-09-18 10:06:13 +0000740 break;
741 case TRUNCLS:
dejanj0e006f22014-02-19 11:56:29 +0000742 ASM_VOLATILE_UNARY64(trunc.l.s)
dejanj8007ea62013-09-18 10:06:13 +0000743 break;
744 case TRUNCLD:
dejanj0e006f22014-02-19 11:56:29 +0000745 ASM_VOLATILE_UNARY64(trunc.l.d)
dejanj8007ea62013-09-18 10:06:13 +0000746 break;
dejanj41833222013-11-14 15:44:42 +0000747 case ADDS:
dejanj0e006f22014-02-19 11:56:29 +0000748 ASM_VOLATILE_BINARY64(add.s)
dejanj41833222013-11-14 15:44:42 +0000749 break;
750 case ADDD:
dejanj0e006f22014-02-19 11:56:29 +0000751 ASM_VOLATILE_BINARY64(add.d)
dejanj41833222013-11-14 15:44:42 +0000752 break;
753 case SUBS:
dejanj0e006f22014-02-19 11:56:29 +0000754 ASM_VOLATILE_BINARY64(sub.s)
dejanj41833222013-11-14 15:44:42 +0000755 break;
756 case SUBD:
dejanj0e006f22014-02-19 11:56:29 +0000757 ASM_VOLATILE_BINARY64(sub.d)
dejanj41833222013-11-14 15:44:42 +0000758 break;
759 case DIVS:
dejanj0e006f22014-02-19 11:56:29 +0000760 ASM_VOLATILE_BINARY64(div.s)
dejanj41833222013-11-14 15:44:42 +0000761 break;
dejanj8007ea62013-09-18 10:06:13 +0000762 default:
763 vassert(0);
764 break;
765 }
tomaae16ca2013-09-18 11:24:25 +0000766#endif
dejanj8007ea62013-09-18 10:06:13 +0000767 return ret;
768}
769
sewardj362cf842012-06-07 08:59:53 +0000770/*---------------------------------------------------------------*/
771/*--- end guest_mips_helpers.c ---*/
772/*---------------------------------------------------------------*/