packages feed

hsXenCtrl-0.0.2: System/Xen/CBindings.hsc

module System.Xen.CBindings
    ( xc_interface_open
    , xc_interface_close
    , xc_find_device_number
    , xc_domain_create
    , xc_domain_dumpcore
    , xc_domain_dumpcore_via_callback
    , xc_domain_max_vcpus
    , xc_domain_pause
    , xc_domain_unpause
    , xc_domain_destroy
    , xc_domain_resume
    , xc_domain_shutdown
    , xc_vcpu_setaffinity
    , xc_vcpu_getaffinity
    , xc_domain_getinfo
    , xc_domain_getinfolist
    , xc_CORE_MAGIC
    , xc_CORE_MAGIC_HVM
    , DomId(..)
    , XCHandle(..)
    ) where

import Data.Bits
import Data.List (foldl1')
import Data.Word
import Data.Array.IArray
import Foreign.C
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Array

#include <xenctrl.h>

xc_CORE_MAGIC :: CInt
xc_CORE_MAGIC = 0xF00FEBED

xc_CORE_MAGIC_HVM :: CInt
xc_CORE_MAGIC_HVM = 0xF00FEBEE

data DomainFlag = Dying | Crashed | Shutdown | Paused | Blocked | Running | HVM | Debugged deriving (Eq, Ord, Show, Enum)

instance Storable [DomainFlag] where
    sizeOf _ = sizeOf (undefined :: CUInt)
    alignment _ = alignment (undefined :: CUInt)
    peek ptr = do
        v <- peek (castPtr ptr)
        return $ fromBits v
    poke ptr a = poke (castPtr ptr) (toBits a)

toBits :: [DomainFlag] -> CUInt
toBits flgs = foldl1' (.|.) (map (bit . fromEnum) flgs)

fromBits :: CUInt -> [DomainFlag]
fromBits v = map (toEnum . fst) flagsSet
  where
  flagsSet :: [(Int,Bool)]
  flagsSet = filter ((==True) . snd) (zip [0..] flgVals)
  flgVals :: [Bool]
  flgVals = map (uncurry testBit) (zip (repeat v) [0..31])

data XC_DomInfo = XC_DomInfo {
    diDomId           :: Word32,
    diSSIDRef         :: Word32,
    diFlags           :: [DomainFlag],
    diShutdownReason  :: XCShutdown,
    diNrPages         :: CUInt,
    diSharedInfoFrame :: CUInt,
    diCpuTime         :: Word64,
    diMaxMemKB        :: CULong,
    diNrOnlineVCPUs   :: CUInt,
    diMaxVCPUId       :: CUInt,
    diDomHandle       :: [XenDomainHandle]
  } deriving (Eq, Ord, Show)

type XenDomainHandle = Word8
type XenDomainHandleT = Ptr Word8

instance Storable XC_DomInfo where
    sizeOf _= (#size xc_dominfo_t)
    alignment _ = alignment (undefined :: Word64)
    peek ptr = do
         domId    <- (#peek xc_dominfo_t, domid) ptr
         ssidRef  <- (#peek xc_dominfo_t, ssidref) ptr
         flags <- peekByteOff ptr (sizeOf domId + sizeOf ssidRef)
         sr    <- (#peek xc_dominfo_t, shutdown_reason) ptr
         nrPgs <- (#peek xc_dominfo_t, nr_pages) ptr
         infoF <- (#peek xc_dominfo_t, shared_info_frame) ptr
         cpuT  <- (#peek xc_dominfo_t, cpu_time) ptr
         maxM  <- (#peek xc_dominfo_t, max_memkb) ptr
         nrOC  <- (#peek xc_dominfo_t, nr_online_vcpus) ptr
         maxCI <- (#peek xc_dominfo_t, max_vcpu_id) ptr
         dh    <- peekArray 16 (plusPtr ptr (#offset xc_dominfo_t, handle))
         return $ XC_DomInfo domId ssidRef flags sr nrPgs infoF cpuT maxM nrOC maxCI dh
    poke ptr a = do
        (#poke xc_dominfo_t, domid) ptr (diDomId a)
        (#poke xc_dominfo_t, ssidref) ptr (diSSIDRef a)
        pokeByteOff ptr (sizeOf (diDomId a) + sizeOf (diSSIDRef a)) (diFlags a)
        (#poke xc_dominfo_t, shutdown_reason) ptr (diShutdownReason a)
        (#poke xc_dominfo_t, nr_pages) ptr (diNrPages a)
        (#poke xc_dominfo_t, shared_info_frame) ptr (diSharedInfoFrame a)
        (#poke xc_dominfo_t, cpu_time) ptr (diCpuTime a)
        (#poke xc_dominfo_t, max_memkb) ptr (diMaxMemKB a)
        (#poke xc_dominfo_t, nr_online_vcpus) ptr (diNrOnlineVCPUs a)
        (#poke xc_dominfo_t, max_vcpu_id) ptr (diMaxVCPUId a)
        let p = plusPtr ptr 76
            domHandles = take 16 $ diDomHandle a ++ repeat 0
        pokeArray p domHandles

-- FIXME VCPU Guest Context Type

-- SHUTDOWN constants can be found in <xen/sched.h>
data XCShutdown = SHUTDOWN_poweroff | SHUTDOWN_reboot | SHUTDOWN_suspend | SHUTDOWN_crash
    deriving (Eq, Ord, Show, Read, Enum)

instance Storable XCShutdown where
    sizeOf _ = sizeOf (undefined :: CInt)
    alignment _ = alignment (undefined :: CInt)
    peek ptr = peek (castPtr ptr :: Ptr CInt) >>= return . toEnum . fromIntegral
    poke ptr a = poke (castPtr ptr :: Ptr CInt) (fromIntegral (fromEnum a))

newtype XCHandle = XCHdl CInt deriving (Eq, Ord, Show)

instance Storable XCHandle where
    sizeOf _ = sizeOf (undefined :: CInt)
    alignment _ = alignment (undefined :: CInt)
    peek ptr = peek (castPtr ptr) >>= return . XCHdl
    poke ptr (XCHdl h) = poke (castPtr ptr) h

newtype DomId = DomId Word32 deriving (Eq, Ord, Show)

instance Storable DomId where
    sizeOf _ = sizeOf (undefined :: Word32)
    alignment _ = alignment (undefined :: Word32)
    peek ptr = peek (castPtr ptr) >>= return . DomId
    poke ptr i = poke (castPtr ptr) i

foreign import ccall unsafe "xc_interface_open"
    xc_interface_open :: IO XCHandle

foreign import ccall unsafe "xc_interface_close"
    xc_interface_close :: XCHandle -> IO CInt

foreign import ccall unsafe "xc_find_device_number"
    xc_find_device_number :: CString -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_create"
    xc_domain_create :: XCHandle -> DomId -> XenDomainHandleT -> Word32 -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_dumpcore"
    xc_domain_dumpcore :: XCHandle -> DomId -> CString -> IO CInt

type Dumpcore_rtn_t = FunPtr (Ptr Word8 -> CString -> CUInt -> IO CInt)

foreign import ccall safe "xenctrl.h xc_domain_dumpcore_via_callback"
    xc_domain_dumpcore_via_callback :: XCHandle -> DomId -> Ptr Word8 -> IO Dumpcore_rtn_t

foreign import ccall unsafe "xenctrl.h xc_domain_max_vcpus"
    xc_domain_max_vcpus :: XCHandle -> DomId -> CUInt -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_pause"
    xc_domain_pause :: XCHandle -> DomId -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_unpause"
    xc_domain_unpause :: XCHandle -> DomId -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_destroy"
    xc_domain_destroy :: XCHandle -> DomId -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_resume"
    xc_domain_resume :: XCHandle -> DomId -> CInt -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_shutdown"
     xc_domain_shutdown :: XCHandle -> DomId -> CInt -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_vcpu_setaffinity"
    xc_vcpu_setaffinity :: XCHandle -> DomId -> CInt -> Word64 -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_vcpu_getaffinity"
    xc_vcpu_getaffinity :: XCHandle -> DomId -> CInt -> Ptr Word64 -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_getinfo"
    xc_domain_getinfo :: XCHandle -> DomId -> CUInt -> Ptr XC_DomInfo -> IO CInt

-- TODO need to base VCPU_Guest_Context on arch specific info
-- how can I trick that info from cabal and use it here?
--
-- foreign import ccall unsafe "xenctrl.h xc_vcpu_setcontext"
--     xc_vcpu_setcontext :: XCHandle -> DomId -> Word32 -> Ptr VCPU_Guest_Context -> IO CInt

foreign import ccall unsafe "xenctrl.h xc_domain_getinfolist"
    xc_domain_getinfolist :: XCHandle -> DomId -> CUInt -> Ptr XC_DomInfo -> CInt

-- Data and functions for debugging
data XC_Core_Header = XC_Core_Header {
      xchMagic       :: CInt
    , xchNrVCPUs     :: CInt
    , xchNrPages     :: CInt
    , xchCTXTOffset  :: CInt
    , xchIndexOffset :: CInt
    , xchPagesOffset :: CInt } deriving (Eq, Ord, Show)

instance Storable XC_Core_Header where
    sizeOf _ = (#size xc_core_header_t)
    alignment _ = alignment (undefined :: CInt)
    peek ptr = do
        m <- (#peek xc_core_header_t, xch_magic) ptr
        v <- (#peek xc_core_header_t, xch_nr_vcpus) ptr
        p <- (#peek xc_core_header_t, xch_nr_pages) ptr
        c <- (#peek xc_core_header_t, xch_ctxt_offset) ptr
        i <- (#peek xc_core_header_t, xch_index_offset) ptr
        g <- (#peek xc_core_header_t, xch_pages_offset) ptr
        return (XC_Core_Header m v p c i g)
    poke ptr (XC_Core_Header m v p c i g) = do
        (#poke xc_core_header_t, xch_magic) ptr m
        (#poke xc_core_header_t, xch_nr_vcpus) ptr v
        (#poke xc_core_header_t, xch_nr_pages) ptr p
        (#poke xc_core_header_t, xch_ctxt_offset) ptr c
        (#poke xc_core_header_t, xch_index_offset) ptr i
        (#poke xc_core_header_t, xch_pages_offset) ptr g