blob: 8392610e80c7b153773a2552c19689a5b528870a [file] [log] [blame]
njnf536bbb2005-06-13 04:21:38 +00001
2/*--------------------------------------------------------------------*/
3/*--- Machine-related stuff. m_machine.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2005 Julian Seward
11 jseward@acm.org
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
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
32#include "pub_core_threadstate.h"
njnf536bbb2005-06-13 04:21:38 +000033#include "pub_core_libcassert.h"
34#include "pub_core_libcbase.h"
35#include "pub_core_machine.h"
sewardje2d1e672005-11-12 23:10:48 +000036#include "pub_core_cpuid.h"
sewardje3826cf2005-11-13 00:30:22 +000037#include "pub_core_libcsignal.h" // for ppc32 messing with SIGILL
38
njnf536bbb2005-06-13 04:21:38 +000039
njnaf839f52005-06-23 03:27:57 +000040#define INSTR_PTR(regs) ((regs).vex.VG_INSTR_PTR)
41#define STACK_PTR(regs) ((regs).vex.VG_STACK_PTR)
42#define FRAME_PTR(regs) ((regs).vex.VG_FRAME_PTR)
njnf536bbb2005-06-13 04:21:38 +000043
44Addr VG_(get_SP) ( ThreadId tid )
45{
46 return STACK_PTR( VG_(threads)[tid].arch );
47}
48
49Addr VG_(get_IP) ( ThreadId tid )
50{
51 return INSTR_PTR( VG_(threads)[tid].arch );
52}
53
54Addr VG_(get_FP) ( ThreadId tid )
55{
56 return FRAME_PTR( VG_(threads)[tid].arch );
57}
58
sewardjacaec5f2005-08-19 16:02:59 +000059Addr VG_(get_LR) ( ThreadId tid )
60{
sewardj2c48c7b2005-11-29 13:05:56 +000061# if defined(VGA_ppc32) || defined(VGA_ppc64)
sewardjacaec5f2005-08-19 16:02:59 +000062 return VG_(threads)[tid].arch.vex.guest_LR;
63# elif defined(VGA_x86) || defined(VGA_amd64)
64 return 0;
65# else
66# error "Unknown arch"
67# endif
68}
69
njnf536bbb2005-06-13 04:21:38 +000070void VG_(set_SP) ( ThreadId tid, Addr sp )
71{
72 STACK_PTR( VG_(threads)[tid].arch ) = sp;
73}
74
75void VG_(set_IP) ( ThreadId tid, Addr ip )
76{
77 INSTR_PTR( VG_(threads)[tid].arch ) = ip;
78}
79
80
81void VG_(get_shadow_regs_area) ( ThreadId tid, OffT offset, SizeT size,
82 UChar* area )
83{
84 ThreadState* tst;
85
86 vg_assert(VG_(is_valid_tid)(tid));
87 tst = & VG_(threads)[tid];
88
89 // Bounds check
90 vg_assert(0 <= offset && offset < sizeof(VexGuestArchState));
91 vg_assert(offset + size <= sizeof(VexGuestArchState));
92
93 VG_(memcpy)( area, (void*)(((Addr)&(tst->arch.vex_shadow)) + offset), size);
94}
95
96void VG_(set_shadow_regs_area) ( ThreadId tid, OffT offset, SizeT size,
97 const UChar* area )
98{
99 ThreadState* tst;
100
101 vg_assert(VG_(is_valid_tid)(tid));
102 tst = & VG_(threads)[tid];
103
104 // Bounds check
105 vg_assert(0 <= offset && offset < sizeof(VexGuestArchState));
106 vg_assert(offset + size <= sizeof(VexGuestArchState));
107
108 VG_(memcpy)( (void*)(((Addr)(&tst->arch.vex_shadow)) + offset), area, size);
109}
110
111
njn6ace3ea2005-06-17 03:06:27 +0000112static void apply_to_GPs_of_tid(VexGuestArchState* vex, void (*f)(Addr))
113{
114#if defined(VGA_x86)
115 (*f)(vex->guest_EAX);
116 (*f)(vex->guest_ECX);
117 (*f)(vex->guest_EDX);
118 (*f)(vex->guest_EBX);
119 (*f)(vex->guest_ESI);
120 (*f)(vex->guest_EDI);
121 (*f)(vex->guest_ESP);
122 (*f)(vex->guest_EBP);
123#elif defined(VGA_amd64)
124 (*f)(vex->guest_RAX);
125 (*f)(vex->guest_RCX);
126 (*f)(vex->guest_RDX);
127 (*f)(vex->guest_RBX);
128 (*f)(vex->guest_RSI);
129 (*f)(vex->guest_RDI);
130 (*f)(vex->guest_RSP);
131 (*f)(vex->guest_RBP);
132 (*f)(vex->guest_R8);
133 (*f)(vex->guest_R9);
134 (*f)(vex->guest_R10);
135 (*f)(vex->guest_R11);
136 (*f)(vex->guest_R12);
137 (*f)(vex->guest_R13);
138 (*f)(vex->guest_R14);
139 (*f)(vex->guest_R15);
sewardj2c48c7b2005-11-29 13:05:56 +0000140#elif defined(VGA_ppc32) || defined(VGA_ppc64)
cerion85665ca2005-06-20 15:51:07 +0000141 /* XXX ask tool about validity? */
142 (*f)(vex->guest_GPR0);
143 (*f)(vex->guest_GPR1);
144 (*f)(vex->guest_GPR2);
145 (*f)(vex->guest_GPR3);
146 (*f)(vex->guest_GPR4);
147 (*f)(vex->guest_GPR5);
148 (*f)(vex->guest_GPR6);
149 (*f)(vex->guest_GPR7);
150 (*f)(vex->guest_GPR8);
151 (*f)(vex->guest_GPR9);
152 (*f)(vex->guest_GPR10);
153 (*f)(vex->guest_GPR11);
154 (*f)(vex->guest_GPR12);
155 (*f)(vex->guest_GPR13);
156 (*f)(vex->guest_GPR14);
157 (*f)(vex->guest_GPR15);
158 (*f)(vex->guest_GPR16);
159 (*f)(vex->guest_GPR17);
160 (*f)(vex->guest_GPR18);
161 (*f)(vex->guest_GPR19);
162 (*f)(vex->guest_GPR20);
163 (*f)(vex->guest_GPR21);
164 (*f)(vex->guest_GPR22);
165 (*f)(vex->guest_GPR23);
166 (*f)(vex->guest_GPR24);
167 (*f)(vex->guest_GPR25);
168 (*f)(vex->guest_GPR26);
169 (*f)(vex->guest_GPR27);
170 (*f)(vex->guest_GPR28);
171 (*f)(vex->guest_GPR29);
172 (*f)(vex->guest_GPR30);
173 (*f)(vex->guest_GPR31);
174 (*f)(vex->guest_CTR);
175 (*f)(vex->guest_LR);
176
njn6ace3ea2005-06-17 03:06:27 +0000177#else
178# error Unknown arch
179#endif
180}
181
182
183void VG_(apply_to_GP_regs)(void (*f)(UWord))
184{
185 ThreadId tid;
186
187 for (tid = 1; tid < VG_N_THREADS; tid++) {
188 if (VG_(is_valid_tid)(tid)) {
189 ThreadState* tst = VG_(get_ThreadState)(tid);
190 apply_to_GPs_of_tid(&(tst->arch.vex), f);
191 }
192 }
193}
194
njn1d0cb0d2005-08-15 01:52:02 +0000195static ThreadId thread_stack_iter = VG_INVALID_THREADID;
196
197void VG_(thread_stack_reset_iter)(void)
njnb506bd82005-06-21 04:01:51 +0000198{
njn1d0cb0d2005-08-15 01:52:02 +0000199 thread_stack_iter = 1;
njnb506bd82005-06-21 04:01:51 +0000200}
njn6ace3ea2005-06-17 03:06:27 +0000201
njn1d0cb0d2005-08-15 01:52:02 +0000202Bool VG_(thread_stack_next)(ThreadId* tid, Addr* stack_min, Addr* stack_max)
203{
204 ThreadId i;
205 for (i = thread_stack_iter; i < VG_N_THREADS; i++) {
206 if (VG_(threads)[i].status != VgTs_Empty) {
207 *tid = i;
208 *stack_min = VG_(get_SP)(i);
209 *stack_max = VG_(threads)[i].client_stack_highest_word;
210 thread_stack_iter = i + 1;
211 return True;
212 }
213 }
214 return False;
215}
sewardj7821e2e2005-08-08 00:35:46 +0000216
sewardje2d1e672005-11-12 23:10:48 +0000217//-------------------------------------------------------------
218/* Details about the capabilities of the underlying (host) CPU. These
219 details are acquired by (1) enquiring with the CPU at startup, or
220 (2) from the AT_SYSINFO entries the kernel gave us (ppc32 cache
221 line size). It's a bit nasty in the sense that there's no obvious
222 way to stop uses of some of this info before it's ready to go.
sewardj10f08cf2005-06-29 10:16:14 +0000223
sewardje2d1e672005-11-12 23:10:48 +0000224 Current dependencies are:
sewardja48a4932005-09-29 11:09:56 +0000225
sewardje2d1e672005-11-12 23:10:48 +0000226 x86: initially: call VG_(machine_get_hwcaps)
sewardj10f08cf2005-06-29 10:16:14 +0000227
sewardje2d1e672005-11-12 23:10:48 +0000228 then safe to use VG_(machine_get_VexArchInfo)
229 and VG_(machine_x86_have_mxcsr)
230 -------------
231 amd64: initially: call VG_(machine_get_hwcaps)
232
233 then safe to use VG_(machine_get_VexArchInfo)
234 -------------
235 ppc32: initially: call VG_(machine_get_hwcaps)
236 call VG_(machine_ppc32_set_clszB)
237
238 then safe to use VG_(machine_get_VexArchInfo)
sewardj2c36d422005-11-13 01:59:22 +0000239 and VG_(machine_ppc32_has_FP)
sewardje2d1e672005-11-12 23:10:48 +0000240 and VG_(machine_ppc32_has_VMX)
cerion1f0d8142005-12-23 00:57:03 +0000241 -------------
242 ppc64: initially: call VG_(machine_get_hwcaps)
243 call VG_(machine_ppc64_set_clszB)
244
245 then safe to use VG_(machine_get_VexArchInfo)
246 and VG_(machine_ppc64_has_VMX)
sewardje2d1e672005-11-12 23:10:48 +0000247
248 VG_(machine_get_hwcaps) may use signals (although it attempts to
249 leave signal state unchanged) and therefore should only be
250 called before m_main sets up the client's signal state.
251*/
252
253/* --------- State --------- */
254static Bool hwcaps_done = False;
255
256/* --- all archs --- */
257static VexArch va;
258static VexArchInfo vai;
sewardja48a4932005-09-29 11:09:56 +0000259
sewardj7821e2e2005-08-08 00:35:46 +0000260#if defined(VGA_x86)
sewardje2d1e672005-11-12 23:10:48 +0000261UInt VG_(machine_x86_have_mxcsr) = 0;
sewardj7821e2e2005-08-08 00:35:46 +0000262#endif
sewardje2d1e672005-11-12 23:10:48 +0000263#if defined(VGA_ppc32)
sewardj2c36d422005-11-13 01:59:22 +0000264UInt VG_(machine_ppc32_has_FP) = 0;
sewardje2d1e672005-11-12 23:10:48 +0000265UInt VG_(machine_ppc32_has_VMX) = 0;
266#endif
sewardj2c48c7b2005-11-29 13:05:56 +0000267#if defined(VGA_ppc64)
268ULong VG_(machine_ppc64_has_VMX) = 0;
269#endif
sewardje2d1e672005-11-12 23:10:48 +0000270
271
272/* Determine what insn set and insn set variant the host has, and
273 record it. To be called once at system startup. Returns False if
274 this a CPU incapable of running Valgrind. */
275
sewardj2c48c7b2005-11-29 13:05:56 +0000276#if defined(VGA_ppc32) || defined(VGA_ppc64)
sewardje3826cf2005-11-13 00:30:22 +0000277#include <setjmp.h> // For jmp_buf
278static jmp_buf env_sigill;
279static void handler_sigill ( Int x ) { __builtin_longjmp(env_sigill,1); }
280#endif
281
sewardje2d1e672005-11-12 23:10:48 +0000282Bool VG_(machine_get_hwcaps)( void )
283{
284 vg_assert(hwcaps_done == False);
285 hwcaps_done = True;
286
287 // Whack default settings into vai, so that we only need to fill in
288 // any interesting bits.
289 LibVEX_default_VexArchInfo(&vai);
290
291#if defined(VGA_x86)
292 { Bool have_sse1, have_sse2;
293 UInt eax, ebx, ecx, edx;
294
295 if (!VG_(has_cpuid)())
296 /* we can't do cpuid at all. Give up. */
297 return False;
298
299 VG_(cpuid)(0, &eax, &ebx, &ecx, &edx);
300 if (eax < 1)
301 /* we can't ask for cpuid(x) for x > 0. Give up. */
302 return False;
303
304 /* get capabilities bits into edx */
305 VG_(cpuid)(1, &eax, &ebx, &ecx, &edx);
306
307 have_sse1 = (edx & (1<<25)) != 0; /* True => have sse insns */
308 have_sse2 = (edx & (1<<26)) != 0; /* True => have sse2 insns */
309
310 if (have_sse2 && have_sse1) {
311 va = VexArchX86;
sewardje3121f32006-01-27 21:23:23 +0000312 vai.hwcaps = VEX_HWCAPS_X86_SSE1;
313 vai.hwcaps |= VEX_HWCAPS_X86_SSE2;
sewardje2d1e672005-11-12 23:10:48 +0000314 VG_(machine_x86_have_mxcsr) = 1;
315 return True;
316 }
317
318 if (have_sse1) {
319 va = VexArchX86;
sewardje3121f32006-01-27 21:23:23 +0000320 vai.hwcaps = VEX_HWCAPS_X86_SSE1;
sewardje2d1e672005-11-12 23:10:48 +0000321 VG_(machine_x86_have_mxcsr) = 1;
322 return True;
323 }
324
sewardje3121f32006-01-27 21:23:23 +0000325 va = VexArchX86;
326 vai.hwcaps = 0; /*baseline - no sse at all*/
sewardje2d1e672005-11-12 23:10:48 +0000327 VG_(machine_x86_have_mxcsr) = 0;
328 return True;
329 }
330
331#elif defined(VGA_amd64)
332 vg_assert(VG_(has_cpuid)());
sewardje3121f32006-01-27 21:23:23 +0000333 va = VexArchAMD64;
334 vai.hwcaps = 0; /*baseline - SSE2 */
sewardje2d1e672005-11-12 23:10:48 +0000335 return True;
336
337#elif defined(VGA_ppc32)
sewardje3826cf2005-11-13 00:30:22 +0000338 { /* ppc32 doesn't seem to have a sane way to find out what insn
339 sets the CPU supports. So we have to arse around with
340 SIGILLs. Yuck. */
341 vki_sigset_t saved_set, tmp_set;
342 struct vki_sigaction saved_act, tmp_act;
343
sewardjb32bc732006-01-27 21:52:39 +0000344 volatile Bool have_F, have_V, have_FX, have_GX;
sewardj7637e9e2006-02-21 17:11:11 +0000345 Int r;
sewardje3826cf2005-11-13 00:30:22 +0000346
347 VG_(sigemptyset)(&tmp_set);
348 VG_(sigaddset)(&tmp_set, VKI_SIGILL);
349
sewardj7637e9e2006-02-21 17:11:11 +0000350 r = VG_(sigprocmask)(VKI_SIG_UNBLOCK, &tmp_set, &saved_set);
351 vg_assert(r == 0);
sewardje3826cf2005-11-13 00:30:22 +0000352
sewardj7637e9e2006-02-21 17:11:11 +0000353 r = VG_(sigaction)(VKI_SIGILL, NULL, &saved_act);
354 vg_assert(r == 0);
sewardje3826cf2005-11-13 00:30:22 +0000355 tmp_act = saved_act;
356
sewardj7637e9e2006-02-21 17:11:11 +0000357 /* NODEFER: signal handler does not return (from the kernel's point of
358 view), hence if it is to successfully catch a signal more than once,
359 we need the NODEFER flag. */
sewardje3826cf2005-11-13 00:30:22 +0000360 tmp_act.sa_flags &= ~VKI_SA_RESETHAND;
361 tmp_act.sa_flags &= ~VKI_SA_SIGINFO;
sewardj7637e9e2006-02-21 17:11:11 +0000362 tmp_act.sa_flags |= VKI_SA_NODEFER;
sewardje3826cf2005-11-13 00:30:22 +0000363
sewardje3121f32006-01-27 21:23:23 +0000364 /* standard FP insns */
365 have_F = True;
sewardje3826cf2005-11-13 00:30:22 +0000366 tmp_act.ksa_handler = handler_sigill;
sewardj7637e9e2006-02-21 17:11:11 +0000367 r = VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
368 vg_assert(r == 0);
sewardje3826cf2005-11-13 00:30:22 +0000369 if (__builtin_setjmp(env_sigill)) {
sewardje3121f32006-01-27 21:23:23 +0000370 have_F = False;
sewardje3826cf2005-11-13 00:30:22 +0000371 } else {
372 __asm__ __volatile__("fmr 0,0");
373 }
374
sewardje3121f32006-01-27 21:23:23 +0000375 /* Altivec insns */
376 have_V = True;
sewardje3826cf2005-11-13 00:30:22 +0000377 tmp_act.ksa_handler = handler_sigill;
sewardj7637e9e2006-02-21 17:11:11 +0000378 r = VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
379 vg_assert(r == 0);
sewardje3826cf2005-11-13 00:30:22 +0000380 if (__builtin_setjmp(env_sigill)) {
sewardje3121f32006-01-27 21:23:23 +0000381 have_V = False;
sewardje3826cf2005-11-13 00:30:22 +0000382 } else {
383 __asm__ __volatile__("vor 0,0,0");
384 }
385
sewardje3121f32006-01-27 21:23:23 +0000386 /* General-Purpose optional (fsqrt, fsqrts) */
387 have_FX = True;
388 tmp_act.ksa_handler = handler_sigill;
sewardj7637e9e2006-02-21 17:11:11 +0000389 r = VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
390 vg_assert(r == 0);
sewardje3121f32006-01-27 21:23:23 +0000391 if (__builtin_setjmp(env_sigill)) {
392 have_FX = False;
393 } else {
394 __asm__ __volatile__("fsqrt 0,0");
395 }
396
397 /* Graphics optional (stfiwx, fres, frsqrte, fsel) */
398 have_GX = True;
399 tmp_act.ksa_handler = handler_sigill;
sewardj7637e9e2006-02-21 17:11:11 +0000400 r = VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
401 vg_assert(r == 0);
sewardje3121f32006-01-27 21:23:23 +0000402 if (__builtin_setjmp(env_sigill)) {
403 have_GX = False;
404 } else {
sewardjb32bc732006-01-27 21:52:39 +0000405 __asm__ __volatile__("frsqrte 0,0");
sewardje3121f32006-01-27 21:23:23 +0000406 }
407
sewardj7637e9e2006-02-21 17:11:11 +0000408 r = VG_(sigaction)(VKI_SIGILL, &saved_act, NULL);
409 vg_assert(r == 0);
410 r = VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL);
411 vg_assert(r == 0);
sewardjb32bc732006-01-27 21:52:39 +0000412 /*
sewardje3121f32006-01-27 21:23:23 +0000413 VG_(printf)("F %d V %d FX %d GX %d\n",
414 (Int)have_F, (Int)have_V, (Int)have_FX, (Int)have_GX);
sewardjb32bc732006-01-27 21:52:39 +0000415 */
sewardje3121f32006-01-27 21:23:23 +0000416 /* Make FP a prerequisite for VMX (bogusly so), and for FX and GX. */
417 if (have_V && !have_F)
418 have_V = False;
419 if (have_FX && !have_F)
420 have_FX = False;
421 if (have_GX && !have_F)
422 have_GX = False;
sewardje3826cf2005-11-13 00:30:22 +0000423
sewardje3121f32006-01-27 21:23:23 +0000424 VG_(machine_ppc32_has_FP) = have_F ? 1 : 0;
425 VG_(machine_ppc32_has_VMX) = have_V ? 1 : 0;
sewardje3826cf2005-11-13 00:30:22 +0000426
427 va = VexArchPPC32;
428
sewardje3121f32006-01-27 21:23:23 +0000429 vai.hwcaps = 0;
430 if (have_F) vai.hwcaps |= VEX_HWCAPS_PPC32_F;
431 if (have_V) vai.hwcaps |= VEX_HWCAPS_PPC32_V;
432 if (have_FX) vai.hwcaps |= VEX_HWCAPS_PPC32_FX;
433 if (have_GX) vai.hwcaps |= VEX_HWCAPS_PPC32_GX;
sewardje3826cf2005-11-13 00:30:22 +0000434
435 /* But we're not done yet: VG_(machine_ppc32_set_clszB) must be
436 called before we're ready to go. */
437 return True;
438 }
sewardje2d1e672005-11-12 23:10:48 +0000439
sewardj2c48c7b2005-11-29 13:05:56 +0000440#elif defined(VGA_ppc64)
sewardje3121f32006-01-27 21:23:23 +0000441 { /* Same idiocy as for ppc32 - arse around with SIGILLs. */
442 vki_sigset_t saved_set, tmp_set;
sewardj2c48c7b2005-11-29 13:05:56 +0000443 struct vki_sigaction saved_act, tmp_act;
444
sewardjb32bc732006-01-27 21:52:39 +0000445 volatile Bool have_F, have_V, have_FX, have_GX;
sewardj2c48c7b2005-11-29 13:05:56 +0000446
447 VG_(sigemptyset)(&tmp_set);
448 VG_(sigaddset)(&tmp_set, VKI_SIGILL);
449
450 VG_(sigprocmask)(VKI_SIG_UNBLOCK, &tmp_set, &saved_set);
451
452 VG_(sigaction)(VKI_SIGILL, NULL, &saved_act);
453 tmp_act = saved_act;
454
sewardj7637e9e2006-02-21 17:11:11 +0000455 /* NODEFER: signal handler does not return (from the kernel's point of
456 view), hence if it is to successfully catch a signal more than once,
457 we need the NODEFER flag. */
sewardj2c48c7b2005-11-29 13:05:56 +0000458 tmp_act.sa_flags &= ~VKI_SA_RESETHAND;
459 tmp_act.sa_flags &= ~VKI_SA_SIGINFO;
sewardj7637e9e2006-02-21 17:11:11 +0000460 tmp_act.sa_flags |= VKI_SA_NODEFER;
sewardj2c48c7b2005-11-29 13:05:56 +0000461
sewardje3121f32006-01-27 21:23:23 +0000462 /* standard FP insns */
463 have_F = True;
sewardj2c48c7b2005-11-29 13:05:56 +0000464 tmp_act.ksa_handler = handler_sigill;
465 VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
sewardj2c48c7b2005-11-29 13:05:56 +0000466 if (__builtin_setjmp(env_sigill)) {
sewardje3121f32006-01-27 21:23:23 +0000467 have_F = False;
468 } else {
469 __asm__ __volatile__("fmr 0,0");
470 }
471
472 /* Altivec insns */
473 have_V = True;
474 tmp_act.ksa_handler = handler_sigill;
475 VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
476 if (__builtin_setjmp(env_sigill)) {
477 have_V = False;
sewardj2c48c7b2005-11-29 13:05:56 +0000478 } else {
479 __asm__ __volatile__("vor 0,0,0");
480 }
481
sewardje3121f32006-01-27 21:23:23 +0000482 /* General-Purpose optional (fsqrt, fsqrts) */
483 have_FX = True;
484 tmp_act.ksa_handler = handler_sigill;
485 VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
486 if (__builtin_setjmp(env_sigill)) {
487 have_FX = False;
488 } else {
489 __asm__ __volatile__("fsqrt 0,0");
490 }
491
492 /* Graphics optional (stfiwx, fres, frsqrte, fsel) */
493 have_GX = True;
494 tmp_act.ksa_handler = handler_sigill;
495 VG_(sigaction)(VKI_SIGILL, &tmp_act, NULL);
496 if (__builtin_setjmp(env_sigill)) {
497 have_GX = False;
498 } else {
sewardjb32bc732006-01-27 21:52:39 +0000499 __asm__ __volatile__("frsqrte 0,0");
sewardje3121f32006-01-27 21:23:23 +0000500 }
501
sewardj2c48c7b2005-11-29 13:05:56 +0000502 VG_(sigaction)(VKI_SIGILL, &saved_act, NULL);
503 VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL);
sewardjb32bc732006-01-27 21:52:39 +0000504 /*
sewardje3121f32006-01-27 21:23:23 +0000505 if (0)
506 VG_(printf)("F %d V %d FX %d GX %d\n",
507 (Int)have_F, (Int)have_V, (Int)have_FX, (Int)have_GX);
sewardjb32bc732006-01-27 21:52:39 +0000508 */
sewardje3121f32006-01-27 21:23:23 +0000509 /* on ppc64, if we don't even have FP, just give up. */
510 if (!have_F)
511 return False;
512
513 VG_(machine_ppc64_has_VMX) = have_V ? 1 : 0;
sewardj2c48c7b2005-11-29 13:05:56 +0000514
515 va = VexArchPPC64;
sewardje3121f32006-01-27 21:23:23 +0000516
517 vai.hwcaps = 0;
518 if (have_V) vai.hwcaps |= VEX_HWCAPS_PPC64_V;
519 if (have_FX) vai.hwcaps |= VEX_HWCAPS_PPC64_FX;
520 if (have_GX) vai.hwcaps |= VEX_HWCAPS_PPC64_GX;
sewardj2c48c7b2005-11-29 13:05:56 +0000521
522 /* But we're not done yet: VG_(machine_ppc64_set_clszB) must be
523 called before we're ready to go. */
524 return True;
525 }
526
sewardje2d1e672005-11-12 23:10:48 +0000527#else
528# error "Unknown arch"
529#endif
530}
531
sewardj2c48c7b2005-11-29 13:05:56 +0000532/* Notify host cpu cache line size. */
sewardje3826cf2005-11-13 00:30:22 +0000533#if defined(VGA_ppc32)
534void VG_(machine_ppc32_set_clszB)( Int szB )
535{
536 vg_assert(hwcaps_done);
537
538 /* Either the value must not have been set yet (zero) or we can
539 tolerate it being set to the same value multiple times, as the
540 stack scanning logic in m_main is a bit stupid. */
cerion1f0d8142005-12-23 00:57:03 +0000541 vg_assert(vai.ppc_cache_line_szB == 0
542 || vai.ppc_cache_line_szB == szB);
sewardje3826cf2005-11-13 00:30:22 +0000543
544 vg_assert(szB == 32 || szB == 128);
cerion1f0d8142005-12-23 00:57:03 +0000545 vai.ppc_cache_line_szB = szB;
sewardje3826cf2005-11-13 00:30:22 +0000546}
547#endif
548
sewardje2d1e672005-11-12 23:10:48 +0000549
sewardj2c48c7b2005-11-29 13:05:56 +0000550/* Notify host cpu cache line size. */
551#if defined(VGA_ppc64)
552void VG_(machine_ppc64_set_clszB)( Int szB )
553{
554 vg_assert(hwcaps_done);
555
556 /* Either the value must not have been set yet (zero) or we can
557 tolerate it being set to the same value multiple times, as the
558 stack scanning logic in m_main is a bit stupid. */
cerion1f0d8142005-12-23 00:57:03 +0000559 vg_assert(vai.ppc_cache_line_szB == 0
560 || vai.ppc_cache_line_szB == szB);
sewardj2c48c7b2005-11-29 13:05:56 +0000561
562 vg_assert(szB == 32 || szB == 128);
cerion1f0d8142005-12-23 00:57:03 +0000563 vai.ppc_cache_line_szB = szB;
sewardj2c48c7b2005-11-29 13:05:56 +0000564}
565#endif
566
567
sewardje2d1e672005-11-12 23:10:48 +0000568/* Fetch host cpu info, once established. */
569void VG_(machine_get_VexArchInfo)( /*OUT*/VexArch* pVa,
570 /*OUT*/VexArchInfo* pVai )
571{
572 vg_assert(hwcaps_done);
sewardje3826cf2005-11-13 00:30:22 +0000573 if (pVa) *pVa = va;
574 if (pVai) *pVai = vai;
sewardje2d1e672005-11-12 23:10:48 +0000575}
sewardj7821e2e2005-08-08 00:35:46 +0000576
577
sewardj53ee1fc2005-12-23 02:29:58 +0000578// Given a pointer to a function as obtained by "& functionname" in C,
579// produce a pointer to the actual entry point for the function. For
580// most platforms it's the identity function. Unfortunately, on
581// ppc64-linux it isn't (sigh).
582void* VG_(fnptr_to_fnentry)( void* f )
583{
584#if defined(VGP_x86_linux)
585 return f;
586#elif defined(VGP_amd64_linux)
587 return f;
588#elif defined(VGP_ppc32_linux)
589 return f;
590#elif defined(VGP_ppc64_linux)
591 /* f is a pointer to a 3-word function descriptor, of which
592 the first word is the entry address. */
593 /* Don't ask me. Really. I have no idea why. */
594 ULong* descr = (ULong*)f;
595 return (void*)(descr[0]);
596#else
597# error "Unknown platform"
598#endif
599}
600
njnf536bbb2005-06-13 04:21:38 +0000601/*--------------------------------------------------------------------*/
602/*--- end ---*/
603/*--------------------------------------------------------------------*/