(* * Copyright 2014, General Dynamics C4 Systems * * This software may be distributed and modified according to the terms of * the GNU General Public License version 2. Note that NO WARRANTY is provided. * See "LICENSE_GPLv2.txt" for details. * * @TAG(GD_GPL) *) theory DetSchedDomainTime_AI imports "$L4V_ARCH/ArchDetSchedAux_AI" begin text {* This theory deals with the preservation of domain_list validity over kernel invocations, as well as ensuring preserving that the domain time is never zero at kernel exit. *} (* Note: domains in the domain list should also be \ maxDomain, but this is not needed right now *) definition "valid_domain_list_2 dlist \ 0 < length dlist \ (\(d,time) \ set dlist. 0 < time)" abbreviation valid_domain_list :: "det_ext state \ bool" where "valid_domain_list \ (\s. valid_domain_list_2 (domain_list s))" lemmas valid_domain_list_def = valid_domain_list_2_def section {* Preservation of domain list validity *} lemma ethread_get_wp[wp]: "\\s. etcb_at (\t. P (f t) s) ptr s\ ethread_get f ptr \P\" unfolding ethread_get_def by (wp | clarsimp simp add: get_etcb_def etcb_at'_def is_etcb_at'_def)+ (* We want wp to use ethread_get_inv before ethread_get_wp *) declare ethread_get_inv[wp del, wp] locale DetSchedDomainTime_AI = assumes finalise_cap_domain_list_inv'[wp]: "\P cap fin. \\s. P (domain_list s)\ arch_finalise_cap cap fin \\_ s. P (domain_list s)\" assumes arch_activate_idle_thread_domain_list_inv'[wp]: "\P t. \\s. P (domain_list s)\ arch_activate_idle_thread t \\_ s. P (domain_list s)\" assumes arch_switch_to_thread_domain_list_inv'[wp]: "\P t. \\s. P (domain_list s)\ arch_switch_to_thread t \\_ s. P (domain_list s)\" assumes arch_get_sanitise_register_info_domain_list_inv'[wp]: "\P t. \\s. P (domain_list s)\ arch_get_sanitise_register_info t \\_ s. P (domain_list s)\" assumes arch_switch_to_idle_thread_domain_list_inv'[wp]: "\P. \\s. P (domain_list s)\ arch_switch_to_idle_thread \\_ s. P (domain_list s)\" assumes handle_arch_fault_reply_domain_list_inv'[wp]: "\P f t x y. \\s. P (domain_list s)\ handle_arch_fault_reply f t x y \\_ s. P (domain_list s)\" assumes init_arch_objects_domain_list_inv'[wp]: "\P t p n s r. \\s. P (domain_list s)\ init_arch_objects t p n s r \\_ s. P (domain_list s)\" assumes arch_tcb_set_ipc_buffer_domain_list_inv'[wp]: "\P t p. \\s. P (domain_list s)\ arch_tcb_set_ipc_buffer t p \\_ s. P (domain_list s)\" assumes arch_post_modify_registers_domain_list_inv'[wp]: "\P t p. \\s. P (domain_list s)\ arch_post_modify_registers t p \\_ s. P (domain_list s)\" assumes arch_invoke_irq_control_domain_list_inv'[wp]: "\P i. \\s. P (domain_list s)\ arch_invoke_irq_control i \\_ s. P (domain_list s)\" assumes handle_vm_fault_domain_list_inv'[wp]: "\P t f. \\s. P (domain_list s)\ handle_vm_fault t f \\_ s. P (domain_list s)\" assumes prepare_thread_delete_domain_list_inv'[wp]: "\P t. \\s. P (domain_list s)\ prepare_thread_delete t \\_ s. P (domain_list s)\" assumes finalise_cap_domain_time_inv'[wp]: "\P cap fin. \\s. P (domain_time s)\ arch_finalise_cap cap fin \\_ s. P (domain_time s)\" assumes arch_activate_idle_thread_domain_time_inv'[wp]: "\P t. \\s. P (domain_time s)\ arch_activate_idle_thread t \\_ s. P (domain_time s)\" assumes arch_switch_to_thread_domain_time_inv'[wp]: "\P t. \\s. P (domain_time s)\ arch_switch_to_thread t \\_ s. P (domain_time s)\" assumes arch_get_sanitise_register_info_domain_time_inv'[wp]: "\P t. \\s. P (domain_time s)\ arch_get_sanitise_register_info t \\_ s. P (domain_time s)\" assumes arch_switch_to_idle_thread_domain_time_inv'[wp]: "\P. \\s. P (domain_time s)\ arch_switch_to_idle_thread \\_ s. P (domain_time s)\" assumes handle_arch_fault_reply_domain_time_inv'[wp]: "\P f t x y. \\s. P (domain_time s)\ handle_arch_fault_reply f t x y \\_ s. P (domain_time s)\" assumes init_arch_objects_domain_time_inv'[wp]: "\P t p n s r. \\s. P (domain_time s)\ init_arch_objects t p n s r \\_ s. P (domain_time s)\" assumes arch_tcb_set_ipc_buffer_domain_time_inv'[wp]: "\P t p. \\s. P (domain_time s)\ arch_tcb_set_ipc_buffer t p \\_ s. P (domain_time s)\" assumes arch_post_modify_registers_domain_time_inv'[wp]: "\P t p. \\s. P (domain_time s)\ arch_post_modify_registers t p \\_ s. P (domain_time s)\" assumes arch_invoke_irq_control_domain_time_inv'[wp]: "\P i. \\s. P (domain_time s)\ arch_invoke_irq_control i \\_ s. P (domain_time s)\" assumes handle_vm_fault_domain_time_inv'[wp]: "\P t f. \\s. P (domain_time s)\ handle_vm_fault t f \\_ s. P (domain_time s)\" assumes prepare_thread_delete_domain_time_inv'[wp]: "\P t. \\s. P (domain_time s)\ prepare_thread_delete t \\_ s. P (domain_time s)\" assumes make_arch_fault_msg_domain_time_inv'[wp]: "\P ft t. \\s. P (domain_time s)\ make_arch_fault_msg ft t \\_ s. P (domain_time s)\" assumes make_arch_fault_msg_domain_list_inv'[wp]: "\P ft t. \\s. P (domain_list s)\ make_arch_fault_msg ft t \\_ s. P (domain_list s)\" assumes arch_post_cap_deletion_domain_time_inv'[wp]: "\P ft. \\s. P (domain_time s)\ arch_post_cap_deletion ft \\_ s. P (domain_time s)\" assumes arch_post_cap_deletion_domain_list_inv'[wp]: "\P ft. \\s. P (domain_list s)\ arch_post_cap_deletion ft \\_ s. P (domain_list s)\" locale DetSchedDomainTime_AI_2 = DetSchedDomainTime_AI + assumes handle_hypervisor_fault_domain_list_inv'[wp]: "\P t f. \\s. P (domain_list s)\ handle_hypervisor_fault t f \\_ s. P (domain_list s)\" assumes handle_hypervisor_fault_domain_time_inv'[wp]: "\P t f. \\s. P (domain_time s)\ handle_hypervisor_fault t f \\_ s. P (domain_time s)\" assumes arch_perform_invocation_domain_list_inv'[wp]: "\P i. \\s. P (domain_list s)\ arch_perform_invocation i \\_ s. P (domain_list s)\" assumes arch_perform_invocation_domain_time_inv'[wp]: "\P i. \\s. P (domain_time s)\ arch_perform_invocation i \\_ s. P (domain_time s)\" assumes handle_interrupt_valid_domain_time: "\i. \\s :: det_ext state. 0 < domain_time s \ handle_interrupt i \\rv s. domain_time s = 0 \ scheduler_action s = choose_new_thread \" assumes handle_reserved_irq_some_time_inv'[wp]: "\P irq. \\s. P (domain_time s)\ handle_reserved_irq irq \\_ s. P (domain_time s)\" assumes handle_reserved_irq_domain_list_inv'[wp]: "\P irq. \\s. P (domain_list s)\ handle_reserved_irq irq \\_ s. P (domain_list s)\" context DetSchedDomainTime_AI begin crunch domain_list_inv[wp]: cap_swap_for_delete, empty_slot, get_object, get_cap, tcb_sched_action "\s. P (domain_list s)" crunch domain_list_inv[wp]: finalise_cap "\s. P (domain_list s)" (wp: crunch_wps hoare_unless_wp select_inv simp: crunch_simps) lemma rec_del_domain_list[wp]: "\\s. P (domain_list s)\ rec_del call \\rv s. P (domain_list s)\" by (wp rec_del_preservation preemption_point_inv' | simp)+ crunch domain_list_inv[wp]: cap_delete, activate_thread "\s. P (domain_list s)" crunch domain_list_inv[wp]: schedule "\s. P (domain_list s)" (wp: hoare_drop_imp simp: Let_def) end crunch (in DetSchedDomainTime_AI_2) domain_list_inv[wp]: handle_interrupt "\s. P (domain_list s)" crunch domain_list_inv[wp]: lookup_cap_and_slot, cap_insert, set_extra_badge "\s. P (domain_list s)" (wp: hoare_drop_imps) context DetSchedDomainTime_AI begin crunch domain_list_inv[wp]: do_ipc_transfer "\s. P (domain_list s)" (wp: crunch_wps simp: zipWithM_x_mapM rule: transfer_caps_loop_pres) crunch domain_list_inv[wp]: copy_mrs "\s. P (domain_list s)" crunch domain_list_inv[wp]: handle_fault "\s. P (domain_list s)" (wp: mapM_wp hoare_drop_imps simp: crunch_simps ignore:copy_mrs) crunch domain_list_inv[wp]: reply_from_kernel, create_cap, retype_region, do_reply_transfer "\s. P (domain_list s)" (wp: hoare_drop_imps) end crunch domain_list_inv[wp]: delete_objects "\s :: det_ext state. P (domain_list s)" (wp: crunch_wps simp: detype_def detype_ext_def wrap_ext_det_ext_ext_def cap_insert_ext_def ignore: freeMemory) crunch domain_list_inv[wp]: update_work_units "\s. P (domain_list s)" crunch domain_list_inv[wp]: preemption_point "\s. P (domain_list s)" (wp: select_inv OR_choiceE_weak_wp ignore: OR_choiceE) crunch domain_list_inv[wp]: reset_untyped_cap "\s. P (domain_list s)" (wp: crunch_wps hoare_unless_wp mapME_x_inv_wp select_inv simp: crunch_simps) context DetSchedDomainTime_AI begin crunch domain_list_inv[wp]: invoke_untyped "\s. P (domain_list s)" (wp: crunch_wps simp: crunch_simps mapM_x_defsym) crunch domain_list_inv[wp]: invoke_tcb, invoke_domain, invoke_irq_control, invoke_irq_handler "\s. P (domain_list s)" (wp: crunch_wps check_cap_inv) end crunch (in DetSchedDomainTime_AI_2) domain_list_inv[wp]: arch_perform_invocation "\s. P (domain_list s)" (wp: crunch_wps check_cap_inv) crunch (in DetSchedDomainTime_AI_2) domain_list_inv[wp]: handle_interrupt "\s. P (domain_list s)" crunch domain_list_inv[wp]: cap_move "\s. P (domain_list s)" context DetSchedDomainTime_AI begin lemma cap_revoke_domain_list_inv[wp]: "\(\s :: det_ext state. P (domain_list s))\ cap_revoke a \\rv s. P (domain_list s)\" by (rule cap_revoke_preservation2) (wp preemption_point_inv'|simp)+ end crunch domain_list_inv[wp]: cancel_badged_sends "\s. P (domain_list s)" (ignore: filterM clearMemory simp: filterM_mapM crunch_simps wp: crunch_wps) context DetSchedDomainTime_AI_2 begin lemma invoke_cnode_domain_list_inv[wp]: "\\s :: det_ext state. P (domain_list s)\ invoke_cnode i \\rv s. P (domain_list s) \" apply (rule hoare_pre) apply (wp crunch_wps cap_move_src_slot_Null hoare_drop_imps hoare_vcg_all_lift | wpc | simp add: invoke_cnode_def crunch_simps split del: if_split)+ done crunch domain_list_inv[wp]: perform_invocation, handle_invocation "\s. P (domain_list s)" (wp: crunch_wps syscall_valid simp: crunch_simps ignore: syscall) crunch domain_list_inv[wp]: handle_recv, handle_yield, handle_call, handle_reply, handle_vm_fault, handle_hypervisor_fault "\s. P (domain_list s)" (wp: crunch_wps simp: crunch_simps) lemma handle_event_domain_list_inv[wp]: "\\s. P (domain_list s) \ handle_event e \\_ s. P (domain_list s) \" apply (cases e, simp_all) apply (rename_tac syscall) apply (case_tac syscall, simp_all add: handle_send_def) apply wpsimp+ done (* no one modifies domain_list - supplied at compile time *) lemma call_kernel_domain_list_inv_det_ext: "\ \s. P (domain_list s) \ (call_kernel e) :: (unit,det_ext) s_monad \\_ s. P (domain_list s) \" unfolding call_kernel_def apply (wp) apply (simp add: schedule_def) apply (wpsimp wp: without_preemption_wp simp: if_apply_def2)+ done end section {* Preservation of domain time remaining *} crunch domain_time_inv[wp]: do_user_op "(\s. P (domain_time s))" (wp: select_wp) context DetSchedDomainTime_AI begin crunch domain_time_inv[wp]: get_cap, activate_thread, set_scheduler_action, tcb_sched_action "\s. P (domain_time s)" crunch domain_time_inv[wp]: guarded_switch_to "\s. P (domain_time s)" (wp: hoare_drop_imp whenE_inv) crunch domain_time_inv[wp]: choose_thread "\s. P (domain_time s)" crunch domain_time_inv[wp]: send_signal "\s. P (domain_time s)" (wp: hoare_drop_imps mapM_x_wp_inv select_wp simp: crunch_simps unless_def) crunch domain_time_inv[wp]: cap_swap_for_delete, empty_slot, get_object, get_cap, tcb_sched_action "\s. P (domain_time s)" crunch domain_time_inv[wp]: finalise_cap "\s. P (domain_time s)" (wp: crunch_wps hoare_drop_imps hoare_unless_wp select_inv mapM_wp subset_refl if_fun_split simp: crunch_simps ignore: tcb_sched_action) lemma rec_del_domain_time[wp]: "\\s. P (domain_time s)\ rec_del call \\rv s. P (domain_time s)\" by (wp rec_del_preservation preemption_point_inv' | simp)+ crunch domain_time_inv[wp]: cap_delete, activate_thread, lookup_cap_and_slot "\s. P (domain_time s)" end crunch domain_time_inv[wp]: cap_insert "\s. P (domain_time s)" (wp: hoare_drop_imps) crunch domain_time_inv[wp]: set_extra_badge "\s. P (domain_time s)" context DetSchedDomainTime_AI begin crunch domain_time_inv[wp]: do_ipc_transfer "\s. P (domain_time s)" (wp: crunch_wps simp: zipWithM_x_mapM rule: transfer_caps_loop_pres) crunch domain_time_inv[wp]: copy_mrs "\s. P (domain_time s)" crunch domain_time_inv[wp]: handle_fault "\s. P (domain_time s)" (wp: mapM_wp hoare_drop_imps simp: crunch_simps ignore:copy_mrs) crunch domain_time_inv[wp]: reply_from_kernel, create_cap, retype_region "\s. P (domain_time s)" crunch domain_time_inv[wp]: do_reply_transfer "\s. P (domain_time s)" (wp: hoare_drop_imps) end crunch domain_time_inv[wp]: delete_objects "\s :: det_ext state. P (domain_time s)" (wp: crunch_wps simp: detype_def detype_ext_def wrap_ext_det_ext_ext_def cap_insert_ext_def ignore: freeMemory) crunch domain_time_inv[wp]: update_work_units "\s. P (domain_time s)" crunch domain_time_inv[wp]: preemption_point "\s. P (domain_time s)" (wp: select_inv OR_choiceE_weak_wp ignore: OR_choiceE) crunch domain_time_inv[wp]: reset_untyped_cap "\s. P (domain_time s)" (wp: crunch_wps hoare_unless_wp mapME_x_inv_wp select_inv simp: crunch_simps) context DetSchedDomainTime_AI begin crunch domain_time_inv[wp]: invoke_untyped "\s. P (domain_time s)" (wp: crunch_wps simp: crunch_simps mapM_x_defsym) crunch domain_time_inv[wp]: invoke_tcb, invoke_domain, invoke_irq_control,invoke_irq_handler "\s. P (domain_time s)" (wp: crunch_wps check_cap_inv) end crunch domain_time_inv[wp]: cap_move "\s. P (domain_time s)" context DetSchedDomainTime_AI begin lemma cap_revoke_domain_time_inv[wp]: "\(\s :: det_ext state. P (domain_time s))\ cap_revoke a \\rv s. P (domain_time s)\" apply (rule cap_revoke_preservation2) apply (wp preemption_point_inv'|simp)+ done end crunch domain_time_inv[wp]: cancel_badged_sends "\s. P (domain_time s)" (ignore: filterM clearMemory simp: filterM_mapM crunch_simps wp: crunch_wps) context DetSchedDomainTime_AI_2 begin lemma invoke_cnode_domain_time_inv[wp]: "\\s :: det_ext state. P (domain_time s)\ invoke_cnode i \\rv s. P (domain_time s) \" apply (rule hoare_pre) apply (wp crunch_wps cap_move_src_slot_Null hoare_drop_imps hoare_vcg_all_lift | wpc | simp add: invoke_cnode_def crunch_simps split del: if_split)+ done crunch domain_time_inv[wp]: perform_invocation, handle_invocation "\s. P (domain_time s)" (wp: crunch_wps syscall_valid simp: crunch_simps ignore: syscall) crunch domain_time_inv[wp]: handle_recv, handle_yield, handle_call, handle_reply, handle_vm_fault, handle_hypervisor_fault "\s. P (domain_time s)" (wp: crunch_wps simp: crunch_simps) lemma handle_event_domain_time_inv: "\\s. P (domain_time s) \ e \ Interrupt \ handle_event e \\_ s. P (domain_time s) \" apply (cases e, simp_all) apply (rename_tac syscall) apply (case_tac syscall, simp_all add: handle_send_def) apply (wp|simp|wpc)+ done crunch domain_time_inv[wp]: send_fault_ipc, handle_call "\s. P (domain_time s)" (wp: hoare_drop_imps mapM_x_wp_inv select_wp without_preemption_wp simp: crunch_simps unless_def) end lemma next_domain_domain_time_left[wp]: "\ valid_domain_list \ next_domain \\_ s. 0 < domain_time s \" apply (rule hoare_pre) apply (simp add: next_domain_def Let_def) apply wp apply (clarsimp simp: valid_domain_list_def) apply (simp add: all_set_conv_all_nth) apply (erule_tac x="Suc (domain_index s) mod length (domain_list s)" in allE) apply clarsimp done context DetSchedDomainTime_AI begin lemma schedule_choose_new_thread_domain_time_left[wp]: "\ valid_domain_list \ schedule_choose_new_thread \\_ s. 0 < domain_time s \" unfolding schedule_choose_new_thread_def by (wpsimp simp: word_gt_0) crunch valid_domain_list: schedule_choose_new_thread valid_domain_list crunch etcb_at[wp]: tcb_sched_action "etcb_at P t" lemma schedule_domain_time_left: "\valid_domain_list and (\s. domain_time s = 0 \ scheduler_action s = choose_new_thread) \ schedule \\_ s. 0 < domain_time s \" (is "\?P\ _ \\_ . ?Q\") supply word_neq_0_conv[simp] apply (simp add: schedule_def) apply (wp|wpc)+ apply (wp hoare_drop_imp)[1] apply (wpsimp wp: gts_wp ethread_get_inv)+ apply auto done end lemma reschedule_required_valid_domain_time: "\ \ \ reschedule_required \\x s. domain_time s = 0 \ scheduler_action s = choose_new_thread\" unfolding reschedule_required_def set_scheduler_action_def by (wp hoare_vcg_imp_lift | simp | wpc)+ (* FIXME: move to where hoare_drop_imp is, add E/R variants etc *) lemma hoare_false_imp: "\P\ f \\r s. \ R r s\ \ \P\ f \\r s. R r s \ Q r s\" by (auto simp: valid_def) context DetSchedDomainTime_AI_2 begin lemma call_kernel_domain_time_inv_det_ext: "\ (\s. 0 < domain_time s) and valid_domain_list and (\s. e \ Interrupt \ ct_running s) \ (call_kernel e) :: (unit,det_ext) s_monad \\_ s. 0 < domain_time s \" unfolding call_kernel_def apply (case_tac "e = Interrupt") apply simp apply (rule hoare_pre) apply ((wp schedule_domain_time_left handle_interrupt_valid_domain_time | wpc | simp)+)[1] apply (rule_tac Q="\_ s. 0 < domain_time s \ valid_domain_list s" in hoare_strengthen_post) apply wp apply fastforce+ (* now non-interrupt case; may throw but does not touch domain_time in handle_event *) apply (wp schedule_domain_time_left without_preemption_wp handle_interrupt_valid_domain_time) apply (rule_tac Q="\_ s. 0 < domain_time s \ valid_domain_list s" in hoare_post_imp) apply fastforce apply (wp handle_event_domain_time_inv)+ apply (rule_tac Q'="\_ s. 0 < domain_time s" in hoare_post_imp_R) apply (wp handle_event_domain_time_inv) apply fastforce+ done end end