cpu (empty) → 0.1.0
raw patch · 10 files changed
+421/−0 lines, 10 filesdep +basedep +bytestringdep +cpusetup-changed
Dependencies added: base, bytestring, cpu
Files
- LICENSE +27/−0
- README.md +8/−0
- Setup.hs +2/−0
- System/Arch.hs +66/−0
- System/Cpuid.hs +43/−0
- System/Endian.hs +95/−0
- cbits/cpuid.c +29/−0
- cbits/endian.c +54/−0
- cpu.cabal +79/−0
- cpuid/Cpuid.hs +18/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2012 Vincent Hanquez <vincent@snarc.org>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,8 @@+Cpu haskell library+===================++The library provides access to property and information helpers related to the cpu:++* Endianness+* Architecture+* Cpuid (for x86 and x86\_64)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ System/Arch.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE CPP #-}+-- |+-- Module : System.Arch+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : unknown+--+module System.Arch+ ( Arch(..)+ , getSystemArch+ ) where++-- | List of all cpu architecture+data Arch = X86+ | X86_64+ | PPC+ | PPC64+ | Sparc+ | Arm+ | Mips+ | SH+ | IA64+ | S390+ | Alpha+ | Hppa+ | Rs6000+ | M68K+ | VAX+ deriving (Show,Eq)++-- | Return the system's cpu architecture+getSystemArch :: Arch+#if defined(ARCH_X86)+getSystemArch = X86+#elif defined(ARCH_X86_64)+getSystemArch = X86_64+#elif defined(ARCH_PPC)+getSystemArch = PPC+#elif defined(ARCH_PPC64)+getSystemArch = PPC64+#elif defined(ARCH_SPARC)+getSystemArch = Sparc+#elif defined(ARCH_ARM)+getSystemArch = Arm+#elif defined(ARCH_MIPS)+getSystemArch = Mips+#elif defined(ARCH_SH)+getSystemArch = SH+#elif defined(ARCH_IA64)+getSystemArch = IA64+#elif defined(ARCH_S390)+getSystemArch = S390+#elif defined(ARCH_ALPHA)+getSystemArch = Alpha+#elif defined(ARCH_HPPA)+getSystemArch = Hppa+#elif defined(ARCH_RS6000)+getSystemArch = Rs6000+#elif defined(ARCH_M68K)+getSystemArch = M68K+#elif defined(ARCH_VAX)+getSystemArch = VAX+#else+getSystemArch = undefined+#endif
+ System/Cpuid.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE CPP #-}+-- |+-- Module : System.Cpuid+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : unknown+--+module System.Cpuid+ ( cpuidWithIndex+ , cpuid+ ) where++import Data.Word+import Control.Applicative+import Foreign.C.Types+import Foreign.Ptr+import Foreign.Storable+import Foreign.Marshal.Alloc++#if defined(ARCH_X86) || defined(ARCH_X86_64)++foreign import ccall safe "cpuid" c_cpuid :: CUInt -> CUInt -> Ptr CUInt -> IO ()++-- | complete cpuid call with eax and ecx set.+cpuidWithIndex :: Word32 -> Word32 -> IO (Word32, Word32, Word32, Word32)+cpuidWithIndex eax ecx = allocaBytes 16 $ \ptr -> do+ c_cpuid (fromIntegral eax) (fromIntegral ecx) ptr+ (,,,) <$> peekW32 ptr <*> peekW32 (ptr `plusPtr` 4) <*> peekW32 (ptr `plusPtr` 8) <*> peekW32 (ptr `plusPtr` 12)+ where peekW32 :: Ptr CUInt -> IO Word32+ peekW32 ptr = fromIntegral <$> peek ptr++#else++cpuidWithIndex :: Word32 -> Word32 -> IO (Word32, Word32, Word32, Word32)+cpuidWithIndex _ _ = error "cpuid is not supported on non-x86 architecture"++#endif++-- | simple cpuid call.+cpuid :: Word32 -> IO (Word32, Word32, Word32, Word32)+cpuid eax = cpuidWithIndex eax 0
+ System/Endian.hs view
@@ -0,0 +1,95 @@+{-# LANGUAGE CPP, ForeignFunctionInterface #-}+-- |+-- Module : System.Endian+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : unknown+--+module System.Endian+ ( Endianness(..)+ , getSystemEndianness+ -- little endian to and from cpu+ , fromLE32+ , fromLE64+ , toLE32+ , toLE64+ -- big endian to and from cpu+ , fromBE32+ , fromBE64+ , toBE32+ , toBE64+ ) where++import Foreign.Marshal.Alloc+import Foreign.Storable+import Foreign.Ptr+import Foreign.C.Types+import System.IO.Unsafe (unsafePerformIO)+import Data.Word++-- | represent the CPU endianness+--+-- Big endian system stores bytes with the MSB as the first byte.+-- Little endian system stores bytes with the LSB as the first byte.+--+-- middle endian is purposely avoided.+data Endianness = LittleEndian+ | BigEndian+ deriving (Show,Eq)++-- | return the system endianness+getSystemEndianness :: Endianness+getSystemEndianness = unsafePerformIO $ alloca $ \p ->+ poke p cst >> peek (castPtr p) >>= return . check+ where cst :: Word32+ cst = 0x01000000+ check :: Word8 -> Endianness+ check x+ | x == 0x01 = BigEndian + | otherwise = LittleEndian++-- | Convert from a big endian 64 bit value to the cpu endianness+fromBE64 :: Word64 -> Word64+fromBE64 = if getSystemEndianness == BigEndian then id else swap64++-- | Convert from a little endian 64 bit value to the cpu endianness+fromLE64 :: Word64 -> Word64+fromLE64 = if getSystemEndianness == LittleEndian then id else swap64++-- | Convert from a big endian 32 bit value to the cpu endianness+fromBE32 :: Word32 -> Word32+fromBE32 = if getSystemEndianness == BigEndian then id else swap32++-- | Convert from a little endian 32 bit value to the cpu endianness+fromLE32 :: Word32 -> Word32+fromLE32 = if getSystemEndianness == LittleEndian then id else swap32++-- | Convert a 64 bit value in cpu endianess to big endian+toBE64 :: Word64 -> Word64+toBE64 = fromBE64++-- | Convert a 64 bit value in cpu endianess to little endian+toLE64 :: Word64 -> Word64+toLE64 = fromLE64++-- | Convert a 32 bit value in cpu endianess to big endian+toBE32 :: Word32 -> Word32+toBE32 = fromBE32++-- | Convert a 32 bit value in cpu endianess to little endian+toLE32 :: Word32 -> Word32+toLE32 = fromLE32++-- | Transform a 32 bit value bytes from a.b.c.d to d.c.b.a+{-# INLINE swap32 #-}+swap32 :: Word32 -> Word32+swap32 = fromIntegral . c_swap32 . fromIntegral++-- | Transform a 64 bit value bytes from a.b.c.d.e.f.g.h to h.g.f.e.d.c.b.a+{-# INLINE swap64 #-}+swap64 :: Word64 -> Word64+swap64 = fromIntegral . c_swap64 . fromIntegral++foreign import ccall safe "bitfn_swap32" c_swap32 :: CUInt -> CUInt+foreign import ccall safe "bitfn_swap64" c_swap64 :: CULLong -> CULLong
+ cbits/cpuid.c view
@@ -0,0 +1,29 @@+#include <stdint.h>++void cpuid(uint32_t eax, uint32_t ecx, uint32_t regs[4])+{+ asm volatile (+#ifdef __i386__+ "push %%ebx\n\t"+ "push %%edx\n\t"+#else+ "push %%rbx\n\t"+ "push %%rdx\n\t"+#endif+ "cpuid\n\t"+ "mov %%eax,(%4)\n\t"+ "mov %%ebx,4(%4)\n\t"+ "mov %%ecx,8(%4)\n\t"+ "mov %%edx,12(%4)\n\t"+#ifdef __i386__+ "pop %%edx\n\t"+ "pop %%ebx\n\t"+#else+ "pop %%rdx\n\t"+ "pop %%rbx\n\t"+#endif+ : "=a" (eax), "=c" (ecx)+ : "0" (eax), "1" (ecx), "S" (regs)+ : "memory"+ );+}
+ cbits/endian.c view
@@ -0,0 +1,54 @@+#include <stdint.h>++#if (defined(__i386__))+# define ARCH_HAS_SWAP32+uint32_t bitfn_swap32(uint32_t a)+{+ asm ("bswap %0" : "=r" (a) : "0" (a));+ return a;+}+/**********************************************************/+# elif (defined(__arm__))+# define ARCH_HAS_SWAP32+uint32_t bitfn_swap32(uint32_t a)+{+ uint32_t tmp = a;+ asm volatile ("eor %1, %0, %0, ror #16\n"+ "bic %1, %1, #0xff0000\n"+ "mov %0, %0, ror #8\n"+ "eor %0, %0, %1, lsr #8\n"+ : "=r" (a), "=r" (tmp) : "0" (a), "1" (tmp));+ return a;+}+/**********************************************************/+# elif defined(__x86_64__)+# define ARCH_HAS_SWAP32+# define ARCH_HAS_SWAP64+uint32_t bitfn_swap32(uint32_t a)+{+ asm ("bswap %0" : "=r" (a) : "0" (a));+ return a;+}++uint64_t bitfn_swap64(uint64_t a)+{+ asm ("bswap %0" : "=r" (a) : "0" (a));+ return a;+}++# endif++#ifndef ARCH_HAS_SWAP32+uint32_t bitfn_swap32(uint32_t a)+{+ return (a << 24) | ((a & 0xff00) << 8) | ((a >> 8) & 0xff00) | (a >> 24);+}+#endif++#ifndef ARCH_HAS_SWAP64+uint64_t bitfn_swap64(uint64_t a)+{+ return ((uint64_t) bitfn_swap32((uint32_t) (a >> 32))) |+ (((uint64_t) bitfn_swap32((uint32_t) a)) << 32);+}+#endif
+ cpu.cabal view
@@ -0,0 +1,79 @@+Name: cpu+Version: 0.1.0+Description: + Lowlevel cpu routines to get basic properties of the cpu platform, like endianness and architecture.+License: BSD3+License-file: LICENSE+Copyright: Vincent Hanquez <vincent@snarc.org>+Author: Vincent Hanquez <vincent@snarc.org>+Maintainer: Vincent Hanquez <vincent@snarc.org>+Synopsis: Cpu information and properties helpers.+Build-Type: Simple+Category: Data+stability: experimental+Cabal-Version: >=1.8+Homepage: http://github.com/vincenthz/hs-cpu+data-files: README.md++Flag executable+ Description: Build the executable+ Default: False++Library+ Build-Depends: base >= 3 && < 5+ Exposed-modules: System.Cpuid+ System.Endian+ System.Arch+ ghc-options: -Wall++ C-sources: cbits/endian.c++ if arch(i386)+ Cpp-options: -DARCH_X86+ if arch(x86_64)+ Cpp-options: -DARCH_X86_64+ if arch(ppc)+ Cpp-options: -DARCH_PPC+ if arch(ppc64)+ Cpp-options: -DARCH_PPC64+ if arch(sparc)+ Cpp-options: -DARCH_SPARC+ if arch(arm)+ Cpp-options: -DARCH_ARM+ if arch(mips)+ Cpp-options: -DARCH_MIPS+ if arch(sh)+ Cpp-options: -DARCH_SH+ if arch(ia64)+ Cpp-options: -DARCH_IA64+ if arch(s390)+ Cpp-options: -DARCH_S390+ if arch(alpha)+ Cpp-options: -DARCH_ALPHA+ if arch(hppa)+ Cpp-options: -DARCH_HPPA+ if arch(rs6000)+ Cpp-options: -DARCH_RS6000+ if arch(m68k)+ Cpp-options: -DARCH_M68K+ if arch(vax)+ Cpp-options: -DARCH_VAX++ if arch(i386) || arch(x86_64)+ C-sources: cbits/cpuid.c++executable cpuid+ hs-source-dirs: cpuid+ Main-is: Cpuid.hs+ if flag(executable)+ Buildable: True+ Build-Depends: base >= 3 && < 5+ , cpu+ , bytestring+ else+ Buildable: False+ ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures++source-repository head+ type: git+ location: git://github.com/vincenthz/hs-cpu
+ cpuid/Cpuid.hs view
@@ -0,0 +1,18 @@+module Main where++import System.Environment+import System.Cpuid+import Text.Printf++usage = do+ error "usage: cpuid <eax> [ecx]"++printResult (eax,ebx,ecx,edx) = do+ printf "%.8x %.8x %.8x %.8x\n" eax ebx ecx edx++main = do+ args <- getArgs+ case args of+ [] -> usage+ eax:[] -> cpuid (read eax) >>= printResult+ eax:ecx:_ -> cpuidWithIndex (read eax) (read ecx) >>= printResult