diff options
author | lloyd <[email protected]> | 2009-10-29 04:17:35 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2009-10-29 04:17:35 +0000 |
commit | 9b35547f5862ac2d34573d7421eb8be05c6064ae (patch) | |
tree | 1d903ab2cbc0d4aff8bbc0d76c0c122ee4c0fd4f /src/utils | |
parent | d5412353bec03ae91d69286ee53369cd9588dcda (diff) |
Add CPUID::have_altivec for AltiVec runtime detection.
Relies on mfspr emulation/trapping by the kernel, which works on (at least)
Linux and NetBSD.
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/cpuid.cpp | 60 | ||||
-rw-r--r-- | src/utils/cpuid.h | 1 |
2 files changed, 61 insertions, 0 deletions
diff --git a/src/utils/cpuid.cpp b/src/utils/cpuid.cpp index f79e3a912..298caf078 100644 --- a/src/utils/cpuid.cpp +++ b/src/utils/cpuid.cpp @@ -98,4 +98,64 @@ u32bit CPUID::cache_line_size() return cl_size; } +bool CPUID::has_altivec() + { + static bool first_time = true; + static bool altivec_capable = false; + + if(first_time) + { +#if defined(BOTAN_TARGET_ARCH_IS_PPC) || defined(BOTAN_TARGET_ARCH_IS_PPC64) + + /* + PVR identifiers for various AltiVec enabled CPUs. Taken from + PearPC and Linux sources, mostly. + */ + const u16bit PVR_G4_7400 = 0x000C; + const u16bit PVR_G5_970 = 0x0039; + const u16bit PVR_G5_970FX = 0x003C; + const u16bit PVR_G5_970MP = 0x0044; + const u16bit PVR_G5_970GX = 0x0045; + const u16bit PVR_POWER6 = 0x003E; + const u16bit PVR_CELL_PPU = 0x0070; + + // Motorola produced G4s with PVR 0x800[0123C] (at least) + const u16bit PVR_G4_74xx_24 = 0x800; + + u32bit pvr = 0; + /* + On PowerPC, MSR 287 is PVR, the Processor Version Number + + Normally it is only accessible to ring 0, but Linux and NetBSD + (at least) will trap and emulate it for us. This is roughly 20x + saner than every other approach I've seen for this (all of which + are entirely OS specific, to boot). + + Apparently OS X doesn't support this, but then again OS X + doesn't really support PPC anymore, so I'm not worrying about it. + + For OSes that aren't (known to) support the emulation, leave pvr + as 0 which will cause all subsequent model number checks to fail. + */ +#if defined(BOTAN_TARGET_OS_IS_LINUX) || defined(BOTAN_TARGET_OS_IS_NETBSD) + asm volatile("mfspr %0, 287" : "=r" (pvr)); +#endif + // Top 16 bit suffice to identify model + pvr >>= 16; + + altivec_capable ||= (pvr == PVR_G4_7400); + altivec_capable ||= ((pvr >> 8) == PVR_G4_74xx_24); + altivec_capable ||= (pvr == PVR_G5_970); + altivec_capable ||= (pvr == PVR_G5_970FX); + altivec_capable ||= (pvr == PVR_G5_970MP); + altivec_capable ||= (pvr == PVR_G5_970GX); + altivec_capable ||= (pvr == PVR_CELL_PPU); +#endif + + first_time = false; + } + + return altivec_capable; + } + } diff --git a/src/utils/cpuid.h b/src/utils/cpuid.h index 0b210768a..8b8021754 100644 --- a/src/utils/cpuid.h +++ b/src/utils/cpuid.h @@ -65,6 +65,7 @@ class CPUID static bool has_intel_aes() { return ((x86_processor_flags() >> CPUID_INTEL_AES_BIT) & 1); } + static bool has_altivec(); private: static u64bit x86_processor_flags(); }; |