(* * Copyright 2019, Data61, CSIRO * * This software may be distributed and modified according to the terms of * the GNU General Public License version 2. Note that NO WARRANTY is provided. * See "LICENSE_GPLv2.txt" for details. * * @TAG(DATA61_GPL) *) theory Invariants_H imports LevityCatch "AInvs.Deterministic_AI" "AInvs.AInvs" "Lib.AddUpdSimps" begin context Arch begin lemmas haskell_crunch_def [crunch_def] = deriveCap_def finaliseCap_def hasCancelSendRights_def sameRegionAs_def isPhysicalCap_def sameObjectAs_def updateCapData_def maskCapRights_def createObject_def capUntypedPtr_def capUntypedSize_def performInvocation_def decodeInvocation_def context begin global_naming global requalify_facts Retype_H.deriveCap_def Retype_H.finaliseCap_def Retype_H.hasCancelSendRights_def Retype_H.sameRegionAs_def Retype_H.isPhysicalCap_def Retype_H.sameObjectAs_def Retype_H.updateCapData_def Retype_H.maskCapRights_def Retype_H.createObject_def Retype_H.capUntypedPtr_def Retype_H.capUntypedSize_def Retype_H.performInvocation_def Retype_H.decodeInvocation_def end end \ \---------------------------------------------------------------------------\ section "Invariants on Executable Spec" (* FIXME RISCV: move up, use everywhere *) abbreviation ptr_range :: "obj_ref \ nat \ machine_word set" where "ptr_range p n \ {p .. p + mask n}" context begin interpretation Arch . definition ps_clear :: "obj_ref \ nat \ kernel_state \ bool" where "ps_clear p n s \ (ptr_range p n - {p}) \ dom (ksPSpace s) = {}" definition pspace_no_overlap' :: "obj_ref \ nat \ kernel_state \ bool" where "pspace_no_overlap' ptr bits \ \s. \x ko. ksPSpace s x = Some ko \ (ptr_range x (objBitsKO ko)) \ {ptr .. (ptr && ~~ mask bits) + mask bits} = {}" definition ko_wp_at' :: "(kernel_object \ bool) \ obj_ref \ kernel_state \ bool" where "ko_wp_at' P p s \ \ko. ksPSpace s p = Some ko \ is_aligned p (objBitsKO ko) \ P ko \ ps_clear p (objBitsKO ko) s" definition obj_at' :: "('a::pspace_storable \ bool) \ machine_word \ kernel_state \ bool" where obj_at'_real_def: "obj_at' P p s \ ko_wp_at' (\ko. \obj. projectKO_opt ko = Some obj \ P obj) p s" definition typ_at' :: "kernel_object_type \ machine_word \ kernel_state \ bool" where "typ_at' T \ ko_wp_at' (\ko. koTypeOf ko = T)" abbreviation ep_at' :: "obj_ref \ kernel_state \ bool" where "ep_at' \ obj_at' ((\x. True) :: endpoint \ bool)" abbreviation ntfn_at' :: "obj_ref \ kernel_state \ bool" where "ntfn_at' \ obj_at' ((\x. True) :: notification \ bool)" abbreviation tcb_at' :: "obj_ref \ kernel_state \ bool" where "tcb_at' \ obj_at' ((\x. True) :: tcb \ bool)" abbreviation real_cte_at' :: "obj_ref \ kernel_state \ bool" where "real_cte_at' \ obj_at' ((\x. True) :: cte \ bool)" abbreviation ko_at' :: "'a::pspace_storable \ obj_ref \ kernel_state \ bool" where "ko_at' v \ obj_at' (\k. k = v)" abbreviation pte_at' :: "obj_ref \ kernel_state \ bool" where "pte_at' \ typ_at' (ArchT PTET)" end record itcb' = itcbState :: thread_state itcbFaultHandler :: cptr itcbIPCBuffer :: vptr itcbBoundNotification :: "machine_word option" itcbPriority :: priority itcbFault :: "fault option" itcbTimeSlice :: nat itcbMCP :: priority definition tcb_to_itcb' :: "tcb \ itcb'" where "tcb_to_itcb' tcb \ \ itcbState = tcbState tcb, itcbFaultHandler = tcbFaultHandler tcb, itcbIPCBuffer = tcbIPCBuffer tcb, itcbBoundNotification = tcbBoundNotification tcb, itcbPriority = tcbPriority tcb, itcbFault = tcbFault tcb, itcbTimeSlice = tcbTimeSlice tcb, itcbMCP = tcbMCP tcb\" lemma itcb_simps[simp]: "itcbState (tcb_to_itcb' tcb) = tcbState tcb" "itcbFaultHandler (tcb_to_itcb' tcb) = tcbFaultHandler tcb" "itcbIPCBuffer (tcb_to_itcb' tcb) = tcbIPCBuffer tcb" "itcbBoundNotification (tcb_to_itcb' tcb) = tcbBoundNotification tcb" "itcbPriority (tcb_to_itcb' tcb) = tcbPriority tcb" "itcbFault (tcb_to_itcb' tcb) = tcbFault tcb" "itcbTimeSlice (tcb_to_itcb' tcb) = tcbTimeSlice tcb" "itcbMCP (tcb_to_itcb' tcb) = tcbMCP tcb" by (auto simp: tcb_to_itcb'_def) definition pred_tcb_at' :: "(itcb' \ 'a) \ ('a \ bool) \ machine_word \ kernel_state \ bool" where "pred_tcb_at' proj test \ obj_at' (\ko. test (proj (tcb_to_itcb' ko)))" abbreviation st_tcb_at' :: "(thread_state \ bool) \ obj_ref \ kernel_state \ bool" where "st_tcb_at' \ pred_tcb_at' itcbState" abbreviation bound_tcb_at' :: "(obj_ref option \ bool) \ obj_ref \ kernel_state \ bool" where "bound_tcb_at' \ pred_tcb_at' itcbBoundNotification" abbreviation mcpriority_tcb_at' :: "(priority \ bool) \ obj_ref \ kernel_state \ bool" where "mcpriority_tcb_at' \ pred_tcb_at' itcbMCP" lemma st_tcb_at'_def: "st_tcb_at' test \ obj_at' (test \ tcbState)" by (simp add: pred_tcb_at'_def o_def) text \ cte with property at \ definition cte_wp_at' :: "(cte \ bool) \ obj_ref \ kernel_state \ bool" where "cte_wp_at' P p s \ \cte::cte. fst (getObject p s) = {(cte,s)} \ P cte" abbreviation cte_at' :: "obj_ref \ kernel_state \ bool" where "cte_at' \ cte_wp_at' \" definition tcb_cte_cases :: "machine_word \ ((tcb \ cte) \ ((cte \ cte) \ tcb \ tcb))" where "tcb_cte_cases \ [ 0 << cteSizeBits \ (tcbCTable, tcbCTable_update), 1 << cteSizeBits \ (tcbVTable, tcbVTable_update), 2 << cteSizeBits \ (tcbReply, tcbReply_update), 3 << cteSizeBits \ (tcbCaller, tcbCaller_update), 4 << cteSizeBits \ (tcbIPCBufferFrame, tcbIPCBufferFrame_update) ]" definition max_ipc_words :: machine_word where "max_ipc_words \ capTransferDataSize + msgMaxLength + msgMaxExtraCaps + 2" definition tcb_st_refs_of' :: "thread_state \ (obj_ref \ reftype) set" where "tcb_st_refs_of' st \ case st of (BlockedOnReceive x _) => {(x, TCBBlockedRecv)} | (BlockedOnSend x _ _ _ _) => {(x, TCBBlockedSend)} | (BlockedOnNotification x) => {(x, TCBSignal)} | _ => {}" definition ep_q_refs_of' :: "endpoint \ (obj_ref \ reftype) set" where "ep_q_refs_of' ep \ case ep of IdleEP => {} | (RecvEP q) => set q \ {EPRecv} | (SendEP q) => set q \ {EPSend}" definition ntfn_q_refs_of' :: "Structures_H.ntfn \ (obj_ref \ reftype) set" where "ntfn_q_refs_of' ntfn \ case ntfn of IdleNtfn => {} | (WaitingNtfn q) => set q \ {NTFNSignal} | (ActiveNtfn b) => {}" definition ntfn_bound_refs' :: "obj_ref option \ (obj_ref \ reftype) set" where "ntfn_bound_refs' t \ set_option t \ {NTFNBound}" definition tcb_bound_refs' :: "obj_ref option \ (obj_ref \ reftype) set" where "tcb_bound_refs' a \ set_option a \ {TCBBound}" definition refs_of' :: "kernel_object \ (obj_ref \ reftype) set" where "refs_of' ko \ case ko of (KOTCB tcb) => tcb_st_refs_of' (tcbState tcb) \ tcb_bound_refs' (tcbBoundNotification tcb) | (KOEndpoint ep) => ep_q_refs_of' ep | (KONotification ntfn) => ntfn_q_refs_of' (ntfnObj ntfn) \ ntfn_bound_refs' (ntfnBoundTCB ntfn) | _ => {}" definition state_refs_of' :: "kernel_state \ obj_ref \ (obj_ref \ reftype) set" where "state_refs_of' s \ \x. case ksPSpace s x of None \ {} | Some ko \ if is_aligned x (objBitsKO ko) \ ps_clear x (objBitsKO ko) s then refs_of' ko else {}" fun live' :: "kernel_object \ bool" where "live' (KOTCB tcb) = (bound (tcbBoundNotification tcb) \ (tcbState tcb \ Inactive \ tcbState tcb \ IdleThreadState) \ tcbQueued tcb)" | "live' (KOEndpoint ep) = (ep \ IdleEP)" | "live' (KONotification ntfn) = (bound (ntfnBoundTCB ntfn) \ (\ts. ntfnObj ntfn = WaitingNtfn ts))" | "live' _ = False" fun zobj_refs' :: "capability \ obj_ref set" where "zobj_refs' (EndpointCap r _ _ _ _ _) = {r}" | "zobj_refs' (NotificationCap r _ _ _) = {r}" | "zobj_refs' (ThreadCap r) = {r}" | "zobj_refs' _ = {}" definition ex_nonz_cap_to' :: "obj_ref \ kernel_state \ bool" where "ex_nonz_cap_to' ref \ \s. \cref. cte_wp_at' (\c. ref \ zobj_refs' (cteCap c)) cref s" definition if_live_then_nonz_cap' :: "kernel_state \ bool" where "if_live_then_nonz_cap' s \ \ptr. ko_wp_at' live' ptr s \ ex_nonz_cap_to' ptr s" fun cte_refs' :: "capability \ obj_ref \ obj_ref set" where "cte_refs' (CNodeCap ref bits _ _) x = (\x. ref + x << cteSizeBits) ` {0 .. mask bits}" | "cte_refs' (ThreadCap ref) x = (\x. ref + x) ` dom tcb_cte_cases" | "cte_refs' (Zombie ref _ n) x = (\x. ref + x << cteSizeBits) ` {0 ..< of_nat n}" | "cte_refs' (IRQHandlerCap irq) x = {x + ucast irq << cteSizeBits}" | "cte_refs' _ _ = {}" abbreviation irq_node' :: "kernel_state \ obj_ref" where "irq_node' s \ intStateIRQNode (ksInterruptState s)" definition ex_cte_cap_wp_to' :: "(capability \ bool) \ obj_ref \ kernel_state \ bool" where "ex_cte_cap_wp_to' P ptr \ \s. \cref. cte_wp_at' (\c. P (cteCap c) \ ptr \ cte_refs' (cteCap c) (irq_node' s)) cref s" abbreviation ex_cte_cap_to' :: "obj_ref \ kernel_state \ bool" where "ex_cte_cap_to' \ ex_cte_cap_wp_to' \" definition if_unsafe_then_cap' :: "kernel_state \ bool" where "if_unsafe_then_cap' s \ \cref. cte_wp_at' (\c. cteCap c \ NullCap) cref s \ ex_cte_cap_to' cref s" section "Valid caps and objects (design spec)" context begin interpretation Arch . primrec acapBits :: "arch_capability \ nat" where "acapBits (ASIDPoolCap _ _) = asidLowBits + word_size_bits" | "acapBits ASIDControlCap = asidHighBits + word_size_bits" | "acapBits (FrameCap _ _ sz _ _) = pageBitsForSize sz" | "acapBits (PageTableCap _ _) = table_size" end primrec zBits :: "zombie_type \ nat" where "zBits (ZombieCNode n) = objBits (undefined::cte) + n" | "zBits (ZombieTCB) = tcbBlockSizeBits" primrec capBits :: "capability \ nat" where "capBits NullCap = 0" | "capBits DomainCap = 0" | "capBits (UntypedCap _ _ b _) = b" | "capBits (EndpointCap _ _ _ _ _ _) = objBits (undefined::endpoint)" | "capBits (NotificationCap _ _ _ _) = objBits (undefined::Structures_H.notification)" | "capBits (CNodeCap _ b _ _) = objBits (undefined::cte) + b" | "capBits (ThreadCap _) = objBits (undefined::tcb)" | "capBits (Zombie _ z _) = zBits z" | "capBits (IRQControlCap) = 0" | "capBits (IRQHandlerCap _) = 0" | "capBits (ReplyCap _ _ _) = objBits (undefined :: tcb)" | "capBits (ArchObjectCap x) = acapBits x" definition capAligned :: "capability \ bool" where "capAligned c \ is_aligned (capUntypedPtr c) (capBits c) \ capBits c < word_bits" definition obj_range' :: "machine_word \ kernel_object \ machine_word set" where "obj_range' p ko \ ptr_range p (objBitsKO ko)" primrec (nonexhaustive) usableUntypedRange :: "capability \ machine_word set" where "usableUntypedRange (UntypedCap _ p n f) = (if f < 2^n then {p+of_nat f .. p + mask n} else {})" definition valid_untyped' :: "bool \ obj_ref \ nat \ nat \ kernel_state \ bool" where "valid_untyped' d ptr bits idx s \ \ptr'. \ ko_wp_at' (\ko. ptr_range ptr bits \ obj_range' ptr' ko \ obj_range' ptr' ko \ usableUntypedRange (UntypedCap d ptr bits idx) \ {}) ptr' s" primrec zombieCTEs :: "zombie_type \ nat" where "zombieCTEs ZombieTCB = 5" | "zombieCTEs (ZombieCNode n) = 2 ^ n" context begin interpretation Arch . definition page_table_at' :: "obj_ref \ kernel_state \ bool" where "page_table_at' x \ \s. is_aligned x ptBits \ (\y < 2 ^ ptTranslationBits. typ_at' (ArchT PTET) (x + (y << word_size_bits)) s)" lemmas vspace_table_at'_defs = page_table_at'_def abbreviation asid_pool_at' :: "obj_ref \ kernel_state \ bool" where "asid_pool_at' \ typ_at' (ArchT ASIDPoolT)" definition asid_wf :: "asid \ bool" where "asid_wf asid \ asid \ mask asid_bits" (* FIXME RISCV: complete design spec invariants *) end end