lh-l4v/spec/capDL/Tcb_D.thy

321 lines
14 KiB
Plaintext

(*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*)
(*
* Operations on thread control blocks.
*)
theory Tcb_D
imports Invocations_D CSpace_D
begin
definition cdl_update_cnode_cap_data :: "cdl_cap \<Rightarrow> word32 \<Rightarrow> cdl_cap"
where "cdl_update_cnode_cap_data cap data \<equiv>
case cap of cdl_cap.CNodeCap oid _ _ sz \<Rightarrow> if data\<noteq>0 then
(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 CNodeCap oid new_guard new_guard_size sz)
else cap
| _ \<Rightarrow> cap"
definition cdl_same_arch_obj_as :: "cdl_cap \<Rightarrow> cdl_cap \<Rightarrow> bool"
where "cdl_same_arch_obj_as capa capb \<equiv>
case capa of AsidPoolCap x _ \<Rightarrow> (
case capb of AsidPoolCap y _ \<Rightarrow> y = x
| _ \<Rightarrow> False)
| AsidControlCap \<Rightarrow> (
case capb of AsidControlCap \<Rightarrow> True
| _ \<Rightarrow> False)
| FrameCap dev ra _ sa _ _ \<Rightarrow> (
case capb of FrameCap dev' rb _ sb _ _ \<Rightarrow> rb = ra \<and> sb = sa \<and> dev = dev'
| _ \<Rightarrow> False)
| cdl_cap.PageTableCap a _ _ \<Rightarrow> (
case capb of cdl_cap.PageTableCap b _ _ \<Rightarrow> b = a
| _ \<Rightarrow> False)
| cdl_cap.PageDirectoryCap a _ _ \<Rightarrow> (
case capb of cdl_cap.PageDirectoryCap b _ _ \<Rightarrow> b = a
| _ \<Rightarrow> False)
| _ \<Rightarrow> False"
definition
decode_tcb_invocation :: "cdl_cap \<Rightarrow> cdl_cap_ref \<Rightarrow> (cdl_cap \<times> cdl_cap_ref) list \<Rightarrow>
cdl_tcb_intent \<Rightarrow> cdl_tcb_invocation except_monad"
where
"decode_tcb_invocation target slot caps intent \<equiv> case intent of
\<comment> \<open>Read another thread's registers.\<close>
TcbReadRegistersIntent suspend flags count \<Rightarrow>
returnOk (ReadRegisters (cap_object target) suspend 0 0) \<sqinter> throw
\<comment> \<open>Write another thread's registers.\<close>
| TcbWriteRegistersIntent resume flags count regs \<Rightarrow>
returnOk (WriteRegisters (cap_object target) resume [0] 0) \<sqinter> throw
\<comment> \<open>Copy registers from one thread to another.\<close>
| TcbCopyRegistersIntent suspend_source resume_target f1 f2 f3 \<Rightarrow>
doE
(source_cap, _) \<leftarrow> throw_on_none $ get_index caps 0;
source_tcb \<leftarrow> (
case source_cap of
TcbCap x \<Rightarrow> returnOk x
| _ \<Rightarrow> throw);
target_tcb \<leftarrow> returnOk $ cap_object target;
returnOk (CopyRegisters target_tcb source_tcb suspend_source resume_target f1 f2 0)
odE \<sqinter> throw
\<comment> \<open>Suspend the target thread.\<close>
| TcbSuspendIntent \<Rightarrow>
returnOk (Suspend (cap_object target)) \<sqinter> throw
\<comment> \<open>Resume the target thread.\<close>
| TcbResumeIntent \<Rightarrow>
returnOk (Resume (cap_object target)) \<sqinter> throw
\<comment> \<open>Configure: target, fault_ep, mcp, priority, cspace_root_data, vspace_root_data, buffer\<close>
| TcbConfigureIntent fault_ep cspace_root_data vspace_root_data buffer \<Rightarrow>
doE
cspace_root \<leftarrow> throw_on_none $ get_index caps 0;
vspace_root \<leftarrow> throw_on_none $ get_index caps 1;
buffer_frame \<leftarrow> throw_on_none $ get_index caps 2;
cspace_root_cap_ref \<leftarrow> returnOk $ (cdl_update_cnode_cap_data (fst cspace_root) cspace_root_data,snd cspace_root);
vspace_root_cap_ref \<leftarrow> returnOk $ vspace_root;
buffer_frame_opt \<leftarrow> returnOk $ (if (buffer \<noteq> 0) then Some (reset_mem_mapping (fst buffer_frame), snd buffer_frame) else None);
returnOk (ThreadControl (cap_object target) slot (Some fault_ep)
(Some cspace_root_cap_ref) (Some vspace_root_cap_ref) (buffer_frame_opt))
odE \<sqinter> throw
\<comment> \<open>Modify a thread's maximum control priority.\<close>
| TcbSetMCPriorityIntent mcp \<Rightarrow>
doE
auth_cap \<leftarrow> throw_on_none $ get_index caps 0;
returnOk (ThreadControl (cap_object target) slot None None None None)
odE \<sqinter> throw
\<comment> \<open>Modify a thread's priority.\<close>
| TcbSetPriorityIntent priority \<Rightarrow>
doE
auth_cap \<leftarrow> throw_on_none $ get_index caps 0;
returnOk (ThreadControl (cap_object target) slot None None None None)
odE \<sqinter> throw
\<comment> \<open>Modify a thread's mcp and priority at the same time.\<close>
| TcbSetSchedParamsIntent mcp priority \<Rightarrow>
doE
auth_cap \<leftarrow> throw_on_none $ get_index caps 0;
returnOk (ThreadControl (cap_object target) slot None None None None)
odE \<sqinter> throw
\<comment> \<open>Modify a thread's IPC buffer.\<close>
| TcbSetIPCBufferIntent buffer \<Rightarrow>
doE
buffer_frame \<leftarrow> throw_on_none $ get_index caps 0;
buffer_frame_opt \<leftarrow> returnOk $ (if (buffer \<noteq> 0) then Some (reset_mem_mapping (fst buffer_frame), snd buffer_frame) else None);
returnOk (ThreadControl (cap_object target) slot None None None buffer_frame_opt)
odE \<sqinter> throw
\<comment> \<open>Update the various spaces (CSpace/VSpace) of a thread.\<close>
| TcbSetSpaceIntent fault_ep cspace_root_data vspace_root_data \<Rightarrow>
doE
cspace_root \<leftarrow> throw_on_none $ get_index caps 0;
vspace_root \<leftarrow> throw_on_none $ get_index caps 1;
cspace_root_cap_ref \<leftarrow> returnOk $ (cdl_update_cnode_cap_data (fst cspace_root) cspace_root_data,snd cspace_root);
vspace_root_cap_ref \<leftarrow> returnOk $ vspace_root;
returnOk (ThreadControl (cap_object target) slot (Some fault_ep)
(Some cspace_root_cap_ref) (Some vspace_root_cap_ref) None)
odE \<sqinter> throw
| TcbBindNTFNIntent \<Rightarrow> doE
(ntfn_cap, _) \<leftarrow> throw_on_none $ get_index caps 0;
returnOk (NotificationControl (cap_object target) (Some (cap_object ntfn_cap)))
odE \<sqinter> throw
| TcbUnbindNTFNIntent \<Rightarrow> returnOk (NotificationControl (cap_object target) None) \<sqinter> throw
| TCBSetTLSBaseIntent \<Rightarrow> returnOk (SetTLSBase (cap_object target)) \<sqinter> throw
"
(* Delete the given slot of a TCB. *)
definition
tcb_empty_thread_slot :: "cdl_object_id \<Rightarrow> cdl_cnode_index \<Rightarrow> unit preempt_monad"
where
"tcb_empty_thread_slot target_tcb target_slot \<equiv> doE
cap \<leftarrow> liftE $ get_cap (target_tcb,target_slot);
whenE (cap \<noteq> NullCap) $
delete_cap (target_tcb, target_slot)
odE"
(* Update the given slot of a TCB with a new cap, delete the previous
* capability that was in the slot. *)
definition
tcb_update_thread_slot :: "cdl_object_id \<Rightarrow> cdl_cap_ref \<Rightarrow> cdl_cnode_index \<Rightarrow> (cdl_cap \<times> cdl_cap_ref) \<Rightarrow> unit preempt_monad"
where
"tcb_update_thread_slot target_tcb tcb_cap_slot target_slot pcap \<equiv>
liftE (do
thread_cap \<leftarrow> get_cap tcb_cap_slot;
when (thread_cap = TcbCap target_tcb)
(insert_cap_child (fst pcap) (snd pcap) (target_tcb, target_slot)
\<sqinter> insert_cap_sibling (fst pcap) (snd pcap) (target_tcb,target_slot))
od)"
(* Update a thread's CSpace root. *)
definition
tcb_update_cspace_root :: "cdl_object_id \<Rightarrow> cdl_cap_ref \<Rightarrow> cdl_cap \<times> cdl_cap_ref \<Rightarrow> unit preempt_monad"
where
"tcb_update_cspace_root target_tcb tcb_cap_ref croot \<equiv>
doE
tcb_empty_thread_slot target_tcb tcb_cspace_slot;
src_cap \<leftarrow> liftE $ get_cap (snd croot);
whenE (is_cnode_cap src_cap \<and> (cap_object src_cap = cap_object (fst croot)))
$ tcb_update_thread_slot target_tcb tcb_cap_ref tcb_cspace_slot croot
odE"
(* Update a thread's VSpace root. *)
definition
tcb_update_vspace_root :: "cdl_object_id \<Rightarrow> cdl_cap_ref \<Rightarrow> (cdl_cap \<times> cdl_cap_ref) \<Rightarrow> unit preempt_monad"
where
"tcb_update_vspace_root target_tcb tcb_cap_ref vroot \<equiv>
doE
tcb_empty_thread_slot target_tcb tcb_vspace_slot;
src_cap \<leftarrow> liftE $ get_cap (snd vroot);
whenE (cdl_same_arch_obj_as (fst vroot) src_cap)
$ tcb_update_thread_slot target_tcb tcb_cap_ref tcb_vspace_slot vroot
odE"
(* Modify the TCB's intent to indicate an error during decode. *)
definition
mark_tcb_intent_error :: "cdl_object_id \<Rightarrow> bool \<Rightarrow> unit k_monad"
where
"mark_tcb_intent_error target_tcb has_error \<equiv>
update_thread target_tcb (\<lambda>t. (t\<lparr>cdl_tcb_intent := (cdl_tcb_intent t)\<lparr>cdl_intent_error := has_error\<rparr>\<rparr>))"
(* Update a thread's IPC buffer. *)
definition
tcb_update_ipc_buffer :: "cdl_object_id \<Rightarrow> cdl_cap_ref \<Rightarrow> (cdl_cap \<times> cdl_cap_ref) \<Rightarrow> unit preempt_monad"
where
"tcb_update_ipc_buffer target_tcb tcb_cap_ref ipc_buffer \<equiv>
doE
tcb_empty_thread_slot target_tcb tcb_ipcbuffer_slot;
liftE $ corrupt_tcb_intent target_tcb;
src_cap \<leftarrow> liftE $ get_cap (snd ipc_buffer);
whenE (cdl_same_arch_obj_as (fst ipc_buffer) src_cap)
$ tcb_update_thread_slot target_tcb tcb_cap_ref tcb_ipcbuffer_slot ipc_buffer
odE
"
(* Resume a thread, aborting any pending operation, and revoking
* any incoming reply caps. *)
definition
restart :: "cdl_object_id \<Rightarrow> unit k_monad"
where
"restart target_tcb \<equiv>
do
cap \<leftarrow> KHeap_D.get_cap (target_tcb,tcb_pending_op_slot);
when (cap \<noteq> RestartCap \<and> cap\<noteq> RunningCap)
(do
CSpace_D.cancel_ipc target_tcb;
KHeap_D.set_cap (target_tcb,tcb_replycap_slot) (cdl_cap.MasterReplyCap target_tcb);
KHeap_D.set_cap (target_tcb,tcb_pending_op_slot) (cdl_cap.RestartCap)
od)
od"
(* Suspend a thread, aborting any pending operation, and revoking
* any incoming reply caps. *)
definition
suspend :: "cdl_object_id \<Rightarrow> unit k_monad"
where
"suspend target_tcb \<equiv> CSpace_D.cancel_ipc target_tcb >>= K (KHeap_D.set_cap (target_tcb,tcb_pending_op_slot) cdl_cap.NullCap)"
definition
bind_notification :: "cdl_object_id \<Rightarrow> cdl_object_id \<Rightarrow> unit k_monad"
where
"bind_notification tcb_id ntfn_id \<equiv> set_cap (tcb_id, tcb_boundntfn_slot) (BoundNotificationCap ntfn_id)"
definition
invoke_tcb :: "cdl_tcb_invocation \<Rightarrow> unit preempt_monad"
where
"invoke_tcb params \<equiv> case params of
\<comment> \<open>Modify a thread's registers.\<close>
WriteRegisters target_tcb resume _ _ \<Rightarrow>
liftE $
do
corrupt_tcb_intent target_tcb;
when resume $ restart target_tcb
od
\<comment> \<open>Read a thread's registers.\<close>
| ReadRegisters src_tcb _ _ _ \<Rightarrow>
liftE $ suspend src_tcb \<sqinter> return ()
\<comment> \<open>Copy registers from one thread to another\<close>
| CopyRegisters target_tcb source_tcb _ _ _ _ _ \<Rightarrow>
liftE $
do
suspend source_tcb \<sqinter> return ();
restart target_tcb \<sqinter> return ();
corrupt_tcb_intent target_tcb
od
\<comment> \<open>Suspend this thread.\<close>
| Suspend target_tcb \<Rightarrow>
liftE $ suspend target_tcb \<sqinter> return ()
\<comment> \<open>Resume this thread.\<close>
| Resume target_tcb \<Rightarrow>
liftE $ restart target_tcb
\<comment> \<open>Update a thread's options.\<close>
| ThreadControl target_tcb tcb_cap_slot faultep croot vroot ipc_buffer \<Rightarrow>
doE
case faultep of
Some x \<Rightarrow> liftE $ update_thread target_tcb (\<lambda>tcb. tcb\<lparr>cdl_tcb_fault_endpoint := x\<rparr>)
| None \<Rightarrow> returnOk ();
\<comment> \<open>Possibly update CSpace\<close>
case croot of
Some x \<Rightarrow> tcb_update_cspace_root target_tcb tcb_cap_slot x
| None \<Rightarrow> returnOk ();
\<comment> \<open>Possibly update VSpace\<close>
case vroot of
Some x \<Rightarrow> tcb_update_vspace_root target_tcb tcb_cap_slot x
| None \<Rightarrow> returnOk ();
\<comment> \<open>Possibly update Ipc Buffer\<close>
case ipc_buffer of
Some x \<Rightarrow> tcb_update_ipc_buffer target_tcb tcb_cap_slot x
| None \<Rightarrow> (returnOk () \<sqinter> (doE tcb_empty_thread_slot target_tcb tcb_ipcbuffer_slot;
liftE $ corrupt_tcb_intent target_tcb odE))
odE
| NotificationControl tcb ntfn \<Rightarrow>
liftE $ (case ntfn of
Some ntfn_id \<Rightarrow> bind_notification tcb ntfn_id
| None \<Rightarrow> unbind_notification tcb)
| SetTLSBase tcb \<Rightarrow> liftE $ corrupt_tcb_intent tcb"
definition
decode_domain_invocation :: "(cdl_cap \<times> cdl_cap_ref) list \<Rightarrow> cdl_domain_intent \<Rightarrow> cdl_domain_invocation except_monad"
where
"decode_domain_invocation caps intent \<equiv> case intent of
DomainSetIntent d \<Rightarrow> returnOk (SetDomain (cap_object (fst (hd caps))) d) \<sqinter> throw"
definition
set_domain :: "cdl_object_id \<Rightarrow> word8 \<Rightarrow> unit k_monad"
where
"set_domain tcb d \<equiv> update_thread tcb (\<lambda>t. (t\<lparr>cdl_tcb_domain := d \<rparr>))"
definition
invoke_domain :: "cdl_domain_invocation \<Rightarrow> unit preempt_monad"
where
"invoke_domain params \<equiv> case params of
SetDomain tcb d \<Rightarrow> liftE $ set_domain tcb d"
end