blob: 4834d0467caa35f90ace76c30a7fc6123278b151 [file] [log] [blame] [edit]
--
-- 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