(* * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) * * SPDX-License-Identifier: GPL-2.0-only *) theory Schedule_DR imports Finalise_DR begin context begin interpretation Arch . (*FIXME: arch_split*) (* getActiveTCBs returns a subset of CapDL's all_active_tcbs. *) lemma getActiveTCBs_subset: "\ getActiveTCB x s' = Some y; invs s'; valid_etcbs s' \ \ x \ all_active_tcbs (transform s')" supply option.case_cong[cong] apply (clarsimp simp: all_active_tcbs_def getActiveTCB_def) apply (clarsimp simp: transform_def transform_objects_def map_add_def domIff) apply (clarsimp dest!: get_tcb_SomeD split: option.splits if_split_asm) apply (rule context_conjI) apply (clarsimp simp: restrict_map_def) apply (frule invs_valid_idle) apply (clarsimp simp: valid_idle_def pred_tcb_def2 get_tcb_def) apply (clarsimp simp: restrict_map_def split: if_split_asm) apply (clarsimp simp: transform_object_def transform_tcb_def) apply (clarsimp simp: infer_tcb_pending_op_def) apply (frule(1) valid_etcbs_tcb_etcb) apply (case_tac "tcb_state y", auto simp: tcb_pending_op_slot_def tcb_boundntfn_slot_def) done (* allActiveTCBs should be a subset of those allowed in CapDL. *) definition allActiveTCBs_relation :: "cdl_object_id set \ word32 set \ bool" where "allActiveTCBs_relation a b \ b \ a" (* allActiveTCBs correspond *) lemma allActiveTCBs_corres: "dcorres allActiveTCBs_relation \ (invs and valid_etcbs) (gets all_active_tcbs) allActiveTCBs" apply (clarsimp simp: allActiveTCBs_def gets_def) apply (clarsimp simp: corres_underlying_def) apply (clarsimp simp: exec_get split_def return_def) apply (clarsimp simp: allActiveTCBs_relation_def) apply (auto simp: getActiveTCBs_subset) done crunch idle_thread[wp]: switch_to_idle_thread "\s. P (idle_thread s)" lemma dcorres_arch_switch_to_idle_thread_return: "dcorres dc \ \ (return ()) arch_switch_to_idle_thread" apply (clarsimp simp: arch_switch_to_idle_thread_def) apply (rule corres_guard_imp) apply (rule dcorres_gets_all_param) apply (rule dcorres_set_vm_root) by simp+ lemma change_current_domain_same: "\(=) s\ change_current_domain \\\r. (=) s\" apply (clarsimp simp: change_current_domain_def exs_valid_def bind_def return_def gets_def modify_def put_def fst_def snd_def get_def select_def) apply (rule_tac x="cdl_current_domain s" in exI) apply clarsimp done lemma switch_to_idle_thread_dcorres: "dcorres dc \ (invs and valid_etcbs) (Schedule_D.switch_to_thread None) switch_to_idle_thread" apply (clarsimp simp: Schedule_D.switch_to_thread_def switch_to_idle_thread_def) apply (rule dcorres_symb_exec_r) apply (rule corres_guard_imp) apply (rule corres_split_noop_rhs) apply (rule dcorres_arch_switch_to_idle_thread_return) apply (clarsimp simp: corres_underlying_def gets_def modify_def get_def put_def do_machine_op_def select_f_def split_def bind_def in_return) apply (clarsimp simp: transform_def transform_current_thread_def transform_asid_table_def) apply assumption apply (wp | simp)+ done (* Switching to the idle thread and switching to "None" are equivalent. *) lemma change_current_domain_and_switch_to_idle_thread_dcorres: "dcorres dc \ (invs and valid_etcbs) (do _ \ change_current_domain; Schedule_D.switch_to_thread None od) switch_to_idle_thread" including no_pre apply (clarsimp simp: Schedule_D.switch_to_thread_def switch_to_idle_thread_def) apply (rule dcorres_symb_exec_r) apply (rule corres_guard_imp) apply (rule corres_symb_exec_l) apply (rule_tac R=\ in corres_split_noop_rhs) apply (rule dcorres_arch_switch_to_idle_thread_return) apply (clarsimp simp: corres_underlying_def gets_def modify_def get_def put_def do_machine_op_def select_f_def split_def bind_def in_return) apply (clarsimp simp: transform_def transform_current_thread_def transform_asid_table_def) apply assumption apply (wp change_current_domain_same | simp)+ done lemma arch_switch_to_thread_dcorres: "dcorres dc \ (invs and (\s. idle_thread s \ t) and valid_etcbs) (return ()) (arch_switch_to_thread t)" apply (clarsimp simp: arch_switch_to_thread_def) apply (rule corres_dummy_return_pl) apply (rule corres_guard_imp) apply (rule corres_split[OF dcorres_set_vm_root]) apply simp apply (rule dcorres_machine_op_noop) apply (simp add: ARM.clearExMonitor_def, wp)[1] apply (wp|simp)+ done crunch idle_thread [wp]: arch_switch_to_thread "\s. P (idle_thread s)" (simp: crunch_simps wp: crunch_wps ignore: ARM.clearExMonitor) (* * Setting the current thread. *) lemma switch_to_thread_corres: "dcorres dc \ (invs and (\s. idle_thread s \ x) and valid_etcbs) (Schedule_D.switch_to_thread (Some x)) (Schedule_A.switch_to_thread x)" apply (clarsimp simp: Schedule_D.switch_to_thread_def Schedule_A.switch_to_thread_def) apply (rule corres_dummy_return_pl) apply (rule corres_symb_exec_r) apply (rule corres_symb_exec_r) apply (rule corres_guard_imp) apply (rule corres_split[OF arch_switch_to_thread_dcorres]) apply simp apply (rule dcorres_rhs_noop_above[OF tcb_sched_action_dcorres]) apply (rule corres_modify [where P=\ and P'="\s. idle_thread s \ x"]) apply (clarsimp simp: transform_def) apply (simp add: transform_current_thread_def transform_asid_table_def) apply (wp+)[4] apply simp apply assumption apply (clarsimp|wp)+ done lemma corrupt_intents_current_thread: "cdl_current_thread (corrupt_intents x p s) = cdl_current_thread s" by (simp add: corrupt_intents_def) crunch cdl_cur: corrupt_frame "\s. cdl_current_thread s = x" (simp: corrupt_intents_current_thread) (* Switching to the active thread has no effect. *) lemma switch_to_thread_idempotent_corres: "dcorres dc (\s. cdl_current_thread s = x) \ (Schedule_D.switch_to_thread x) (return ())" apply (clarsimp simp: Schedule_D.switch_to_thread_def) apply (clarsimp simp: modify_def) apply (clarsimp simp: corres_underlying_def) apply (clarsimp simp: transform_def transform_current_thread_def) apply (clarsimp simp: in_return) apply (auto simp: in_return get_def put_def split_def bind_def)[1] done (* getActiveTCB on the idle thread always returns None. *) lemma getActiveTCB_idle: "invs s \ getActiveTCB (idle_thread s) s = None" apply (frule invs_valid_idle) apply (clarsimp simp: valid_idle_def getActiveTCB_def) apply (clarsimp simp: pred_tcb_at_def get_tcb_def get_obj_def obj_at_def) done lemma switch_to_thread_same_corres: "dcorres dc (\s. x = y) (invs and (\s. idle_thread s \ x) and valid_etcbs) (Schedule_D.switch_to_thread (Some y)) (Schedule_A.switch_to_thread x)" supply if_cong[cong] apply (clarsimp simp: Schedule_D.switch_to_thread_def Schedule_A.switch_to_thread_def) apply (rule corres_dummy_return_pl) apply (rule corres_symb_exec_r) apply (rule corres_symb_exec_r) apply (rule corres_guard_imp) apply (rule corres_split[OF arch_switch_to_thread_dcorres]) apply simp apply (rule dcorres_rhs_noop_above[OF tcb_sched_action_dcorres]) apply (rule corres_modify [where P'="\s. idle_thread s \ x"]) apply (clarsimp simp: transform_def transform_current_thread_def transform_asid_table_def) apply (simp add: transform_current_thread_def transform_asid_table_def) apply (wp+)[4] apply simp apply assumption apply (clarsimp|wp)+ done lemma set_scheduler_action_dcorres: "dcorres dc \ \ (return ()) (set_scheduler_action sa)" by (clarsimp simp: corres_underlying_def set_scheduler_action_def modify_def get_def put_def bind_def return_def) lemma switch_to_thread_None_dcorres_L: "dcorres dc (\s. cdl_current_thread s = None) \ (do _ \ change_current_domain; Schedule_D.switch_to_thread None od) (return ())" apply (auto simp: Schedule_D.switch_to_thread_def modify_def corres_underlying_def get_def put_def bind_def return_def change_current_domain_def gets_def select_def transform_def) done lemma switch_to_thread_None_dcorres: "dcorres dc \ (\s. cur_thread s = idle_thread s) (do _ \ change_current_domain; Schedule_D.switch_to_thread None od) (return ())" apply (rule_tac Q="\s. cdl_current_thread s = None" and Q'="\" in stronger_corres_guard_imp) apply (rule switch_to_thread_None_dcorres_L) apply (clarsimp simp: transform_def transform_current_thread_def)+ done lemma schedule_resume_cur_thread_dcorres_L: "\cur cur_ts. dcorres dc ((\s. \t tcb. cdl_current_thread s = Some t \ (\d. s = s \cdl_current_domain := d\) \ t \ active_tcbs_in_domain (cdl_current_domain s) s) or (\s. cdl_current_thread s = None)) \ Schedule_D.schedule (do idle_t \ gets idle_thread; assert (runnable cur_ts \ cur = idle_t) od)" unfolding Schedule_D.schedule_def apply (rule corres_either_alternate2) apply (rule corres_guard_imp) apply (rule corres_symb_exec_l_Ex) apply (clarsimp) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule dcorres_symb_exec_r) apply (clarsimp simp: assert_def) apply (rule conjI, clarsimp) apply (fold dc_def) apply (rule switch_to_thread_idempotent_corres) apply (rule conjI, clarsimp) apply (rule switch_to_thread_idempotent_corres) apply (clarsimp simp: corres_underlying_def fail_def) apply (wp | simp)+ apply (fastforce simp: select_def gets_def active_tcbs_in_domain_def bind_def return_def domIff get_def fst_def modify_def put_def change_current_domain_def) apply simp apply (rule corres_guard_imp) apply (rule dcorres_symb_exec_r) apply (clarsimp simp: assert_def) apply (rule conjI, clarsimp) apply (rule switch_to_thread_None_dcorres_L) apply (rule conjI, clarsimp) apply (rule switch_to_thread_None_dcorres_L) apply (clarsimp simp: corres_underlying_def fail_def) apply (wp | simp | fastforce)+ done lemma schedule_resume_cur_thread_dcorres: "\cur cur_ts. dcorres dc \ (\s. cur = cur_thread s \ st_tcb_at ((=) cur_ts) cur s \ valid_etcbs s \ valid_sched s \ invs s \ scheduler_action s = resume_cur_thread) Schedule_D.schedule (do idle_t \ gets idle_thread; assert (runnable cur_ts \ cur = idle_t) od)" apply (rule stronger_corres_guard_imp) apply (rule schedule_resume_cur_thread_dcorres_L) apply (case_tac "cur \ idle_thread s'") apply (clarsimp simp: valid_sched_def valid_sched_action_def is_activatable_def invs_def valid_state_def pred_tcb_at_def obj_at_def ct_in_cur_domain_def in_cur_domain_def) apply (frule(1) valid_etcbs_tcb_etcb) apply (auto simp: transform_def transform_current_thread_def all_active_tcbs_def transform_objects_def active_tcbs_in_domain_def etcb_at_def tcb_boundntfn_slot_def tcb_pending_op_slot_def map_add_def restrict_map_def option_map_def transform_object_def transform_tcb_def valid_idle_def st_tcb_def2 get_tcb_def transform_cnode_contents_def infer_tcb_pending_op_def transform_cap_def domIff st_tcb_at_kh_def obj_at_def only_idle_def split: option.splits if_split Structures_A.kernel_object.splits Structures_A.thread_state.splits)[1] (* cur = idle_thread s' *) apply (subgoal_tac "cdl_current_thread s = None") apply (clarsimp simp: transform_def transform_current_thread_def)+ done lemma schedule_switch_thread_helper: "\ valid_etcbs s; valid_sched s; invs s; scheduler_action s = switch_thread t \ \ t \ active_tcbs_in_domain (cur_domain s) (transform s)" apply (clarsimp simp: valid_sched_def valid_sched_action_def weak_valid_sched_action_def is_activatable_def invs_def valid_state_def pred_tcb_at_def obj_at_def switch_in_cur_domain_def in_cur_domain_def only_idle_def) apply (frule(1) valid_etcbs_tcb_etcb) apply (clarsimp simp: valid_idle_def pred_tcb_at_def) apply (drule_tac s="idle_thread s" in sym) apply (auto simp: transform_def transform_current_thread_def all_active_tcbs_def transform_objects_def active_tcbs_in_domain_def etcb_at_def map_add_def restrict_map_def option_map_def transform_object_def transform_tcb_def valid_idle_def pred_tcb_at_def get_tcb_def tcb_pending_op_slot_def tcb_boundntfn_slot_def transform_cnode_contents_def infer_tcb_pending_op_def transform_cap_def domIff st_tcb_at_kh_def obj_at_def only_idle_def split: option.splits if_split Structures_A.kernel_object.splits Structures_A.thread_state.splits) done lemma schedule_choose_new_thread_helper: "\ ready_queues s (cur_domain s) prio \ []; t = hd (ready_queues s (cur_domain s) prio); valid_sched_except_blocked s; invs s; scheduler_action s = choose_new_thread \ \ (\y. cdl_objects (transform s) t = Some y) \ t \ active_tcbs_in_domain (cur_domain s) (transform s)" apply (clarsimp simp: valid_sched_def valid_sched_action_def is_activatable_def invs_def valid_state_def pred_tcb_at_def obj_at_def DetSchedInvs_AI.valid_queues_def max_non_empty_queue_def only_idle_def) apply (erule_tac x="cur_domain s" in allE) apply (erule_tac x="prio" in allE) apply clarsimp apply (erule_tac x="hd (ready_queues s (cur_domain s) prio)" in ballE) apply (clarsimp simp: valid_idle_def pred_tcb_at_def) apply (drule_tac s="idle_thread s" in sym) apply (auto simp: transform_def transform_current_thread_def all_active_tcbs_def transform_objects_def active_tcbs_in_domain_def etcb_at_def is_etcb_at_def map_add_def restrict_map_def option_map_def transform_object_def transform_tcb_def valid_idle_def st_tcb_def2 get_tcb_def transform_cnode_contents_def infer_tcb_pending_op_def transform_cap_def domIff st_tcb_at_kh_def obj_at_def only_idle_def tcb_pending_op_slot_def tcb_boundntfn_slot_def split: option.splits if_split Structures_A.kernel_object.splits Structures_A.thread_state.splits) done lemma idle_thread_not_in_queue: "\ valid_idle s; DetSchedInvs_AI.valid_queues s; ready_queues s d p \ [] \ \ idle_thread s \ hd (ready_queues s d p)" apply (clarsimp simp: valid_idle_def DetSchedInvs_AI.valid_queues_def pred_tcb_at_def obj_at_def) apply (erule_tac x="d" in allE) apply (erule_tac x="p" in allE) apply clarsimp apply (erule_tac x="idle_thread s" in ballE) apply clarsimp apply (frule hd_in_set) apply clarsimp done lemma change_current_domain_dcorres: "dcorres dc \ \ change_current_domain next_domain" by (auto simp: corres_underlying_def change_current_domain_def next_domain_def bind_def return_def modify_def Let_def put_def select_def get_def transform_def trans_state_def transform_objects_def transform_cdt_def transform_current_thread_def transform_asid_table_def) lemma max_set_not_empty: "\x::'a::{linorder,finite}. f x \ [] \ f (Max {x. f x \ []}) \ []" apply (rule_tac S="{x. f x \ []}" in Max_prop) apply auto done lemma next_domain_valid_sched_except_blocked[wp]: "\ valid_sched_except_blocked and (\s. scheduler_action s = choose_new_thread)\ next_domain \ \_. valid_sched_except_blocked \" apply (simp add: next_domain_def Let_def) apply (wp, simp add: valid_sched_def valid_sched_action_2_def ct_not_in_q_2_def) done lemma schedule_def_2: "Schedule_D.schedule \ do change_current_domain; (do next_domain \ gets cdl_current_domain; threads \ gets (active_tcbs_in_domain next_domain); next_thread \ select threads; Schedule_D.switch_to_thread (Some next_thread) od \ Schedule_D.switch_to_thread None) od" unfolding Schedule_D.schedule_def apply (subst alternative_bind_distrib_2, simp) done lemma schedule_choose_new_thread_dcorres: "dcorres dc \ (\s. valid_etcbs s \ valid_sched_except_blocked s \ invs s \ scheduler_action s = choose_new_thread) Schedule_D.schedule schedule_choose_new_thread" unfolding schedule_choose_new_thread_def guarded_switch_to_def bind_assoc choose_thread_def max_non_empty_queue_def supply if_cong[cong] apply (rule dcorres_symb_exec_r, rename_tac dom_t) apply (case_tac "dom_t \ 0") apply (clarsimp) apply (rule dcorres_symb_exec_r, rename_tac cur_dom) apply (rule dcorres_symb_exec_r, rename_tac rq) apply (rule dcorres_rhs_noop_below_True[OF set_scheduler_action_dcorres]) (* No threads in ready_queues *) apply (rule corres_guard_imp) apply (rule corres_if_rhs) apply (clarsimp simp: Schedule_D.schedule_def) apply (rule corres_alternate2) apply (rule change_current_domain_and_switch_to_idle_thread_dcorres) (* Threads in ready_queues *) apply (simp only: Schedule_D.schedule_def) apply (rule corres_alternate1) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule_tac P'="\s. ready_queues s (cur_domain s) = rq \ valid_etcbs s \ valid_sched_except_blocked s \ invs s \ scheduler_action s = choose_new_thread" in stronger_corres_guard_imp) apply (rule corres_symb_exec_l_Ex) apply (clarsimp) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule switch_to_thread_same_corres) apply clarsimp apply (frule_tac prio="(Max {prio. ready_queues s' (cur_domain s') prio \ []})" in schedule_choose_new_thread_helper,simp,simp,simp,simp,simp) apply (clarsimp simp: valid_sched_def DetSchedInvs_AI.valid_queues_def max_non_empty_queue_def) apply (auto simp: select_def gets_def get_def bind_def return_def active_tcbs_in_domain_def invs_def valid_state_def valid_objs_def change_current_domain_def Schedule_D.switch_to_thread_def modify_def put_def option_map_def restrict_map_def map_add_def get_tcb_def transform_def transform_current_thread_def cur_tcb_def tcb_at_def)[1] apply (clarsimp simp: invs_def valid_state_def valid_sched_def max_non_empty_queue_def) apply (frule_tac p="Max {prio. ready_queues s' (cur_domain s') prio \ []}" in idle_thread_not_in_queue,simp,simp) apply (clarsimp) apply (wp hoare_drop_imp| simp | clarsimp simp: valid_sched_def)+ apply (frule max_set_not_empty, fastforce) apply (wp hoare_drop_imp| simp)+ (* dom_t = 0 *) apply (simp only: schedule_def_2) apply (rule corres_guard_imp) apply (rule_tac P=\ and P'=\ and R="\_. \" and R'="\_ s. valid_etcbs s \ valid_sched_except_blocked s \ invs s \ scheduler_action s = choose_new_thread" in corres_split) apply (rule change_current_domain_dcorres) apply (clarsimp) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r, rename_tac rq) apply (fold dc_def, rule dcorres_rhs_noop_below_True[OF set_scheduler_action_dcorres]) apply (rule corres_guard_imp) apply (rule corres_if_rhs) (* No threads in ready queues *) apply (rule corres_alternate2) apply (rule switch_to_idle_thread_dcorres) (* threads in ready queues *) apply (rule corres_alternate1) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule_tac P'="\s. ready_queues s (cur_domain s) = rq \ valid_etcbs s \ valid_sched_except_blocked s \ invs s \ scheduler_action s = choose_new_thread" in stronger_corres_guard_imp) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule switch_to_thread_same_corres) apply clarsimp apply (frule_tac prio="(Max {prio. ready_queues s' (cur_domain s') prio \ []})" in schedule_choose_new_thread_helper,simp,simp,simp,simp,simp) apply (clarsimp simp: invs_def valid_state_def valid_sched_def) apply (auto simp: select_def gets_def get_def bind_def return_def active_tcbs_in_domain_def invs_def valid_state_def valid_objs_def change_current_domain_def Schedule_D.switch_to_thread_def modify_def put_def option_map_def restrict_map_def map_add_def get_tcb_def transform_def transform_current_thread_def cur_tcb_def tcb_at_def)[1] apply (clarsimp simp: invs_def valid_state_def valid_sched_def max_non_empty_queue_def) apply (frule_tac p="Max {prio. ready_queues s' (cur_domain s') prio \ []}" in idle_thread_not_in_queue,simp,simp) apply (clarsimp) apply (wp hoare_drop_imp | clarsimp)+ apply (frule max_set_not_empty, fastforce) apply (wp hoare_drop_imp | clarsimp)+ apply simp apply (wp | clarsimp)+ unfolding dc_def apply (wp next_domain_valid_etcbs | simp)+ apply (wp tcb_sched_action_transform | clarsimp simp: valid_sched_def)+ done lemma schedule_choose_new_thread_dcorres_fragment: "\cur_ts cur. dcorres dc \ (\s. cur = cur_thread s \ st_tcb_at ((=) cur_ts) cur s \ valid_etcbs s \ valid_sched s \ invs s \ scheduler_action s = choose_new_thread) Schedule_D.schedule (do y \ when (runnable cur_ts) (tcb_sched_action tcb_sched_enqueue cur); schedule_choose_new_thread od)" apply (rule dcorres_symb_exec_r) apply (rule corres_guard_imp) apply (rule schedule_choose_new_thread_dcorres) apply (wp tcb_sched_action_transform| simp add: valid_sched_def st_tcb_at_def obj_at_def not_cur_thread_def| clarsimp simp: transform_def)+ done lemma dcorres_If_both: "\ dcorres r P P' h m ; dcorres r P Q' h n \ \ dcorres r P (\s. if b then P' s else Q' s) h (if b then m else n)" by (case_tac b; simp) lemma set_scheduler_action_transform: "\\ps. transform ps = cs\ set_scheduler_action a \\r s. transform s = cs\" by (clarsimp simp: set_scheduler_action_def etcb_at_def| wp )+ crunch valid_idle_etcb[wp]: set_scheduler_action valid_idle_etcb (* RHS copy-pasted from schedule_dcorres switch_thread case *) lemma schedule_switch_thread_dcorres: "dcorres dc \ (\s. cur = cur_thread s \ st_tcb_at ((=) cur_ts) cur s \ valid_etcbs s \ valid_sched s \ invs s \ scheduler_action s = switch_thread target) Schedule_D.schedule (do y <- when (runnable cur_ts) (tcb_sched_action tcb_sched_enqueue cur); it <- gets idle_thread; target_prio <- ethread_get tcb_priority target; ct_prio <- ethread_get_when (cur \ it) tcb_priority cur; fastfail <- schedule_switch_thread_fastfail cur it ct_prio target_prio; cur_dom <- gets cur_domain; highest <- gets (is_highest_prio cur_dom target_prio); if fastfail \ \ highest then do y <- tcb_sched_action tcb_sched_enqueue target; y <- set_scheduler_action choose_new_thread; schedule_choose_new_thread od else if runnable cur_ts \ ct_prio = target_prio then do y <- tcb_sched_action tcb_sched_append target; y <- set_scheduler_action choose_new_thread; schedule_choose_new_thread od else do y <- guarded_switch_to target; set_scheduler_action resume_cur_thread od od)" (is "dcorres _ _ (\s. ?PRE s) _ _") supply ethread_get_wp[wp del] apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule dcorres_If_both) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply simp apply (rule schedule_choose_new_thread_dcorres) apply (wp set_scheduler_action_transform tcb_sched_action_transform)+ apply (rule dcorres_If_both) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply simp apply (rule schedule_choose_new_thread_dcorres) apply (wp set_scheduler_action_transform tcb_sched_action_transform)+ apply (simp add: Schedule_D.schedule_def guarded_switch_to_def bind_assoc) apply (rule corres_alternate1) apply (rule_tac P=\ and P'="?PRE" in stronger_corres_guard_imp) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule dcorres_rhs_noop_below_True[OF set_scheduler_action_dcorres]) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule corres_symb_exec_l_Ex) apply (rule switch_to_thread_same_corres) apply (wpsimp wp: gts_wp hoare_drop_imp)+ apply (frule schedule_switch_thread_helper, simp,simp,simp) apply (fastforce simp: select_def gets_def get_def bind_def return_def active_tcbs_in_domain_def invs_def valid_state_def valid_objs_def change_current_domain_def Schedule_D.switch_to_thread_def modify_def put_def option_map_def restrict_map_def map_add_def get_tcb_def transform_def transform_current_thread_def cur_tcb_def tcb_at_def) apply (clarsimp) apply (frule invs_valid_idle) apply (fastforce simp: pred_tcb_at_def obj_at_def valid_idle_def valid_sched_def valid_sched_action_def weak_valid_sched_action_def) apply (wp tcb_sched_action_transform hoare_drop_imp[where f="ethread_get tcb_priority x" for x] hoare_drop_imp[where f="ethread_get_when b tcb_priority t" for b t] hoare_drop_imp[where f="gets cur_domain"] | clarsimp simp add: schedule_switch_thread_fastfail_def split del: if_split | split if_split)+ apply (fastforce elim: st_tcb_weakenE simp: valid_sched_def valid_blocked_def valid_blocked_except_def not_cur_thread_def valid_sched_action_def weak_valid_sched_action_def) apply (wp tcb_sched_action_transform, clarsimp) done (* * The schedulers correspond. * * Most of the difficulties in this proof arise from needing to dance * around differences in switching to the idle thread: The CapDL spec * switches to "None", while the abstract spec switches to an actual * thread. *) lemma schedule_dcorres: "dcorres dc \ (invs and valid_sched and valid_etcbs) Schedule_D.schedule Schedule_A.schedule" supply if_cong[cong] apply (clarsimp simp: Schedule_A.schedule_def) apply (rule dcorres_symb_exec_r) apply (rename_tac cur) apply (rule dcorres_symb_exec_r) apply (rename_tac cur_ts) apply (rule dcorres_symb_exec_r) apply (rename_tac "sa", case_tac "sa") (* sa = resume_cur_thread *) apply clarsimp apply (rule schedule_resume_cur_thread_dcorres) (* sa = switch_thread *) apply clarsimp apply (rule schedule_switch_thread_dcorres) (* sa = choose_new_thread *) apply clarsimp apply (rule schedule_choose_new_thread_dcorres_fragment) apply (wp gts_st_tcb | simp )+ done (* * The next few lemmas show that updating the register NextIP in the * tcb context of a thread does affect the state translation to capDL *) lemma get_tcb_message_info_nextPC [simp]: "get_tcb_message_info (tcb_arch_update (tcb_context_update (\ctx. ctx(NextIP := pc))) tcb) = get_tcb_message_info tcb" by (simp add: get_tcb_message_info_def arch_tcb_context_get_def msg_info_register_def ARM.msgInfoRegister_def) lemma map_msg_registers_nextPC [simp]: "map ((tcb_context tcb)(NextIP := pc)) msg_registers = map (tcb_context tcb) msg_registers" by (simp add: msg_registers_def ARM.msgRegisters_def upto_enum_red fromEnum_def toEnum_def enum_register) lemma get_ipc_buffer_words_nextPC [simp]: "get_ipc_buffer_words m (tcb_arch_update (tcb_context_update (\ctx. ctx(NextIP := pc))) tcb) = get_ipc_buffer_words m tcb" by (rule ext) (simp add: get_ipc_buffer_words_def) lemma get_tcb_mrs_nextPC [simp]: "get_tcb_mrs m (tcb_arch_update (tcb_context_update (\ctx. ctx(NextIP := pc))) tcb) = get_tcb_mrs m tcb" by (simp add: get_tcb_mrs_def Let_def arch_tcb_context_get_def) lemma transform_tcb_NextIP: "transform_tcb m t (tcb_arch_update (tcb_context_update (\ctx. ctx(NextIP:= pc))) tcb) = transform_tcb m t tcb" by (auto simp add: transform_tcb_def transform_full_intent_def Let_def cap_register_def ARM.capRegister_def arch_tcb_context_get_def) (* * setNextPC in the tcb context is not observable on the capDL level. *) lemma as_user_setNextPC_corres: "dcorres dc \ \ (return x) (as_user t (setNextPC pc))" supply option.case_cong[cong] apply (clarsimp simp: corres_underlying_def gets_the_def as_user_def setNextPC_def get_tcb_def setRegister_def simpler_modify_def select_f_def return_def in_monad set_object_def get_object_def split: option.splits Structures_A.kernel_object.splits) apply (subst tcb_context_update_aux) apply (simp add: transform_def transform_current_thread_def) apply (clarsimp simp: transform_objects_update_kheap_same_caps transform_tcb_NextIP transform_objects_update_same arch_tcb_update_aux3) done crunch transform_inv[wp]: set_thread_state_ext "\s. transform s = cs" lemma dcorres_dummy_set_thread_state_runnable: "dcorres dc \ (not_idle_thread ptr and st_tcb_at (\t. (infer_tcb_pending_op ptr t) = (infer_tcb_pending_op ptr st)) ptr) (return ()) (set_thread_state ptr st)" supply option.case_cong[cong] if_cong[cong] apply (rule wp_to_dcorres) apply (clarsimp simp:set_thread_state_def not_idle_thread_def set_object_def get_object_def | wp)+ apply (clarsimp simp:transform_def transform_current_thread_def st_tcb_at_def obj_at_def | rule ext)+ apply (clarsimp simp:transform_objects_def not_idle_thread_def dest!:get_tcb_SomeD) apply (case_tac "x = ptr") apply (clarsimp simp:transform_tcb_def) apply (clarsimp simp:restrict_map_def Map.map_add_def) done (* * Activating threads is not observable on the capDL level. *) lemma activate_thread_corres: "dcorres dc \ (ct_in_state activatable and invs and valid_etcbs) (do t \ gets cdl_current_thread; case t of Some thread \ do restart \ has_restart_cap thread; when restart $ KHeap_D.set_cap (thread,tcb_pending_op_slot) RunningCap od | None \ return () od) activate_thread" apply (simp add: activate_thread_def has_restart_cap_def gets_def bind_assoc) apply (rule dcorres_absorb_get_r) apply (rule dcorres_absorb_get_l) apply (simp add:get_thread_state_def bind_assoc thread_get_def) apply (rule dcorres_absorb_gets_the) apply (case_tac "cdl_current_thread (transform s'a) = None") apply (clarsimp simp: ct_in_state_def pred_tcb_at_def obj_at_def cdl_current_thread transform_current_thread_def valid_idle_def arch_activate_idle_thread_def split : if_splits dest!:get_tcb_SomeD invs_valid_idle) apply clarsimp apply (subgoal_tac "not_idle_thread (cur_thread s'b) s'b") prefer 2 apply (clarsimp simp:transform_def transform_current_thread_def) apply (clarsimp simp:not_idle_thread_def)+ apply (frule(1) valid_etcbs_get_tcb_get_etcb, clarsimp) apply (frule opt_object_tcb) apply simp apply simp apply (clarsimp simp:transform_tcb_def gets_def gets_the_def has_restart_cap_def get_thread_def bind_assoc cdl_current_thread transform_current_thread_def) apply (rule dcorres_absorb_get_l) apply (simp add:assert_opt_def when_def) apply (case_tac "tcb_state obj'") apply (clarsimp simp:infer_tcb_pending_op_def tcb_pending_op_slot_def tcb_boundntfn_slot_def when_def pred_tcb_at_def ct_in_state_def obj_at_def dest!:get_tcb_SomeD)+ apply (rule corres_guard_imp) apply (rule dcorres_symb_exec_r) apply (rule dcorres_symb_exec_r) apply (rule set_thread_state_corres[unfolded tcb_pending_op_slot_def]) apply simp apply (wpsimp wp: dcorres_to_wp[OF as_user_setNextPC_corres,simplified])+ apply (simp add:invs_mdb pred_tcb_at_def obj_at_def invs_valid_idle generates_pending_def not_idle_thread_def) apply (clarsimp simp:infer_tcb_pending_op_def arch_activate_idle_thread_def when_def pred_tcb_at_def ct_in_state_def obj_at_def tcb_pending_op_slot_def tcb_boundntfn_slot_def dest!:get_tcb_SomeD)+ done end end