(* * Copyright 2014, General Dynamics C4 Systems * * SPDX-License-Identifier: GPL-2.0-only *) (* The TCB and thread related specifications. *) chapter "Threads and TCBs" theory Tcb_A imports TcbAcc_A Schedule_A ArchTcb_A begin context begin interpretation Arch . requalify_consts arch_activate_idle_thread sanitise_register arch_get_sanitise_register_info arch_post_modify_registers end section "Activating Threads" text \Threads that are active always have a master Reply capability to themselves stored in their reply slot. This is so that a derived Reply capability can be generated immediately if they wish to issue one. This function sets up a new master Reply capability if one does not exist.\ definition "setup_reply_master thread \ do old_cap <- get_cap (thread, tcb_cnode_index 2); when (old_cap = NullCap) $ do set_original (thread, tcb_cnode_index 2) True; set_cap (ReplyCap thread True {AllowGrant, AllowWrite}) (thread, tcb_cnode_index 2) od od" text \Reactivate a thread if it is not already running.\ definition restart :: "obj_ref \ (unit,'z::state_ext) s_monad" where "restart thread \ do state \ get_thread_state thread; when (\ runnable state \ \ idle state) $ do cancel_ipc thread; setup_reply_master thread; set_thread_state thread Restart; do_extended_op (tcb_sched_action (tcb_sched_enqueue) thread); do_extended_op (possible_switch_to thread) od od" text \This action is performed at the end of a system call immediately before control is restored to a used thread. If it needs to be restarted then its program counter is set to the operation it was performing rather than the next operation. The idle thread is handled specially.\ definition activate_thread :: "(unit,'z::state_ext) s_monad" where "activate_thread \ do thread \ gets cur_thread; state \ get_thread_state thread; (case state of Running \ return () | Restart \ (do pc \ as_user thread getRestartPC; as_user thread $ setNextPC pc; set_thread_state thread Running od) | IdleThreadState \ arch_activate_idle_thread thread | _ \ fail) od" section "Thread Message Formats" definition load_word_offs :: "obj_ref \ nat \ (machine_word,'z::state_ext) s_monad" where "load_word_offs ptr offs \ do_machine_op $ loadWord (ptr + of_nat (offs * word_size))" definition load_word_offs_word :: "obj_ref \ data \ (machine_word,'z::state_ext) s_monad" where "load_word_offs_word ptr offs \ do_machine_op $ loadWord (ptr + (offs * word_size))" text \Copy message registers from one thread to another.\ definition copy_mrs :: "obj_ref \ obj_ref option \ obj_ref \ obj_ref option \ length_type \ (length_type,'z::state_ext) s_monad" where "copy_mrs sender sbuf receiver rbuf n \ do hardware_mrs \ return $ take (unat n) msg_registers; mapM (\r. do v \ as_user sender $ getRegister r; as_user receiver $ setRegister r v od) hardware_mrs; buf_mrs \ case (sbuf, rbuf) of (Some sb_ptr, Some rb_ptr) \ mapM (\x. do v \ load_word_offs sb_ptr x; store_word_offs rb_ptr x v od) [length msg_registers + 1 ..< Suc (unat n)] | _ \ return []; return $ min n $ nat_to_len $ length hardware_mrs + length buf_mrs od" text \The ctable and vtable slots of the TCB.\ definition get_tcb_ctable_ptr :: "obj_ref \ cslot_ptr" where "get_tcb_ctable_ptr tcb_ref \ (tcb_ref, tcb_cnode_index 0)" definition get_tcb_vtable_ptr :: "obj_ref \ cslot_ptr" where "get_tcb_vtable_ptr tcb_ref \ (tcb_ref, tcb_cnode_index 1)" text \Optionally update the tcb at an address.\ definition option_update_thread :: "obj_ref \ ('a \ tcb \ tcb) \ 'a option \ (unit,'z::state_ext) s_monad" where "option_update_thread thread fn \ case_option (return ()) (\v. thread_set (fn v) thread)" text \Check that a related capability is at an address. This is done before calling @{const cap_insert} to avoid a corner case where the would-be parent of the cap to be inserted has been moved or deleted.\ definition check_cap_at :: "cap \ cslot_ptr \ (unit,'z::state_ext) s_monad \ (unit,'z::state_ext) s_monad" where "check_cap_at cap slot m \ do cap' \ get_cap slot; when (same_object_as cap cap') m od" text \Helper function for binding notifications\ definition bind_notification :: "obj_ref \ obj_ref \ (unit,'z::state_ext) s_monad" where "bind_notification tcbptr ntfnptr \ do ntfn \ get_notification ntfnptr; ntfn' \ return $ ntfn_set_bound_tcb ntfn (Some tcbptr); set_notification ntfnptr ntfn'; set_bound_notification tcbptr $ Some ntfnptr od" text \TCB capabilities confer authority to perform seven actions. A thread can request to yield its timeslice to another, to suspend or resume another, to reconfigure another thread, or to copy register sets into, out of or between other threads.\ fun invoke_tcb :: "tcb_invocation \ (data list,'z::state_ext) p_monad" where "invoke_tcb (Suspend thread) = liftE (do suspend thread; return [] od)" | "invoke_tcb (Resume thread) = liftE (do restart thread; return [] od)" | "invoke_tcb (ThreadControl target slot faultep mcp priority croot vroot buffer) = doE liftE $ option_update_thread target (tcb_fault_handler_update o K) faultep; liftE $ case mcp of None \ return() | Some (newmcp, _) \ set_mcpriority target newmcp; (case croot of None \ returnOk () | Some (new_cap, src_slot) \ doE cap_delete (target, tcb_cnode_index 0); liftE $ check_cap_at new_cap src_slot $ check_cap_at (ThreadCap target) slot $ cap_insert new_cap src_slot (target, tcb_cnode_index 0) odE); (case vroot of None \ returnOk () | Some (new_cap, src_slot) \ doE cap_delete (target, tcb_cnode_index 1); liftE $ check_cap_at new_cap src_slot $ check_cap_at (ThreadCap target) slot $ cap_insert new_cap src_slot (target, tcb_cnode_index 1) odE); (case buffer of None \ returnOk () | Some (ptr, frame) \ doE cap_delete (target, tcb_cnode_index 4); liftE $ thread_set (\t. t \ tcb_ipc_buffer := ptr \) target; liftE $ case frame of None \ return () | Some (new_cap, src_slot) \ check_cap_at new_cap src_slot $ check_cap_at (ThreadCap target) slot $ cap_insert new_cap src_slot (target, tcb_cnode_index 4); cur \ liftE $ gets cur_thread; liftE $ when (target = cur) (do_extended_op reschedule_required) odE); liftE $ case priority of None \ return() | Some (prio, _) \ do_extended_op (set_priority target prio); returnOk [] odE" | "invoke_tcb (CopyRegisters dest src suspend_source resume_target transfer_frame transfer_integer transfer_arch) = (liftE $ do when suspend_source $ suspend src; when resume_target $ restart dest; when transfer_frame $ do mapM_x (\r. do v \ as_user src $ getRegister r; as_user dest $ setRegister r v od) frame_registers; pc \ as_user dest getRestartPC; as_user dest $ setNextPC pc od; when transfer_integer $ mapM_x (\r. do v \ as_user src $ getRegister r; as_user dest $ setRegister r v od) gpRegisters; cur \ gets cur_thread; arch_post_modify_registers cur dest; when (dest = cur) (do_extended_op reschedule_required); return [] od)" | "invoke_tcb (ReadRegisters src suspend_source n arch) = (liftE $ do when suspend_source $ suspend src; self \ gets cur_thread; regs \ return (take (unat n) $ frame_registers @ gp_registers); as_user src $ mapM getRegister regs od)" | "invoke_tcb (WriteRegisters dest resume_target values arch) = (liftE $ do self \ gets cur_thread; b \ arch_get_sanitise_register_info dest; as_user dest $ do zipWithM (\r v. setRegister r (sanitise_register b r v)) (frameRegisters @ gpRegisters) values; pc \ getRestartPC; setNextPC pc od; arch_post_modify_registers self dest; when resume_target $ restart dest; when (dest = self) (do_extended_op reschedule_required); return [] od)" | "invoke_tcb (NotificationControl tcb (Some ntfnptr)) = (liftE $ do bind_notification tcb ntfnptr; return [] od)" | "invoke_tcb (NotificationControl tcb None) = (liftE $ do unbind_notification tcb; return [] od)" | "invoke_tcb (SetTLSBase tcb tls_base) = (liftE $ do as_user tcb $ setRegister tlsBaseRegister tls_base; cur \ gets cur_thread; when (tcb = cur) (do_extended_op reschedule_required); return [] od)" definition set_domain :: "obj_ref \ domain \ unit det_ext_monad" where "set_domain tptr new_dom \ do cur \ gets cur_thread; tcb_sched_action tcb_sched_dequeue tptr; thread_set_domain tptr new_dom; ts \ get_thread_state tptr; when (runnable ts) (tcb_sched_action tcb_sched_enqueue tptr); when (tptr = cur) reschedule_required od" definition invoke_domain:: "obj_ref \ domain \ (data list,'z::state_ext) p_monad" where "invoke_domain thread domain \ liftE (do do_extended_op (set_domain thread domain); return [] od)" text \Get all of the message registers, both from the sending thread's current register file and its IPC buffer.\ definition get_mrs :: "obj_ref \ obj_ref option \ message_info \ (message list,'z::state_ext) s_monad" where "get_mrs thread buf info \ do context \ thread_get (arch_tcb_get_registers o tcb_arch) thread; cpu_mrs \ return (map context msg_registers); buf_mrs \ case buf of None \ return [] | Some pptr \ mapM (\x. load_word_offs pptr x) [length msg_registers + 1 ..< Suc msg_max_length]; return (take (unat (mi_length info)) $ cpu_mrs @ buf_mrs) od" end