(* * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) * * SPDX-License-Identifier: GPL-2.0-only *) theory ArchFinalise_IF imports Finalise_IF begin context Arch begin global_naming RISCV64 named_theorems Finalise_IF_assms crunches arch_post_cap_deletion for globals_equiv[Finalise_IF_assms, wp]: "globals_equiv st" lemma dmo_maskInterrupt_reads_respects[Finalise_IF_assms]: "reads_respects aag l \ (do_machine_op (maskInterrupt m irq))" unfolding maskInterrupt_def apply (rule use_spec_ev) apply (rule do_machine_op_spec_reads_respects) apply (simp add: equiv_valid_def2) apply (rule modify_ev2) apply (fastforce simp: equiv_for_def) apply (wp modify_wp | simp)+ done lemma arch_post_cap_deletion_read_respects[Finalise_IF_assms, wp]: "reads_respects aag l \ (arch_post_cap_deletion acap)" by wpsimp lemma equiv_asid_sa_update[Finalise_IF_assms, simp]: "equiv_asid asid (scheduler_action_update f s) s' = equiv_asid asid s s'" "equiv_asid asid s (scheduler_action_update f s') = equiv_asid asid s s'" by (auto simp: equiv_asid_def) lemma equiv_asid_ready_queues_update[Finalise_IF_assms, simp]: "equiv_asid asid (ready_queues_update f s) s' = equiv_asid asid s s'" "equiv_asid asid s (ready_queues_update f s') = equiv_asid asid s s'" by (auto simp: equiv_asid_def) lemma arch_finalise_cap_makes_halted[Finalise_IF_assms]: "\invs and valid_cap (ArchObjectCap arch_cap) and (\s. ex = is_final_cap' (ArchObjectCap arch_cap) s) and cte_wp_at ((=) (ArchObjectCap arch_cap)) slot\ arch_finalise_cap arch_cap ex \\rv s. \t \ obj_refs_ac (fst rv). halted_if_tcb t s\" by (wpsimp simp: arch_finalise_cap_def) (* FIXME: move *) lemma set_object_modifies_at_most: "modifies_at_most aag {pasObjectAbs aag ptr} (\s. \ asid_pool_at ptr s \ (\asid_pool. obj \ ArchObj (ASIDPool asid_pool))) (set_object ptr obj)" apply (rule modifies_at_mostI) apply (wp set_object_equiv_but_for_labels) apply clarsimp done lemma set_thread_state_reads_respects[Finalise_IF_assms]: assumes domains_distinct: "pas_domains_distinct aag" shows "reads_respects aag l (\s. is_subject aag (cur_thread s)) (set_thread_state ref ts)" unfolding set_thread_state_def fun_app_def apply (simp add: bind_assoc[symmetric]) apply (rule pre_ev) apply (rule_tac P'=\ in bind_ev) apply (rule set_thread_state_ext_reads_respects) apply (case_tac "aag_can_read aag ref \ aag_can_affect aag l ref") apply (wp set_object_reads_respects gets_the_ev) apply (fastforce simp: get_tcb_def split: option.splits elim: reads_equivE affects_equivE equiv_forE) apply (simp add: equiv_valid_def2) apply (rule equiv_valid_rv_bind) apply (rule equiv_valid_rv_trivial) apply (wp | simp)+ apply (rule_tac P=\ and P'=\ and L="{pasObjectAbs aag ref}" and L'="{pasObjectAbs aag ref}" in ev2_invisible[OF domains_distinct]) apply (blast | simp add: labels_are_invisible_def)+ apply (rule set_object_modifies_at_most) apply (rule set_object_modifies_at_most) apply (simp | wp)+ apply (blast dest: get_tcb_not_asid_pool_at) apply (subst thread_set_def[symmetric, simplified fun_app_def]) apply (wp | simp)+ done lemma set_thread_state_runnable_reads_respects[Finalise_IF_assms]: assumes domains_distinct: "pas_domains_distinct aag" shows "runnable ts \ reads_respects aag l \ (set_thread_state ref ts)" unfolding set_thread_state_def fun_app_def apply (simp add: bind_assoc[symmetric]) apply (rule pre_ev) apply (rule_tac P'=\ in bind_ev) apply (rule set_thread_state_ext_runnable_reads_respects) apply (case_tac "aag_can_read aag ref \ aag_can_affect aag l ref") apply (wp set_object_reads_respects gets_the_ev) apply (fastforce simp: get_tcb_def split: option.splits elim: reads_equivE affects_equivE equiv_forE) apply (simp add: equiv_valid_def2) apply (rule equiv_valid_rv_bind) apply (rule equiv_valid_rv_trivial) apply (wp | simp)+ apply (rule_tac P=\ and P'=\ and L="{pasObjectAbs aag ref}" and L'="{pasObjectAbs aag ref}" in ev2_invisible[OF domains_distinct]) apply (blast | simp add: labels_are_invisible_def)+ apply (rule set_object_modifies_at_most) apply (rule set_object_modifies_at_most) apply (simp | wp)+ apply (blast dest: get_tcb_not_asid_pool_at) apply (subst thread_set_def[symmetric, simplified fun_app_def]) apply (wp thread_set_st_tcb_at | simp)+ done lemma set_bound_notification_none_reads_respects[Finalise_IF_assms]: assumes domains_distinct: "pas_domains_distinct aag" shows "reads_respects aag l \ (set_bound_notification ref None)" unfolding set_bound_notification_def fun_app_def apply (rule pre_ev(5)[where Q=\]) apply (case_tac "aag_can_read aag ref \ aag_can_affect aag l ref") apply (wp set_object_reads_respects gets_the_ev)[1] apply (fastforce simp: get_tcb_def split: option.splits elim: reads_equivE affects_equivE equiv_forE) apply (simp add: equiv_valid_def2) apply (rule equiv_valid_rv_bind) apply (rule equiv_valid_rv_trivial) apply (wp | simp)+ apply (rule_tac P=\ and P'=\ and L="{pasObjectAbs aag ref}" and L'="{pasObjectAbs aag ref}" in ev2_invisible[OF domains_distinct]) apply (blast | simp add: labels_are_invisible_def)+ apply (rule set_object_modifies_at_most) apply (rule set_object_modifies_at_most) apply (simp | wp)+ apply (blast dest: get_tcb_not_asid_pool_at) apply simp done lemma set_tcb_queue_reads_respects[Finalise_IF_assms, wp]: "reads_respects aag l \ (set_tcb_queue d prio queue)" unfolding equiv_valid_def2 equiv_valid_2_def apply (clarsimp simp: set_tcb_queue_def bind_def modify_def put_def get_def) apply (rule conjI) apply (rule reads_equiv_ready_queues_update, assumption) apply (fastforce simp: reads_equiv_def affects_equiv_def states_equiv_for_def equiv_for_def) apply (rule affects_equiv_ready_queues_update, assumption) apply (clarsimp simp: reads_equiv_def affects_equiv_def states_equiv_for_def equiv_for_def equiv_asids_def equiv_asid_def) apply (rule ext) apply force done lemma set_tcb_queue_modifies_at_most: "modifies_at_most aag L (\s. pasDomainAbs aag d \ L \ {}) (set_tcb_queue d prio queue)" apply (rule modifies_at_mostI) apply (simp add: set_tcb_queue_def modify_def, wp) apply (force simp: equiv_but_for_labels_def states_equiv_for_def equiv_for_def equiv_asids_def) done lemma set_notification_equiv_but_for_labels[Finalise_IF_assms]: "\equiv_but_for_labels aag L st and K (pasObjectAbs aag ntfnptr \ L)\ set_notification ntfnptr ntfn \\_. equiv_but_for_labels aag L st\" unfolding set_simple_ko_def apply (wp set_object_equiv_but_for_labels get_object_wp) apply (clarsimp simp: asid_pool_at_kheap partial_inv_def obj_at_def split: kernel_object.splits) done lemma thread_set_reads_respects[Finalise_IF_assms]: assumes domains_distinct[wp]: "pas_domains_distinct aag" shows "reads_respects aag l \ (thread_set x y)" unfolding thread_set_def fun_app_def apply (case_tac "aag_can_read aag y \ aag_can_affect aag l y") apply (wp set_object_reads_respects) apply (clarsimp, rule reads_affects_equiv_get_tcb_eq, simp+)[1] apply (simp add: equiv_valid_def2) apply (rule equiv_valid_rv_guard_imp) apply (rule_tac L="{pasObjectAbs aag y}" and L'="{pasObjectAbs aag y}" in ev2_invisible[OF domains_distinct]) apply (assumption | simp add: labels_are_invisible_def)+ apply (rule modifies_at_mostI[where P="\"] | wp set_object_equiv_but_for_labels | simp | (clarify, drule get_tcb_not_asid_pool_at))+ done lemma aag_cap_auth_ASIDPoolCap: "pas_cap_cur_auth aag (ArchObjectCap (ASIDPoolCap r asid)) \ pas_refined aag s \ is_subject aag r" unfolding aag_cap_auth_def by (simp add: clas_no_asid cap_auth_conferred_def arch_cap_auth_conferred_def cli_no_irqs pas_refined_all_auth_is_owns) lemma aag_cap_auth_PageDirectory: "pas_cap_cur_auth aag (ArchObjectCap (PageTableCap word (Some a))) \ pas_refined aag s \ is_subject aag word" unfolding aag_cap_auth_def by (simp add: clas_no_asid cap_auth_conferred_def arch_cap_auth_conferred_def cli_no_irqs pas_refined_all_auth_is_owns) lemma aag_cap_auth_ASIDPoolCap_asid: "\ pas_cap_cur_auth aag (ArchObjectCap (ASIDPoolCap r asid)); asid' \ 0; asid_high_bits_of asid' = asid_high_bits_of asid; pas_refined aag s \ \ is_subject_asid aag asid'" apply (frule (1) aag_cap_auth_ASIDPoolCap) apply (unfold aag_cap_auth_def) apply (rule is_subject_into_is_subject_asid) apply auto done lemma aag_cap_auth_PageCap_asid: "\ pas_cap_cur_auth aag (ArchObjectCap (FrameCap dev ref r sz (Some (a, b)))); pas_refined aag s \ \ is_subject_asid aag a" by (auto simp: aag_cap_auth_def cap_links_asid_slot_def label_owns_asid_slot_def intro: pas_refined_Control_into_is_subject_asid) lemma aag_cap_auth_PageTableCap: "\ pas_cap_cur_auth aag (ArchObjectCap (PageTableCap word option)); pas_refined aag s \ \ is_subject aag word" unfolding aag_cap_auth_def by (simp add: clas_no_asid cap_auth_conferred_def arch_cap_auth_conferred_def cli_no_irqs pas_refined_all_auth_is_owns) lemma aag_cap_auth_PageTableCap_asid: "\ pas_cap_cur_auth aag (ArchObjectCap (PageTableCap word (Some (a, b)))); pas_refined aag s \ \ is_subject_asid aag a" by (auto simp: aag_cap_auth_def cap_links_asid_slot_def label_owns_asid_slot_def intro: pas_refined_Control_into_is_subject_asid) lemma aag_cap_auth_PageDirectoryCap: "\ pas_cap_cur_auth aag (ArchObjectCap (PageTableCap word option)); pas_refined aag s \ \ is_subject aag word" unfolding aag_cap_auth_def by (simp add: clas_no_asid cap_auth_conferred_def arch_cap_auth_conferred_def cli_no_irqs pas_refined_all_auth_is_owns) lemma aag_cap_auth_PageDirectoryCap_asid: "\ pas_cap_cur_auth aag (ArchObjectCap (PageTableCap word (Some (a,vref)))); pas_refined aag s \ \ is_subject_asid aag a" unfolding aag_cap_auth_def by (auto simp: cap_links_asid_slot_def label_owns_asid_slot_def intro: pas_refined_Control_into_is_subject_asid) lemmas aag_cap_auth_subject = aag_cap_auth_ASIDPoolCap_asid aag_cap_auth_PageCap_asid aag_cap_auth_PageTableCap_asid lemma prepare_thread_delete_reads_respects_f[Finalise_IF_assms]: "reads_respects_f aag l \ (prepare_thread_delete thread)" unfolding prepare_thread_delete_def by wp lemma arch_finalise_cap_reads_respects[Finalise_IF_assms]: "reads_respects aag l (pas_refined aag and invs and cte_wp_at ((=) (ArchObjectCap cap)) slot and K (pas_cap_cur_auth aag (ArchObjectCap cap))) (arch_finalise_cap cap final)" unfolding arch_finalise_cap_def apply (rule gen_asm_ev) apply (case_tac cap) apply simp apply (simp split: bool.splits) apply (intro impI conjI) by (wp delete_asid_pool_reads_respects unmap_page_reads_respects unmap_page_table_reads_respects delete_asid_reads_respects find_vspace_for_asid_reads_respects | simp add: invs_psp_aligned invs_vspace_objs invs_valid_objs valid_cap_def valid_arch_state_asid_table invs_arch_state wellformed_mapdata_def split: option.splits bool.splits | intro impI conjI allI | elim conjE | drule cte_wp_valid_cap | fastforce dest: aag_can_read_own_asids aag_cap_auth_subject)+ (*NOTE: Required to dance around the issue of the base potentially being zero and thus we can't conclude it is in the current subject.*) lemma requiv_riscv_asid_table_asid_high_bits_of_asid_eq': "\ pas_cap_cur_auth aag (ArchObjectCap (ASIDPoolCap p b)); reads_equiv aag s t; pas_refined aag x \ \ asid_table s (asid_high_bits_of b) = asid_table t (asid_high_bits_of b)" apply (subgoal_tac "asid_high_bits_of 0 = asid_high_bits_of 1") apply (case_tac "b = 0") apply (subgoal_tac "is_subject_asid aag 1") apply ((fastforce intro: requiv_riscv_asid_table_asid_high_bits_of_asid_eq aag_cap_auth_ASIDPoolCap_asid)+)[2] apply (auto intro: requiv_riscv_asid_table_asid_high_bits_of_asid_eq aag_cap_auth_ASIDPoolCap_asid)[1] apply (simp add: asid_high_bits_of_def asid_low_bits_def) done lemma pt_cap_aligned: "\ caps_of_state s p = Some (ArchObjectCap (PageTableCap word x)); valid_caps (caps_of_state s) s \ \ is_aligned word pt_bits" by (auto simp: obj_ref_of_def pt_bits_def pageBits_def dest!: cap_aligned_valid[OF valid_capsD, unfolded cap_aligned_def, THEN conjunct1]) lemma maskInterrupt_no_mem: "maskInterrupt a b \\ms. P (underlying_memory ms)\" by (wpsimp simp: maskInterrupt_def) lemma set_irq_state_valid_global_objs: "set_irq_state state irq \valid_global_objs\" apply (simp add: set_irq_state_def) apply (wp modify_wp) apply (fastforce simp: valid_global_objs_def) done lemma set_irq_state_globals_equiv[Finalise_IF_assms]: "set_irq_state state irq \globals_equiv st\" apply (simp add: set_irq_state_def) apply (wp dmo_no_mem_globals_equiv maskInterrupt_no_mem modify_wp) apply (simp add: globals_equiv_interrupt_states_update) done lemma set_notification_globals_equiv[Finalise_IF_assms]: "\globals_equiv st and valid_arch_state\ set_notification ptr ntfn \\_. globals_equiv st\" unfolding set_simple_ko_def apply (wp set_object_globals_equiv get_object_wp) apply (fastforce simp: obj_at_def valid_arch_state_def dest: valid_global_arch_objs_pt_at) done lemma delete_asid_globals_equiv: "\globals_equiv st and valid_arch_state\ delete_asid asid pt \\_. globals_equiv st\" unfolding delete_asid_def by (wpsimp wp: set_vm_root_globals_equiv set_asid_pool_globals_equiv simp: hwASIDFlush_def) lemma arch_finalise_cap_globals_equiv[Finalise_IF_assms]: "\globals_equiv st and invs and valid_arch_cap cap\ arch_finalise_cap cap b \\_. globals_equiv st\" apply (induct cap; simp add: arch_finalise_cap_def) by (wp delete_asid_pool_globals_equiv case_option_wp unmap_page_globals_equiv unmap_page_table_globals_equiv delete_asid_globals_equiv | wpc | clarsimp simp: valid_arch_cap_def wellformed_mapdata_def)+ declare arch_get_sanitise_register_info_def[simp] crunch globals_equiv[Finalise_IF_assms, wp]: prepare_thread_delete "globals_equiv st" (wp: dxo_wp_weak) lemma set_bound_notification_globals_equiv[Finalise_IF_assms]: "\globals_equiv s and valid_arch_state\ set_bound_notification ref ts \\_. globals_equiv s\" unfolding set_bound_notification_def apply (wp set_object_globals_equiv dxo_wp_weak |simp)+ apply (intro impI conjI allI) by (fastforce simp: valid_arch_state_def obj_at_def tcb_at_def2 get_tcb_def is_tcb_def dest: get_tcb_SomeD valid_global_arch_objs_pt_at split: option.splits kernel_object.splits)+ end global_interpretation Finalise_IF_1?: Finalise_IF_1 proof goal_cases interpret Arch . case 1 show ?case by (unfold_locales; (fact Finalise_IF_assms)?) qed end