| -- |
| -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) |
| -- |
| -- SPDX-License-Identifier: BSD-2-Clause |
| -- |
| |
| {-# OPTIONS_GHC -fno-warn-unused-binds #-} |
| |
| module CapDL.MakeModel where |
| |
| import CapDL.Model |
| import CapDL.AST |
| import CapDL.State |
| |
| import Prelude () |
| import Prelude.Compat |
| import Data.Maybe |
| import Data.List.Compat |
| import qualified Data.Either as Either |
| import Data.Data |
| import Data.Word |
| import Data.Bits |
| import Data.Function (on) |
| import qualified Data.Set as Set |
| import qualified Data.Map as Map |
| import qualified Control.Monad.State as ST |
| import Control.Monad |
| import Control.Monad.Writer (tell) |
| import Text.PrettyPrint (text) |
| |
| -- | A spec can place objects in explicit slots, or not. |
| -- This keeps track of the most recently used slot, and returns |
| -- the next slot when needed. |
| type SlotState = ST.State Word |
| |
| getSlot :: SlotState Word |
| getSlot = do |
| slot <- ST.get |
| return $ slot + 1 |
| |
| putSlot :: Word -> SlotState () |
| putSlot = ST.put |
| |
| evalSlotState :: SlotState a -> a |
| evalSlotState = (`ST.evalState` maxBound) -- HACK: `getSlot maxBound` wraps to slot 0 |
| |
| isUntyped :: KernelObject Word -> Bool |
| isUntyped Untyped{} = True |
| isUntyped _ = False |
| |
| emptyModel arch = Model arch Map.empty Map.empty |
| emptyIdents = Idents Map.empty |
| |
| printID :: ObjID -> String |
| printID (name, Nothing) = name |
| printID (name, Just num) = name ++ "[" ++ show num ++ "]" |
| |
| baseName :: QName -> NameRef |
| baseName = last |
| |
| qNames :: QName -> [NameRef] |
| qNames = init |
| |
| sameName :: ObjID -> ObjID -> Bool |
| sameName (first, _) (second, _) = first == second |
| |
| numObject :: Map.Map ObjID a -> Name -> Word |
| numObject objs name = |
| if Map.member (name, Just 0) objs |
| then fromIntegral $ length $ filter (sameName (name, Nothing)) $ Map.keys objs |
| else error $ "Unknown reference: " ++ name |
| |
| refToID :: NameRef -> ObjID |
| refToID (name, []) = (name, Nothing) |
| refToID (name, [Only n]) = (name, Just n) |
| refToID names = error ("A unique identifer was expected at " ++ show names) |
| |
| unrange :: Word -> Range -> [Maybe Word] |
| unrange num range = case range of |
| Only id -> [Just id] |
| FromTo first last -> map Just list |
| where list = if first <= last |
| then [first..last] |
| else [first,first-1..last] |
| From first -> map Just [first..num - 1] |
| To last -> map Just [0..last] |
| All -> map Just [0..num - 1] |
| |
| refToIDs :: Map.Map ObjID a -> NameRef -> [ObjID] |
| refToIDs _ (name, []) = [(name, Nothing)] |
| refToIDs objs (name, ranges) = |
| zip (repeat name) $ concatMap (unrange (numObject objs name)) ranges |
| |
| makeIDs :: Name -> Maybe Word -> [ObjID] |
| makeIDs name Nothing = [(name,Nothing)] |
| makeIDs name (Just num) = zip (repeat name) (map Just [0..(num - 1)]) |
| |
| members :: Ord k => [k] -> Map.Map k a -> Bool |
| members names objs = all (`Map.member` objs) names |
| |
| addCovered :: ObjMap Word -> [ObjID] -> [ObjID] -> [ObjID] |
| addCovered objs names cov = |
| if members names objs |
| then cov ++ names -- FIXME: needed to preserve order, but inefficient |
| else error ("At least one object reference is unknown: " ++ show names) |
| |
| addUTCover :: ObjMap Word -> CoverMap -> [ObjID] -> ObjID -> CoverMap |
| addUTCover objs covers names ut = |
| Map.insertWith (addCovered objs) ut names covers |
| |
| addUTCovers :: ObjMap Word -> CoverMap -> [ObjID] -> [ObjID] -> CoverMap |
| addUTCovers _ covers _ [] = covers |
| addUTCovers objs covers n [ut] = addUTCover objs covers n ut |
| addUTCovers objs covers n (ut:uts) = |
| addUTCovers objs (addUTCover objs covers n ut) [ut] uts |
| |
| addUTDecl :: ObjMap Word -> ObjID -> CoverMap -> NameRef -> CoverMap |
| addUTDecl objs ut covers names = addUTCover objs covers (refToIDs objs names) ut |
| |
| addUTDecls :: ObjMap Word -> ObjID -> CoverMap -> [NameRef] -> CoverMap |
| addUTDecls objs ut = foldl' (addUTDecl objs ut) |
| |
| getUntypedCover :: Maybe NameRef -> ObjMap Word -> CoverMap -> Decl -> CoverMap |
| getUntypedCover prevName objs covers (ObjDecl (KODecl objName obj)) = |
| if null (objDecls obj) |
| then |
| let (name, num) = refToID $ baseName objName |
| qns = qNames objName |
| in addUTCovers objs covers (makeIDs name num) |
| (map refToID (reverse (maybeCons prevName qns))) |
| else |
| let name = refToID $ baseName objName |
| qns = qNames objName |
| covers' = addUTCovers objs covers [name] |
| (map refToID (reverse (maybeCons prevName qns))) |
| covers'' = addUTDecls objs name covers' (Either.rights (objDecls obj)) |
| in getUntypedCovers (Just (baseName objName)) objs covers'' |
| (map ObjDecl (Either.lefts (objDecls obj))) |
| where maybeCons (Just x) xs = x:xs |
| maybeCons Nothing xs = xs |
| getUntypedCover _ _ covers _ = covers |
| |
| getUntypedCovers :: Maybe NameRef -> ObjMap Word -> CoverMap -> [Decl] -> CoverMap |
| getUntypedCovers prevName objs = |
| foldl' (getUntypedCover prevName objs) |
| |
| -- A child of an untyped may be mentioned multiple times in the spec. |
| -- When parsing, this creates multiple entries in the cover list. |
| -- We normalise the untyped cover by removing duplicates. |
| -- |
| -- This feature is deprecated; generate warnings when we encounter it. |
| dedupCoverIDs :: CoverMap -> Logger CoverMap |
| dedupCoverIDs = sequenceA . Map.mapWithKey (dedup Set.empty Set.empty) |
| where dedup _ _ _ [] = return [] :: Logger [ObjID] |
| -- constrain monad type; otherwise we need FlexibleContexts |
| dedup seen reported utID (x:xs) |
| | Set.member x seen = do |
| when (Set.notMember x reported) $ do |
| tell $ text $ "warning: specifying untyped child multiple times is deprecated: " ++ |
| "ut = " ++ printID utID ++ ", child = " ++ printID x ++ "\n" |
| dedup seen (Set.insert x reported) utID xs |
| | otherwise = (x:) <$> dedup (Set.insert x seen) reported utID xs |
| |
| emptyUntyped :: KernelObject Word |
| emptyUntyped = Untyped Nothing Nothing |
| |
| getUTObj :: ObjMap Word -> ObjID -> KernelObject Word |
| getUTObj objs ut = |
| case Map.lookup ut objs of |
| Nothing -> emptyUntyped |
| Just obj -> |
| if isUntyped obj |
| then obj |
| else error ("Untyped object expected at \""++ printID ut ++ |
| "\", but found instead: " ++ show obj) |
| |
| addUTName :: ObjMap Word -> ObjID -> ObjMap Word |
| addUTName objs ut = Map.insert ut (getUTObj objs ut) objs |
| |
| addUTNames :: ObjMap Word -> [ObjID] -> ObjMap Word |
| addUTNames objs [] = objs |
| addUTNames objs [ut] = addUTName objs ut |
| addUTNames objs (ut:uts) = addUTNames (addUTName objs ut) uts |
| |
| addUntyped :: ObjMap Word -> Decl -> ObjMap Word |
| addUntyped objs (ObjDecl (KODecl objName obj)) = |
| if null (objDecls obj) |
| then |
| let qns = qNames objName |
| in addUTNames objs (map refToID qns) |
| else |
| let qns = qNames objName |
| objs' = addUTNames objs (map refToID qns) |
| in addUntypeds objs' (map ObjDecl (Either.lefts (objDecls obj))) |
| addUntyped objs _ = objs |
| |
| addUntypeds :: ObjMap Word -> [Decl] -> ObjMap Word |
| addUntypeds = foldl' addUntyped |
| |
| getTCBAddr :: [ObjParam] -> Maybe Word |
| getTCBAddr [] = Nothing |
| getTCBAddr (TCBExtraParam (Addr addr) : _) = Just addr |
| getTCBAddr (_ : xs ) = getTCBAddr xs |
| |
| getTCBip :: [ObjParam] -> Maybe Word |
| getTCBip [] = Nothing |
| getTCBip (TCBExtraParam (IP ip) : _) = Just ip |
| getTCBip (_ : xs ) = getTCBip xs |
| |
| getTCBsp :: [ObjParam] -> Maybe Word |
| getTCBsp [] = Nothing |
| getTCBsp (TCBExtraParam (SP sp) : _) = Just sp |
| getTCBsp (_ : xs ) = getTCBsp xs |
| |
| getTCBprio :: [ObjParam] -> Maybe Integer |
| getTCBprio [] = Nothing |
| getTCBprio (TCBExtraParam (Prio prio) : _) = Just prio |
| getTCBprio (_ : xs) = getTCBprio xs |
| |
| getTCBmax_prio :: [ObjParam] -> Maybe Integer |
| getTCBmax_prio [] = Nothing |
| getTCBmax_prio (TCBExtraParam (MaxPrio max_prio) : _) = Just max_prio |
| getTCBmax_prio (_ : xs) = getTCBmax_prio xs |
| |
| getTCBaffinity :: [ObjParam] -> Maybe Integer |
| getTCBaffinity [] = Nothing |
| getTCBaffinity (TCBExtraParam (Affinity affinity) : _) = Just affinity |
| getTCBaffinity (_ : xs) = getTCBaffinity xs |
| |
| getTCBresume :: [ObjParam] -> Maybe Bool |
| getTCBresume [] = Nothing |
| getTCBresume (TCBExtraParam (Resume resume) : _) = Just resume |
| getTCBresume (_ : xs) = getTCBresume xs |
| |
| getExtraInfo :: Name -> [ObjParam] -> Maybe TCBExtraInfo |
| getExtraInfo n params = |
| -- FIXME: This is really hacky hardcoding the acceptable combinations of attributes. |
| case (getTCBAddr params, getTCBip params, getTCBsp params, getTCBprio params, getTCBmax_prio params, getTCBaffinity params, getTCBresume params) of |
| (Just addr, Just ip, Just sp, Just prio, Just max_prio, Just affinity, resume) -> |
| Just $ TCBExtraInfo addr (Just ip) (Just sp) (Just prio) (Just max_prio) (Just affinity) resume |
| (Just addr, Nothing, Nothing, Nothing, Nothing, Just affinity, resume) -> |
| Just $ TCBExtraInfo addr Nothing Nothing Nothing Nothing (Just affinity) resume |
| (Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) -> Nothing |
| params -> error $ "Incorrect extra tcb parameters: " ++ n ++ show params |
| |
| getCNodeHasUntyped :: [ObjParam] -> Maybe Bool |
| getCNodeHasUntyped [] = Nothing |
| getCNodeHasUntyped (CNodeExtraParam (HasUntyped untyped) : _) = Just untyped |
| getCNodeHasUntyped (_ : xs) = getCNodeHasUntyped xs |
| |
| getCNodeExtraInfo :: [ObjParam] -> CNodeExtraInfo |
| getCNodeExtraInfo params = CNodeExtraInfo (getCNodeHasUntyped params) |
| |
| getTCBDom :: [ObjParam] -> Integer |
| getTCBDom [] = 0 |
| getTCBDom (Dom dom : _) = dom |
| getTCBDom (_ : xs) = getTCBDom xs |
| |
| getFaultEP :: [ObjParam] -> Maybe Word |
| getFaultEP [] = Nothing |
| getFaultEP (FaultEP fault_ep : _) = Just fault_ep |
| getFaultEP (_ : xs) = getFaultEP xs |
| |
| getInitArguments :: [ObjParam] -> [Word] |
| getInitArguments [] = [] |
| getInitArguments (InitArguments init : _) = init |
| getInitArguments (_ : xs) = getInitArguments xs |
| |
| getSCPeriod :: [ObjParam] -> Maybe Word64 |
| getSCPeriod [] = Nothing |
| getSCPeriod (SCExtraParam (Period period) : _) = Just period |
| getSCPeriod (_ : xs) = getSCPeriod xs |
| |
| getSCBudget :: [ObjParam] -> Maybe Word64 |
| getSCBudget [] = Nothing |
| getSCBudget (SCExtraParam (Budget budget) : _) = Just budget |
| getSCBudget (_ : xs) = getSCBudget xs |
| |
| getSCData :: [ObjParam] -> Maybe Word |
| getSCData [] = Nothing |
| getSCData (SCExtraParam (SCData scData) : _) = Just scData |
| getSCData (_ : xs) = getSCData xs |
| |
| getCBExtraInfo :: [ObjParam] -> Maybe Word |
| getCBExtraInfo [] = Nothing |
| getCBExtraInfo (CBExtraParam (CBNumber x) : _) = Just x |
| getCBExtraInfo (_ : xs) = getCBExtraInfo xs |
| |
| getSCExtraInfo :: Name -> [ObjParam] -> Maybe SCExtraInfo |
| getSCExtraInfo n params = |
| -- FIXME: This is really hacky hardcoding the acceptable combinations of attributes. |
| case (getSCPeriod params, getSCBudget params, getSCData params) of |
| (Just period, Just budget, Just scData) -> |
| Just $ SCExtraInfo (Just period) (Just budget) (Just scData) |
| (Just period, Just budget, Nothing) -> |
| Just $ SCExtraInfo (Just period) (Just budget) Nothing |
| (Nothing, Nothing, Nothing) -> Nothing |
| params -> error $ "Incorrect extra sc parameters: " ++ n ++ show params |
| |
| getIOAPICIrqIoapic :: [ObjParam] -> Word |
| getIOAPICIrqIoapic [] = error $ "Incorrect ioapic irq parameters" |
| getIOAPICIrqIoapic (IOAPICIRQExtraParam (IOAPIC ioapic) : _) = ioapic |
| getIOAPICIrqIoapic (_ : xs) = getIOAPICIrqIoapic xs |
| |
| getIOAPICIrqPin :: [ObjParam] -> Word |
| getIOAPICIrqPin [] = error $ "Incorrect ioapic irq parameters" |
| getIOAPICIrqPin (IOAPICIRQExtraParam (Pin pin) : _) = pin |
| getIOAPICIrqPin (_ : xs) = getIOAPICIrqPin xs |
| |
| getIOAPICIrqLevel :: [ObjParam] -> Word |
| getIOAPICIrqLevel [] = error $ "Incorrect ioapic irq parameters" |
| getIOAPICIrqLevel (IOAPICIRQExtraParam (Level level) : _) = level |
| getIOAPICIrqLevel (_ : xs) = getIOAPICIrqLevel xs |
| |
| getIOAPICIrqPolarity :: [ObjParam] -> Word |
| getIOAPICIrqPolarity [] = error $ "Incorrect ioapic irq parameters" |
| getIOAPICIrqPolarity (IOAPICIRQExtraParam (Polarity polarity) : _) = polarity |
| getIOAPICIrqPolarity (_ : xs) = getIOAPICIrqPolarity xs |
| |
| getMSIIrqHandle :: [ObjParam] -> Word |
| getMSIIrqHandle [] = error $ "Incorrect msi irq parameters" |
| getMSIIrqHandle (MSIIRQExtraParam (MSIHandle handle) : _) = handle |
| getMSIIrqHandle (_ : xs) = getMSIIrqHandle xs |
| |
| getMSIIrqPCIBus :: [ObjParam] -> Word |
| getMSIIrqPCIBus [] = error $ "Incorrect msi irq parameters" |
| getMSIIrqPCIBus (MSIIRQExtraParam (MSIPCIBus bus) : _) = bus |
| getMSIIrqPCIBus (_ : xs) = getMSIIrqPCIBus xs |
| |
| getMSIIrqPCIDev :: [ObjParam] -> Word |
| getMSIIrqPCIDev [] = error $ "Incorrect msi irq parameters" |
| getMSIIrqPCIDev (MSIIRQExtraParam (MSIPCIDev dev) : _) = dev |
| getMSIIrqPCIDev (_ : xs) = getMSIIrqPCIDev xs |
| |
| getMSIIrqPCIFun :: [ObjParam] -> Word |
| getMSIIrqPCIFun [] = error $ "Incorrect msi irq parameters" |
| getMSIIrqPCIFun (MSIIRQExtraParam (MSIPCIFun fun) : _) = fun |
| getMSIIrqPCIFun (_ : xs) = getMSIIrqPCIFun xs |
| |
| getARMIrqTrigger :: Name -> [ObjParam] -> Word |
| getARMIrqTrigger n [] = error ("Incorrect Arm irq parameters: missing 'trigger': " ++ n) |
| getARMIrqTrigger _ (ARMIRQExtraParam (ARMIRQTrigger trigger) : _) = trigger |
| getARMIrqTrigger n (_ : xs) = getARMIrqTrigger n xs |
| |
| getARMIrqTarget :: Name -> [ObjParam] -> Word |
| getARMIrqTarget n [] = error ("Incorrect Arm irq parameters: missing 'target': " ++ n) |
| getARMIrqTarget _ (ARMIRQExtraParam (ARMIRQTarget target) : _) = target |
| getARMIrqTarget n (_ : xs) = getARMIrqTarget n xs |
| |
| getMaybeBitSize :: [ObjParam] -> Maybe Word |
| getMaybeBitSize [] = Nothing |
| getMaybeBitSize (BitSize x : _) = Just x |
| getMaybeBitSize (_ : xs) = getMaybeBitSize xs |
| |
| getBitSize :: Name -> [ObjParam] -> Word |
| getBitSize n xs = |
| case getMaybeBitSize xs of |
| Nothing -> error ("Needs bitsize parameter: " ++ n) |
| Just sz -> sz |
| |
| getVMSize :: Name -> [ObjParam] -> Word |
| getVMSize n [] = error ("Needs vmsize parameter: " ++ n) |
| getVMSize n (VMSize 0 : _) = error ("Cannot make a frame object that has size 0: " ++ n) |
| getVMSize _ (VMSize x : _) = x |
| getVMSize n (_ : xs) = getVMSize n xs |
| |
| getMaybePaddr :: [ObjParam] -> Maybe Word |
| getMaybePaddr [] = Nothing |
| getMaybePaddr (Paddr x : _) = Just x |
| getMaybePaddr (_ : xs) = getMaybePaddr xs |
| |
| getMaybeFill :: [ObjParam] -> Maybe [[String]] |
| getMaybeFill [] = Nothing |
| getMaybeFill (FrameExtraParam (Fill f) : _) = Just f |
| getMaybeFill(_ : xs) = getMaybeFill xs |
| |
| getLevel :: Name -> [ObjParam] -> Word |
| getLevel n [] = error ("Needs level parameter: " ++ n) |
| getLevel _ (IOPTLevel l : _) = l |
| getLevel n (_ : xs) = getLevel n xs |
| |
| getDomainID :: Name -> [ObjParam] -> Word |
| getDomainID n [] = error ("Needs domainID parameter: " ++ n) |
| getDomainID _ (DomainID x : _) = x |
| getDomainID n (_ : xs) = getDomainID n xs |
| |
| getPCIDevice :: Name -> [ObjParam] -> (Word, Word, Word) |
| getPCIDevice n [] = error ("Needs pciDevice parameter: " ++ n) |
| getPCIDevice _ (PCIDevice x : _) = x |
| getPCIDevice n (_ : xs) = getPCIDevice n xs |
| |
| getARMIODevice :: Name -> [ObjParam] -> Word |
| getARMIODevice n [] = error ("Needs iospace parameter: " ++ n) |
| getARMIODevice _ (ARMIOSpace x : _) = x |
| getARMIODevice n (_ : xs) = getARMIODevice n xs |
| |
| getPorts :: Name -> [ObjParam] -> (Word, Word) |
| getPorts n [] = error ("Needs ports parameter: " ++ n) |
| getPorts _ (Ports x : _) = x |
| getPorts n (_ : xs) = getPorts n xs |
| |
| getMaybeAsidHigh :: [ObjParam] -> Maybe Word |
| getMaybeAsidHigh [] = Nothing |
| getMaybeAsidHigh (AsidHigh asidHigh : _) = Just asidHigh |
| getMaybeAsidHigh (_ : ps) = getMaybeAsidHigh ps |
| |
| -- need this hack because 'Constr' isn't 'Ord'. "Ord a" must group by constrs! |
| sortConstrs :: (Data a, Ord a) => [a] -> [a] |
| sortConstrs = sortBy (\x y -> if toConstr x == toConstr y then EQ else compare x y) |
| |
| subsetConstrs :: (Ord a, Data a) => [a] -> [a] -> Bool |
| subsetConstrs = isSubsequenceOf `on` (map toConstr . sortConstrs) |
| |
| containsConstr :: (Data a) => a -> [a] -> Bool |
| containsConstr x xs = toConstr x `elem` map toConstr xs |
| |
| numConstrs :: (Data a) => a -> Int |
| numConstrs x = length $ dataTypeConstrs $ dataTypeOf x |
| |
| removeConstr :: Data a => a -> [a] -> [a] |
| removeConstr x xs = filter (\y -> toConstr x /= toConstr y) xs |
| |
| validObjPars :: KO -> Bool |
| validObjPars (Obj TCB_T ps []) = |
| subsetConstrs ps (replicate (numConstrs (Addr undefined)) (TCBExtraParam undefined) |
| ++ [InitArguments undefined, Dom undefined, FaultEP undefined]) |
| validObjPars (Obj CNode_T ps []) = |
| subsetConstrs ps [BitSize undefined, CNodeExtraParam $ HasUntyped undefined] |
| validObjPars (Obj Untyped_T ps _) = subsetConstrs ps [BitSize undefined, Paddr undefined] |
| validObjPars (Obj Frame_T ps []) = |
| subsetConstrs ps [VMSize undefined, Paddr undefined, FrameExtraParam undefined] && |
| (not (containsConstr (Paddr undefined) ps) || containsConstr (VMSize undefined) ps) |
| validObjPars (Obj ASIDPool_T ps []) = subsetConstrs ps [AsidHigh undefined] |
| validObjPars (Obj IOPT_T ps []) = subsetConstrs ps [IOPTLevel undefined] |
| validObjPars (Obj IOPorts_T ps []) = subsetConstrs ps [Ports undefined] |
| validObjPars (Obj IODevice_T ps []) = subsetConstrs ps [DomainID undefined, PCIDevice undefined] |
| validObjPars (Obj ARMIODevice_T ps []) = subsetConstrs ps [ARMIOSpace undefined] |
| validObjPars (Obj SC_T ps []) = |
| subsetConstrs ps (replicate (numConstrs (Addr undefined)) (SCExtraParam undefined) |
| ++ [BitSize undefined]) |
| validObjPars (Obj IOAPICIrqSlot_T ps []) = |
| subsetConstrs ps (replicate (numConstrs (Addr undefined)) (IOAPICIRQExtraParam undefined)) |
| validObjPars (Obj MSIIrqSlot_T ps []) = |
| subsetConstrs ps (replicate (numConstrs (Addr undefined)) (MSIIRQExtraParam undefined)) |
| validObjPars (Obj ARMIrqSlot_T ps []) = |
| subsetConstrs ps (replicate (numConstrs (Addr undefined)) (ARMIRQExtraParam undefined)) |
| validObjPars (Obj ARMCB_T ps []) = |
| subsetConstrs ps (replicate (numConstrs (Addr undefined)) (CBExtraParam undefined)) |
| validObjPars obj = null (params obj) |
| |
| -- For converting frame sizes to size bits |
| wordLog2 :: Word -> Int |
| wordLog2 w = finiteBitSize w - 1 - countLeadingZeros w |
| |
| objectOf :: Name -> KO -> KernelObject Word |
| objectOf n obj = |
| if validObjPars obj |
| then case obj of |
| Obj Endpoint_T [] [] -> Endpoint |
| Obj Notification_T [] [] -> Notification |
| Obj TCB_T ps [] -> |
| TCB Map.empty (getFaultEP ps) (getExtraInfo n ps) (getTCBDom ps) (getInitArguments ps) |
| Obj CNode_T ps [] -> CNode Map.empty (getBitSize n ps) (getCNodeExtraInfo ps) |
| Obj Untyped_T ps _ -> Untyped (getMaybeBitSize ps) (getMaybePaddr ps) |
| Obj ASIDPool_T ps [] -> ASIDPool Map.empty (getMaybeAsidHigh ps) |
| Obj PT_T _ [] -> PT Map.empty |
| Obj PD_T _ [] -> PD Map.empty |
| Obj PML4_T _ [] -> PML4 Map.empty |
| Obj PDPT_T _ [] -> PDPT Map.empty |
| Obj PUD_T _ [] -> PUD Map.empty |
| Obj PGD_T _ [] -> PGD Map.empty |
| Obj Frame_T ps [] -> |
| let size = getVMSize n ps |
| bits = wordLog2 size |
| in if bits < 0 || 2^bits /= size |
| then error $ "Frame size not power of 2: " ++ n ++ " = " ++ show obj |
| else Frame (fromIntegral bits) (getMaybePaddr ps) (getMaybeFill ps) |
| Obj IOPT_T ps [] -> IOPT Map.empty (getLevel n ps) |
| Obj IOPorts_T ps [] -> IOPorts (getPorts n ps) |
| Obj IODevice_T ps [] -> IODevice Map.empty (getDomainID n ps) (getPCIDevice n ps) |
| Obj ARMIODevice_T ps [] -> ARMIODevice Map.empty (getARMIODevice n ps) |
| Obj IrqSlot_T [] [] -> CNode Map.empty 0 (CNodeExtraInfo Nothing) |
| Obj IOAPICIrqSlot_T ps [] -> IOAPICIrq Map.empty (getIOAPICIrqIoapic ps) (getIOAPICIrqPin ps) (getIOAPICIrqLevel ps) (getIOAPICIrqPolarity ps) |
| Obj MSIIrqSlot_T ps [] -> MSIIrq Map.empty (getMSIIrqHandle ps) (getMSIIrqPCIBus ps) (getMSIIrqPCIDev ps) (getMSIIrqPCIFun ps) |
| Obj ARMIrqSlot_T ps [] -> ARMIrq Map.empty (getARMIrqTrigger n ps) (getARMIrqTarget n ps) |
| Obj VCPU_T [] [] -> VCPU |
| Obj SC_T ps [] -> SC (getSCExtraInfo n ps) (getMaybeBitSize ps) |
| Obj RTReply_T [] [] -> RTReply |
| Obj ARMSID_T [] [] -> ARMSID |
| Obj ARMCB_T ps [] -> ARMCB (getCBExtraInfo ps) |
| Obj _ _ (_:_) -> |
| error $ "Only untyped caps can have objects as content: " ++ |
| n ++ " = " ++ show obj |
| _ -> error ("Could not convert: " ++ n ++ " = " ++ show obj) |
| else error ("Incorrect params for " ++ n) |
| |
| insertObjects :: [ObjID] -> KernelObject Word -> ObjMap Word -> ObjMap Word |
| insertObjects ids obj objs = foldl' (\map id->Map.insert id obj map) objs ids |
| |
| isMember :: Name -> ObjMap Word -> Bool |
| isMember name objs = |
| Map.member (name, Nothing) objs || Map.member (name, Just 0) objs |
| |
| addObject :: ObjMap Word -> Decl -> ObjMap Word |
| addObject objs (ObjDecl (KODecl objName obj)) = |
| if not $ CapDL.AST.koType obj == Untyped_T && isMember name objs |
| then if isMember name objs |
| then error ("Duplicate name declaration: " ++ name) |
| else let |
| objs' = insertObjects (makeIDs name num) (objectOf name obj) objs |
| in addObjects objs' (map ObjDecl (Either.lefts (objDecls obj))) |
| else objs |
| where (name, num) = refToID $ baseName objName |
| addObject s _ = s |
| |
| addObjects :: ObjMap Word -> [Decl] -> ObjMap Word |
| addObjects = foldl' addObject |
| |
| addIRQ :: IRQMap -> (Word, ObjID) -> IRQMap |
| addIRQ irqNode (slot, irq) = |
| if Map.member slot irqNode |
| then error ("IRQ already mapped: " ++ show slot) |
| else Map.insert slot irq irqNode |
| |
| addIRQs :: IRQMap -> [(Word, ObjID)] -> IRQMap |
| addIRQs = foldl' addIRQ |
| |
| getSlotIRQs :: ObjMap Word -> CapMapping -> SlotState [(Word, ObjID)] |
| getSlotIRQs objs (IRQMapping slot nameRef) = do |
| slot' <- checkSlot slot |
| let irqs = refToIDs objs nameRef |
| lastSlot = slot' + fromIntegral (length irqs - 1) |
| putSlot lastSlot |
| return $ zip [slot'..lastSlot] irqs |
| getSlotIRQs _ _ = error "not an IRQMapping" |
| |
| addIRQMapping :: ObjMap Word -> SlotState IRQMap -> CapMapping -> SlotState IRQMap |
| addIRQMapping objs irqNode cm = do |
| slotIRQs <- getSlotIRQs objs cm |
| node <- irqNode |
| return $ addIRQs node slotIRQs |
| |
| addIRQMappings :: ObjMap Word -> IRQMap -> [CapMapping] -> SlotState IRQMap |
| addIRQMappings objs irqNode = |
| foldl' (addIRQMapping objs) (return irqNode) |
| |
| addIRQNode :: ObjMap Word -> IRQMap -> Decl -> IRQMap |
| addIRQNode objs irqNode (IRQDecl irqs) = |
| if Map.null irqNode |
| then evalSlotState (addIRQMappings objs irqNode irqs) |
| else error "Duplicate IRQ node declaration" |
| addIRQNode _ irqNode _ = irqNode |
| |
| addIRQNodes :: ObjMap Word -> IRQMap -> [Decl] -> IRQMap |
| addIRQNodes objs = foldl' (addIRQNode objs) |
| |
| insertMapping :: KernelObject Word -> (Word, Cap) -> KernelObject Word |
| insertMapping obj (slot, cap) = |
| if hasSlots obj |
| then let mappings = slots obj |
| in if Map.member slot mappings |
| then error ("Slot already filled: " ++ show slot) |
| else obj {slots = Map.insert slot cap mappings} |
| else error ("This object does not support cap mappings: " ++ show obj) |
| |
| insertMappings :: KernelObject Word -> [(Word, Cap)] -> KernelObject Word |
| insertMappings = foldl' insertMapping |
| |
| getBadge :: [CapParam] -> Word |
| getBadge [] = 0 |
| getBadge (Badge n : _) = n |
| getBadge (_ : xs) = getBadge xs |
| |
| getRights :: [CapParam] -> CapRights |
| getRights [] = Set.empty |
| getRights (Rights r : ps) = r `Set.union` getRights ps |
| getRights (_ : ps) = getRights ps |
| |
| getGuard :: [CapParam] -> Word |
| getGuard [] = 0 |
| getGuard (Guard n : _) = n |
| getGuard (_ : ps) = getGuard ps |
| |
| getGuardSize :: [CapParam] -> Word |
| getGuardSize [] = 0 |
| getGuardSize (GuardSize n : _) = n |
| getGuardSize (_ : ps) = getGuardSize ps |
| |
| getReplys :: [CapParam] -> [CapParam] |
| getReplys [] = [] |
| getReplys (Reply : ps) = Reply : getReplys ps |
| getReplys (MasterReply : ps) = MasterReply : getReplys ps |
| getReplys (_ : ps) = getReplys ps |
| |
| getMaybeAsid :: [CapParam] -> Maybe Asid |
| getMaybeAsid [] = Nothing |
| getMaybeAsid (Asid asid : _) = Just asid |
| getMaybeAsid (_ : ps) = getMaybeAsid ps |
| |
| getCached :: [CapParam] -> Bool |
| getCached [] = True |
| getCached (Cached c : _) = c |
| getCached (_ : ps) = getCached ps |
| |
| getMaybeMapping :: [CapParam] -> Maybe (ObjID, Word) |
| getMaybeMapping [] = Nothing |
| getMaybeMapping (FrameMapping c s : _) = Just (refToID c, s) |
| getMaybeMapping (_ : ps) = getMaybeMapping ps |
| |
| validCapPars :: KernelObject Word -> [CapParam] -> Bool |
| validCapPars (Endpoint {}) ps = |
| subsetConstrs (removeConstr (Rights undefined) ps) [Badge undefined] |
| validCapPars (Notification {}) ps = |
| subsetConstrs (removeConstr (Rights undefined) ps) [Badge undefined] |
| validCapPars (TCB {}) ps = |
| subsetConstrs ps [Reply, MasterReply] && |
| (not (containsConstr Reply ps) || not (containsConstr MasterReply ps)) |
| validCapPars (CNode {}) ps = subsetConstrs ps [Guard undefined, GuardSize undefined] |
| validCapPars (Frame {}) ps = |
| subsetConstrs (removeConstr (Rights undefined) ps) [Asid undefined, Cached undefined, |
| FrameMapping undefined undefined] |
| validCapPars (RTReply {}) ps = subsetConstrs ps [Rights undefined] |
| validCapPars (PD {}) ps = subsetConstrs ps [Asid undefined] |
| validCapPars (PT {}) ps = subsetConstrs ps [Asid undefined] |
| validCapPars (PML4 {}) ps = subsetConstrs ps [Asid undefined] |
| validCapPars (PDPT {}) ps = subsetConstrs ps [Asid undefined] |
| validCapPars (PUD {}) ps = subsetConstrs ps [Asid undefined] |
| validCapPars (PGD {}) ps = subsetConstrs ps [Asid undefined] |
| validCapPars _ ps = null ps |
| |
| objCapOf :: ObjID -> KernelObject Word -> ObjID -> [CapParam] -> Cap |
| objCapOf containerName obj objRef params = |
| if validCapPars obj params |
| then case obj of |
| Endpoint -> EndpointCap objRef (getBadge params) (getRights params) |
| Notification -> |
| NotificationCap objRef (getBadge params) (getRights params) |
| RTReply -> RTReplyCap objRef (getRights params) |
| TCB {} -> |
| case getReplys params of |
| [] -> TCBCap objRef |
| [Reply] -> ReplyCap objRef |
| [MasterReply] -> MasterReplyCap objRef |
| _ -> error "invalid cap" |
| Untyped {} -> UntypedCap objRef |
| CNode _ 0 _ -> IRQHandlerCap objRef --FIXME: This should check if the obj is in the irqNode |
| CNode {} -> CNodeCap objRef (getGuard params) (getGuardSize params) |
| Frame {} -> FrameCap objRef (getRights params) (getMaybeAsid params) (getCached params) |
| (getMaybeMapping params) |
| PML4 {} -> PML4Cap objRef (getMaybeAsid params) |
| PDPT {} -> PDPTCap objRef (getMaybeAsid params) |
| PD {} -> PDCap objRef (getMaybeAsid params) |
| PT {} -> PTCap objRef (getMaybeAsid params) |
| PUD {} -> PUDCap objRef (getMaybeAsid params) |
| PGD {} -> PGDCap objRef (getMaybeAsid params) |
| ASIDPool {} -> ASIDPoolCap objRef |
| IOPT {} -> IOPTCap objRef |
| IOPorts {} -> IOPortsCap objRef |
| IODevice {} -> IOSpaceCap objRef |
| ARMIODevice {} -> ARMIOSpaceCap objRef |
| VCPU {} -> VCPUCap objRef |
| SC {} -> SCCap objRef |
| IOAPICIrq {} -> IRQIOAPICHandlerCap objRef |
| MSIIrq {} -> IRQMSIHandlerCap objRef |
| ARMIrq {} -> ARMIRQHandlerCap objRef |
| ARMSID {} -> ARMSIDCap objRef |
| ARMCB {} -> ARMCBCap objRef |
| else error ("Incorrect params for cap to " ++ printID objRef ++ " in " ++ |
| printID containerName ++ "; got " ++ show params) |
| |
| capOf :: ObjMap Word -> ObjID -> [CapParam] -> ObjID -> Cap |
| capOf objs containerName xs id = |
| case Map.lookup id objs of |
| Nothing -> |
| error ("Unknown object \"" ++ printID id ++ |
| "\" for cap in " ++ printID containerName) |
| Just obj -> objCapOf containerName obj id xs |
| |
| capsOf :: ObjMap Word -> ObjID -> [ObjID] -> [CapParam] -> [Cap] |
| capsOf objs name ids xs = map (capOf objs name xs) ids |
| |
| checkSlot :: Maybe Word -> SlotState Word |
| checkSlot (Just slot) = return slot |
| checkSlot Nothing = getSlot |
| |
| validCapPars' :: Name -> [CapParam] -> Bool |
| validCapPars' name ps |
| | name == schedControl = subsetConstrs ps [Core undefined] |
| | otherwise = null ps |
| |
| getCore :: ObjID -> [CapParam] -> Word |
| getCore containerName [] = |
| error ("Needs core parameter for sched_control cap in " ++ printID containerName) |
| getCore _ (Core n:_) = n |
| getCore containerName (_:ps) = getCore containerName ps |
| |
| capOf' :: ObjID -> Name -> [CapParam] -> Cap |
| capOf' containerName capName ps |
| | capName == ioSpaceMaster = IOSpaceMasterCap |
| | capName == asidControl = ASIDControlCap |
| | capName == irqControl = IRQControlCap |
| | capName == domain = DomainCap |
| | capName == schedControl = SchedControlCap (getCore containerName ps) |
| | otherwise = |
| error ("capOf' called with a name it doesn't know about: " ++ capName) |
| |
| slotsAndCapsOf :: ObjMap Word-> ObjID -> CapMapping -> SlotState [(Word, Cap)] |
| slotsAndCapsOf objs objName (CapMapping slot _ nameRef params _) |
| | fst nameRef `elem` capStrings && null (snd nameRef) = do |
| let (name, []) = nameRef |
| if validCapPars' name params |
| then do |
| slot' <- checkSlot slot |
| putSlot slot' |
| return [(slot', capOf' objName name params)] |
| else error ("Incorrect params for cap to " ++ name ++ |
| " in " ++ printID objName) |
| | otherwise = do |
| slot' <- checkSlot slot |
| let caps = capsOf objs objName (refToIDs objs nameRef) params |
| lastSlot = slot' + fromIntegral (length caps - 1) |
| putSlot lastSlot |
| return $ zip [slot'..lastSlot] caps |
| slotsAndCapsOf _ _ (CopyOf slot _ _ _ _) = do |
| slot' <- checkSlot slot |
| putSlot slot' |
| return [(slot', NullCap)] |
| slotsAndCapsOf _ _ _ = error "IRQ or ASID mapping" |
| |
| addMapping :: ObjMap Word -> ObjID -> KernelObject Word -> CapMapping |
| -> SlotState (KernelObject Word) |
| addMapping objs n obj cm = do |
| slotCaps <- slotsAndCapsOf objs n cm |
| return $ insertMappings obj slotCaps |
| |
| addMappings :: ObjMap Word -> ObjID -> KernelObject Word -> [CapMapping] |
| -> SlotState (KernelObject Word) |
| addMappings objs n = |
| foldM (addMapping objs n) |
| |
| hasUnnumbered :: [CapMapping] -> Bool |
| hasUnnumbered [] = False |
| hasUnnumbered (x:xs) = |
| case slot x of |
| Nothing -> True |
| _ -> hasUnnumbered xs |
| |
| hasCopy :: [CapMapping] -> Bool |
| hasCopy [] = False |
| hasCopy (CopyOf {}:_) = True |
| hasCopy (_:xs) = hasCopy xs |
| |
| validMapping :: [CapMapping] -> Bool |
| validMapping mappings = not $ hasCopy mappings && hasUnnumbered mappings |
| |
| addCap :: Model Word -> (ObjID, [CapMapping]) -> Model Word |
| addCap (Model arch objs irqNode cdt untypedCovers) (id, mappings) = |
| case Map.lookup id objs of |
| Nothing -> error ("Unknown cap container: " ++ printID id) |
| Just obj -> |
| if validMapping mappings |
| then Model arch (Map.insert id mapped objs) irqNode cdt untypedCovers |
| else error $ printID id ++ |
| " uses both copies of caps and unnumbered slots" |
| where mapped = evalSlotState (addMappings objs id obj mappings) |
| |
| addCapDecl :: Model Word -> Decl -> Model Word |
| addCapDecl m@(Model _ objs _ _ _) (CapDecl names mappings) = |
| foldl' addCap m (zip (refToIDs objs names) (repeat mappings)) |
| addCapDecl s _ = s |
| |
| addCapDecls :: [Decl] -> Model Word -> Model Word |
| addCapDecls decls m = foldl' addCapDecl m decls |
| |
| insertCapIdentMapping :: ObjID -> Idents CapName -> CapName -> Word |
| -> Idents CapName |
| insertCapIdentMapping obj (Idents ids) name slot = |
| Idents (Map.insert name (obj,slot) ids) |
| |
| addCapIdentMapping' :: ObjMap Word -> ObjID -> Idents CapName -> Word -> NameRef |
| -> NameRef -> Idents CapName |
| addCapIdentMapping' m obj ids slot (names, range) ref = |
| let len = length $ refToIDs m ref |
| names' = case range of |
| [] -> if len == 1 |
| then [(names, Nothing)] |
| else error ("Cannot give a unique name to an array of caps: " |
| ++ names) |
| [All] -> zip (repeat names) (map Just [0..fromIntegral len - 1]) |
| _ -> error "invalid range" |
| lastSlot = slot + fromIntegral len - 1 |
| slots = [slot..lastSlot] |
| in foldl' (\ids' (name, s) -> insertCapIdentMapping obj ids' name s) |
| ids (zip names' slots) |
| |
| addCapIdentMapping :: ObjMap Word -> ObjID -> Idents CapName -> CapMapping |
| -> Idents CapName |
| addCapIdentMapping m obj ids (CapMapping (Just slot) (Just names) ref _ _) = |
| addCapIdentMapping' m obj ids slot names ref |
| addCapIdentMapping m obj ids (CopyOf (Just slot) (Just names) ref _ _) = |
| addCapIdentMapping' m obj ids slot names ref |
| addCapIdentMapping _ _ i _ = i |
| |
| addCapIdentMappings :: ObjMap Word -> NameRef -> Idents CapName -> [CapMapping] |
| -> Idents CapName |
| addCapIdentMappings m obj = |
| foldl' (addCapIdentMapping m (head (refToIDs m obj))) |
| |
| addCapIdent :: ObjMap Word -> Idents CapName -> Decl -> Idents CapName |
| addCapIdent _ (Idents ids) (CapNameDecl name target slot) = |
| Idents (Map.insert (name, Nothing) (target', slot) ids) |
| where |
| target' = refToID target |
| addCapIdent m i (CapDecl obj mappings) = addCapIdentMappings m obj i mappings |
| addCapIdent _ i _ = i |
| |
| capIdents :: ObjMap Word -> [Decl] -> Idents CapName |
| capIdents m = foldl' (addCapIdent m) emptyIdents |
| |
| -- FIXME: inefficient, use a proper data structure for this |
| type CapRefMappings = CapRef -> Maybe CapRef |
| |
| -- Follow a mapping transitively to the end |
| transMapping :: (Show a, Eq a) => (a -> Maybe a) -> a -> a |
| transMapping = transMappingE [] |
| |
| -- FIXME: I'm sure there is a library function for this somewhere |
| transMappingE :: (Show a, Eq a) => [a] -> (a -> Maybe a) -> a -> a |
| transMappingE seen m x = |
| if x `elem` seen |
| then error ("Cyclic reference: " ++ show x) |
| else |
| case m x of |
| Nothing -> x |
| Just l -> transMappingE (x:seen) m l |
| |
| funUpd :: Eq a => (a -> b) -> a -> b -> a -> b |
| funUpd f x y z = if z == x then y else f z |
| |
| empty :: a -> Maybe b |
| empty _ = Nothing |
| |
| addCapCopyRef :: Idents CapName -> ObjID -> CapRefMappings -> |
| CapMapping -> CapRefMappings |
| addCapCopyRef (Idents ids) obj m (CopyOf (Just slot) _ target _ _) = |
| funUpd m (obj, slot) (Map.lookup (refToID target) ids) |
| addCapCopyRef _ _ m _ = m |
| |
| addCapCopyRefs :: ObjMap Word -> Idents CapName -> CapRefMappings -> Decl |
| -> CapRefMappings |
| addCapCopyRefs map ids m (CapDecl objs mappings) = |
| foldl' (\m' obj -> foldl' (addCapCopyRef ids obj) m' mappings) |
| m (refToIDs map objs) |
| addCapCopyRefs _ _ m _ = m |
| |
| capCopyGraph :: ObjMap Word -> Idents CapName -> [Decl] -> CapRefMappings |
| capCopyGraph m ids = foldl' (addCapCopyRefs m ids) empty |
| |
| getMasked :: [CapParam] -> CapRights |
| getMasked [] = allRights |
| getMasked (Masked r : ps) = Set.intersection r (getMasked ps) |
| getMasked (_ : ps) = getMasked ps |
| |
| copyCapParams :: [CapParam] -> Cap -> Cap |
| copyCapParams params cap |
| | hasRights cap = cap {capRights = Set.intersection rights $ capRights cap} |
| | otherwise = cap |
| where rights = getMasked params |
| |
| getSrcCap :: Idents CapName -> CapRefMappings -> Model Word -> ObjID -> Cap |
| getSrcCap (Idents ids) refs m src = |
| case Map.lookup src ids of |
| Nothing -> error ("Unknown cap reference: " ++ printID src) |
| Just srcRef -> |
| case maybeSlotCap (transMapping refs srcRef) m of |
| Nothing -> error ("Could not resolve cap reference: "++ |
| show (transMapping refs srcRef)) |
| Just cap -> cap |
| |
| addCapCopy :: Idents CapName -> CapRefMappings -> ObjID -> |
| Model Word -> CapMapping -> Model Word |
| addCapCopy ids refs obj m (CopyOf (Just slot) _ src params _) = |
| let caps = map (getSrcCap ids refs m) (refToIDs (cap_ids ids) src) |
| slots = [slot..(slot + fromIntegral (length caps))] |
| caps' = map (copyCapParams params) caps |
| in foldl' (\m' (cap, slot') -> ST.execState (setCap (obj,slot') cap) m') |
| m (zip caps' slots) |
| addCapCopy _ _ _ m _ = m |
| |
| -- FIXME: this recursion pattern over all mappings is duplicated all over |
| -- the place. factor out. |
| addCapCopies :: Idents CapName -> CapRefMappings -> NameRef -> |
| Model Word -> CapMapping -> Model Word |
| addCapCopies ids refs names m@(Model _ map _ _ _) copy = |
| foldl' (\model obj -> addCapCopy ids refs obj model copy) m |
| (refToIDs map names) |
| |
| addCapCopyDecl :: Idents CapName -> CapRefMappings -> Model Word -> Decl -> |
| Model Word |
| addCapCopyDecl ids refs m (CapDecl obj mappings) = |
| foldl' (addCapCopies ids refs obj) m mappings |
| addCapCopyDecl _ _ m _ = m |
| |
| addCapCopyDecls :: Idents CapName -> CapRefMappings -> Model Word -> [Decl] -> |
| Model Word |
| addCapCopyDecls ids refs = foldl' (addCapCopyDecl ids refs) |
| |
| getCapCopy :: Idents CapName -> ObjMap Word -> ObjID -> CopyMap -> |
| CapMapping -> CopyMap |
| getCapCopy ids _ obj copies (CopyOf (Just slot) _ src _ _) = |
| let capNames = refToIDs (cap_ids ids) src |
| capRefs = zip (repeat obj) [slot..(slot + fromIntegral (length capNames))] |
| in foldl' (\copies' (capRef, capName) -> Map.insert capRef capName copies') |
| copies (zip capRefs capNames) |
| getCapCopy _ _ _ m _ = m |
| |
| getCapCopies :: Idents CapName -> ObjMap Word -> NameRef -> CopyMap -> |
| CapMapping -> CopyMap |
| getCapCopies ids m names copies copy = |
| foldl' (\copies obj -> getCapCopy ids m obj copies copy) copies |
| (refToIDs m names) |
| |
| getCapCopyDecl :: Idents CapName -> ObjMap Word -> CopyMap -> Decl -> CopyMap |
| getCapCopyDecl ids m copies (CapDecl obj mappings) = |
| foldl' (getCapCopies ids m obj) copies mappings |
| getCapCopyDecl _ _ copies _ = copies |
| |
| getCapCopyDecls :: Idents CapName -> ObjMap Word -> [Decl] -> CopyMap |
| getCapCopyDecls ids m = foldl' (getCapCopyDecl ids m) Map.empty |
| |
| slotRefToCapRef :: Idents CapName -> SlotRef -> CapRef |
| slotRefToCapRef _ (Left (obj, slot)) = (refToID obj, slot) |
| slotRefToCapRef ids (Right name) = |
| case Map.lookup (refToID name) (cap_ids ids) of |
| Just capRef -> capRef |
| Nothing -> error $ "Unknown cap reference: " ++ printID (refToID name) |
| |
| insertCDT :: CapRef -> CapRef -> CDT -> CDT |
| insertCDT child parent cdt = |
| if isNothing (Map.lookup child cdt) |
| then Map.insert child parent cdt |
| else error $ show child ++ " has multiple parents" |
| |
| getDeclOrSlotRef :: Idents CapName -> CapRef -> CDT -> Either Decl SlotRef -> CDT |
| getDeclOrSlotRef ids parent cdt (Left decl@(CDTDecl child _)) = |
| let child' = slotRefToCapRef ids child |
| cdt' = insertCDT child' parent cdt |
| in getCDTDecl ids cdt' decl |
| getDeclOrSlotRef _ _ _ (Left _) = error "not a CDTDecl" |
| getDeclOrSlotRef ids parent cdt (Right child) = |
| let child' = slotRefToCapRef ids child |
| in insertCDT child' parent cdt |
| |
| getCDTDecl :: Idents CapName -> CDT -> Decl -> CDT |
| getCDTDecl ids cdt (CDTDecl parent children) = |
| foldl' (getDeclOrSlotRef ids parent') cdt children |
| where parent' = slotRefToCapRef ids parent |
| getCDTDecl _ cdt _ = cdt |
| |
| getCDTDecls :: Idents CapName -> [Decl] -> CDT |
| getCDTDecls ids = foldl' (getCDTDecl ids) Map.empty |
| |
| addCDTMapping :: Idents CapName -> ObjID -> CDT -> CapMapping -> SlotState CDT |
| addCDTMapping ids obj cdt mapping |
| | isJust (maybeParent mapping) = do |
| slot' <- checkSlot (slot mapping) |
| putSlot slot' |
| let parent = slotRefToCapRef ids $ fromJust $ maybeParent mapping |
| child = (obj, slot') |
| return $ insertCDT child parent cdt |
| | otherwise = return cdt |
| |
| addCDTMappings :: Idents CapName -> CDT -> (ObjID, [CapMapping]) -> SlotState CDT |
| addCDTMappings ids cdt (obj, mappings) = |
| foldM (addCDTMapping ids obj) cdt mappings |
| |
| addCDTCapDecl :: ObjMap Word -> Idents CapName -> CDT -> Decl -> CDT |
| addCDTCapDecl objs ids cdt (CapDecl names mappings) = |
| foldl' (\cdt capDecl -> evalSlotState (addCDTMappings ids cdt capDecl)) |
| cdt (zip (refToIDs objs names) (repeat mappings)) |
| addCDTCapDecl _ _ cdt _ = cdt |
| |
| addCDTCapDecls :: ObjMap Word -> Idents CapName -> CDT -> [Decl] -> CDT |
| addCDTCapDecls objs ids = foldl' (addCDTCapDecl objs ids) |
| |
| makeModel :: Module -> Logger (Model Word, Idents CapName, CopyMap) |
| makeModel (Module arch decls) = do |
| let objs = addObjects Map.empty decls |
| objs' = addUntypeds objs decls |
| irqs = addIRQNodes objs' Map.empty decls |
| ids = capIdents objs' decls |
| refs = capCopyGraph objs' ids decls |
| copies = getCapCopyDecls ids objs' decls |
| cdt = getCDTDecls ids decls |
| cdt' = addCDTCapDecls objs' ids cdt decls |
| covers <- dedupCoverIDs $ getUntypedCovers Nothing objs' Map.empty decls |
| return (flip (addCapCopyDecls ids refs) decls . |
| addCapDecls decls $ |
| Model arch objs' irqs cdt' covers, |
| ids, copies) |