/* set host SSE control word to the default mode expected
by VEX-generated code. */
- cmpl $0, VG_(have_mxcsr_x86)
+ cmpl $0, VG_(machine_x86_have_mxcsr)
jz L1
pushl $0x1F80
ldmxcsr (%esp)
%mxcsr or %fpucw. We can't mess with %eax here as it
holds the tentative return value, but any other is OK. */
/* This fails for self-hosting, so skip in that case */
-#ifndef ENABLE_INNER
+#if !defined(ENABLE_INNER)
pushl $0
fstcw (%esp)
cmpl $0x027F, (%esp)
popl %esi /* get rid of the word without trashing %eflags */
jnz invariant_violation
- cmpl $0, VG_(have_mxcsr_x86)
- jz L2
#endif
+ cmpl $0, VG_(machine_x86_have_mxcsr)
+ jz L2
pushl $0
stmxcsr (%esp)
andl $0xFFFFFFC0, (%esp) /* mask out status flags */
#include "pub_core_libcassert.h"
#include "pub_core_libcbase.h"
#include "pub_core_machine.h"
+#include "pub_core_cpuid.h"
#define INSTR_PTR(regs) ((regs).vex.VG_INSTR_PTR)
#define STACK_PTR(regs) ((regs).vex.VG_STACK_PTR)
return False;
}
-//////////////////////////////////////////////////////////////////
-// Architecture specifics
+//-------------------------------------------------------------
+/* Details about the capabilities of the underlying (host) CPU. These
+ details are acquired by (1) enquiring with the CPU at startup, or
+ (2) from the AT_SYSINFO entries the kernel gave us (ppc32 cache
+ line size). It's a bit nasty in the sense that there's no obvious
+ way to stop uses of some of this info before it's ready to go.
-#if defined(VGA_ppc32)
-/* PPC: what is the cache line size (for dcbz etc) ? This info is
- harvested on Linux at startup from the AT_SYSINFO entries. 0 means
- not-yet-set. */
-Int VG_(cache_line_size_ppc32) = 0;
+ Current dependencies are:
+
+ x86: initially: call VG_(machine_get_hwcaps)
+
+ then safe to use VG_(machine_get_VexArchInfo)
+ and VG_(machine_x86_have_mxcsr)
+ -------------
+ amd64: initially: call VG_(machine_get_hwcaps)
+
+ then safe to use VG_(machine_get_VexArchInfo)
+ -------------
+ ppc32: initially: call VG_(machine_get_hwcaps)
+ call VG_(machine_ppc32_set_clszB)
+
+ then safe to use VG_(machine_get_VexArchInfo)
+ and VG_(machine_ppc32_has_FPU)
+ and VG_(machine_ppc32_has_VMX)
+
+ VG_(machine_get_hwcaps) may use signals (although it attempts to
+ leave signal state unchanged) and therefore should only be
+ called before m_main sets up the client's signal state.
+*/
-/* Altivec enabled? Harvested on startup from the AT_HWCAP entry. */
-Int VG_(have_altivec_ppc32) = 0;
+/* --------- State --------- */
+static Bool hwcaps_done = False;
+
+/* --- all archs --- */
+static VexArch va;
+static VexArchInfo vai;
+
+#if defined(VGA_x86)
+UInt VG_(machine_x86_have_mxcsr) = 0;
#endif
+#if defined(VGA_ppc32)
+UInt VG_(machine_ppc32_has_FPU) = 0;
+UInt VG_(machine_ppc32_has_VMX) = 0;
+#endif
+
+
+/* Determine what insn set and insn set variant the host has, and
+ record it. To be called once at system startup. Returns False if
+ this a CPU incapable of running Valgrind. */
+Bool VG_(machine_get_hwcaps)( void )
+{
+ vg_assert(hwcaps_done == False);
+ hwcaps_done = True;
+
+ // Whack default settings into vai, so that we only need to fill in
+ // any interesting bits.
+ LibVEX_default_VexArchInfo(&vai);
#if defined(VGA_x86)
-/* X86: set to 1 if the host is able to do {ld,st}mxcsr (load/store
- the SSE control/status register. For most modern CPUs this will be
- 1. It is set to 1, if possible, by m_translate.getArchAndArchInfo.
- The value is read by m_dispatch.dispatch-x86.S, which is why it is
- an Int rather than a Bool.
-
- Ugly hack: this has to start as 0 and be set to 1 in the normal
- case, rather than the other way round, because the dispatch loop
- needs it, and it runs before the first translation is made. Yet it
- is the act of making that first translation which causes
- getArchAndArchInfo to set this value to its final value. So it is
- necessary to start this value off at 0 as only that guarantees that
- the dispatch loop will not SIGILL on its first attempt. */
-Int VG_(have_mxcsr_x86) = 0;
+ { Bool have_sse1, have_sse2;
+ UInt eax, ebx, ecx, edx;
+
+ if (!VG_(has_cpuid)())
+ /* we can't do cpuid at all. Give up. */
+ return False;
+
+ VG_(cpuid)(0, &eax, &ebx, &ecx, &edx);
+ if (eax < 1)
+ /* we can't ask for cpuid(x) for x > 0. Give up. */
+ return False;
+
+ /* get capabilities bits into edx */
+ VG_(cpuid)(1, &eax, &ebx, &ecx, &edx);
+
+ have_sse1 = (edx & (1<<25)) != 0; /* True => have sse insns */
+ have_sse2 = (edx & (1<<26)) != 0; /* True => have sse2 insns */
+
+ if (have_sse2 && have_sse1) {
+ va = VexArchX86;
+ vai.subarch = VexSubArchX86_sse2;
+ VG_(machine_x86_have_mxcsr) = 1;
+ return True;
+ }
+
+ if (have_sse1) {
+ va = VexArchX86;
+ vai.subarch = VexSubArchX86_sse1;
+ VG_(machine_x86_have_mxcsr) = 1;
+ return True;
+ }
+
+ va = VexArchX86;
+ vai.subarch = VexSubArchX86_sse0;
+ VG_(machine_x86_have_mxcsr) = 0;
+ return True;
+ }
+
+#elif defined(VGA_amd64)
+ vg_assert(VG_(has_cpuid)());
+ va = VexArchAMD64;
+ vai.subarch = VexSubArch_NONE;
+ return True;
+
+#elif defined(VGA_ppc32)
+ va = VexArchPPC32;
+ vai.subarch = VexSubArchPPC32_AV;
+ /* But we're not done yet: VG_(machine_ppc32_set_clszB) must be
+ called before we're ready to go. */
+ return True;
+
+#else
+# error "Unknown arch"
#endif
+}
+
+
+/* Fetch host cpu info, once established. */
+void VG_(machine_get_VexArchInfo)( /*OUT*/VexArch* pVa,
+ /*OUT*/VexArchInfo* pVai )
+{
+ vg_assert(hwcaps_done);
+ *pVa = va;
+ *pVai = vai;
+}
/*--------------------------------------------------------------------*/
// Get the current process stack rlimit.
VG_(getrlimit)(VKI_RLIMIT_STACK, &VG_(client_rlimit_stack));
+ //--------------------------------------------------------------
+ // Figure out what sort of CPU we're on, and whether it is
+ // able to run V.
+ VG_(debugLog)(1, "main", "Get hardware capabilities ...\n");
+ { VexArch vex_arch;
+ VexArchInfo vex_archinfo;
+ Bool ok = VG_(machine_get_hwcaps)();
+ if (!ok) {
+ VG_(printf)("\n");
+ VG_(printf)("valgrind: fatal error: unsupported CPU.\n");
+ VG_(printf)(" Supported CPUs are:\n");
+ VG_(printf)(" * x86 (practically any; Pentium-I or above), "
+ "AMD Athlon or above)\n");
+ VG_(printf)(" * AMD Athlon64/Opteron\n");
+ VG_(printf)(" * PowerPC (most; ppc405 and above)\n");
+ VG_(printf)("\n");
+ VG_(exit)(1);
+ }
+ VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
+ VG_(debugLog)(1, "main", "... arch = %s, subarch = %s\n",
+ LibVEX_ppVexArch ( vex_arch ),
+ LibVEX_ppVexSubArch( vex_archinfo.subarch ) );
+ }
+
//============================================================
// Command line argument handling order:
// * If --help/--help-debug are present, show usage message
#include "pub_core_basics.h"
#include "pub_core_aspacemgr.h"
-#include "pub_core_cpuid.h"
-#include "pub_core_machine.h" // For VG_(cache_line_size_ppc32)
- // and VG_(have_altivec_ppc)
+
+#include "pub_core_machine.h" // For VG_(machine_get_VexArchInfo)
// and VG_(get_SP)
- // and VG_(have_mxcsr_x86)
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcprint.h"
#include "pub_core_transtab.h"
-/*------------------------------------------------------------*/
-/*--- Determining arch/subarch. ---*/
-/*------------------------------------------------------------*/
-
-// Returns the architecture and auxiliary information, or indicates
-// that this subarchitecture is unable to run Valgrind. Returns False
-// to indicate we cannot proceed further.
-
-static Bool getArchAndArchInfo( /*OUT*/VexArch* vex_arch,
- /*OUT*/VexArchInfo* vai )
-{
- // Whack default settings into vai, so that we only need to fill in
- // any interesting bits.
- LibVEX_default_VexArchInfo(vai);
-
-#if defined(VGA_x86)
- { Bool have_sse1, have_sse2;
- UInt eax, ebx, ecx, edx;
-
- if (!VG_(has_cpuid)())
- /* we can't do cpuid at all. Give up. */
- return False;
-
- VG_(cpuid)(0, &eax, &ebx, &ecx, &edx);
- if (eax < 1)
- /* we can't ask for cpuid(x) for x > 0. Give up. */
- return False;
-
- /* get capabilities bits into edx */
- VG_(cpuid)(1, &eax, &ebx, &ecx, &edx);
-
- have_sse1 = (edx & (1<<25)) != 0; /* True => have sse insns */
- have_sse2 = (edx & (1<<26)) != 0; /* True => have sse2 insns */
-
- VG_(have_mxcsr_x86) = 1;
-
- if (have_sse2 && have_sse1) {
- *vex_arch = VexArchX86;
- vai->subarch = VexSubArchX86_sse2;
- return True;
- }
-
- if (have_sse1) {
- *vex_arch = VexArchX86;
- vai->subarch = VexSubArchX86_sse1;
- return True;
- }
-
- {
- *vex_arch = VexArchX86;
- vai->subarch = VexSubArchX86_sse0;
- VG_(have_mxcsr_x86) = 0;
- return True;
- }
- }
-
-#elif defined(VGA_amd64)
- vg_assert(VG_(has_cpuid)());
- *vex_arch = VexArchAMD64;
- vai->subarch = VexSubArch_NONE;
- return True;
-
-#elif defined(VGA_ppc32)
- *vex_arch = VexArchPPC32;
- vai->subarch = VG_(have_altivec_ppc32) ? VexSubArchPPC32_AV
- : VexSubArchPPC32_noAV;
- vai->ppc32_cache_line_szB = VG_(cache_line_size_ppc32);
- return True;
-
-#else
-# error Unknown architecture
-#endif
-}
-
-
/*------------------------------------------------------------*/
/*--- %SP-update pass ---*/
/*------------------------------------------------------------*/
Int debugging_verbosity,
ULong bbs_done )
{
- Addr64 redir, orig_addr_noredir = orig_addr;
- Int tmpbuf_used, verbosity, i;
- Bool notrace_until_done, do_self_check;
- UInt notrace_until_limit = 0;
- NSegment* seg;
- VexGuestExtents vge;
-
- /* Indicates what arch we are running on, and other important info
- (subarch variant, cache line size). */
- static VexArchInfo vex_archinfo;
- static VexArch vex_arch = VexArch_INVALID;
+ Addr64 redir, orig_addr_noredir = orig_addr;
+ Int tmpbuf_used, verbosity, i;
+ Bool notrace_until_done, do_self_check;
+ UInt notrace_until_limit = 0;
+ NSegment* seg;
+ VexArch vex_arch;
+ VexArchInfo vex_archinfo;
+ VexGuestExtents vge;
+ VexTranslateResult tres;
/* Make sure Vex is initialised right. */
- VexTranslateResult tres;
+
static Bool vex_init_done = False;
if (!vex_init_done) {
- Bool ok = getArchAndArchInfo( &vex_arch, &vex_archinfo );
- if (!ok) {
- VG_(printf)("\n");
- VG_(printf)("valgrind: fatal error: unsupported CPU.\n");
- VG_(printf)(" Supported CPUs are:\n");
- VG_(printf)(" * x86 (practically any; Pentium-I or above), "
- "AMD Athlon or above)\n");
- VG_(printf)(" * AMD Athlon64/Opteron\n");
- VG_(printf)(" * PowerPC with Altivec\n");
- VG_(printf)("\n");
- VG_(exit)(1);
- }
- if (VG_(clo_verbosity) > 2) {
- VG_(message)(Vg_DebugMsg,
- "Host CPU: arch = %s, subarch = %s",
- LibVEX_ppVexArch ( vex_arch ),
- LibVEX_ppVexSubArch( vex_archinfo.subarch ) );
- }
-
LibVEX_Init ( &failure_exit, &log_bytes,
1, /* debug_paranoia */
False, /* valgrind support */
VGP_PUSHCC(VgpVexTime);
- /* Actually do the translation. */
+ /* ------ Actually do the translation. ------ */
tl_assert2(VG_(tdict).tool_instrument,
"you forgot to set VgToolInterface function 'tool_instrument'");
+ /* Get the CPU info established at startup. */
+ VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
+
/* Set up closure arg for "chase_into_ok" */
chase_into_ok__CLOSURE_tid = tid;
#define VG_O_STACK_PTR (offsetof(VexGuestArchState, VG_STACK_PTR))
-// Architecture specifics
+//-------------------------------------------------------------
+/* Details about the capabilities of the underlying (host) CPU. These
+ details are acquired by (1) enquiring with the CPU at startup, or
+ (2) from the AT_SYSINFO entries the kernel gave us (ppc32 cache
+ line size). It's a bit nasty in the sense that there's no obvious
+ way to stop uses of some of this info before it's ready to go.
+
+ Current dependencies are:
+
+ x86: initially: call VG_(machine_get_hwcaps)
+
+ then safe to use VG_(machine_get_VexArchInfo)
+ and VG_(machine_x86_have_mxcsr)
+ -------------
+ amd64: initially: call VG_(machine_get_hwcaps)
+
+ then safe to use VG_(machine_get_VexArchInfo)
+ -------------
+ ppc32: initially: call VG_(machine_get_hwcaps)
+ call VG_(machine_ppc32_set_clszB)
+
+ then safe to use VG_(machine_get_VexArchInfo)
+ and VG_(machine_ppc32_has_FPU)
+ and VG_(machine_ppc32_has_VMX)
+
+ VG_(machine_get_hwcaps) may use signals (although it attempts to
+ leave signal state unchanged) and therefore should only be
+ called before m_main sets up the client's signal state.
+*/
+
+/* Determine what insn set and insn set variant the host has, and
+ record it. To be called once at system startup. Returns False if
+ this a CPU incapable of running Valgrind. */
+extern Bool VG_(machine_get_hwcaps)( void );
+/* Fetch host cpu info, as per above comment. */
+extern void VG_(machine_get_VexArchInfo)( /*OUT*/VexArch*,
+ /*OUT*/VexArchInfo* );
+
+/* Notify host cpu cache line size, as per above comment. */
#if defined(VGA_ppc32)
-// PPC: what is the cache line size (for dcbz etc) ?
-// This info is harvested on Linux at startup from the AT_SYSINFO
-// entries.
-extern Int VG_(cache_line_size_ppc32);
-// Altivec enabled? Harvested on startup from the AT_HWCAP entry
-extern Int VG_(have_altivec_ppc32);
+extern void VG_(machine_ppc32_set_clszB)( Int );
#endif
-// X86: set to 1 if the host is able to do {ld,st}mxcsr (load/store
-// the SSE control/status register.
+/* X86: set to 1 if the host is able to do {ld,st}mxcsr (load/store
+ the SSE control/status register), else zero. Is referenced from
+ assembly code, so do not change from a 32-bit int. */
#if defined(VGA_x86)
-extern Int VG_(have_mxcsr_x86);
+extern UInt VG_(machine_x86_have_mxcsr);
+#endif
+
+/* PPC32: set to 1 if FP instructions are supported in user-space,
+ else 0. Is referenced from assembly code, so do not change from a
+ 32-bit int. */
+#if defined(VGA_ppc32)
+extern UInt VG_(machine_ppc32_has_FPU);
#endif
+/* PPC32: set to 1 if Altivec instructions are supported in
+ user-space, else 0. Is referenced from assembly code, so do not
+ change from a 32-bit int. */
+#if defined(VGA_ppc32)
+extern UInt VG_(machine_ppc32_has_VMX);
+#endif
#endif // __PUB_CORE_MACHINE_H