| -- |
| -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) |
| -- |
| -- SPDX-License-Identifier: BSD-2-Clause |
| -- |
| |
| {-# LANGUAGE DeriveDataTypeable, TemplateHaskell #-} |
| module CapDL.Model where |
| |
| import Prelude () |
| import Prelude.Compat |
| import qualified Data.Map as Map |
| import Data.Map (Map) |
| import qualified Data.Set as Set |
| import Data.Set (Set) |
| import Data.Data |
| import Data.Word |
| import Control.Lens |
| |
| -- Supported architectures: |
| data Arch = IA32 | ARM11 | X86_64 | AARCH64 | RISCV deriving (Eq, Show) |
| |
| -- Access rights of capabilities. Not all capability types support all rights. |
| data Rights = Read |
| | Write |
| | Grant |
| | GrantReply |
| deriving (Eq, Show, Enum, Ord, Typeable, Data) |
| |
| type CapRights = Set Rights |
| |
| allRights :: CapRights |
| allRights = Set.fromList [Read, Write, Grant, GrantReply] |
| |
| -- |
| -- Object identifiers. |
| -- |
| -- Currently, each object is described by a string (its name), possibly |
| -- followed by a word (an index). The latter feature allows arrays of |
| -- objects to be specified without having to give them explicit names |
| -- (for instance, when declaring large numbers of frames for a process). |
| -- |
| -- These may later be converted to a type variable. |
| -- |
| type ObjID = (String, Maybe Word) |
| |
| type Asid = (Word, Word) |
| |
| -- |
| -- Capabilities. |
| -- |
| -- Each cap has a type (what the cap does), and a bunch of attributes |
| -- (such as the rights, what object the capability gives access to, |
| -- etc). |
| -- |
| data Cap |
| = NullCap |
| | UntypedCap { capObj :: ObjID } |
| | EndpointCap { |
| capObj :: ObjID, |
| capBadge :: Word, |
| capRights :: CapRights } |
| | NotificationCap { |
| capObj :: ObjID, |
| capBadge :: Word, |
| capRights :: CapRights } |
| | ReplyCap { capObj :: ObjID } |
| | MasterReplyCap { capObj :: ObjID } |
| | CNodeCap { |
| capObj :: ObjID, |
| capGuard :: Word, |
| capGuardSize :: Word } |
| | TCBCap { capObj :: ObjID } |
| | IRQControlCap |
| | IRQHandlerCap { capObj :: ObjID } |
| | IRQIOAPICHandlerCap { |
| capObj :: ObjID } |
| | IRQMSIHandlerCap { |
| capObj :: ObjID } |
| | DomainCap |
| | SCCap { capObj :: ObjID } |
| | SchedControlCap { core :: Word } |
| | RTReplyCap { |
| capObj :: ObjID, |
| capRights :: CapRights } |
| | VCPUCap { |
| capObj :: ObjID } |
| |
| -- arch specific caps, ARM11, IA32, X86_64 and AARCH64 merged |
| | FrameCap { |
| capObj :: ObjID, |
| capRights :: CapRights, |
| capMaybeAsid :: Maybe Asid, |
| capCached :: Bool, |
| capMaybeMapping :: Maybe (ObjID, Word) } |
| | PTCap { |
| capObj :: ObjID, |
| capMaybeAsid :: Maybe Asid } |
| | PDCap { |
| capObj :: ObjID, |
| capMaybeAsid :: Maybe Asid } |
| | PDPTCap { |
| capObj :: ObjID, |
| capMaybeAsid :: Maybe Asid } |
| | PML4Cap { |
| capObj :: ObjID, |
| capMaybeAsid :: Maybe Asid } |
| | PUDCap { |
| capObj :: ObjID, |
| capMaybeAsid :: Maybe Asid } |
| | PGDCap { |
| capObj :: ObjID, |
| capMaybeAsid :: Maybe Asid } |
| | ASIDControlCap -- only one ASIDTable in the system |
| | ASIDPoolCap { |
| capObj :: ObjID } |
| |
| -- ARM specific caps |
| | ARMIOSpaceCap { capObj :: ObjID } |
| | ARMIRQHandlerCap { capObj :: ObjID } |
| | ARMSIDCap { capObj :: ObjID } |
| | ARMCBCap { capObj :: ObjID } |
| |
| -- X86 specific caps |
| | IOPortsCap { |
| capObj :: ObjID} |
| | IOSpaceMasterCap -- can mint to any IOSpaceCap |
| | IOSpaceCap { capObj :: ObjID } |
| | IOPTCap { capObj :: ObjID } |
| |
| deriving (Eq, Ord, Show) |
| |
| -- Use Template Haskell to create Prisms corresponding to the Cap constructors. |
| -- In combination with "Control.Lens.Extras (is)" this allows us to easily write |
| -- things like "is _CNodeCap". |
| makePrisms ''Cap |
| |
| -- Kernel Objects |
| |
| type CapMap a = Map a Cap |
| |
| data CNodeExtraInfo = CNodeExtraInfo { |
| hasUntyped :: Maybe Bool } |
| deriving (Eq, Show) |
| |
| data TCBExtraInfo = TCBExtraInfo { |
| ipcBufferAddr :: Word, |
| ip :: Maybe Word, |
| sp :: Maybe Word, |
| prio :: Maybe Integer, |
| max_prio :: Maybe Integer, |
| affin :: Maybe Integer, |
| resume :: Maybe Bool } |
| deriving (Eq, Show) |
| |
| data SCExtraInfo = SCExtraInfo { |
| period :: Maybe Word64, |
| budget :: Maybe Word64, |
| scData :: Maybe Word } |
| deriving (Eq, Show) |
| |
| -- |
| -- Kernel objects in memory. |
| -- |
| -- This type represents attributes associated with in-memory kernel |
| -- objects. The type parameter 'a' is the type used to name caps. (For |
| -- example, a C implementation would use a 32-bit word, while another |
| -- implementation may pre-decode caps in a list of words). |
| -- |
| data KernelObject a |
| = Endpoint |
| | Notification |
| | TCB { |
| slots :: CapMap a, |
| faultEndpoint :: Maybe Word, |
| extraInfo :: Maybe TCBExtraInfo, |
| dom :: Integer, |
| initArguments :: [Word] } |
| | CNode { |
| slots :: CapMap a, |
| sizeBits :: Word, |
| cnode_extraInfo :: CNodeExtraInfo } |
| | Untyped { |
| maybeSizeBits :: Maybe Word, |
| maybePaddr :: Maybe Word } |
| | SC { |
| sc_extraInfo :: Maybe SCExtraInfo, |
| maybeSizeBits :: Maybe Word} |
| | RTReply |
| | VCPU |
| |
| -- arch specific objects, ARM11, IA32, X86_64, AARCH64 and RISCV mixed |
| | ASIDPool { slots :: CapMap a, |
| capAsidHigh :: Maybe Word } |
| | PT { slots :: CapMap a } |
| | PD { slots :: CapMap a } |
| | PDPT { slots :: CapMap a } |
| | PML4 { slots :: CapMap a } |
| | PUD { slots :: CapMap a } |
| | PGD { slots :: CapMap a } |
| | Frame { |
| vmSizeBits :: Word, |
| maybePaddr :: Maybe Word, |
| maybeFill :: Maybe [[String]] } |
| |
| -- ARM specific objects |
| | ARMIODevice { |
| slots :: CapMap a, |
| armiospace :: Word} |
| | ARMIrq { |
| slots :: CapMap a, |
| trigger :: Word, |
| target :: Word } |
| |
| -- fake kernel objects for smmu |
| | ARMSID |
| | ARMCB { bankNumber :: Maybe Word } |
| |
| -- X86 specific objects |
| | IOPorts { ports :: (Word, Word) } |
| | IODevice { |
| slots :: CapMap a, |
| domainID :: Word, |
| pciDevice :: (Word, Word, Word)} |
| | IOPT { |
| slots :: CapMap a, |
| level :: Word } |
| | IOAPICIrq { |
| slots :: CapMap a, |
| ioapic :: Word, |
| ioapic_pin :: Word, |
| ioapic_level :: Word, |
| ioapic_polarity :: Word } |
| | MSIIrq { |
| slots :: CapMap a, |
| handle :: Word, |
| bus :: Word, |
| dev :: Word, |
| fun :: Word } |
| deriving (Eq, Show) |
| |
| objPaddr :: KernelObject a -> Maybe Word |
| objPaddr (Frame _ paddr _) = paddr |
| objPaddr (Untyped _ paddr) = paddr |
| objPaddr _ = Nothing |
| |
| data KOType |
| = Endpoint_T |
| | Notification_T |
| | TCB_T |
| | CNode_T |
| | Untyped_T |
| | IrqSlot_T |
| | IOAPICIrqSlot_T |
| | MSIIrqSlot_T |
| | ARMIrqSlot_T |
| | ARMSID_T |
| | ARMCB_T |
| | ASIDPool_T |
| | PT_T |
| | PD_T |
| | PDPT_T |
| | PML4_T |
| | PUD_T |
| | PGD_T |
| | Frame_T |
| | IOPorts_T |
| | IODevice_T |
| | ARMIODevice_T |
| | IOPT_T |
| | VCPU_T |
| | SC_T |
| | RTReply_T |
| deriving (Show, Eq, Ord, Enum) |
| |
| -- Lookup table of object sizes, to be passed in externally. |
| type ObjectSizeMap = Map KOType Word |
| |
| -- |
| -- A reference to a capability. |
| -- |
| -- The ObjID is the kernel object the capability sits within (which will |
| -- be either a CNode or a TCB), and the Word represents the slot |
| -- (indexed from 0). |
| -- |
| type CapRef = (ObjID, Word) |
| |
| -- The name of a cap, used when copying caps. |
| type CapName = ObjID |
| |
| type ObjMap a = Map ObjID (KernelObject a) |
| |
| type IRQMap = Map Word ObjID |
| |
| -- Map from untypeds to the lists of objects they cover. |
| -- Note that we use lists to preserve ordering. The Python capDL |
| -- allocator uses ordering to describe where objects are to be allocated |
| -- within each untyped. |
| -- |
| -- This list may contain duplicate IDs while parsing; see |
| -- 'CapDL.MakeModel.dedupCoverIDs'. |
| type CoverMap = Map ObjID [ObjID] |
| |
| -- UTs without cover decls aren't recorded, so return '[]' for those |
| getUTCover :: ObjID -> CoverMap -> [ObjID] |
| getUTCover = Map.findWithDefault [] |
| |
| type CDT = Map CapRef CapRef |
| |
| -- |
| -- The state of the system. |
| -- |
| -- The system state consists of: |
| -- |
| -- 1. The architecture in use; |
| -- 2. The objects currently present; |
| -- 3. The global irq node; and |
| -- 4. The cap derivation tree (which allows us to determine which |
| -- objects are derived from which other objects) |
| -- |
| -- Two forms of model exist. The first is an abstract model where |
| -- CSpaces are assumed to be flat. Caps are identified by a Word |
| -- pointing somewhere in the CSpace. |
| -- |
| -- The second model is a more concrete object where caps are assumed to |
| -- be in a tree of CNodes. Caps are identified by a list of Words |
| -- indicating the offsets of the target cap in each level of the tree. |
| -- |
| data Model a |
| = Model { |
| arch :: Arch, |
| objects :: ObjMap a, |
| irqNode :: IRQMap, |
| cdt :: CDT, |
| untypedCovers :: CoverMap } |
| deriving Show |
| |
| data Idents cap_id = Idents { |
| cap_ids :: Map cap_id CapRef |
| } deriving Show |
| |
| type CopyMap = Map CapRef CapName |
| |
| -- |
| -- Each TCB contains several cap slots. The following constants define the |
| -- slot numbers in which they will be found if the TCB is treated as |
| -- a CNode. |
| -- |
| tcbCTableSlot :: Word |
| tcbCTableSlot = 0 |
| |
| tcbVTableSlot :: Word |
| tcbVTableSlot = 1 |
| |
| tcbReplySlot :: Word |
| tcbReplySlot = 2 |
| |
| tcbCallerSlot :: Word |
| tcbCallerSlot = 3 |
| |
| tcbIPCBufferSlot :: Word |
| tcbIPCBufferSlot = 4 |
| |
| tcbFaultEPSlot :: Word |
| tcbFaultEPSlot = 5 |
| |
| tcbSCSlot :: Word |
| tcbSCSlot = 6 |
| |
| tcbTempFaultEPSlot :: Word |
| tcbTempFaultEPSlot = 7 |
| |
| tcbBoundVCPUSlot :: Word |
| tcbBoundVCPUSlot = 8 |
| |
| -- |
| -- The string used when defining an IOSpaceMasterCap, an ASIDControlCap, |
| -- an IRQControlCap, a DomainCap or a SchedControlCap. |
| -- |
| ioSpaceMaster :: String |
| ioSpaceMaster = "io_space_master" |
| |
| asidControl :: String |
| asidControl = "asid_control" |
| |
| irqControl :: String |
| irqControl = "irq_control" |
| |
| domain :: String |
| domain = "domain" |
| |
| schedControl :: String |
| schedControl = "sched_control" |
| |
| capStrings :: [String] |
| capStrings = [ioSpaceMaster, asidControl, irqControl, domain, schedControl] |
| |
| -- |
| -- Determine if the given capability points to an object. |
| -- |
| hasObjID :: Cap -> Bool |
| hasObjID NullCap = False |
| hasObjID IOSpaceMasterCap = False |
| hasObjID ASIDControlCap = False |
| hasObjID IRQControlCap = False |
| hasObjID DomainCap = False |
| hasObjID (SchedControlCap {}) = False |
| hasObjID _ = True |
| |
| -- |
| -- Get the object a particular cap points to. |
| -- |
| -- This function is partial, not all caps point to an object. |
| -- |
| objID :: Cap -> ObjID |
| objID = capObj |
| |
| -- |
| -- Determine if the given cap has rights. |
| -- |
| hasRights :: Cap -> Bool |
| hasRights (RTReplyCap {}) = True |
| hasRights (NotificationCap {}) = True |
| hasRights (EndpointCap {}) = True |
| hasRights (FrameCap {}) = True |
| hasRights _ = False |
| |
| -- |
| -- Determine if the given object has capability slots. |
| -- |
| hasSlots :: KernelObject a -> Bool |
| hasSlots (TCB {}) = True |
| hasSlots (CNode {}) = True |
| hasSlots (ASIDPool {}) = True |
| hasSlots (PT {}) = True |
| hasSlots (PD {}) = True |
| hasSlots (PDPT {}) = True |
| hasSlots (PML4 {}) = True |
| hasSlots (PUD {}) = True |
| hasSlots (PGD {}) = True |
| hasSlots (ARMIODevice {}) = True |
| hasSlots (ARMIrq {}) = True |
| hasSlots (IODevice {}) = True |
| hasSlots (IOPT {}) = True |
| hasSlots (IOAPICIrq {}) = True |
| hasSlots (MSIIrq {}) = True |
| hasSlots _ = False |