blob: 67040a72cf75b038c40841dcb5cac206db8e5e1d [file] [log] [blame] [edit]
--
-- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
--
-- SPDX-License-Identifier: BSD-2-Clause
--
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
module CapDL.ParserUtils where
import CapDL.AST
import CapDL.Model
import Text.ParserCombinators.Parsec
import qualified Text.ParserCombinators.Parsec.Token as PT
import Text.ParserCombinators.Parsec.Language
import Prelude ()
import Prelude.Compat
import qualified Data.Set as Set
import qualified Data.Map as Map
import Data.Word
import Data.Char (isSpace)
data Maps = Maps {
refMap :: Map.Map Name ObjID,
addrMap :: Map.Map ObjID (Word, Word),
covMap :: Map.Map ObjID (Set.Set ObjID),
irqMap :: Map.Map Word Name
}
emptyMaps :: Maps
emptyMaps = Maps Map.empty Map.empty Map.empty Map.empty
type MapParser = GenParser Char Maps
capDL_Lang = emptyDef {
commentStart = "/*",
commentEnd = "*/",
commentLine = "--",
nestedComments = True,
identStart = letter,
identLetter = alphaNum <|> oneOf "-_@.",
opStart = opLetter capDL_Lang,
opLetter = oneOf ":=",
reservedNames = ["objects", "caps"],
caseSensitive = True
}
lexer :: PT.TokenParser Maps
lexer = PT.makeTokenParser capDL_Lang
whiteSpace= PT.whiteSpace lexer
lexeme = PT.lexeme lexer
symbol = PT.symbol lexer
natural = PT.natural lexer
parens = PT.parens lexer
braces = PT.braces lexer
brackets = PT.brackets lexer
semi = PT.semi lexer
dot = PT.dot lexer
comma = PT.comma lexer
colon = PT.colon lexer
identifier= PT.identifier lexer
reserved = PT.reserved lexer
stringLiteral = PT.stringLiteral lexer
name :: MapParser Name
name = identifier
number :: MapParser Word
number = do
n <- natural
return (fromIntegral n)
integer :: MapParser Integer
integer = do
n <- natural
return $ fromIntegral n
integer64 :: MapParser Word64
integer64 = do
n <- natural
return $ fromIntegral n
name_ref :: MapParser NameRef
name_ref = do
n <- name
rs <- ranges
return (n,rs)
qname :: MapParser QName
qname = sepBy1 name_ref (symbol "/")
keyw :: String -> a -> MapParser a
keyw st v = do
reserved st
return v
parse_either :: MapParser a -> MapParser b -> MapParser (Either a b)
parse_either a b =
do x <- a
return $ Left x
<|> do x <- b
return $ Right x
parse_arch :: MapParser Arch
parse_arch = do
reserved "arch"
keyw "ia32" IA32 <|> keyw "arm11" ARM11 <|> keyw "x86_64" X86_64 <|> keyw "aarch64" AARCH64 <|> keyw "riscv" RISCV
object_type :: MapParser KOType
object_type =
keyw "ep" Endpoint_T
<|> keyw "notification" Notification_T
<|> keyw "tcb" TCB_T
<|> keyw "cnode" CNode_T
<|> keyw "ut" Untyped_T
<|> keyw "irq" IrqSlot_T
<|> keyw "ioapic_irq" IOAPICIrqSlot_T
<|> keyw "msi_irq" MSIIrqSlot_T
<|> keyw "arm_irq" ARMIrqSlot_T
<|> keyw "asid_pool" ASIDPool_T
<|> keyw "pt" PT_T
<|> keyw "pd" PD_T
<|> keyw "pml4" PML4_T
<|> keyw "pdpt" PDPT_T
<|> keyw "pud" PUD_T
<|> keyw "pgd" PGD_T
<|> keyw "frame" Frame_T
<|> keyw "io_ports" IOPorts_T
<|> keyw "io_device" IODevice_T
<|> keyw "arm_io_device" ARMIODevice_T
<|> keyw "io_pt" IOPT_T
<|> keyw "vcpu" VCPU_T
<|> keyw "sc" SC_T
<|> keyw "rtreply" RTReply_T
<|> keyw "streamid" ARMSID_T
<|> keyw "contextbank" ARMCB_T
obj_bit_size :: MapParser ObjParam
obj_bit_size = do
n <- number
reserved "bits"
return $ BitSize n
obj_vm_type :: Word -> MapParser ObjParam
obj_vm_type n =
keyw "k" (VMSize (n * 2^10))
<|> keyw "M" (VMSize (n * 2^20))
obj_vm_size :: MapParser ObjParam
obj_vm_size = do
n <- number
obj_vm_type n
obj_paddr :: MapParser ObjParam
obj_paddr = do
reserved "paddr"
colon
n <- number
return $ Paddr n
cnode_has_untyped :: MapParser CNodeExtraParam
cnode_has_untyped = do
reserved "untyped"
colon
keyw "True" (HasUntyped True) <|> keyw "False" (HasUntyped False)
cnode_extra_param :: MapParser ObjParam
cnode_extra_param = do
param <- (cnode_has_untyped)
return $ CNodeExtraParam param
io_pt_level :: MapParser ObjParam
io_pt_level = do
reserved "level"
colon
l <- number
return $ IOPTLevel l
tcb_addr :: MapParser TCBExtraParam
tcb_addr = do
reserved "addr"
colon
n <- number
return $ Addr n
tcb_ip :: MapParser TCBExtraParam
tcb_ip = do
reserved "ip"
colon
n <- number
return $ IP n
tcb_sp :: MapParser TCBExtraParam
tcb_sp = do
reserved "sp"
colon
n <- number
return $ SP n
tcb_prio :: MapParser TCBExtraParam
tcb_prio = do
reserved "prio"
colon
n <- integer
return $ Prio n
tcb_max_prio :: MapParser TCBExtraParam
tcb_max_prio = do
reserved "max_prio"
colon
n <- integer
return $ MaxPrio n
tcb_affinity :: MapParser TCBExtraParam
tcb_affinity = do
reserved "affinity"
colon
n <- integer
return $ Affinity n
tcb_resume :: MapParser TCBExtraParam
tcb_resume = do
reserved "resume"
colon
keyw "True" (Resume True) <|> keyw "False" (Resume False)
tcb_extra_param :: MapParser ObjParam
tcb_extra_param = do
param <- (tcb_addr
<|> tcb_ip
<|> tcb_sp
<|> tcb_prio
<|> tcb_max_prio
<|> tcb_resume
<|> tcb_affinity)
return $ TCBExtraParam param
tcb_dom :: MapParser ObjParam
tcb_dom = do
reserved "dom"
colon
n <- integer
return $ Dom n
tcb_fault_ep :: MapParser ObjParam
tcb_fault_ep = do
reserved "fault_ep"
colon
n <- number
return $ FaultEP n
init_arguments :: MapParser ObjParam
init_arguments = do
reserved "init"
colon
list <- brackets (sepBy number comma)
return $ InitArguments list
domain_id :: MapParser ObjParam
domain_id = do
reserved "domainID"
colon
dom <- number
return $ DomainID dom
pci_device :: MapParser ObjParam
pci_device = do
pci_bus <- number
colon
pci_dev <- number
dot
pci_fun <- number
return $ PCIDevice (pci_bus, pci_dev, pci_fun)
arm_iospace :: MapParser ObjParam
arm_iospace = do
reserved "iospace"
colon
iospace <- number
return $ ARMIOSpace iospace
sc_period :: MapParser SCExtraParam
sc_period = do
reserved "period"
colon
n <- integer64
return $ Period n
cb_number :: MapParser CBExtraParam
cb_number = do
reserved "bank"
colon
n <- number
return $ CBNumber n
sc_budget :: MapParser SCExtraParam
sc_budget = do
reserved "budget"
colon
n <- integer64
return $ Budget n
sc_data :: MapParser SCExtraParam
sc_data = do
reserved "data"
colon
n <- number
return $ SCData n
sc_extra_param :: MapParser ObjParam
sc_extra_param = do
param <- (sc_period
<|> sc_budget
<|> sc_data)
return $ SCExtraParam param
cb_extra_param :: MapParser ObjParam
cb_extra_param = do
param <- cb_number
return $ CBExtraParam param
ioapic_irq_ioapic :: MapParser IOAPICIRQExtraParam
ioapic_irq_ioapic = do
reserved "ioapic_num"
colon
n <- number
return $ IOAPIC n
ioapic_irq_pin :: MapParser IOAPICIRQExtraParam
ioapic_irq_pin = do
reserved "ioapic_pin"
colon
n <- number
return $ Pin n
ioapic_irq_level :: MapParser IOAPICIRQExtraParam
ioapic_irq_level = do
reserved "ioapic_level"
colon
n <- number
return $ Level n
ioapic_irq_polarity :: MapParser IOAPICIRQExtraParam
ioapic_irq_polarity = do
reserved "ioapic_polarity"
colon
n <- number
return $ Polarity n
ioapic_irq_extra_param :: MapParser ObjParam
ioapic_irq_extra_param = do
param <- (ioapic_irq_ioapic
<|> ioapic_irq_pin
<|> ioapic_irq_level
<|> ioapic_irq_polarity)
return $ IOAPICIRQExtraParam param
msi_irq_handle :: MapParser MSIIRQExtraParam
msi_irq_handle = do
reserved "msi_handle"
colon
n <- number
return $ MSIHandle n
msi_irq_pci_bus :: MapParser MSIIRQExtraParam
msi_irq_pci_bus = do
reserved "msi_pci_bus"
colon
n <- number
return $ MSIPCIBus n
msi_irq_pci_dev :: MapParser MSIIRQExtraParam
msi_irq_pci_dev = do
reserved "msi_pci_dev"
colon
n <- number
return $ MSIPCIDev n
msi_irq_pci_fun :: MapParser MSIIRQExtraParam
msi_irq_pci_fun = do
reserved "msi_pci_fun"
colon
n <- number
return $ MSIPCIFun n
msi_irq_extra_param :: MapParser ObjParam
msi_irq_extra_param = do
param <- (msi_irq_handle
<|> msi_irq_pci_bus
<|> msi_irq_pci_dev
<|> msi_irq_pci_fun)
return $ MSIIRQExtraParam param
arm_irq_trigger :: MapParser ARMIRQExtraParam
arm_irq_trigger = do
reserved "trigger"
colon
n <- keyw "level" 0 <|> keyw "edge" 1
return $ ARMIRQTrigger n
arm_irq_target :: MapParser ARMIRQExtraParam
arm_irq_target = do
reserved "target"
colon
n <- number
return $ ARMIRQTarget n
arm_irq_extra_param :: MapParser ObjParam
arm_irq_extra_param = do
param <- (arm_irq_trigger
<|> arm_irq_target)
return $ ARMIRQExtraParam param
fill_param :: MapParser FrameExtraParam
fill_param = do
reserved "fill"
colon
fill_args <- brackets (sepBy (braces (sepBy1 (many1 notFillEnd) whiteSpace)) comma)
return $ Fill fill_args
where
notFillEnd = satisfy (\x -> not (isSpace x || x == '}'))
frame_extra_param :: MapParser ObjParam
frame_extra_param = do
param <- fill_param
return $ FrameExtraParam param
ports_param :: MapParser ObjParam
ports_param = do
reserved "ports"
colon
r <- brackets (parse_port_range)
return $ Ports r
where
parse_port_range = do
start <- number
symbol ".."
end <- number
return (start, end)
asid_high_param :: MapParser ObjParam
asid_high_param = do
reserved "asid_high"
colon
AsidHigh <$> number
object_param :: MapParser ObjParam
object_param =
try obj_bit_size
<|> try obj_vm_size
<|> io_pt_level
<|> tcb_extra_param
<|> frame_extra_param
<|> tcb_dom
<|> tcb_fault_ep
<|> init_arguments
<|> obj_paddr
<|> domain_id
<|> pci_device
<|> arm_iospace
<|> sc_extra_param
<|> ioapic_irq_extra_param
<|> msi_irq_extra_param
<|> arm_irq_extra_param
<|> ports_param
<|> asid_high_param
<|> cb_extra_param
<|> cnode_extra_param
object_params :: MapParser [ObjParam]
object_params =
parens (sepBy object_param comma)
<|> return []
symbolic_slot :: MapParser Word
symbolic_slot =
keyw "cspace" tcbCTableSlot
<|> keyw "vspace" tcbVTableSlot
<|> keyw "reply_slot" tcbReplySlot
<|> keyw "caller_slot" tcbCallerSlot
<|> keyw "ipc_buffer_slot" tcbIPCBufferSlot
<|> keyw "fault_ep_slot" tcbFaultEPSlot
<|> keyw "sc_slot" tcbSCSlot
<|> keyw "temp_fault_ep_slot" tcbTempFaultEPSlot
<|> keyw "bound_vcpu" tcbBoundVCPUSlot
parse_slot :: MapParser Word
parse_slot = number <|> symbolic_slot
maybe_slot :: MapParser (Maybe Word)
maybe_slot =
do n <- parse_slot
colon
return $ Just n
<|> return Nothing
chr :: Char -> a -> MapParser a
chr c v = lexeme (char c) >> return v
right :: MapParser Rights
right =
chr 'R' Read
<|> chr 'W' Write
<|> chr 'G' Grant
<|> chr 'X' Grant
<|> chr 'P' GrantReply
parse_rights :: MapParser CapRights
parse_rights = do
rs <- many1 right
return $ Set.fromList rs
range :: MapParser Range
range =
(try $ do
a <- number
symbol ".."
b <- number
return $ FromTo a b)
<|> (try $ do
symbol ".."
b <- number
return $ To b)
<|> (try $ do
a <- number
symbol ".."
return $ From a)
<|> (try $ do
n <- number
return $ Only n)
ranges :: MapParser [Range]
ranges =
(try (symbol "[" >> symbol "]" >> return [All]))
<|> brackets (sepBy1 range comma)
<|> return []
parse_asid :: MapParser Asid
parse_asid = do
symbol "("
high <- number
symbol ","
low <- number
symbol ")"
return (high, low)
cap_param :: MapParser CapParam
cap_param =
do
reserved "masked"
colon
r <- parse_rights
return $ Masked r
<|> do
r <- parse_rights
return $ Rights r
<|> do
reserved "guard"
colon
n <- number
return $ Guard n
<|> do
reserved "guard_size"
colon
n <- number
return $ GuardSize n
<|> do
reserved "badge"
colon
n <- number
return $ Badge n
<|> do
reserved "core"
colon
n <- number
return $ Core n
<|> do
reserved "reply"
return Reply
<|> do
reserved "master_reply"
return MasterReply
<|> do
reserved "asid"
colon
asid <- parse_asid
return $ Asid asid
<|> do
reserved "cached"
return $ Cached True
<|> do
reserved "uncached"
return $ Cached False
<|> do
reserved "mapping"
colon
(container_name, slot) <- cap_ref
return $ FrameMapping container_name slot
cap_params :: MapParser [CapParam]
cap_params =
parens (sepBy1 cap_param comma) <|> return []
opt_semi :: MapParser String
opt_semi = semi <|> return ""
irq_mapping :: MapParser CapMapping
irq_mapping = do
sl <- maybe_slot
obj <- name_ref
return $ IRQMapping sl obj
irq_decl :: MapParser Decl
irq_decl = do
ms <- sepEndBy irq_mapping opt_semi
return $ IRQDecl ms
irq_decls :: MapParser [Decl]
irq_decls = do
reserved "irq maps"
irqs <- braces (irq_decl)
return [irqs]
cap_ref :: MapParser (NameRef, Word)
cap_ref = do
symbol "("
obj <- name_ref
comma
slot <- parse_slot
symbol ")"
return (obj, slot)
slot_ref :: MapParser SlotRef
slot_ref =
(do
capRef <- cap_ref
return $ Left capRef)
<|> (do
name <- name_ref
return $ Right name)
maybe_parent :: MapParser (Maybe SlotRef)
maybe_parent =
optionMaybe $ try $ do
reserved "- child_of"
slot_ref
cdt_decl_or_slot_ref :: MapParser (Either Decl SlotRef)
cdt_decl_or_slot_ref =
(do
slotRef <- slot_ref
return $ Right slotRef)
<|> (do
cdtDecl <- cdt_decl
return $ Left cdtDecl)
cdt_decl :: MapParser Decl
cdt_decl = do
capRef <- slot_ref
children <- braces (sepEndBy cdt_decl_or_slot_ref opt_semi)
return $ CDTDecl capRef children
cdt_decls :: MapParser [Decl]
cdt_decls = do
reserved "cdt"
braces $ many (try cdt_decl)