| -- | |
| -- 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) |