2014-07-14 19:32:44 +00:00
|
|
|
(*
|
2020-03-09 06:18:30 +00:00
|
|
|
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
|
2014-07-14 19:32:44 +00:00
|
|
|
*
|
2020-03-09 06:18:30 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
2014-07-14 19:32:44 +00:00
|
|
|
*)
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Operations on CSpace
|
|
|
|
*)
|
|
|
|
|
|
|
|
theory CSpace_D
|
|
|
|
imports
|
|
|
|
PageTableUnmap_D
|
|
|
|
begin
|
|
|
|
|
|
|
|
(* Does the given cap have any children? *)
|
|
|
|
definition
|
|
|
|
has_children :: "cdl_cap_ref \<Rightarrow> cdl_state \<Rightarrow> bool"
|
|
|
|
where
|
|
|
|
"has_children parent s = (\<exists>child. is_cdt_parent s parent child)"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Ensure that the given cap does not contain any children
|
|
|
|
* in the CDT.
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
ensure_no_children :: "cdl_cap_ref \<Rightarrow> unit except_monad"
|
|
|
|
where
|
|
|
|
"ensure_no_children x \<equiv> doE
|
|
|
|
c \<leftarrow> liftE $ gets (has_children x);
|
|
|
|
whenE c $ throw
|
|
|
|
odE"
|
|
|
|
|
|
|
|
(* Ensure that the given cap slot is empty. *)
|
|
|
|
definition
|
|
|
|
ensure_empty :: "cdl_cap_ref \<Rightarrow> unit except_monad"
|
|
|
|
where
|
|
|
|
"ensure_empty cap_ref \<equiv> doE
|
|
|
|
cap \<leftarrow> liftE $ get_cap cap_ref;
|
|
|
|
unlessE (cap = NullCap) $ throw
|
|
|
|
odE"
|
|
|
|
|
|
|
|
(* Insert a new cap into an object. The cap will have no parent. *)
|
|
|
|
definition
|
|
|
|
insert_cap_orphan :: "cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"insert_cap_orphan new_cap dest_slot \<equiv> do
|
|
|
|
old_cap \<leftarrow> get_cap dest_slot;
|
|
|
|
assert (old_cap = NullCap);
|
|
|
|
set_cap dest_slot new_cap
|
|
|
|
od"
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-05-09 11:05:01 +00:00
|
|
|
primrec (nonexhaustive)
|
|
|
|
available_range :: "cdl_cap \<Rightarrow> cdl_object_id set"
|
|
|
|
where
|
2016-08-12 04:24:37 +00:00
|
|
|
"available_range (UntypedCap _ r available) = available"
|
2014-07-14 19:32:44 +00:00
|
|
|
|
2016-10-31 04:50:20 +00:00
|
|
|
definition
|
2015-05-09 11:05:01 +00:00
|
|
|
set_available_range :: "cdl_cap \<Rightarrow> cdl_object_id set \<Rightarrow> cdl_cap"
|
|
|
|
where
|
2016-10-31 04:50:20 +00:00
|
|
|
"set_available_range cap nrange \<equiv>
|
|
|
|
case cap of UntypedCap d r available \<Rightarrow> UntypedCap d r nrange | _ \<Rightarrow> cap"
|
|
|
|
|
|
|
|
lemmas set_avaiable_range_simps[simp] = set_available_range_def[split_simps cdl_cap.split]
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
definition
|
|
|
|
set_untyped_cap_as_full :: "cdl_cap \<Rightarrow> cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> unit k_monad"
|
2015-05-09 11:05:01 +00:00
|
|
|
where
|
|
|
|
"set_untyped_cap_as_full src_cap new_cap src_slot \<equiv>
|
2014-07-14 19:32:44 +00:00
|
|
|
if (is_untyped_cap src_cap \<and> is_untyped_cap new_cap
|
|
|
|
\<and> cap_objects src_cap = cap_objects new_cap) then
|
2014-07-17 16:22:50 +00:00
|
|
|
(set_cap src_slot (set_available_range src_cap {}))
|
2014-07-14 19:32:44 +00:00
|
|
|
else return ()"
|
|
|
|
|
|
|
|
(* Insert a new cap into an object. The cap will be a sibling. *)
|
|
|
|
definition
|
|
|
|
insert_cap_sibling :: "cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> cdl_cap_ref \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"insert_cap_sibling new_cap src_slot dest_slot \<equiv> do
|
|
|
|
src_cap \<leftarrow> get_cap src_slot;
|
|
|
|
old_cap \<leftarrow> get_cap dest_slot;
|
|
|
|
assert (old_cap = NullCap);
|
|
|
|
set_untyped_cap_as_full src_cap new_cap src_slot;
|
|
|
|
set_cap dest_slot new_cap;
|
|
|
|
p \<leftarrow> gets $ opt_parent src_slot;
|
|
|
|
case p of
|
|
|
|
None \<Rightarrow> return ()
|
|
|
|
| Some parent \<Rightarrow> set_parent dest_slot parent
|
|
|
|
od"
|
|
|
|
|
|
|
|
(* Insert a new cap into an object. The cap will be a child. *)
|
|
|
|
definition
|
|
|
|
insert_cap_child :: "cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> cdl_cap_ref \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"insert_cap_child new_cap src_slot dest_slot \<equiv> do
|
|
|
|
src_cap \<leftarrow> get_cap src_slot;
|
|
|
|
old_cap \<leftarrow> get_cap dest_slot;
|
|
|
|
assert (old_cap = NullCap);
|
|
|
|
set_untyped_cap_as_full src_cap new_cap src_slot;
|
|
|
|
set_cap dest_slot new_cap;
|
|
|
|
set_parent dest_slot src_slot
|
|
|
|
od"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Delete an ASID pool.
|
|
|
|
*)
|
|
|
|
definition
|
2014-09-05 04:48:22 +00:00
|
|
|
delete_asid_pool :: "cdl_cnode_index \<Rightarrow> cdl_object_id \<Rightarrow> unit k_monad"
|
2014-07-14 19:32:44 +00:00
|
|
|
where
|
|
|
|
"delete_asid_pool base ptr \<equiv> do
|
|
|
|
asid_table \<leftarrow> gets cdl_asid_table;
|
2014-09-05 04:48:22 +00:00
|
|
|
asid_table' \<leftarrow> return $ asid_table (base \<mapsto> NullCap);
|
2014-07-14 19:32:44 +00:00
|
|
|
modify (\<lambda>s. s \<lparr>cdl_asid_table := asid_table'\<rparr>)
|
|
|
|
od \<sqinter> return ()"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Delete a particular ASID, decactivating the PD using it
|
|
|
|
* in the process.
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
delete_asid :: "cdl_asid \<Rightarrow> cdl_object_id \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"delete_asid asid pd \<equiv> do
|
|
|
|
asid_table \<leftarrow> gets cdl_asid_table;
|
|
|
|
case asid_table (fst asid) of
|
|
|
|
Some NullCap \<Rightarrow> return ()
|
2014-09-05 04:48:22 +00:00
|
|
|
| Some (AsidPoolCap p _) \<Rightarrow> set_cap (p, (snd asid)) NullCap
|
2014-07-14 19:32:44 +00:00
|
|
|
| _ \<Rightarrow> fail
|
|
|
|
od \<sqinter> return ()"
|
|
|
|
|
|
|
|
definition
|
|
|
|
get_irq_slot :: "cdl_irq \<Rightarrow> cdl_state \<Rightarrow> cdl_cap_ref"
|
|
|
|
where
|
|
|
|
"get_irq_slot irq s \<equiv> (cdl_irq_node s irq, 0)"
|
|
|
|
|
2019-06-05 10:18:48 +00:00
|
|
|
text \<open>Actions to be taken after deleting an IRQ Handler capability.\<close>
|
2014-07-14 19:32:44 +00:00
|
|
|
definition
|
|
|
|
deleting_irq_handler :: "cdl_irq \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"deleting_irq_handler irq \<equiv>
|
|
|
|
gets (get_irq_slot irq) >>= delete_cap_simple"
|
|
|
|
|
|
|
|
definition
|
2015-11-02 00:00:32 +00:00
|
|
|
cancel_ipc ::"cdl_object_id \<Rightarrow> unit k_monad"
|
|
|
|
where "cancel_ipc ptr \<equiv>
|
2014-07-14 19:32:44 +00:00
|
|
|
do cap \<leftarrow> KHeap_D.get_cap (ptr,tcb_pending_op_slot);
|
|
|
|
(case cap of
|
2018-11-21 10:12:08 +00:00
|
|
|
PendingSyncRecvCap _ is_reply _ \<Rightarrow> ( do
|
2014-07-14 19:32:44 +00:00
|
|
|
when is_reply $ update_thread_fault ptr (\<lambda>x. False);
|
|
|
|
revoke_cap_simple (ptr,tcb_replycap_slot);
|
|
|
|
when (\<not> is_reply) $ set_cap (ptr,tcb_pending_op_slot) NullCap
|
|
|
|
od )
|
2018-11-21 10:12:08 +00:00
|
|
|
| PendingSyncSendCap _ _ _ _ _ _ \<Rightarrow> (do
|
2014-07-14 19:32:44 +00:00
|
|
|
revoke_cap_simple (ptr,tcb_replycap_slot);
|
|
|
|
set_cap (ptr,tcb_pending_op_slot) NullCap
|
|
|
|
od)
|
2015-11-02 00:00:32 +00:00
|
|
|
| PendingNtfnRecvCap _ \<Rightarrow> (do
|
2014-07-14 19:32:44 +00:00
|
|
|
revoke_cap_simple (ptr,tcb_replycap_slot);
|
|
|
|
set_cap (ptr, tcb_pending_op_slot) NullCap
|
|
|
|
od)
|
|
|
|
| _ \<Rightarrow> return ())
|
|
|
|
od"
|
|
|
|
|
2017-02-17 05:08:34 +00:00
|
|
|
definition
|
|
|
|
prepare_thread_delete ::"cdl_object_id \<Rightarrow> unit k_monad"
|
|
|
|
where "prepare_thread_delete ptr \<equiv> return ()" (* for ARM it does nothing *)
|
2015-09-02 05:43:39 +00:00
|
|
|
|
2019-06-05 10:18:48 +00:00
|
|
|
text \<open>Actions that must be taken when a capability is deleted. Returns a
|
2014-07-14 19:32:44 +00:00
|
|
|
Zombie capability if deletion requires a long-running operation and also a
|
2019-06-05 10:18:48 +00:00
|
|
|
possible IRQ to be cleared.\<close>
|
2014-07-14 19:32:44 +00:00
|
|
|
fun
|
2018-02-07 04:08:43 +00:00
|
|
|
finalise_cap :: "cdl_cap \<Rightarrow> bool \<Rightarrow> (cdl_cap \<times> cdl_cap) k_monad"
|
2014-07-14 19:32:44 +00:00
|
|
|
where
|
2018-02-07 04:08:43 +00:00
|
|
|
"finalise_cap NullCap final = return (NullCap, NullCap)"
|
|
|
|
| "finalise_cap RestartCap final = return (NullCap, NullCap)"
|
|
|
|
| "finalise_cap (UntypedCap dev r a) final = return (NullCap, NullCap)"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "finalise_cap (EndpointCap r b R) final =
|
2018-02-07 04:08:43 +00:00
|
|
|
(liftM (K (NullCap, NullCap)) $ when final $ cancel_all_ipc r)"
|
2015-11-02 00:00:32 +00:00
|
|
|
| "finalise_cap (NotificationCap r b R) final =
|
2018-02-07 04:08:43 +00:00
|
|
|
(liftM (K (NullCap, NullCap)) $ when final $
|
2015-09-02 05:43:39 +00:00
|
|
|
do
|
2015-11-02 00:00:32 +00:00
|
|
|
unbind_maybe_notification r;
|
2017-07-12 05:13:51 +00:00
|
|
|
cancel_all_ipc r
|
2015-09-02 05:43:39 +00:00
|
|
|
od)"
|
2018-11-21 10:12:08 +00:00
|
|
|
| "finalise_cap (ReplyCap r R) final = return (NullCap, NullCap)"
|
2018-02-07 04:08:43 +00:00
|
|
|
| "finalise_cap (MasterReplyCap r) final = return (NullCap, NullCap)"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "finalise_cap (CNodeCap r bits g sz) final =
|
2018-02-07 04:08:43 +00:00
|
|
|
(return (if final then ZombieCap r else NullCap, NullCap))"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "finalise_cap (TcbCap r) final =
|
|
|
|
(do
|
2015-11-02 00:00:32 +00:00
|
|
|
when final $ (do unbind_notification r;
|
|
|
|
cancel_ipc r;
|
2017-02-17 05:08:34 +00:00
|
|
|
KHeap_D.set_cap (r, tcb_pending_op_slot) cdl_cap.NullCap;
|
|
|
|
prepare_thread_delete r od);
|
2018-02-07 04:08:43 +00:00
|
|
|
return (if final then (ZombieCap r) else NullCap, NullCap)
|
2014-07-14 19:32:44 +00:00
|
|
|
od)"
|
2018-11-21 10:12:08 +00:00
|
|
|
| "finalise_cap (PendingSyncSendCap r _ _ _ _ _) final = return (NullCap, NullCap)"
|
|
|
|
| "finalise_cap (PendingSyncRecvCap r _ _) final = return (NullCap, NullCap)"
|
2018-02-07 04:08:43 +00:00
|
|
|
| "finalise_cap (PendingNtfnRecvCap r) final = return (NullCap, NullCap)"
|
|
|
|
| "finalise_cap IrqControlCap final = return (NullCap, NullCap)"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "finalise_cap (IrqHandlerCap irq) final = (
|
|
|
|
if final then do
|
|
|
|
deleting_irq_handler irq;
|
2018-02-07 04:08:43 +00:00
|
|
|
return (NullCap, (IrqHandlerCap irq))
|
2014-07-14 19:32:44 +00:00
|
|
|
od
|
2018-02-07 04:08:43 +00:00
|
|
|
else return (NullCap, NullCap))"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "finalise_cap (ZombieCap r) final =
|
2018-02-07 04:08:43 +00:00
|
|
|
(do assert final; return (ZombieCap r, NullCap) od)"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "finalise_cap (AsidPoolCap ptr asid) final = (
|
|
|
|
if final then do
|
|
|
|
delete_asid_pool asid ptr;
|
2018-02-07 04:08:43 +00:00
|
|
|
return (NullCap, NullCap)
|
2014-07-14 19:32:44 +00:00
|
|
|
od
|
2018-02-07 04:08:43 +00:00
|
|
|
else return (NullCap, NullCap))"
|
|
|
|
| "finalise_cap AsidControlCap final = return (NullCap,NullCap)"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "finalise_cap (PageDirectoryCap ptr x (Some asid)) final = (
|
|
|
|
if final \<and> x = Real then do
|
|
|
|
delete_asid asid ptr;
|
2018-02-07 04:08:43 +00:00
|
|
|
return (NullCap, NullCap)
|
2014-07-14 19:32:44 +00:00
|
|
|
od
|
2018-02-07 04:08:43 +00:00
|
|
|
else return (NullCap, NullCap))"
|
2014-09-05 04:48:22 +00:00
|
|
|
| "finalise_cap (PageTableCap ptr x (Some asid)) final = (
|
2014-07-14 19:32:44 +00:00
|
|
|
if (final \<and> x = Real) then do
|
2014-09-05 04:48:22 +00:00
|
|
|
unmap_page_table asid ptr;
|
2018-02-07 04:08:43 +00:00
|
|
|
return (NullCap, NullCap)
|
2014-07-14 19:32:44 +00:00
|
|
|
od
|
2018-02-07 04:08:43 +00:00
|
|
|
else return (NullCap, NullCap))"
|
2016-08-12 04:24:37 +00:00
|
|
|
| "finalise_cap (FrameCap dev ptr _ s x (Some asid)) final = (
|
2014-07-14 19:32:44 +00:00
|
|
|
if x = Real then do
|
2014-09-05 04:48:22 +00:00
|
|
|
unmap_page asid ptr s;
|
2018-02-07 04:08:43 +00:00
|
|
|
return (NullCap, NullCap)
|
2014-07-14 19:32:44 +00:00
|
|
|
od
|
2018-02-07 04:08:43 +00:00
|
|
|
else return (NullCap, NullCap))"
|
|
|
|
| "finalise_cap _ final = return (NullCap, NullCap)"
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
|
2019-06-05 10:18:48 +00:00
|
|
|
text \<open>The fast_finalise operation is used to delete a capability when it is
|
2014-07-14 19:32:44 +00:00
|
|
|
known that a long-running operation is impossible. It is equivalent to calling
|
|
|
|
the regular finalise operation. It cannot be defined in that way as doing so
|
2019-06-05 10:18:48 +00:00
|
|
|
would create a circular definition.\<close>
|
2014-07-14 19:32:44 +00:00
|
|
|
lemma fast_finalise_def2:
|
|
|
|
"fast_finalise cap final = do
|
|
|
|
assert (can_fast_finalise cap);
|
|
|
|
result \<leftarrow> finalise_cap cap final;
|
2018-02-07 04:08:43 +00:00
|
|
|
assert (result = (NullCap, NullCap))
|
2014-07-14 19:32:44 +00:00
|
|
|
od"
|
2018-07-29 06:52:12 +00:00
|
|
|
unfolding can_fast_finalise_def
|
|
|
|
by (rule finalise_cap.cases[of "(cap,final)"]; simp add: assert_def liftM_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
(*
|
|
|
|
* Atomically swap the two given caps.
|
|
|
|
*)
|
|
|
|
|
|
|
|
definition
|
|
|
|
swap_cap :: "cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"swap_cap cap1 slot1 cap2 slot2 \<equiv> do
|
|
|
|
set_cap slot1 cap2;
|
|
|
|
set_cap slot2 cap1;
|
|
|
|
swap_parents slot1 slot2
|
|
|
|
od"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Move the given cap from one location to another,
|
|
|
|
* possibly modifying it along the way.
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
move_cap :: "cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> cdl_cap_ref \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"move_cap cap src_slot dest_slot \<equiv> do
|
|
|
|
insert_cap_orphan cap dest_slot;
|
|
|
|
set_cap src_slot NullCap;
|
|
|
|
swap_parents src_slot dest_slot
|
|
|
|
od"
|
|
|
|
|
|
|
|
definition
|
2014-08-09 05:16:17 +00:00
|
|
|
monadic_rel_optionation_form :: "('a \<Rightarrow> ('s, 'b) nondet_monad)
|
2014-07-14 19:32:44 +00:00
|
|
|
\<Rightarrow> (('a \<times> 's) option \<times> ('b \<times> 's) option) set"
|
|
|
|
where
|
2014-08-09 05:16:17 +00:00
|
|
|
"monadic_rel_optionation_form f =
|
2014-07-14 19:32:44 +00:00
|
|
|
{(x, y). (x \<noteq> None \<and> y \<noteq> None \<and> the y \<in> fst (split f (the x)))
|
|
|
|
\<or> (x \<noteq> None \<and> y = None \<and> snd (split f (the x)))
|
|
|
|
\<or> (x = None \<and> y = None)}"
|
|
|
|
|
|
|
|
definition
|
|
|
|
monadic_option_dest :: "('a \<times> 's) option set \<Rightarrow> (('a \<times> 's) set \<times> bool)"
|
|
|
|
where
|
|
|
|
"monadic_option_dest S = (Some -` S, None \<in> S)"
|
|
|
|
|
|
|
|
lemma use_option_form:
|
2014-08-09 05:16:17 +00:00
|
|
|
"f x = (\<lambda>s. monadic_option_dest (monadic_rel_optionation_form f `` {Some (x, s)}))"
|
|
|
|
by (simp add: monadic_rel_optionation_form_def monadic_option_dest_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
lemma ex_option: " (\<exists>x. P x) = ((\<exists>y. P (Some y)) \<or> P None)"
|
|
|
|
apply safe
|
|
|
|
apply (case_tac x, auto)
|
|
|
|
done
|
|
|
|
|
|
|
|
lemma use_option_form_bind:
|
|
|
|
"f x >>= g = (\<lambda>s. monadic_option_dest
|
2014-08-09 05:16:17 +00:00
|
|
|
((monadic_rel_optionation_form f O monadic_rel_optionation_form g) `` {Some (x, s)}))"
|
2014-07-14 19:32:44 +00:00
|
|
|
apply (rule ext)
|
2014-08-09 05:16:17 +00:00
|
|
|
apply (simp add: monadic_rel_optionation_form_def monadic_option_dest_def
|
2014-07-14 19:32:44 +00:00
|
|
|
bind_def split_def)
|
2016-01-28 03:07:42 +00:00
|
|
|
apply (simp add: relcomp_unfold ex_option image_def prod_eq_iff Bex_def)
|
2014-07-14 19:32:44 +00:00
|
|
|
apply fastforce
|
|
|
|
done
|
|
|
|
|
|
|
|
definition
|
|
|
|
monadic_trancl :: "('a \<Rightarrow> ('s, 'a) nondet_monad)
|
|
|
|
\<Rightarrow> 'a \<Rightarrow> ('s, 'a) nondet_monad"
|
|
|
|
where
|
2014-08-09 05:16:17 +00:00
|
|
|
"monadic_trancl f x = (\<lambda>s. monadic_option_dest ((monadic_rel_optionation_form f)\<^sup>* `` {Some (x, s)}))"
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
definition
|
|
|
|
monadic_trancl_preemptible ::
|
|
|
|
"('a \<Rightarrow> ('s, 'e + 'a) nondet_monad)
|
|
|
|
\<Rightarrow> ('a \<Rightarrow> ('s, 'e + 'a) nondet_monad)"
|
|
|
|
where
|
|
|
|
"monadic_trancl_preemptible f x
|
|
|
|
= monadic_trancl (lift f) (Inr x)"
|
|
|
|
|
|
|
|
definition
|
|
|
|
cap_removeable :: "cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> cdl_state \<Rightarrow> bool"
|
|
|
|
where
|
|
|
|
"cap_removeable cap slot s =
|
|
|
|
(cap = NullCap
|
|
|
|
\<or> (\<exists>p. cap = ZombieCap p \<and> swp opt_cap s ` (({p} \<times> UNIV) - {slot})
|
|
|
|
\<subseteq> {Some NullCap, None}))"
|
|
|
|
|
|
|
|
definition
|
|
|
|
finalise_slot_inner1 :: "cdl_cap_ref \<Rightarrow> (cdl_cap \<times> bool) k_monad"
|
|
|
|
where
|
|
|
|
"finalise_slot_inner1 victim = do
|
|
|
|
cap \<leftarrow> get_cap victim;
|
|
|
|
final \<leftarrow> is_final_cap cap;
|
|
|
|
(cap', irqopt) \<leftarrow> finalise_cap cap final;
|
|
|
|
removeable \<leftarrow> gets $ cap_removeable cap' victim;
|
|
|
|
when (\<not> removeable) (set_cap victim cap')
|
|
|
|
\<sqinter> set_cap victim cap';
|
|
|
|
return (cap', removeable)
|
|
|
|
od"
|
|
|
|
|
|
|
|
definition
|
|
|
|
get_zombie_range :: "cdl_cap \<Rightarrow> cdl_state \<Rightarrow> cdl_cap_ref set"
|
|
|
|
where
|
|
|
|
"get_zombie_range cap =
|
|
|
|
(\<lambda>s. case cap of ZombieCap p \<Rightarrow> dom (swp opt_cap s) \<inter> ({p} \<times> UNIV)
|
|
|
|
| _ \<Rightarrow> {})"
|
|
|
|
|
|
|
|
definition
|
|
|
|
swap_for_delete :: "cdl_cap_ref \<Rightarrow> cdl_cap_ref \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"swap_for_delete ptr1 ptr2 = do
|
|
|
|
cap1 \<leftarrow> get_cap ptr1;
|
|
|
|
cap2 \<leftarrow> get_cap ptr2;
|
|
|
|
swap_cap cap1 ptr1 cap2 ptr2
|
|
|
|
od"
|
|
|
|
|
|
|
|
definition
|
|
|
|
"finalise_slot_inner2 =
|
|
|
|
(\<lambda>(region, finalised).
|
|
|
|
liftE (do (victim', remove) \<leftarrow> select region;
|
|
|
|
(cap', removeable) \<leftarrow> finalise_slot_inner1 victim';
|
|
|
|
region' \<leftarrow> gets $ get_zombie_range cap';
|
|
|
|
return (region \<union> (region' \<times> {True}), if removeable then {(victim', remove)} else {})
|
|
|
|
od) \<sqinter>
|
|
|
|
liftE (do (slot, slot') \<leftarrow> select {(x, y). (x, True) \<in> region \<and> (y, True) \<in> region \<and> x \<noteq> y};
|
|
|
|
swap_for_delete slot slot';
|
|
|
|
return (region, {})
|
|
|
|
od) \<sqinter>
|
|
|
|
liftE (do victim' \<leftarrow> select {x. (x, True) \<in> finalised};
|
|
|
|
empty_slot victim';
|
|
|
|
return (region, {})
|
|
|
|
od) \<sqinter>
|
|
|
|
throw
|
|
|
|
)"
|
|
|
|
|
|
|
|
definition
|
|
|
|
finalise_slot :: "cdl_cap_ref \<Rightarrow> unit preempt_monad"
|
|
|
|
where
|
|
|
|
"finalise_slot victim = doE
|
|
|
|
(region, finalised) \<leftarrow>
|
|
|
|
monadic_trancl_preemptible finalise_slot_inner2
|
|
|
|
({(victim, False)}, {});
|
|
|
|
whenE (victim \<notin> fst ` finalised) throw
|
|
|
|
odE"
|
|
|
|
|
|
|
|
definition
|
|
|
|
delete_cap :: "cdl_cap_ref \<Rightarrow> unit preempt_monad"
|
|
|
|
where
|
|
|
|
"delete_cap victim = doE
|
|
|
|
finalise_slot victim;
|
|
|
|
liftE $ empty_slot victim
|
|
|
|
odE"
|
|
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Revoke all the descendants of the given cap.
|
|
|
|
*
|
|
|
|
* If the CDT is being modelled, this will delete all the
|
|
|
|
* descendants of the given cap. Wonderful things happen
|
|
|
|
* if we happen to, in this process, delete something
|
|
|
|
* that contains the cap we are trying to revoke.
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
revoke_cap :: "cdl_cap_ref \<Rightarrow> unit preempt_monad"
|
|
|
|
where
|
|
|
|
"revoke_cap victim = doE
|
|
|
|
fin \<leftarrow> monadic_trancl_preemptible (K (doE
|
|
|
|
S \<leftarrow> liftE $ gets $ descendants_of victim;
|
|
|
|
if S = {} then returnOk True
|
|
|
|
else doE
|
|
|
|
child \<leftarrow> liftE $ select S;
|
|
|
|
cap \<leftarrow> liftE $ get_cap child;
|
|
|
|
assertE (cap \<noteq> NullCap);
|
|
|
|
delete_cap child;
|
|
|
|
Monads_D.throw \<sqinter> returnOk False
|
|
|
|
odE
|
|
|
|
odE)) False;
|
|
|
|
unlessE fin throw
|
|
|
|
odE"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Get the badge the given thread object is using to
|
|
|
|
* perform its IPC send operation.
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
get_tcb_ep_badge :: "cdl_tcb \<Rightarrow> cdl_badge option"
|
|
|
|
where
|
|
|
|
"get_tcb_ep_badge t \<equiv>
|
|
|
|
case (cdl_tcb_caps t tcb_pending_op_slot) of
|
2018-11-21 10:12:08 +00:00
|
|
|
Some (PendingSyncSendCap _ badge _ _ _ _) \<Rightarrow> Some badge
|
2014-07-14 19:32:44 +00:00
|
|
|
| _ \<Rightarrow> None"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Cancel all pending send operations to the given endpoint
|
|
|
|
* that are using the given badge.
|
|
|
|
*)
|
|
|
|
definition
|
2015-11-02 00:00:32 +00:00
|
|
|
cancel_badged_sends :: "cdl_object_id \<Rightarrow> cdl_badge \<Rightarrow> unit k_monad"
|
2014-07-14 19:32:44 +00:00
|
|
|
where
|
2015-11-02 00:00:32 +00:00
|
|
|
"cancel_badged_sends ep badge \<equiv>
|
2014-08-09 05:16:17 +00:00
|
|
|
modify (\<lambda>s. s\<lparr>cdl_objects := map_option
|
2014-07-14 19:32:44 +00:00
|
|
|
(\<lambda>obj. case obj of
|
|
|
|
Tcb t \<Rightarrow>
|
|
|
|
if (is_thread_blocked_on_endpoint t ep
|
|
|
|
\<and> get_tcb_ep_badge t = Some badge) then
|
|
|
|
Tcb (remove_pending_operation t cdl_cap.RestartCap)
|
|
|
|
else
|
|
|
|
Tcb t
|
|
|
|
| _ \<Rightarrow> obj) \<circ> (cdl_objects s)\<rparr>)"
|
|
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Regenerate the target object.
|
|
|
|
*
|
|
|
|
* Any children of the cap are first revoked. The object
|
|
|
|
* is then reset into its original (as-if just created)
|
|
|
|
* state. But maybe not. It's complex.
|
|
|
|
*
|
|
|
|
* In the C implementation, attempting to recycle a
|
|
|
|
* non-master cap may do something that is not
|
|
|
|
* a recycle. (Should be perhaps return an error?)
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
clear_object_caps :: "cdl_object_id \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"clear_object_caps ptr = do
|
|
|
|
ptrs \<leftarrow> gets (\<lambda>s. {cptr. fst cptr = ptr \<and> opt_cap cptr s \<noteq> None});
|
|
|
|
ptrlist \<leftarrow> select {xs. set xs = ptrs \<and> distinct xs};
|
|
|
|
mapM_x empty_slot ptrlist
|
|
|
|
od"
|
|
|
|
|
|
|
|
definition cdl_default_tcb :: "cdl_object"
|
|
|
|
where "cdl_default_tcb \<equiv> Tcb \<lparr>cdl_tcb_caps =
|
|
|
|
[tcb_cspace_slot \<mapsto> cdl_cap.NullCap, tcb_vspace_slot \<mapsto> cdl_cap.NullCap, tcb_replycap_slot \<mapsto>
|
|
|
|
cdl_cap.NullCap, tcb_caller_slot \<mapsto> cdl_cap.NullCap, tcb_ipcbuffer_slot \<mapsto> cdl_cap.NullCap,
|
2015-11-02 00:00:32 +00:00
|
|
|
tcb_pending_op_slot \<mapsto> cdl_cap.NullCap, tcb_boundntfn_slot \<mapsto> cdl_cap.NullCap],
|
2014-07-14 19:32:44 +00:00
|
|
|
cdl_tcb_fault_endpoint = 0,
|
|
|
|
cdl_tcb_intent =
|
|
|
|
\<lparr>cdl_intent_op = None, cdl_intent_error = False,cdl_intent_cap = 0, cdl_intent_extras = [],
|
|
|
|
cdl_intent_recv_slot = None\<rparr>, cdl_tcb_has_fault = False, cdl_tcb_domain = minBound\<rparr>"
|
|
|
|
|
|
|
|
definition obj_tcb :: "cdl_object \<Rightarrow> cdl_tcb"
|
|
|
|
where "obj_tcb obj \<equiv> case obj of Tcb tcb \<Rightarrow> tcb"
|
|
|
|
|
|
|
|
definition tcb_caps_merge :: "cdl_tcb \<Rightarrow> cdl_tcb \<Rightarrow> cdl_tcb"
|
|
|
|
where "tcb_caps_merge regtcb captcb \<equiv> regtcb\<lparr>cdl_tcb_caps
|
2015-11-02 00:00:32 +00:00
|
|
|
:= (cdl_tcb_caps captcb)(tcb_pending_op_slot \<mapsto> the (cdl_tcb_caps regtcb tcb_pending_op_slot), tcb_boundntfn_slot \<mapsto> the (cdl_tcb_caps regtcb tcb_boundntfn_slot))\<rparr>"
|
2014-07-14 19:32:44 +00:00
|
|
|
|
|
|
|
definition merge_with_dft_tcb :: "cdl_object_id \<Rightarrow> unit k_monad"
|
|
|
|
where "merge_with_dft_tcb o_id \<equiv>
|
|
|
|
do
|
|
|
|
new_intent \<leftarrow> select UNIV;
|
|
|
|
KHeap_D.update_thread o_id (cdl_tcb_intent_update (\<lambda>x. new_intent) \<circ> (tcb_caps_merge (obj_tcb cdl_default_tcb)))
|
|
|
|
od"
|
|
|
|
|
|
|
|
fun
|
|
|
|
reset_mem_mapping :: "cdl_cap \<Rightarrow> cdl_cap"
|
|
|
|
where
|
2016-08-12 04:24:37 +00:00
|
|
|
"reset_mem_mapping (FrameCap dev p rts sz b mp) = FrameCap dev p rts sz b None"
|
2014-07-14 19:32:44 +00:00
|
|
|
| "reset_mem_mapping (PageTableCap ptr b mp) = PageTableCap ptr b None"
|
|
|
|
| "reset_mem_mapping (PageDirectoryCap ptr b ma) = PageDirectoryCap ptr b None"
|
|
|
|
| "reset_mem_mapping cap = cap"
|
|
|
|
|
2017-07-12 05:13:51 +00:00
|
|
|
|
2014-07-14 19:32:44 +00:00
|
|
|
(*
|
|
|
|
* Walk a user's CSpace to convert a user's CPTR into a cap slot.
|
|
|
|
*)
|
|
|
|
function
|
|
|
|
resolve_address_bits ::
|
|
|
|
"cdl_cap \<Rightarrow> cdl_cptr \<Rightarrow> nat \<Rightarrow> (cdl_cap_ref \<times> nat) fault_monad"
|
|
|
|
where
|
|
|
|
"resolve_address_bits cnode_cap cap_ptr remaining_size = doE
|
|
|
|
unlessE (is_cnode_cap cnode_cap) $ throw;
|
|
|
|
|
2018-06-22 14:50:46 +00:00
|
|
|
\<comment> \<open>Fetch the next level CNode.\<close>
|
2014-07-14 19:32:44 +00:00
|
|
|
cnode \<leftarrow> liftE $ get_cnode $ cap_object cnode_cap;
|
|
|
|
radix_size \<leftarrow> returnOk $ cdl_cnode_size_bits cnode;
|
|
|
|
guard_size \<leftarrow> returnOk $ cap_guard_size cnode_cap;
|
|
|
|
cap_guard \<leftarrow> returnOk $ cap_guard cnode_cap;
|
|
|
|
level_size \<leftarrow> returnOk (radix_size + guard_size);
|
|
|
|
assertE (level_size \<noteq> 0);
|
|
|
|
|
2018-06-22 14:50:46 +00:00
|
|
|
\<comment> \<open>Ensure the guard matches up.\<close>
|
2014-07-14 19:32:44 +00:00
|
|
|
guard \<leftarrow> returnOk $ (cap_ptr >> (remaining_size-guard_size)) && (mask guard_size);
|
|
|
|
unlessE (guard_size \<le> remaining_size \<and> guard = cap_guard) $ throw;
|
|
|
|
|
2018-06-22 14:50:46 +00:00
|
|
|
\<comment> \<open>Ensure we still enough unresolved bits left in our CPTR.\<close>
|
2014-07-14 19:32:44 +00:00
|
|
|
whenE (level_size > remaining_size) $ throw;
|
|
|
|
|
2018-06-22 14:50:46 +00:00
|
|
|
\<comment> \<open>Find the next slot.\<close>
|
2014-07-14 19:32:44 +00:00
|
|
|
offset \<leftarrow> returnOk $ (cap_ptr >> (remaining_size-level_size)) && (mask radix_size);
|
|
|
|
slot \<leftarrow> returnOk (cap_object cnode_cap, unat offset);
|
|
|
|
size_left \<leftarrow> returnOk (remaining_size - level_size);
|
|
|
|
if (size_left = 0) then
|
|
|
|
returnOk (slot, 0)
|
|
|
|
else
|
|
|
|
doE
|
|
|
|
next_cap \<leftarrow> liftE $ get_cap (slot);
|
|
|
|
if is_cnode_cap next_cap then
|
|
|
|
resolve_address_bits next_cap cap_ptr size_left
|
|
|
|
else
|
|
|
|
returnOk (slot, size_left)
|
|
|
|
odE
|
|
|
|
odE"
|
|
|
|
by fastforce+
|
|
|
|
|
|
|
|
termination resolve_address_bits
|
|
|
|
apply (relation "measure (\<lambda>(a,b,c). c)")
|
|
|
|
apply (auto simp: in_monad)
|
|
|
|
done
|
|
|
|
|
|
|
|
definition
|
|
|
|
lookup_slot :: "cdl_object_id \<Rightarrow> cdl_cptr \<Rightarrow> cdl_cap_ref fault_monad"
|
|
|
|
where
|
|
|
|
"lookup_slot thread cptr \<equiv>
|
|
|
|
doE
|
|
|
|
cspace_root \<leftarrow> liftE $ get_cap (thread, tcb_cspace_slot);
|
|
|
|
(slot, _) \<leftarrow> resolve_address_bits cspace_root cptr word_bits;
|
|
|
|
returnOk slot
|
|
|
|
odE"
|
|
|
|
|
|
|
|
definition
|
|
|
|
lookup_cap :: "cdl_object_id \<Rightarrow> cdl_cptr \<Rightarrow> cdl_cap fault_monad"
|
|
|
|
where
|
|
|
|
"lookup_cap thread cptr \<equiv>
|
|
|
|
doE
|
|
|
|
slot \<leftarrow> lookup_slot thread cptr;
|
|
|
|
liftE $ get_cap slot
|
|
|
|
odE"
|
|
|
|
|
|
|
|
definition
|
|
|
|
lookup_cap_and_slot :: "cdl_object_id \<Rightarrow> cdl_cptr \<Rightarrow> (cdl_cap \<times> cdl_cap_ref) fault_monad"
|
|
|
|
where
|
|
|
|
"lookup_cap_and_slot thread cptr \<equiv>
|
|
|
|
doE
|
|
|
|
slot \<leftarrow> lookup_slot thread cptr;
|
|
|
|
cap \<leftarrow> liftE $ get_cap slot;
|
|
|
|
returnOk (cap, slot)
|
|
|
|
odE"
|
|
|
|
|
|
|
|
definition
|
|
|
|
lookup_slot_for_cnode_op :: "cdl_cap \<Rightarrow> cdl_cptr \<Rightarrow> nat \<Rightarrow> cdl_cap_ref except_monad"
|
|
|
|
where
|
2016-11-03 22:15:38 +00:00
|
|
|
"lookup_slot_for_cnode_op croot cptr depth \<equiv>
|
2014-07-14 19:32:44 +00:00
|
|
|
doE
|
|
|
|
whenE (depth < 1 \<or> depth > word_bits) throw;
|
2016-11-03 22:15:38 +00:00
|
|
|
(slot, rem) \<leftarrow> fault_to_except $ resolve_address_bits croot cptr depth;
|
2014-07-14 19:32:44 +00:00
|
|
|
if rem = 0 then returnOk slot else throw
|
|
|
|
odE"
|
|
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Update the badge of a cap, masking off bits the lower specs are unable
|
|
|
|
* to store for implementation reasons.
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
badge_update :: "word32 \<Rightarrow> cdl_cap \<Rightarrow> cdl_cap"
|
|
|
|
where
|
|
|
|
"badge_update data cap \<equiv> update_cap_badge (data && mask badge_bits) cap"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Transform a capability based on a request from the user.
|
|
|
|
*
|
|
|
|
* The "data" word is interpreted differently for different cap types.
|
|
|
|
*
|
|
|
|
* We return a set of possible caps to allow for non-deterministic
|
|
|
|
* implementations, to avoid messy implementation details of the CDT
|
|
|
|
* in lower-level models.
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
|
|
definition
|
|
|
|
update_cap_data :: "bool \<Rightarrow> word32 \<Rightarrow> cdl_cap \<Rightarrow> cdl_cap k_monad"
|
|
|
|
where
|
|
|
|
"update_cap_data preserve data cap \<equiv>
|
|
|
|
return $ case cap of
|
|
|
|
EndpointCap _ b _ \<Rightarrow>
|
|
|
|
if b = 0 \<and> \<not> preserve then
|
|
|
|
badge_update data cap
|
|
|
|
else
|
|
|
|
NullCap
|
2015-11-02 00:00:32 +00:00
|
|
|
| NotificationCap _ b _ \<Rightarrow>
|
2014-07-14 19:32:44 +00:00
|
|
|
if b = 0 \<and> \<not> preserve then
|
|
|
|
badge_update data cap
|
|
|
|
else
|
|
|
|
NullCap
|
|
|
|
| CNodeCap object guard guard_size sz \<Rightarrow>
|
|
|
|
let
|
|
|
|
reserved_bits = 3;
|
|
|
|
guard_bits = 18;
|
|
|
|
guard_size_bits = 5;
|
|
|
|
|
|
|
|
new_guard_size = unat ((data >> reserved_bits) && mask guard_size_bits);
|
|
|
|
new_guard = (data >> (reserved_bits + guard_size_bits)) && mask (min (unat ((data >> reserved_bits) && mask guard_size_bits)) guard_bits)
|
|
|
|
in
|
|
|
|
if new_guard_size + sz > word_bits then NullCap else
|
|
|
|
(CNodeCap object new_guard new_guard_size sz)
|
|
|
|
| _ \<Rightarrow> cap"
|
|
|
|
|
|
|
|
(*
|
|
|
|
* Some caps may not be copied/minted. In this case the following function
|
|
|
|
* returns NullCap or throws.
|
|
|
|
*
|
|
|
|
* PageTable and PageDirectory caps may not be copied if already mapped. This is
|
|
|
|
* left out here and modelled by nondeterminism.
|
|
|
|
*)
|
|
|
|
definition
|
|
|
|
derive_cap :: "cdl_cap_ref \<Rightarrow> cdl_cap \<Rightarrow> cdl_cap except_monad"
|
|
|
|
where
|
|
|
|
"derive_cap slot cap \<equiv> case cap of
|
2016-08-12 04:24:37 +00:00
|
|
|
UntypedCap _ _ _ \<Rightarrow> doE ensure_no_children slot; returnOk cap odE
|
2018-11-21 10:12:08 +00:00
|
|
|
| ReplyCap _ _ \<Rightarrow> returnOk NullCap
|
2014-07-14 19:32:44 +00:00
|
|
|
| MasterReplyCap oref \<Rightarrow> returnOk NullCap
|
|
|
|
| IrqControlCap \<Rightarrow> returnOk NullCap
|
|
|
|
| ZombieCap _ \<Rightarrow> returnOk NullCap
|
2016-08-12 04:24:37 +00:00
|
|
|
| FrameCap dev p r sz b x \<Rightarrow> returnOk (FrameCap dev p r sz b None)
|
2014-07-14 19:32:44 +00:00
|
|
|
| PageTableCap _ _ _ \<Rightarrow> throw \<sqinter> returnOk cap
|
|
|
|
| PageDirectoryCap _ _ _ \<Rightarrow> throw \<sqinter> returnOk cap
|
|
|
|
| _ \<Rightarrow> returnOk cap"
|
|
|
|
|
2014-07-18 15:21:34 +00:00
|
|
|
|
|
|
|
(* This function is here to make it available in both Tcb_D and
|
|
|
|
PageTable_D *)
|
|
|
|
|
|
|
|
(* Modify the TCB's IpcBuffer or Registers in an arbitrary fashion. *)
|
|
|
|
definition
|
|
|
|
corrupt_tcb_intent :: "cdl_object_id \<Rightarrow> unit k_monad"
|
|
|
|
where
|
|
|
|
"corrupt_tcb_intent target_tcb \<equiv>
|
|
|
|
do
|
|
|
|
new_intent \<leftarrow> select UNIV;
|
|
|
|
update_thread target_tcb (\<lambda>t. t\<lparr>cdl_tcb_intent := new_intent\<rparr>)
|
|
|
|
od"
|
|
|
|
|
2014-07-14 19:32:44 +00:00
|
|
|
end
|