1911 lines
84 KiB
Plaintext
1911 lines
84 KiB
Plaintext
(*
|
|
* Copyright 2014, General Dynamics C4 Systems
|
|
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
*)
|
|
|
|
theory VSpace_C
|
|
imports TcbAcc_C CSpace_C PSpace_C TcbQueue_C
|
|
begin
|
|
|
|
autocorres
|
|
[ skip_heap_abs, skip_word_abs,
|
|
scope = handleVMFault,
|
|
scope_depth = 0,
|
|
c_locale = kernel_all_substitute
|
|
] "../c/build/$L4V_ARCH/kernel_all.c_pp"
|
|
|
|
context begin interpretation Arch . (*FIXME: arch_split*)
|
|
|
|
lemma ccorres_name_pre_C:
|
|
"(\<And>s. s \<in> P' \<Longrightarrow> ccorres_underlying sr \<Gamma> r xf arrel axf P {s} hs f g)
|
|
\<Longrightarrow> ccorres_underlying sr \<Gamma> r xf arrel axf P P' hs f g"
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule_tac xf'=id in ccorres_abstract, rule ceqv_refl)
|
|
apply (rule_tac P="rv' \<in> P'" in ccorres_gen_asm2)
|
|
apply assumption
|
|
apply simp
|
|
apply simp
|
|
done
|
|
|
|
lemma ccorres_flip_Guard:
|
|
assumes cc: "ccorres_underlying sr \<Gamma> r xf arrel axf A C hs a (Guard F S (Guard F' S' c))"
|
|
shows "ccorres_underlying sr \<Gamma> r xf arrel axf A C hs a (Guard F' S' (Guard F S c))"
|
|
apply (rule ccorres_name_pre_C)
|
|
using cc
|
|
apply (case_tac "s \<in> (S' \<inter> S)")
|
|
apply (clarsimp simp: ccorres_underlying_def)
|
|
apply (erule exec_handlers.cases;
|
|
fastforce elim!: exec_Normal_elim_cases intro: exec_handlers.intros exec.Guard)
|
|
apply (clarsimp simp: ccorres_underlying_def)
|
|
apply (case_tac "s \<in> S")
|
|
apply (fastforce intro: exec.Guard exec.GuardFault exec_handlers.intros)
|
|
apply (fastforce intro: exec.Guard exec.GuardFault exec_handlers.intros)
|
|
done
|
|
|
|
end
|
|
|
|
context kernel_m begin
|
|
|
|
local_setup
|
|
\<open>AutoCorresModifiesProofs.new_modifies_rules "../c/build/$L4V_ARCH/kernel_all.c_pp"\<close>
|
|
|
|
lemma pageBitsForSize_le:
|
|
"pageBitsForSize x \<le> 30"
|
|
by (simp add: pageBitsForSize_def bit_simps split: vmpage_size.splits)
|
|
|
|
lemma unat_of_nat_pageBitsForSize [simp]:
|
|
"unat (of_nat (pageBitsForSize x)::machine_word) = pageBitsForSize x"
|
|
apply (subst unat_of_nat64)
|
|
apply (rule order_le_less_trans, rule pageBitsForSize_le)
|
|
apply (simp add: word_bits_def)
|
|
apply simp
|
|
done
|
|
|
|
lemma checkVPAlignment_ccorres:
|
|
"ccorres (\<lambda>a c. if to_bool c then a = Inr () else a = Inl AlignmentError) ret__unsigned_long_'
|
|
\<top>
|
|
(UNIV \<inter> \<lbrace>sz = framesize_to_H \<acute>sz \<and> \<acute>sz < 3\<rbrace> \<inter> \<lbrace>\<acute>w = w\<rbrace>)
|
|
[]
|
|
(checkVPAlignment sz w)
|
|
(Call checkVPAlignment_'proc)"
|
|
apply (cinit lift: sz_' w_')
|
|
apply (csymbr)
|
|
apply clarsimp
|
|
apply (rule ccorres_Guard [where A=\<top> and C'=UNIV])
|
|
apply (simp split: if_split)
|
|
apply (rule conjI)
|
|
apply (clarsimp simp: mask_def unlessE_def returnOk_def)
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule ccorres_return_C)
|
|
apply simp
|
|
apply simp
|
|
apply simp
|
|
apply simp
|
|
apply (simp split: if_split add: to_bool_def)
|
|
apply (clarsimp simp: mask_def unlessE_def throwError_def split: if_split)
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule ccorres_return_C)
|
|
apply simp
|
|
apply simp
|
|
apply simp
|
|
apply simp
|
|
apply (simp split: if_split add: to_bool_def)
|
|
apply (clarsimp split: if_split)
|
|
apply (simp add: word_less_nat_alt)
|
|
apply (rule order_le_less_trans, rule pageBitsForSize_le)
|
|
apply simp
|
|
done
|
|
|
|
lemma rf_asidTable:
|
|
"\<lbrakk> (\<sigma>, x) \<in> rf_sr; valid_arch_state' \<sigma>; idx \<le> mask asid_high_bits \<rbrakk>
|
|
\<Longrightarrow> case riscvKSASIDTable (ksArchState \<sigma>)
|
|
idx of
|
|
None \<Rightarrow>
|
|
index (riscvKSASIDTable_' (globals x)) (unat idx) =
|
|
NULL
|
|
| Some v \<Rightarrow>
|
|
index (riscvKSASIDTable_' (globals x)) (unat idx) = Ptr v \<and>
|
|
index (riscvKSASIDTable_' (globals x)) (unat idx) \<noteq> NULL"
|
|
apply (clarsimp simp: rf_sr_def cstate_relation_def Let_def
|
|
carch_state_relation_def
|
|
array_relation_def)
|
|
apply (drule_tac x=idx in spec)+
|
|
apply (clarsimp simp: mask_def split: option.split)
|
|
apply (drule sym, simp)
|
|
apply (simp add: option_to_ptr_def option_to_0_def)
|
|
apply (clarsimp simp: invs'_def valid_state'_def valid_arch_state'_def
|
|
valid_asid_table'_def ran_def)
|
|
done
|
|
|
|
lemma getKSASIDTable_ccorres_stuff:
|
|
"\<lbrakk> invs' \<sigma>; (\<sigma>, x) \<in> rf_sr; idx' = unat idx;
|
|
idx < 2 ^ asid_high_bits \<rbrakk>
|
|
\<Longrightarrow> case riscvKSASIDTable (ksArchState \<sigma>)
|
|
idx of
|
|
None \<Rightarrow>
|
|
index (riscvKSASIDTable_' (globals x))
|
|
idx' =
|
|
NULL
|
|
| Some v \<Rightarrow>
|
|
index (riscvKSASIDTable_' (globals x))
|
|
idx' = Ptr v \<and>
|
|
index (riscvKSASIDTable_' (globals x))
|
|
idx' \<noteq> NULL"
|
|
apply (drule rf_asidTable [where idx=idx])
|
|
apply fastforce
|
|
apply (simp add: mask_def)
|
|
apply (simp add: word_le_minus_one_leq)
|
|
apply (clarsimp split: option.splits)
|
|
done
|
|
|
|
lemma asidLowBits_handy_convs:
|
|
"sint Kernel_C.asidLowBits = 9"
|
|
"Kernel_C.asidLowBits \<noteq> 0x20"
|
|
"unat Kernel_C.asidLowBits = asid_low_bits"
|
|
by (simp add: Kernel_C.asidLowBits_def asid_low_bits_def)+
|
|
|
|
lemma rf_sr_riscvKSASIDTable:
|
|
"\<lbrakk> (s, s') \<in> rf_sr; n \<le> 2 ^ asid_high_bits - 1 \<rbrakk>
|
|
\<Longrightarrow> index (riscvKSASIDTable_' (globals s')) (unat n)
|
|
= option_to_ptr (riscvKSASIDTable (ksArchState s) n)"
|
|
by (clarsimp simp: rf_sr_def cstate_relation_def Let_def
|
|
carch_state_relation_def array_relation_def)
|
|
|
|
lemma asid_high_bits_word_bits:
|
|
"asid_high_bits < word_bits"
|
|
by (simp add: asid_high_bits_def word_bits_def)
|
|
|
|
lemma array_relation_update:
|
|
"\<lbrakk> array_relation R bnd table (arr :: 'a['b :: finite]);
|
|
x' = unat (x :: ('td :: len) word); R v v';
|
|
unat bnd < card (UNIV :: 'b set) \<rbrakk>
|
|
\<Longrightarrow> array_relation R bnd (table (x := v))
|
|
(Arrays.update arr x' v')"
|
|
by (simp add: array_relation_def word_le_nat_alt split: if_split)
|
|
|
|
definition
|
|
vm_fault_type_from_H :: "vmfault_type \<Rightarrow> machine_word"
|
|
where
|
|
"vm_fault_type_from_H fault \<equiv>
|
|
case fault of
|
|
vmfault_type.RISCVInstructionAccessFault \<Rightarrow> scast Kernel_C.RISCVInstructionAccessFault
|
|
| vmfault_type.RISCVLoadAccessFault \<Rightarrow> scast Kernel_C.RISCVLoadAccessFault
|
|
| vmfault_type.RISCVStoreAccessFault \<Rightarrow> scast Kernel_C.RISCVStoreAccessFault
|
|
| vmfault_type.RISCVInstructionPageFault \<Rightarrow> scast Kernel_C.RISCVInstructionPageFault
|
|
| vmfault_type.RISCVLoadPageFault \<Rightarrow> scast Kernel_C.RISCVLoadPageFault
|
|
| vmfault_type.RISCVStorePageFault \<Rightarrow> scast Kernel_C.RISCVStorePageFault"
|
|
|
|
lemmas vm_fault_defs_C =
|
|
Kernel_C.RISCVInstructionAccessFault_def
|
|
Kernel_C.RISCVLoadAccessFault_def
|
|
Kernel_C.RISCVStoreAccessFault_def
|
|
Kernel_C.RISCVInstructionPageFault_def
|
|
Kernel_C.RISCVLoadPageFault_def
|
|
Kernel_C.RISCVStorePageFault_def
|
|
|
|
(* FIXME: automate this *)
|
|
lemma seL4_Fault_VMFault_new'_spec:
|
|
"\<lbrace> \<lambda>s. s = \<sigma> \<rbrace> seL4_Fault_VMFault_new' addr FSR i
|
|
\<lbrace> \<lambda>r s. s = \<sigma>
|
|
\<and> seL4_Fault_VMFault_lift r = \<lparr>address_CL = addr, FSR_CL = FSR && mask 5, instructionFault_CL = i && mask 1\<rparr>
|
|
\<and> seL4_Fault_get_tag r = scast seL4_Fault_VMFault \<rbrace>"
|
|
apply (rule hoare_weaken_pre, rule hoare_strengthen_post)
|
|
apply (rule autocorres_transfer_spec_no_modifies
|
|
[where cs="undefined\<lparr>globals := \<sigma>, address_' := addr,
|
|
FSR_' := FSR, instructionFault_' := i\<rparr>",
|
|
OF seL4_Fault_VMFault_new'_def seL4_Fault_VMFault_new_spec
|
|
seL4_Fault_VMFault_new_modifies])
|
|
by auto
|
|
|
|
lemma no_fail_seL4_Fault_VMFault_new':
|
|
"no_fail \<top> (seL4_Fault_VMFault_new' addr fault i)"
|
|
apply (rule terminates_spec_no_fail'[OF seL4_Fault_VMFault_new'_def seL4_Fault_VMFault_new_spec])
|
|
apply clarsimp
|
|
apply terminates_trivial
|
|
done
|
|
|
|
lemma returnVMFault_corres:
|
|
"\<lbrakk> addr = addr'; i = i' && mask 1; fault = fault' && mask 5 \<rbrakk> \<Longrightarrow>
|
|
corres_underlying
|
|
{(x, y). cstate_relation x y} True True
|
|
(lift_rv id (\<lambda>y. ()) (\<lambda>e. e) (\<lambda>_ _. False)
|
|
(\<lambda>e f e'. f = SCAST(32 signed \<rightarrow> 64) EXCEPTION_FAULT \<and>
|
|
(\<exists>vf. e = ArchFault (VMFault (address_CL vf) [instructionFault_CL vf, FSR_CL vf])
|
|
\<and> errfault e' = Some (SeL4_Fault_VMFault vf))))
|
|
\<top> \<top>
|
|
(throwError (Fault_H.fault.ArchFault (VMFault addr [i, fault])))
|
|
(do f <- seL4_Fault_VMFault_new' addr' fault' i';
|
|
_ <- modify (current_fault_'_update (\<lambda>_. f));
|
|
e <- gets errglobals;
|
|
return (scast EXCEPTION_FAULT, e)
|
|
od)"
|
|
apply (rule corres_symb_exec_r)
|
|
apply (rename_tac vmf)
|
|
apply (rule_tac F="seL4_Fault_VMFault_lift vmf = \<lparr>address_CL = addr, FSR_CL = fault && mask 5, instructionFault_CL = i && mask 1\<rparr>
|
|
\<and> seL4_Fault_get_tag vmf = scast seL4_Fault_VMFault"
|
|
in corres_gen_asm2)
|
|
apply (rule lift_rv_throwError;
|
|
clarsimp simp: exception_defs seL4_Fault_VMFault_lift)
|
|
apply (wpsimp wp: valid_spec_to_wp'[OF seL4_Fault_VMFault_new'_spec]
|
|
no_fail_seL4_Fault_VMFault_new'
|
|
simp: mask_twice)+
|
|
done
|
|
|
|
lemma handleVMFault_ccorres:
|
|
"ccorres ((\<lambda>f ex v. ex = scast EXCEPTION_FAULT
|
|
\<and> (\<exists>vf. f = ArchFault (VMFault (address_CL vf)
|
|
[instructionFault_CL vf, FSR_CL vf])
|
|
\<and> errfault v = Some (SeL4_Fault_VMFault vf))) \<currency> \<bottom>\<bottom>)
|
|
(liftxf errstate id (K ()) ret__unsigned_long_')
|
|
\<top>
|
|
(UNIV \<inter> \<lbrace>\<acute>thread = tcb_ptr_to_ctcb_ptr thread\<rbrace>
|
|
\<inter> \<lbrace>\<acute>vm_faultType = vm_fault_type_from_H vm_fault\<rbrace>)
|
|
[]
|
|
(handleVMFault thread vm_fault)
|
|
(Call handleVMFault_'proc)"
|
|
(* FIXME: make this a real ac_init *)
|
|
apply (rule corres_to_ccorres_rv_spec_errglobals[OF _ _ refl],
|
|
rule handleVMFault'_ac_corres[simplified o_def])
|
|
prefer 3 apply simp
|
|
apply (simp add: handleVMFault_def handleVMFault'_def liftE_bindE condition_const
|
|
ucast_ucast_mask bind_assoc)
|
|
apply (rule corres_split_deprecated[OF _ read_stval_ccorres[ac]], drule sym, clarsimp)
|
|
apply (wpc; simp add: vm_fault_type_from_H_def vm_fault_defs_C
|
|
true_def false_def bind_assoc)
|
|
apply (rule returnVMFault_corres;
|
|
clarsimp simp: exception_defs mask_twice lift_rv_def mask_def vmFaultTypeFSR_def)+
|
|
apply (wpsimp simp: mask_def | terminates_trivial)+
|
|
done
|
|
|
|
lemma unat_asidLowBits [simp]:
|
|
"unat Kernel_C.asidLowBits = asidLowBits"
|
|
by (simp add: asidLowBits_def Kernel_C.asidLowBits_def asid_low_bits_def)
|
|
|
|
lemma asid_wf_eq_mask_eq:
|
|
"asid_wf asid = (asid && mask asid_bits = asid)"
|
|
by (simp add: asid_wf_def and_mask_eq_iff_le_mask)
|
|
|
|
lemma leq_asid_bits_shift:
|
|
"asid_wf x \<Longrightarrow> (x::machine_word) >> asid_low_bits \<le> mask asid_high_bits"
|
|
unfolding asid_wf_def
|
|
apply (rule word_leI)
|
|
apply (simp add: nth_shiftr word_size)
|
|
apply (rule ccontr)
|
|
apply (clarsimp simp: linorder_not_less asid_high_bits_def asid_low_bits_def)
|
|
apply (simp add: mask_def)
|
|
apply (simp add: upper_bits_unset_is_l2p_64 [symmetric])
|
|
apply (simp add: asid_bits_def word_bits_def)
|
|
apply (erule_tac x="n+9" in allE) (*asid_low_bits*)
|
|
apply (simp add: linorder_not_less)
|
|
apply (drule test_bit_size)
|
|
apply (simp add: word_size)
|
|
done
|
|
|
|
lemma ucast_asid_high_bits_is_shift:
|
|
"asid_wf asid \<Longrightarrow> ucast (asid_high_bits_of (ucast asid)) = asid >> asid_low_bits"
|
|
unfolding asid_wf_def
|
|
apply (simp add: mask_def upper_bits_unset_is_l2p_64 [symmetric])
|
|
apply (simp add: asid_high_bits_of_def mask_2pm1[symmetric] ucast_ucast_mask)
|
|
using shiftr_mask_eq[where n=9 and x=asid, simplified]
|
|
apply (simp add: asid_low_bits_def word_size asid_bits_def word_bits_def mask_def)
|
|
apply word_bitwise
|
|
apply simp
|
|
done
|
|
|
|
lemma rf_sr_asidTable_None:
|
|
"\<lbrakk> (\<sigma>, x) \<in> rf_sr; asid_wf asid; valid_arch_state' \<sigma> \<rbrakk> \<Longrightarrow>
|
|
(index (riscvKSASIDTable_' (globals x)) (unat (asid >> asid_low_bits)) = ap_Ptr 0) =
|
|
(riscvKSASIDTable (ksArchState \<sigma>) (ucast (asid_high_bits_of (ucast asid))) = None)"
|
|
apply (simp add: ucast_asid_high_bits_is_shift)
|
|
apply (clarsimp simp: rf_sr_def cstate_relation_def Let_def carch_state_relation_def)
|
|
apply (simp add: array_relation_def option_to_0_def)
|
|
apply (erule_tac x="asid >> asid_low_bits" in allE)
|
|
apply (erule impE)
|
|
apply (simp add: leq_asid_bits_shift flip: mask_2pm1)
|
|
apply (drule sym [where t="index a b" for a b])
|
|
apply (simp add: option_to_0_def option_to_ptr_def split: option.splits)
|
|
apply (clarsimp simp: valid_arch_state'_def valid_asid_table'_def ran_def)
|
|
done
|
|
|
|
lemma clift_ptr_safe:
|
|
"clift (h, x) ptr = Some a
|
|
\<Longrightarrow> ptr_safe ptr x"
|
|
by (erule lift_t_ptr_safe[where g = c_guard])
|
|
|
|
lemma clift_ptr_safe2:
|
|
"clift htd ptr = Some a
|
|
\<Longrightarrow> ptr_safe ptr (hrs_htd htd)"
|
|
by (cases htd, simp add: hrs_htd_def clift_ptr_safe)
|
|
|
|
lemma ptTranslationBits_mask_le: "(x::machine_word) && 0x1FF < 0x200"
|
|
by (word_bitwise)
|
|
|
|
lemma ptrFromPAddr_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile> {s}
|
|
Call ptrFromPAddr_'proc
|
|
\<lbrace> \<acute>ret__ptr_to_void = Ptr (ptrFromPAddr (paddr_' s) ) \<rbrace>"
|
|
apply vcg
|
|
apply (simp add: RISCV64.ptrFromPAddr_def RISCV64.pptrBase_def pptrBaseOffset_def paddrBase_def
|
|
canonical_bit_def)
|
|
done
|
|
|
|
lemma addrFromPPtr_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile> {s}
|
|
Call addrFromPPtr_'proc
|
|
\<lbrace> \<acute>ret__unsigned_long = (addrFromPPtr (ptr_val (pptr_' s)) ) \<rbrace>"
|
|
apply vcg
|
|
apply (simp add: addrFromPPtr_def RISCV64.pptrBase_def pptrBaseOffset_def paddrBase_def
|
|
canonical_bit_def)
|
|
done
|
|
|
|
lemma corres_symb_exec_unknown_r:
|
|
assumes "\<And>rv. corres_underlying sr nf nf' r P P' a (c rv)"
|
|
shows "corres_underlying sr nf nf' r P P' a (unknown >>= c)"
|
|
apply (simp add: unknown_def)
|
|
apply (rule corres_symb_exec_r[OF assms]; wp select_inv non_fail_select)
|
|
done
|
|
|
|
lemma isPageTablePTE_def2:
|
|
"isPageTablePTE pte = (\<exists>ppn global user. pte = PageTablePTE ppn global user)"
|
|
by (simp add: isPageTablePTE_def split: pte.splits)
|
|
|
|
lemma getPPtrFromHWPTE_spec':
|
|
"\<forall>s. \<Gamma> \<turnstile> \<lbrace>s. hrs_htd \<acute>t_hrs \<Turnstile>\<^sub>t \<acute>pte___ptr_to_struct_pte_C \<rbrace>
|
|
Call getPPtrFromHWPTE_'proc
|
|
\<lbrace> \<acute>ret__ptr_to_struct_pte_C =
|
|
pte_Ptr (ptrFromPAddr (pte_CL.ppn_CL (pte_lift
|
|
(the (clift \<^bsup>s\<^esup>t_hrs \<^bsup>s\<^esup>pte___ptr_to_struct_pte_C))) << pageBits)) \<rbrace>"
|
|
by vcg (simp add: bit_simps)
|
|
|
|
lemma getPPtrFromHWPTE_corres:
|
|
"ccorres (\<lambda>_ ptr. ptr = pte_Ptr (getPPtrFromHWPTE pte))
|
|
ret__ptr_to_struct_pte_C_'
|
|
(ko_at' pte ptePtr and K (isPageTablePTE pte))
|
|
\<lbrace> \<acute>pte___ptr_to_struct_pte_C = pte_Ptr ptePtr \<rbrace>
|
|
hs
|
|
(return ())
|
|
(Call getPPtrFromHWPTE_'proc)"
|
|
apply (rule ccorres_from_vcg)
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (clarsimp simp: return_def rf_sr_def cstate_relation_def Let_def cpspace_relation_def)
|
|
apply (drule (1) cmap_relation_ko_atD)
|
|
apply (clarsimp simp: typ_heap_simps getPPtrFromHWPTE_def cpte_relation_def Let_def
|
|
isPageTablePTE_def2 bit_simps)
|
|
done
|
|
|
|
lemma isPTEPageTable_spec':
|
|
"\<forall>s. \<Gamma> \<turnstile> \<lbrace>s. hrs_htd \<acute>t_hrs \<Turnstile>\<^sub>t \<acute>pte___ptr_to_struct_pte_C \<rbrace>
|
|
Call isPTEPageTable_'proc
|
|
\<lbrace> \<forall>cpte pte. clift \<^bsup>s\<^esup>t_hrs \<^bsup>s\<^esup>pte___ptr_to_struct_pte_C = Some cpte \<longrightarrow>
|
|
cpte_relation pte cpte \<longrightarrow>
|
|
\<acute>ret__unsigned_long = from_bool (isPageTablePTE pte) \<rbrace>"
|
|
by vcg
|
|
(auto simp: from_bool_def cpte_relation_def isPageTablePTE_def2 Let_def
|
|
readable_from_vm_rights_def writable_from_vm_rights_def bit_simps
|
|
split: bool.split if_split pte.splits vmrights.splits)
|
|
|
|
lemma readable_from_vm_rights0:
|
|
"(readable_from_vm_rights vm = (0::machine_word)) = (vm = VMKernelOnly)"
|
|
by (auto simp add: readable_from_vm_rights_def split: vmrights.splits)
|
|
|
|
lemma isPTEPageTable_corres:
|
|
"ccorres (\<lambda>_ isPTE. isPTE = from_bool (isPageTablePTE pte))
|
|
ret__unsigned_long_'
|
|
(ko_at' pte ptePtr)
|
|
\<lbrace> \<acute>pte___ptr_to_struct_pte_C = pte_Ptr ptePtr \<rbrace>
|
|
hs
|
|
(return ())
|
|
(Call isPTEPageTable_'proc)"
|
|
apply (rule ccorres_from_vcg)
|
|
apply (rule allI, rule conseqPre)
|
|
apply vcg
|
|
apply (clarsimp simp: return_def)
|
|
apply (drule rf_sr_cpte_relation)
|
|
apply (drule (1) cmap_relation_ko_atD)
|
|
apply (clarsimp simp: typ_heap_simps)
|
|
apply (cases pte; simp add: readable_from_vm_rights0 isPageTablePTE_def from_bool_def
|
|
cpte_relation_def writable_from_vm_rights_def)
|
|
done
|
|
|
|
lemma ccorres_checkPTAt:
|
|
"ccorres_underlying srel Ga rrel xf arrel axf P P' hs (a ()) c \<Longrightarrow>
|
|
ccorres_underlying srel Ga rrel xf arrel axf
|
|
(\<lambda>s. page_table_at' pt s \<longrightarrow> P s) P' hs (checkPTAt pt >>= a) c"
|
|
unfolding checkPTAt_def by (rule ccorres_stateAssert)
|
|
|
|
lemma pteAtIndex_ko[wp]:
|
|
"\<lbrace>\<top>\<rbrace> pteAtIndex level pt vptr \<lbrace>\<lambda>pte. ko_at' pte (ptSlotIndex level pt vptr)\<rbrace>"
|
|
unfolding pteAtIndex_def by (wpsimp wp: getPTE_wp)
|
|
|
|
lemma ptBitsLeft_bound:
|
|
"level \<le> maxPTLevel \<Longrightarrow> ptBitsLeft level \<le> canonical_bit"
|
|
by (simp add: ptBitsLeft_def bit_simps maxPTLevel_def canonical_bit_def)
|
|
|
|
lemma unat_of_nat_ptBitsLeft [simp]:
|
|
"level \<le> maxPTLevel \<Longrightarrow> unat (of_nat (ptBitsLeft level)::machine_word) = ptBitsLeft level"
|
|
apply (subst unat_of_nat64)
|
|
apply (rule order_le_less_trans, erule ptBitsLeft_bound)
|
|
apply (simp add: word_bits_def canonical_bit_def)
|
|
apply simp
|
|
done
|
|
|
|
lemma pte_at'_ptSlotIndex:
|
|
"page_table_at' pt s \<Longrightarrow> pte_at' (ptSlotIndex level pt vptr) s"
|
|
apply (simp add: ptSlotIndex_def ptIndex_def)
|
|
apply (drule page_table_pte_atI'[where x="ucast (vptr >> ptBitsLeft level)"])
|
|
apply (simp add: ucast_ucast_mask bit_simps)
|
|
done
|
|
|
|
lemma ptTranslationBits_word_bits:
|
|
"ptTranslationBits < LENGTH(machine_word_len)"
|
|
by (simp add: bit_simps)
|
|
|
|
lemmas unat_and_mask_le_ptTrans = unat_and_mask_le[OF ptTranslationBits_word_bits]
|
|
|
|
lemma lookupPTSlotFromLevel_ccorres:
|
|
defines
|
|
"ptSlot_upd \<equiv>
|
|
Guard ShiftError \<lbrace>ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C < 0x40\<rbrace>
|
|
(Guard MemorySafety
|
|
\<lbrace> (\<acute>vptr >> unat (ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C)) && 0x1FF = 0 \<or>
|
|
array_assertion \<acute>pt (unat ((\<acute>vptr >> unat (ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C)) && 0x1FF))
|
|
(hrs_htd \<acute>t_hrs) \<rbrace>
|
|
(\<acute>ret___struct_lookupPTSlot_ret_C :==
|
|
ptSlot_C_update
|
|
(\<lambda>_. \<acute>pt +\<^sub>p uint ((\<acute>vptr >> unat (ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C)) && 0x1FF))
|
|
\<acute>ret___struct_lookupPTSlot_ret_C))"
|
|
shows
|
|
"ccorres (\<lambda>(bitsLeft,ptSlot) cr. bitsLeft = unat (ptBitsLeft_C cr) \<and> ptSlot_C cr = Ptr ptSlot)
|
|
ret__struct_lookupPTSlot_ret_C_'
|
|
(page_table_at' pt and (\<lambda>_. level \<le> maxPTLevel))
|
|
(\<lbrace> ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C = of_nat (ptTranslationBits * level + ptBits) \<rbrace>
|
|
\<inter> \<lbrace> \<acute>level = of_nat level \<rbrace> \<inter> \<lbrace> \<acute>pt = Ptr pt \<rbrace> \<inter> \<lbrace> \<acute>vptr = vptr \<rbrace>)
|
|
(SKIP#hs)
|
|
(lookupPTSlotFromLevel level pt vptr)
|
|
(ptSlot_upd;;
|
|
\<acute>ret__unsigned_long :== CALL isPTEPageTable(ptSlot_C \<acute>ret___struct_lookupPTSlot_ret_C);;
|
|
WHILE \<acute>ret__unsigned_long \<noteq> 0 \<and> 0 < \<acute>level DO
|
|
\<acute>level :== \<acute>level - 1;;
|
|
\<acute>ret___struct_lookupPTSlot_ret_C :==
|
|
ptBitsLeft_C_update (\<lambda>_. ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C - 9)
|
|
\<acute>ret___struct_lookupPTSlot_ret_C;;
|
|
\<acute>pt :== CALL getPPtrFromHWPTE(ptSlot_C \<acute>ret___struct_lookupPTSlot_ret_C);;
|
|
ptSlot_upd;;
|
|
\<acute>ret__unsigned_long :== CALL isPTEPageTable(ptSlot_C \<acute>ret___struct_lookupPTSlot_ret_C)
|
|
OD;;
|
|
return_C ret__struct_lookupPTSlot_ret_C_'_update ret___struct_lookupPTSlot_ret_C_')"
|
|
proof (induct level arbitrary: pt)
|
|
note unat_and_mask_le_ptTrans[simp] neq_0_unat[simp]
|
|
|
|
have misc_simps[simp]:
|
|
"pageBits = pt_bits"
|
|
"of_nat pageBits = of_nat pt_bits"
|
|
"pt_bits - 3 = ptTranslationBits"
|
|
"unat (of_nat pt_bits::machine_word) = pt_bits"
|
|
"\<And>x::machine_word. x * 8 = x << pte_bits"
|
|
"0x1FF = (mask ptTranslationBits :: machine_word)"
|
|
by (auto simp: bit_simps mask_def shiftl_t2n)
|
|
|
|
case 0
|
|
show ?case
|
|
apply (simp only: ptSlot_upd_def lookupPTSlotFromLevel.simps(1))
|
|
apply (cinitlift pt_' vptr_', simp only:)
|
|
apply (rule ccorres_rhs_assoc)+
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule ccorres_Guard_Seq)
|
|
apply (rule ccorres_move_array_assertion_pt)
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (simp add: whileAnno_def)
|
|
apply (rule ccorres_expand_while_iff_Seq[THEN iffD1])
|
|
apply (rule ccorres_cond_false[where R="\<top>" and
|
|
R'="\<lbrace> \<acute>level = 0 \<and>
|
|
ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C = of_nat ptBits \<and>
|
|
ptSlot_C \<acute>ret___struct_lookupPTSlot_ret_C =
|
|
pte_Ptr pt +\<^sub>p uint ((vptr >> ptBits) && mask ptTranslationBits) \<rbrace>"])
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule ccorres_return_C)
|
|
apply clarsimp
|
|
apply clarsimp
|
|
apply clarsimp
|
|
apply (rule TrueI)
|
|
apply (clarsimp simp: bit_simps pt_slot_offset_def pt_index_def pt_bits_left_def shiftl_t2n)
|
|
apply vcg
|
|
apply clarsimp
|
|
apply (vcg spec=modifies)
|
|
apply clarsimp
|
|
apply vcg
|
|
apply (vcg spec=modifies)
|
|
apply clarsimp
|
|
apply (drule pte_at'_ptSlotIndex[where level=0 and vptr=vptr])
|
|
apply (clarsimp simp: pt_slot_offset_def pt_index_def pt_bits_left_def c_guard_abs_pte)
|
|
apply (clarsimp simp: bit_simps)
|
|
done
|
|
|
|
case (Suc level)
|
|
have [simp]:
|
|
"Suc level \<le> maxPTLevel \<Longrightarrow>
|
|
unat (of_nat ptTranslationBits +
|
|
of_nat ptTranslationBits * of_nat level +
|
|
of_nat pt_bits :: machine_word) =
|
|
ptTranslationBits + ptTranslationBits * level + pt_bits"
|
|
by (simp add: bit_simps word_less_nat_alt maxPTLevel_def unat_word_ariths unat_of_nat_eq)
|
|
|
|
show ?case
|
|
apply (simp only: lookupPTSlotFromLevel.simps)
|
|
apply (subst ptSlot_upd_def)
|
|
\<comment> \<open>cinitlift will not fully eliminate pt and vptr,
|
|
so we double the precondition to remember the connection\<close>
|
|
apply (rule ccorres_guard_imp[where Q=Q and A=Q and
|
|
Q'="A' \<inter> \<lbrace>\<acute>pt = pte_Ptr pt\<rbrace> \<inter> \<lbrace>\<acute>vptr = vptr\<rbrace>" and
|
|
A'=A' for Q A']; simp)
|
|
apply (cinitlift pt_' vptr_', simp only:) \<comment> \<open>Warns about ptSlot_upd, which is fine\<close>
|
|
apply (rename_tac vptrC ptC)
|
|
apply (rule ccorres_rhs_assoc)+
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule ccorres_gen_asm[where P="Suc level \<le> maxPTLevel"])
|
|
apply (rule ccorres_Guard_Seq)
|
|
apply (rule ccorres_move_array_assertion_pt)
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (rule_tac G'="\<lbrace> ptSlot_C \<acute>ret___struct_lookupPTSlot_ret_C =
|
|
pte_Ptr (ptSlotIndex (Suc level) pt vptr) \<and>
|
|
ptBitsLeft_C \<acute>ret___struct_lookupPTSlot_ret_C =
|
|
of_nat (ptBitsLeft (Suc level)) \<and>
|
|
\<acute>level = of_nat (Suc level) \<and>
|
|
\<acute>vptr = vptr \<and>
|
|
\<acute>pt = ptC \<and>
|
|
hrs_htd \<acute>t_hrs,c_guard \<Turnstile>\<^sub>t pte_Ptr (ptSlotIndex (Suc level) pt vptr)
|
|
\<rbrace>"
|
|
in ccorres_symb_exec_l')
|
|
apply (rename_tac pte)
|
|
apply (rule ccorres_add_return)
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule_tac xf'=ret__unsigned_long_' in ccorres_split_nothrow_call)
|
|
apply (rule_tac pte=pte in isPTEPageTable_corres)
|
|
apply simp
|
|
apply simp
|
|
apply simp
|
|
apply (simp only: ptSlot_upd_def)
|
|
apply ceqv
|
|
apply (rename_tac from_bl)
|
|
apply (fold ptSlot_upd_def)
|
|
apply (unfold whileAnno_def)[1]
|
|
apply (rule ccorres_expand_while_iff_Seq[THEN iffD1])
|
|
apply (rule_tac R="\<top>" and
|
|
R'="\<lbrace>\<acute>ret__unsigned_long = from_bl \<and> \<acute>level = of_nat (Suc level)\<rbrace>"
|
|
in ccorres_cond_strong)
|
|
apply (clarsimp simp: maxPTLevel_def word_less_nat_alt unat_word_ariths
|
|
unat_of_nat_eq)
|
|
apply (rule ccorres_rhs_assoc)+
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (rule ccorres_add_return)
|
|
apply (rule_tac xf'="pt_'" in ccorres_split_nothrow_call)
|
|
apply (rule_tac pte=pte in getPPtrFromHWPTE_corres)
|
|
apply simp
|
|
apply simp
|
|
apply simp
|
|
apply ceqv \<comment> \<open>Warns about ptSlot_upd, which is fine\<close>
|
|
apply (rule ccorres_checkPTAt)
|
|
apply simp
|
|
apply (rule ccorres_rhs_assoc2)+
|
|
apply (rule Suc[unfolded whileAnno_def])
|
|
apply simp
|
|
apply wp
|
|
apply simp
|
|
apply (vcg exspec=getPPtrFromHWPTE_spec')
|
|
apply vcg
|
|
apply (vcg spec=modifies)
|
|
apply vcg
|
|
apply (vcg spec=modifies)
|
|
apply (rule ccorres_return_C; simp)
|
|
apply simp
|
|
apply wp
|
|
prefer 2
|
|
apply assumption
|
|
prefer 4
|
|
apply (wp hoare_drop_imps)
|
|
apply simp
|
|
apply (vcg exspec=isPTEPageTable_spec')
|
|
apply clarsimp
|
|
apply (clarsimp simp: ptBitsLeft_def bit_simps)
|
|
apply (wpsimp simp: pteAtIndex_def)
|
|
apply (wpsimp simp: pteAtIndex_def wp: empty_fail_getObject)
|
|
apply vcg
|
|
apply (vcg spec=modifies)
|
|
apply clarsimp
|
|
apply (drule pte_at'_ptSlotIndex[where vptr=vptr and level="Suc level"])
|
|
apply (simp add: c_guard_abs_pte)
|
|
apply (simp add: ptSlotIndex_def ptIndex_def ptBitsLeft_def)
|
|
apply (simp add: bit_simps word_less_nat_alt maxPTLevel_def unat_word_ariths unat_of_nat_eq)
|
|
done
|
|
qed
|
|
|
|
|
|
lemma lookupPTSlot_ccorres:
|
|
"ccorres (\<lambda>(bitsLeft,ptSlot) cr. bitsLeft = unat (ptBitsLeft_C cr) \<and> ptSlot_C cr = Ptr ptSlot)
|
|
ret__struct_lookupPTSlot_ret_C_'
|
|
(page_table_at' pt)
|
|
(\<lbrace>\<acute>vptr = vptr \<rbrace> \<inter> \<lbrace>\<acute>lvl1pt = Ptr pt \<rbrace>)
|
|
hs
|
|
(lookupPTSlot pt vptr)
|
|
(Call lookupPTSlot_'proc)"
|
|
apply (cinit lift: lvl1pt_')
|
|
apply (rename_tac lvl1pt)
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (rule ccorres_symb_exec_r2)
|
|
apply (rule ccorres_rhs_assoc2)+
|
|
apply (rule lookupPTSlotFromLevel_ccorres)
|
|
apply vcg
|
|
apply (vcg spec=modifies)
|
|
apply vcg
|
|
apply (vcg spec=modifies)
|
|
apply vcg
|
|
apply (vcg spec=modifies)
|
|
apply (simp add: bit_simps maxPTLevel_def)
|
|
done
|
|
|
|
abbreviation
|
|
"findVSpaceForASID_xf \<equiv>
|
|
liftxf errstate findVSpaceForASID_ret_C.status_C
|
|
findVSpaceForASID_ret_C.vspace_root_C
|
|
ret__struct_findVSpaceForASID_ret_C_'"
|
|
|
|
lemma ccorres_pre_getObject_asidpool:
|
|
assumes cc: "\<And>rv. ccorres r xf (P rv) (P' rv) hs (f rv) c"
|
|
shows "ccorres r xf
|
|
(\<lambda>s. (\<forall>asidpool. ko_at' asidpool p s \<longrightarrow> P asidpool s))
|
|
{s. \<forall> asidpool asidpool'. cslift s (ap_Ptr p) = Some asidpool' \<and> casid_pool_relation asidpool asidpool'
|
|
\<longrightarrow> s \<in> P' asidpool}
|
|
hs (getObject p >>= (\<lambda>rv :: asidpool. f rv)) c"
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule ccorres_symb_exec_l)
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule cc)
|
|
apply (rule conjI)
|
|
apply (rule_tac Q="ko_at' rv p s" in conjunct1)
|
|
apply assumption
|
|
apply assumption
|
|
apply (wpsimp wp: getASID_wp empty_fail_getObject)+
|
|
apply (erule cmap_relationE1 [OF rf_sr_cpspace_asidpool_relation],
|
|
erule ko_at_projectKO_opt)
|
|
apply simp
|
|
done
|
|
|
|
lemma asid_wf_table_guard[unfolded asid_high_bits_def, simplified]:
|
|
"asid_wf asid \<Longrightarrow> asid >> asid_low_bits < 2^asid_high_bits"
|
|
apply (simp add: asid_wf_def)
|
|
apply (simp add: mask_def asid_bits_def asid_low_bits_def asid_high_bits_def)
|
|
apply word_bitwise
|
|
done
|
|
|
|
lemma asidLowBits_guard0[simp]:
|
|
"0 <=s Kernel_C.asidLowBits"
|
|
by (simp add: Kernel_C.asidLowBits_def)
|
|
|
|
lemma asidLowBits_shift_guard[unfolded word_bits_def, simplified, simp]:
|
|
"Kernel_C.asidLowBits <s of_nat word_bits"
|
|
by (simp add: Kernel_C.asidLowBits_def word_bits_def)
|
|
|
|
lemma asidPool_table_guard[simplified, simp]:
|
|
"p && 2^asid_low_bits - 1 < 2^LENGTH(asid_low_len)" for p :: machine_word
|
|
apply (fold mask_2pm1)
|
|
apply (rule le_less_trans)
|
|
apply (rule word_and_mask_le_2pm1)
|
|
apply (simp add: asid_low_bits_def)
|
|
done
|
|
|
|
lemma findVSpaceForASID_ccorres:
|
|
"ccorres
|
|
(lookup_failure_rel \<currency> (\<lambda>pteptrc pteptr. pteptr = pte_Ptr pteptrc))
|
|
findVSpaceForASID_xf
|
|
(valid_arch_state' and (\<lambda>_. asid_wf asid))
|
|
(UNIV \<inter> \<lbrace>\<acute>asid___unsigned_long = asid\<rbrace> )
|
|
[]
|
|
(findVSpaceForASID asid)
|
|
(Call findVSpaceForASID_'proc)"
|
|
apply (rule ccorres_gen_asm)
|
|
apply (cinit lift: asid___unsigned_long_')
|
|
apply (rule ccorres_assertE)+
|
|
apply (rule ccorres_liftE_Seq)
|
|
apply (simp add: liftME_def bindE_assoc)
|
|
apply (rule ccorres_pre_gets_riscvKSASIDTable_ksArchState')
|
|
apply (case_tac "asidTable (ucast (asid_high_bits_of (ucast asid)))")
|
|
(* Case where the first look-up fails *)
|
|
apply clarsimp
|
|
apply (rule_tac P="valid_arch_state' and _" and P'=UNIV in ccorres_from_vcg_throws)
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (clarsimp simp: throwError_def return_def bindE_def NonDetMonad.lift_def
|
|
EXCEPTION_NONE_def EXCEPTION_LOOKUP_FAULT_def
|
|
lookup_fault_lift_invalid_root asid_wf_table_guard)
|
|
apply (frule rf_sr_asidTable_None[where asid=asid, THEN iffD2],
|
|
simp add: asid_wf_eq_mask_eq, assumption, assumption)
|
|
apply (solves \<open>simp\<close>)
|
|
(* Case where the first look-up succeeds *)
|
|
apply clarsimp
|
|
apply (rule ccorres_liftE_Seq)
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule ccorres_pre_getObject_asidpool)
|
|
apply (rename_tac asidPool)
|
|
apply (case_tac "inv ASIDPool asidPool (asid && mask asid_low_bits) = Some 0")
|
|
apply (solves \<open>clarsimp simp: ccorres_fail'\<close>)
|
|
apply (rule_tac P="\<lambda>s. asidTable=riscvKSASIDTable (ksArchState s) \<and>
|
|
valid_arch_state' s \<and> asid_wf asid"
|
|
and P'="{s'. (\<exists>ap'. cslift s' (ap_Ptr (the (asidTable (ucast (asid_high_bits_of (ucast asid))))))
|
|
= Some ap' \<and> casid_pool_relation asidPool ap')}"
|
|
in ccorres_from_vcg_throws_nofail)
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (simp add: asid_wf_table_guard)
|
|
apply (clarsimp simp: ucast_asid_high_bits_is_shift)
|
|
apply (frule_tac idx="asid >> asid_low_bits" in rf_asidTable, assumption,
|
|
simp add: leq_asid_bits_shift)
|
|
apply (clarsimp simp: typ_heap_simps)
|
|
apply (case_tac asidPool, clarsimp simp: inv_def)
|
|
apply (simp add: casid_pool_relation_def)
|
|
apply (case_tac ap', simp)
|
|
apply (clarsimp simp: array_relation_def)
|
|
apply (erule_tac x="asid && 2 ^ asid_low_bits - 1" in allE)
|
|
apply (simp add: word_and_le1 mask_def option_to_ptr_def option_to_0_def asid_low_bits_of_p2m1_eq)
|
|
apply (rename_tac "fun" array)
|
|
apply (case_tac "fun (asid && 2 ^ asid_low_bits - 1)", clarsimp)
|
|
apply (clarsimp simp: throwError_def return_def EXCEPTION_NONE_def EXCEPTION_LOOKUP_FAULT_def)
|
|
apply (solves \<open>simp add: lookup_fault_lift_invalid_root Kernel_C.asidLowBits_def\<close>)
|
|
apply (clarsimp simp add: asid_low_bits_def asid_bits_def)
|
|
apply (fastforce simp: returnOk_def return_def
|
|
checkPTAt_def in_monad stateAssert_def liftE_bindE
|
|
get_def bind_def assert_def fail_def
|
|
split: if_splits)
|
|
apply simp+
|
|
done
|
|
|
|
lemma ccorres_pre_gets_riscvKSGlobalPT_ksArchState:
|
|
assumes cc: "\<And>rv. ccorres r xf (P rv) (P' rv) hs (f rv) c"
|
|
shows "ccorres r xf
|
|
(\<lambda>s. (\<forall>rv. riscvKSGlobalPT (ksArchState s) = rv \<longrightarrow> P rv s))
|
|
(P' (ptr_val riscvKSGlobalPT_Ptr))
|
|
hs (gets (riscvKSGlobalPT \<circ> ksArchState) >>= (\<lambda>rv. f rv)) c"
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule ccorres_symb_exec_l)
|
|
defer
|
|
apply wp[1]
|
|
apply (rule gets_sp)
|
|
apply (clarsimp simp: empty_fail_def simpler_gets_def)
|
|
apply assumption
|
|
apply clarsimp
|
|
defer
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule cc)
|
|
apply clarsimp
|
|
apply assumption
|
|
apply (drule rf_sr_riscvKSGlobalPT)
|
|
apply simp
|
|
done
|
|
|
|
(* FIXME move *)
|
|
lemma ccorres_from_vcg_might_throw:
|
|
"(\<forall>\<sigma>. Gamm \<turnstile> {s. P \<sigma> \<and> s \<in> P' \<and> (\<sigma>, s) \<in> sr} c
|
|
{s. \<exists>(rv, \<sigma>') \<in> fst (a \<sigma>). (\<sigma>', s) \<in> sr \<and> r rv (xf s)},
|
|
{s. \<exists>(rv, \<sigma>') \<in> fst (a \<sigma>). (\<sigma>', s) \<in> sr \<and> arrel rv (axf s)})
|
|
\<Longrightarrow> ccorres_underlying sr Gamm r xf arrel axf P P' (SKIP # hs) a c"
|
|
apply (rule ccorresI')
|
|
apply (drule_tac x=s in spec)
|
|
apply (erule exec_handlers.cases, simp_all)
|
|
apply clarsimp
|
|
apply (erule exec_handlers.cases, simp_all)[1]
|
|
apply (auto elim!: exec_Normal_elim_cases)[1]
|
|
apply (drule(1) exec_abrupt[rotated])
|
|
apply simp
|
|
apply (clarsimp simp: unif_rrel_simps elim!: exec_Normal_elim_cases)
|
|
apply fastforce
|
|
apply (clarsimp simp: unif_rrel_simps)
|
|
apply (drule hoare_sound)
|
|
apply (clarsimp simp: cvalid_def HoarePartialDef.valid_def)
|
|
apply fastforce
|
|
done
|
|
|
|
end
|
|
|
|
context kernel_m begin
|
|
|
|
(* FIXME: move *)
|
|
lemma ccorres_h_t_valid_riscvKSGlobalPT:
|
|
"ccorres r xf P P' hs f (f' ;; g') \<Longrightarrow>
|
|
ccorres r xf P P' hs f (Guard C_Guard {s'. s' \<Turnstile>\<^sub>c riscvKSGlobalPT_Ptr} f';; g')"
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule ccorres_move_c_guards[where P = \<top>])
|
|
apply clarsimp
|
|
apply assumption
|
|
apply simp
|
|
by (clarsimp simp add: rf_sr_def cstate_relation_def Let_def)
|
|
|
|
(* MOVE copied from CSpace_RAB_C *)
|
|
lemma ccorres_gen_asm_state:
|
|
assumes rl: "\<And>s. P s \<Longrightarrow> ccorres r xf G G' hs a c"
|
|
shows "ccorres r xf (G and P) G' hs a c"
|
|
proof (rule ccorres_guard_imp2)
|
|
show "ccorres r xf (G and (\<lambda>_. \<exists>s. P s)) G' hs a c"
|
|
apply (rule ccorres_gen_asm)
|
|
apply (erule exE)
|
|
apply (erule rl)
|
|
done
|
|
next
|
|
fix s s'
|
|
assume "(s, s') \<in> rf_sr" and "(G and P) s" and "s' \<in> G'"
|
|
thus "(G and (\<lambda>_. \<exists>s. P s)) s \<and> s' \<in> G'"
|
|
by fastforce
|
|
qed
|
|
|
|
(* FIXME shadows two other identical versions in other files *)
|
|
lemma ccorres_abstract_known:
|
|
"\<lbrakk> \<And>rv' t t'. ceqv \<Gamma> xf' rv' t t' g (g' rv'); ccorres rvr xf P P' hs f (g' val) \<rbrakk>
|
|
\<Longrightarrow> ccorres rvr xf P (P' \<inter> {s. xf' s = val}) hs f g"
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule_tac xf'=xf' in ccorres_abstract)
|
|
apply assumption
|
|
apply (rule_tac P="rv' = val" in ccorres_gen_asm2)
|
|
apply simp
|
|
apply simp
|
|
done
|
|
|
|
lemma setObject_modify:
|
|
fixes v :: "'a :: pspace_storable" shows
|
|
"\<lbrakk> obj_at' (P :: 'a \<Rightarrow> bool) p s; updateObject v = updateObject_default v;
|
|
(1 :: machine_word) < 2 ^ objBits v \<rbrakk>
|
|
\<Longrightarrow> setObject p v s
|
|
= modify (ksPSpace_update (\<lambda>ps. ps (p \<mapsto> injectKO v))) s"
|
|
apply (clarsimp simp: setObject_def split_def exec_gets obj_at'_def lookupAround2_known1
|
|
assert_opt_def updateObject_default_def bind_assoc)
|
|
apply (simp add: projectKO_def alignCheck_assert)
|
|
apply (simp add: project_inject objBits_def)
|
|
apply (clarsimp simp only: objBitsT_koTypeOf[symmetric] koTypeOf_injectKO)
|
|
apply (frule(2) in_magnitude_check[where s'=s])
|
|
apply (simp add: magnitudeCheck_assert in_monad)
|
|
apply (simp add: simpler_modify_def)
|
|
done
|
|
|
|
lemma ccorres_name_pre_C:
|
|
"(\<And>s. s \<in> P' \<Longrightarrow> ccorres_underlying sr \<Gamma> r xf arrel axf P {s} hs f g)
|
|
\<Longrightarrow> ccorres_underlying sr \<Gamma> r xf arrel axf P P' hs f g"
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule_tac xf'=id in ccorres_abstract, rule ceqv_refl)
|
|
apply (rule_tac P="rv' \<in> P'" in ccorres_gen_asm2)
|
|
apply assumption
|
|
apply simp
|
|
apply simp
|
|
done
|
|
|
|
lemma addrFromKPPtr_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile> {s}
|
|
Call addrFromKPPtr_'proc
|
|
\<lbrace>\<acute>ret__unsigned_long = addrFromKPPtr (ptr_val (pptr_' s))\<rbrace>"
|
|
apply vcg
|
|
apply (simp add: addrFromKPPtr_def kernelELFBaseOffset_def
|
|
kernelELFBase_def kernelELFPAddrBase_def)
|
|
done
|
|
|
|
lemma isValidVTableRoot_def2:
|
|
"isValidVTableRoot cap =
|
|
(\<exists>pt asid vref. cap = ArchObjectCap (PageTableCap pt (Some (asid,vref))))"
|
|
unfolding isValidVTableRoot_def
|
|
by (auto split: capability.splits arch_capability.splits option.splits)
|
|
|
|
lemma setVMRoot_ccorres:
|
|
"ccorres dc xfdc
|
|
(all_invs_but_ct_idle_or_in_cur_domain' and tcb_at' thread)
|
|
(UNIV \<inter> {s. tcb_' s = tcb_ptr_to_ctcb_ptr thread}) hs
|
|
(setVMRoot thread) (Call setVMRoot_'proc)"
|
|
supply Collect_const[simp del]
|
|
apply (cinit lift: tcb_')
|
|
apply (rule ccorres_move_array_assertion_tcb_ctes)
|
|
apply (rule ccorres_move_c_guard_tcb_ctes)
|
|
apply (simp add: getThreadVSpaceRoot_def locateSlot_conv bit_simps asid_bits_def)
|
|
apply (ctac, rename_tac vRootCap vRootCap')
|
|
apply (rule ccorres_assert2)
|
|
apply (csymbr, rename_tac vRootTag)
|
|
apply (simp add: cap_get_tag_isCap_ArchObject2)
|
|
apply (rule ccorres_Cond_rhs_Seq)
|
|
apply (subst will_throw_and_catch)
|
|
apply (simp split: capability.split arch_capability.split option.split)
|
|
apply (fastforce simp: isCap_simps)
|
|
apply (rule ccorres_pre_gets_riscvKSGlobalPT_ksArchState[unfolded o_def])
|
|
apply (rule ccorres_rhs_assoc)+
|
|
apply (rule ccorres_h_t_valid_riscvKSGlobalPT)
|
|
apply csymbr
|
|
apply ccorres_rewrite
|
|
apply (subst bind_return_unit)
|
|
apply (ctac (no_vcg) add: setVSpaceRoot_ccorres)
|
|
apply (simp flip: dc_def)
|
|
apply (rule ccorres_return_void_C)
|
|
apply (rule hoare_post_taut[where P=\<top>])
|
|
apply (simp add: catch_def bindE_bind_linearise bind_assoc liftE_def)
|
|
apply csymbr
|
|
apply csymbr
|
|
apply csymbr
|
|
apply csymbr
|
|
apply simp
|
|
apply ((wpc; (solves \<open>clarsimp simp: isCap_simps isValidVTableRoot_def\<close>)?), simp)+
|
|
apply (simp add: catch_def bindE_bind_linearise bind_assoc liftE_def)
|
|
apply (rule_tac f'=lookup_failure_rel
|
|
and r'="\<lambda>pte_ptr pte_ptr'. pte_ptr' = pte_Ptr pte_ptr"
|
|
and xf'=find_ret_'
|
|
in ccorres_split_nothrow_case_sum)
|
|
apply (ctac add: findVSpaceForASID_ccorres)
|
|
apply ceqv
|
|
apply (rename_tac vspace vspace')
|
|
apply (rule_tac P="capPTBasePtr_CL (cap_page_table_cap_lift vRootCap')
|
|
= capPTBasePtr (capCap vRootCap)"
|
|
in ccorres_gen_asm2)
|
|
apply simp
|
|
apply (rule ccorres_Cond_rhs_Seq)
|
|
apply (simp add: whenE_def throwError_def dc_def[symmetric], ccorres_rewrite)
|
|
apply (rule ccorres_rhs_assoc)
|
|
apply (rule ccorres_h_t_valid_riscvKSGlobalPT)
|
|
apply csymbr
|
|
apply (rule ccorres_pre_gets_riscvKSGlobalPT_ksArchState[unfolded comp_def])
|
|
apply (rule ccorres_add_return2)
|
|
apply (ctac (no_vcg) add: setVSpaceRoot_ccorres)
|
|
apply (rule ccorres_return_void_C)
|
|
apply (rule hoare_post_taut[where P=\<top>])
|
|
apply (simp add: whenE_def returnOk_def flip: dc_def)
|
|
apply (csymbr)
|
|
apply (ctac (no_vcg) add: setVSpaceRoot_ccorres)
|
|
apply (rule ccorres_cond_true_seq, simp add: dc_def[symmetric], ccorres_rewrite)
|
|
apply (rule ccorres_rhs_assoc)
|
|
apply (rule ccorres_h_t_valid_riscvKSGlobalPT)
|
|
apply csymbr
|
|
apply (rule ccorres_pre_gets_riscvKSGlobalPT_ksArchState[unfolded comp_def])
|
|
apply (rule ccorres_add_return2)
|
|
apply (ctac (no_vcg) add: setVSpaceRoot_ccorres)
|
|
apply (rule ccorres_return_void_C)
|
|
apply (rule hoare_post_taut[where P=\<top>])
|
|
apply (simp, rule wp_post_tautE)
|
|
apply clarsimp
|
|
apply (vcg)
|
|
apply (simp add: isCap_simps)
|
|
apply (wpsimp wp: getSlotCap_wp)
|
|
apply vcg
|
|
apply (clarsimp simp: Collect_const_mem)
|
|
apply (rule conjI)
|
|
apply (frule cte_at_tcb_at_32', drule cte_at_cte_wp_atD)
|
|
apply (clarsimp simp: cte_level_bits_def tcbVTableSlot_def)
|
|
apply (rule_tac x="cteCap cte" in exI)
|
|
apply (rule conjI, erule cte_wp_at_weakenE', simp)
|
|
apply (clarsimp simp: invs_cicd_no_0_obj' invs_cicd_arch_state' isCap_simps)
|
|
apply (frule cte_wp_at_valid_objs_valid_cap'; clarsimp simp: invs_cicd_valid_objs')
|
|
apply (clarsimp simp: valid_cap'_def wellformed_mapdata'_def isValidVTableRoot_def2)
|
|
apply (clarsimp simp: tcb_cnode_index_defs cte_level_bits_def tcbVTableSlot_def)
|
|
apply (clarsimp simp: isCap_simps isValidVTableRoot_def2)
|
|
apply (clarsimp simp: cap_get_tag_isCap_ArchObject2)
|
|
by (clarsimp simp: cap_get_tag_isCap_ArchObject[symmetric]
|
|
cap_lift_page_table_cap cap_to_H_def
|
|
cap_page_table_cap_lift_def isCap_simps
|
|
to_bool_def mask_def isZombieTCB_C_def Let_def
|
|
elim!: ccap_relationE
|
|
split: if_split_asm cap_CL.splits)
|
|
|
|
lemma ccorres_seq_IF_False:
|
|
"ccorres_underlying sr \<Gamma> r xf arrel axf G G' hs a (IF False THEN x ELSE y FI ;; c) = ccorres_underlying sr \<Gamma> r xf arrel axf G G' hs a (y ;; c)"
|
|
by simp
|
|
|
|
(* FIXME x64: needed? *)
|
|
lemma ptrFromPAddr_mask6_simp[simp]:
|
|
"ptrFromPAddr ps && mask 6 = ps && mask 6"
|
|
unfolding ptrFromPAddr_def pptrBase_def pptrBaseOffset_def RISCV64.pptrBase_def canonical_bit_def
|
|
paddrBase_def
|
|
by (subst add.commute, subst mask_add_aligned ; simp add: is_aligned_def)
|
|
|
|
(* FIXME: move *)
|
|
lemma register_from_H_bound[simp]:
|
|
"unat (register_from_H v) < 35"
|
|
by (cases v, simp_all add: "StrictC'_register_defs")
|
|
|
|
(* FIXME: move *)
|
|
lemma register_from_H_inj:
|
|
"inj register_from_H"
|
|
apply (rule inj_onI)
|
|
apply (case_tac x)
|
|
by (case_tac y, simp_all add: "StrictC'_register_defs")+
|
|
|
|
(* FIXME: move *)
|
|
lemmas register_from_H_eq_iff[simp]
|
|
= inj_on_eq_iff [OF register_from_H_inj, simplified]
|
|
|
|
lemma setRegister_ccorres:
|
|
"ccorres dc xfdc \<top>
|
|
(UNIV \<inter> \<lbrace>\<acute>thread = tcb_ptr_to_ctcb_ptr thread\<rbrace> \<inter> \<lbrace>\<acute>reg = register_from_H reg\<rbrace>
|
|
\<inter> {s. w_' s = val}) []
|
|
(asUser thread (setRegister reg val))
|
|
(Call setRegister_'proc)"
|
|
apply (cinit' lift: thread_' reg_' w_')
|
|
apply (simp add: asUser_def dc_def[symmetric] split_def split del: if_split)
|
|
apply (rule ccorres_pre_threadGet)
|
|
apply (rule ccorres_Guard)
|
|
apply (simp add: setRegister_def simpler_modify_def exec_select_f_singleton)
|
|
apply (rule_tac P="\<lambda>tcb. (atcbContextGet o tcbArch) tcb = rv"
|
|
in threadSet_ccorres_lemma2 [unfolded dc_def])
|
|
apply vcg
|
|
apply (clarsimp simp: setRegister_def HaskellLib_H.runState_def
|
|
simpler_modify_def typ_heap_simps)
|
|
apply (subst StateSpace.state.fold_congs[OF refl refl])
|
|
apply (rule globals.fold_congs[OF refl refl])
|
|
apply (rule heap_update_field_hrs, simp)
|
|
apply (fastforce intro: typ_heap_simps)
|
|
apply simp
|
|
apply (erule(1) rf_sr_tcb_update_no_queue2,
|
|
(simp add: typ_heap_simps')+)
|
|
apply (rule ball_tcb_cte_casesI, simp+)
|
|
apply (clarsimp simp: ctcb_relation_def ccontext_relation_def cregs_relation_def
|
|
atcbContextSet_def atcbContextGet_def
|
|
carch_tcb_relation_def
|
|
split: if_split)
|
|
apply (clarsimp simp: Collect_const_mem register_from_H_sless
|
|
register_from_H_less)
|
|
apply (auto intro: typ_heap_simps elim: obj_at'_weakenE)
|
|
done
|
|
|
|
lemma msgRegisters_ccorres:
|
|
"n < unat n_msgRegisters \<Longrightarrow>
|
|
register_from_H (RISCV64_H.msgRegisters ! n) = (index kernel_all_substitute.msgRegisters n)"
|
|
apply (simp add: kernel_all_substitute.msgRegisters_def msgRegisters_unfold fupdate_def)
|
|
apply (simp add: Arrays.update_def n_msgRegisters_def nth_Cons' split: if_split)
|
|
done
|
|
|
|
(* usually when we call setMR directly, we mean to only set a registers, which will
|
|
fit in actual registers *)
|
|
lemma setMR_as_setRegister_ccorres:
|
|
notes dc_simp[simp del]
|
|
shows
|
|
"ccorres (\<lambda>rv rv'. rv' = of_nat offset + 1) ret__unsigned_'
|
|
(tcb_at' thread and K (TCB_H.msgRegisters ! offset = reg \<and> offset < length msgRegisters))
|
|
(UNIV \<inter> \<lbrace>\<acute>reg___unsigned_long = val\<rbrace>
|
|
\<inter> \<lbrace>\<acute>offset = of_nat offset\<rbrace>
|
|
\<inter> \<lbrace>\<acute>receiver = tcb_ptr_to_ctcb_ptr thread\<rbrace>) hs
|
|
(asUser thread (setRegister reg val))
|
|
(Call setMR_'proc)"
|
|
apply (rule ccorres_grab_asm)
|
|
apply (cinit' lift: reg___unsigned_long_' offset_' receiver_')
|
|
apply (clarsimp simp: n_msgRegisters_def length_of_msgRegisters)
|
|
apply (rule ccorres_cond_false)
|
|
apply (rule ccorres_move_const_guards)
|
|
apply (rule ccorres_add_return2)
|
|
apply (ctac add: setRegister_ccorres)
|
|
apply (rule ccorres_from_vcg_throws[where P'=UNIV and P=\<top>])
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (clarsimp simp: dc_def return_def)
|
|
apply (rule hoare_post_taut[of \<top>])
|
|
apply (vcg exspec=setRegister_modifies)
|
|
apply (clarsimp simp: n_msgRegisters_def length_of_msgRegisters not_le conj_commute)
|
|
apply (subst msgRegisters_ccorres[symmetric])
|
|
apply (clarsimp simp: n_msgRegisters_def length_of_msgRegisters unat_of_nat_eq)
|
|
apply (clarsimp simp: word_less_nat_alt word_le_nat_alt unat_of_nat_eq not_le[symmetric])
|
|
done
|
|
|
|
lemma wordFromMessageInfo_spec:
|
|
defines "mil s \<equiv> seL4_MessageInfo_lift (mi_' s)"
|
|
shows "\<forall>s. \<Gamma> \<turnstile> {s} Call wordFromMessageInfo_'proc
|
|
\<lbrace>\<acute>ret__unsigned_long = (label_CL (mil s) << 12)
|
|
|| (capsUnwrapped_CL (mil s) << 9)
|
|
|| (extraCaps_CL (mil s) << 7)
|
|
|| length_CL (mil s)\<rbrace>"
|
|
unfolding mil_def
|
|
apply vcg
|
|
apply (simp del: scast_id add: seL4_MessageInfo_lift_def mask_shift_simps)
|
|
apply word_bitwise
|
|
done
|
|
|
|
lemma wordFromMessageInfo_ccorres [corres]:
|
|
"ccorres (=) ret__unsigned_long_'
|
|
\<top> {s. mi = message_info_to_H (mi_' s)} []
|
|
(return (wordFromMessageInfo mi)) (Call wordFromMessageInfo_'proc)"
|
|
apply (rule ccorres_from_spec_modifies [where P = \<top>, simplified])
|
|
apply (rule wordFromMessageInfo_spec)
|
|
apply (rule wordFromMessageInfo_modifies)
|
|
apply simp
|
|
apply clarsimp
|
|
apply (simp add: return_def wordFromMessageInfo_def Let_def message_info_to_H_def
|
|
msgLengthBits_def msgExtraCapBits_def
|
|
msgMaxExtraCaps_def shiftL_nat word_bw_assocs word_bw_comms word_bw_lcs)
|
|
done
|
|
|
|
(* FIXME move *)
|
|
lemma register_from_H_eq:
|
|
"(r = r') = (register_from_H r = register_from_H r')"
|
|
apply (case_tac r, simp_all add: C_register_defs)
|
|
by (case_tac r', simp_all add: C_register_defs)+
|
|
|
|
lemma setMessageInfo_ccorres:
|
|
"ccorres dc xfdc (tcb_at' thread)
|
|
(UNIV \<inter> \<lbrace>mi = message_info_to_H mi'\<rbrace>) hs
|
|
(setMessageInfo thread mi)
|
|
(\<acute>ret__unsigned_long :== CALL wordFromMessageInfo(mi');;
|
|
CALL setRegister(tcb_ptr_to_ctcb_ptr thread,
|
|
scast Kernel_C.msgInfoRegister,
|
|
\<acute>ret__unsigned_long))"
|
|
unfolding setMessageInfo_def
|
|
apply (rule ccorres_guard_imp2)
|
|
apply ctac
|
|
apply simp
|
|
apply (ctac add: setRegister_ccorres)
|
|
apply wp
|
|
apply vcg
|
|
apply (simp add: RISCV64_H.msgInfoRegister_def RISCV64.msgInfoRegister_def
|
|
Kernel_C.msgInfoRegister_def Kernel_C.a1_def)
|
|
done
|
|
|
|
lemma performPageGetAddress_ccorres:
|
|
"ccorres (K (K \<bottom>) \<currency> dc) (liftxf errstate id (K ()) ret__unsigned_long_')
|
|
\<top>
|
|
(UNIV \<inter> {s. vbase_ptr_' s = Ptr ptr}) []
|
|
(liftE (performPageInvocation (PageGetAddr ptr)))
|
|
(Call performPageGetAddress_'proc)"
|
|
apply (simp only: liftE_liftM ccorres_liftM_simp)
|
|
apply (cinit lift: vbase_ptr_')
|
|
apply csymbr
|
|
apply (rule ccorres_pre_getCurThread)
|
|
apply (clarsimp simp: setMRs_def zipWithM_x_mapM_x mapM_x_Nil length_of_msgRegisters
|
|
zip_singleton msgRegisters_unfold mapM_x_singleton)
|
|
apply (ctac add: setRegister_ccorres)
|
|
apply csymbr
|
|
apply (rule ccorres_add_return2)
|
|
apply (rule ccorres_rhs_assoc2)
|
|
apply (rule ccorres_split_nothrow_novcg[where r'=dc and xf'=xfdc])
|
|
apply (unfold setMessageInfo_def)
|
|
apply ctac
|
|
apply (simp only: fun_app_def)
|
|
apply (ctac add: setRegister_ccorres)
|
|
apply wp
|
|
apply vcg
|
|
apply ceqv
|
|
apply (rule_tac P=\<top> and P'=UNIV in ccorres_from_vcg_throws)
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (clarsimp simp: return_def)
|
|
apply wp
|
|
apply (simp add: guard_is_UNIV_def)
|
|
apply wp
|
|
apply vcg
|
|
apply (auto simp: RISCV64_H.fromPAddr_def message_info_to_H_def mask_def
|
|
RISCV64_H.msgInfoRegister_def RISCV64.msgInfoRegister_def
|
|
Kernel_C.msgInfoRegister_def
|
|
word_sle_def word_sless_def Kernel_C.a1_def
|
|
kernel_all_global_addresses.msgRegisters_def fupdate_def)
|
|
done
|
|
|
|
lemma ccorres_pre_getObject_pte:
|
|
assumes cc: "\<And>rv. ccorres r xf (P rv) (P' rv) hs (f rv) c"
|
|
shows "ccorres r xf
|
|
(\<lambda>s. (\<forall>pte. ko_at' pte p s \<longrightarrow> P pte s))
|
|
{s. \<forall>pte pte'. cslift s (pte_Ptr p) = Some pte' \<and> cpte_relation pte pte'
|
|
\<longrightarrow> s \<in> P' pte}
|
|
hs (getObject p >>= (\<lambda>rv. f rv)) c"
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule ccorres_symb_exec_l)
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule cc)
|
|
apply (rule conjI)
|
|
apply (rule_tac Q="ko_at' rv p s" in conjunct1)
|
|
apply assumption
|
|
apply assumption
|
|
apply (wp getPTE_wp empty_fail_getObject | simp)+
|
|
apply clarsimp
|
|
apply (erule cmap_relationE1 [OF rf_sr_cpte_relation],
|
|
erule ko_at_projectKO_opt)
|
|
apply simp
|
|
done
|
|
|
|
lemmas unfold_checkMapping_return
|
|
= from_bool_0[where 'a=machine_word_len, folded exception_defs]
|
|
to_bool_def
|
|
|
|
lemma checkMappingPPtr_pte_ccorres:
|
|
assumes pre:
|
|
"\<And>pte \<sigma>. \<Gamma> \<turnstile> {s. True \<and> (\<exists>pte'. cslift s (pte_Ptr pte_ptr) = Some pte' \<and> cpte_relation pte pte')
|
|
\<and> (\<sigma>, s) \<in> rf_sr}
|
|
call1 ;; Cond S return_void_C Skip
|
|
{s. (\<sigma>, s) \<in> rf_sr \<and> (isPagePTE pte) \<and> ptePPN pte << ptBits = addrFromPPtr pptr},
|
|
{s. (\<sigma>, s) \<in> rf_sr \<and> \<not> ((isPagePTE pte) \<and> ptePPN pte << ptBits = addrFromPPtr pptr)}"
|
|
shows
|
|
"ccorres_underlying rf_sr \<Gamma> (inr_rrel dc) xfdc (inl_rrel dc) xfdc
|
|
\<top> UNIV (SKIP # hs)
|
|
(doE
|
|
pte \<leftarrow> withoutFailure $ getObject pte_ptr;
|
|
checkMappingPPtr pptr pte
|
|
odE)
|
|
(call1;; Cond S return_void_C Skip)"
|
|
apply (simp add: checkMappingPPtr_def liftE_bindE)
|
|
apply (rule ccorres_symb_exec_l[where Q'="\<lambda>_. UNIV", OF _ _ getObject_ko_at, simplified])
|
|
apply (rule stronger_ccorres_guard_imp)
|
|
apply (rule ccorres_from_vcg_might_throw[where P=\<top>])
|
|
apply (rule allI)
|
|
apply (rule conseqPost, rule conseqPre, rule_tac \<sigma>1=\<sigma> and pte1=rv in pre)
|
|
apply clarsimp
|
|
apply (erule CollectE, assumption)
|
|
apply (clarsimp simp: Bex_def isPagePTE_def in_monad split: pte.splits)
|
|
apply (fastforce simp: Bex_def isPagePTE_def in_monad split: pte.splits)
|
|
apply (wp empty_fail_getObject | simp)+
|
|
apply (erule cmap_relationE1[OF rf_sr_cpte_relation])
|
|
apply (erule ko_at_projectKO_opt)
|
|
apply simp
|
|
apply (wp empty_fail_getObject | simp add: objBits_simps bit_simps)+
|
|
done
|
|
|
|
lemma ccorres_return_void_C':
|
|
"ccorres_underlying rf_sr \<Gamma> (inr_rrel dc) xfdc (inl_rrel dc) xfdc (\<lambda>_. True) UNIV (SKIP # hs) (return (Inl rv)) return_void_C"
|
|
apply (rule ccorres_from_vcg_throws)
|
|
apply (simp add: return_def)
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply auto
|
|
done
|
|
|
|
lemma multiple_add_less_nat:
|
|
"a < (c :: nat) \<Longrightarrow> x dvd a \<Longrightarrow> x dvd c \<Longrightarrow> b < x
|
|
\<Longrightarrow> a + b < c"
|
|
apply (subgoal_tac "b < c - a")
|
|
apply simp
|
|
apply (erule order_less_le_trans)
|
|
apply (rule dvd_imp_le)
|
|
apply simp
|
|
apply simp
|
|
done
|
|
|
|
lemma findVSpaceForASID_page_table_at'_simple[wp]:
|
|
notes checkPTAt_inv[wp del]
|
|
shows "\<lbrace>\<top>\<rbrace> findVSpaceForASID asid
|
|
\<lbrace>\<lambda>rv s. page_table_at' rv s\<rbrace>,-"
|
|
apply (simp add: findVSpaceForASID_def)
|
|
apply (wpsimp wp: getASID_wp simp: checkPTAt_def)
|
|
done
|
|
|
|
lemmas ccorres_name_ksCurThread = ccorres_pre_getCurThread[where f="\<lambda>_. f'" for f',
|
|
unfolded getCurThread_def, simplified gets_bind_ign]
|
|
|
|
lemma of_nat_pageBitsForSize:
|
|
"unat x = pageBitsForSize sz \<Longrightarrow> x = of_nat (pageBitsForSize sz)" for x::machine_word
|
|
by (drule sym, simp)
|
|
|
|
lemma checkMappingPPtr_def2:
|
|
"checkMappingPPtr p pte =
|
|
(if isPagePTE pte \<and> ptrFromPAddr (ptePPN pte << ptBits) = p
|
|
then returnOk()
|
|
else throw InvalidRoot)"
|
|
unfolding checkMappingPPtr_def
|
|
by (cases pte; simp add: isPagePTE_def unlessE_def cong: if_cong)
|
|
|
|
lemma pte_pte_invalid_new_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile> \<lbrace>s. True\<rbrace>
|
|
Call pte_pte_invalid_new_'proc
|
|
\<lbrace> pte_lift \<acute>ret__struct_pte_C = \<lparr>
|
|
pte_CL.ppn_CL = 0,
|
|
pte_CL.sw_CL = 0,
|
|
pte_CL.dirty_CL = 0,
|
|
pte_CL.accessed_CL = 0,
|
|
pte_CL.global_CL = 0,
|
|
pte_CL.user_CL = 0,
|
|
pte_CL.execute_CL = 0,
|
|
pte_CL.write_CL = 0,
|
|
pte_CL.read_CL = 0,
|
|
pte_CL.valid_CL = 0\<rparr>
|
|
\<rbrace>"
|
|
by (rule allI, rule conseqPre, vcg) (clarsimp simp: pte_lift_def fupdate_def)
|
|
|
|
lemma unmapPage_ccorres:
|
|
"ccorres dc xfdc (invs' and (\<lambda>_. asid_wf asid))
|
|
(\<lbrace> framesize_to_H \<acute>page_size = sz \<and> \<acute>page_size < 3 \<rbrace> \<inter>
|
|
\<lbrace> \<acute>asid___unsigned_long = asid \<rbrace> \<inter> \<lbrace> \<acute>vptr = vptr \<rbrace> \<inter> \<lbrace> \<acute>pptr___unsigned_long = pptr \<rbrace>)
|
|
hs
|
|
(unmapPage sz asid vptr pptr) (Call unmapPage_'proc)"
|
|
apply (rule ccorres_gen_asm)
|
|
apply (cinit lift: page_size_' asid___unsigned_long_' vptr_' pptr___unsigned_long_')
|
|
apply (simp add: ignoreFailure_liftM)
|
|
apply (fold dc_def)
|
|
apply (ctac add: findVSpaceForASID_ccorres)
|
|
apply (rename_tac vspace find_ret)
|
|
apply (rule ccorres_liftE_Seq)
|
|
apply (simp add: Collect_False del: Collect_const)
|
|
apply (ctac add: lookupPTSlot_ccorres)
|
|
apply csymbr
|
|
apply (simp (no_asm) add: split_def del: Collect_const)
|
|
apply (rule ccorres_split_unless_throwError_cond[where Q=\<top> and Q'=\<top>])
|
|
apply (clarsimp simp: of_nat_pageBitsForSize split: if_split)
|
|
apply (simp add: throwError_def flip: dc_def)
|
|
apply (rule ccorres_return_void_C)
|
|
apply (simp add: dc_def[symmetric])
|
|
apply (rule ccorres_rhs_assoc2, rule ccorres_rhs_assoc2,
|
|
rule ccorres_rhs_assoc2, rule ccorres_rhs_assoc2)
|
|
apply (subst bindE_assoc[symmetric])
|
|
apply (rule ccorres_splitE_novcg)
|
|
apply (simp only: inl_rrel_inl_rrel)
|
|
apply (rule checkMappingPPtr_pte_ccorres[simplified])
|
|
apply (rule conseqPre, vcg exspec=isPTEPageTable_spec')
|
|
apply (clarsimp simp: cpte_relation_def Let_def pte_lift_def isPagePTE_def
|
|
typ_heap_simps isPageTablePTE_def bit_simps from_bool_def
|
|
split: if_split_asm pte.split_asm)
|
|
apply (rule ceqv_refl)
|
|
apply (simp add: unfold_checkMapping_return liftE_bindE
|
|
Collect_const[symmetric] dc_def[symmetric]
|
|
del: Collect_const)
|
|
apply csymbr
|
|
apply (rule ccorres_split_nothrow_novcg)
|
|
apply (simp add: dc_def[symmetric] ptr_add_assertion_def split_def)
|
|
apply ccorres_rewrite
|
|
apply (rule storePTE_Basic_ccorres)
|
|
apply (simp add: cpte_relation_def Let_def)
|
|
apply ceqv
|
|
apply (rule ccorres_liftE)
|
|
apply (rule ccorres_call)
|
|
apply (rule ccorres_rel_imp)
|
|
apply (rule sfence_ccorres, simp, simp)
|
|
apply (simp add: xfdc_def)
|
|
apply simp
|
|
apply wp
|
|
apply (simp add: guard_is_UNIV_def)
|
|
apply wp
|
|
apply (simp add: guard_is_UNIV_def)
|
|
apply vcg
|
|
apply wpsimp
|
|
apply (vcg exspec=lookupPTSlot_modifies)
|
|
apply ccorres_rewrite
|
|
apply (simp add: throwError_def flip: dc_def)
|
|
apply (rule ccorres_return_void_C)
|
|
apply wp
|
|
apply (vcg exspec=findVSpaceForASID_modifies)
|
|
apply clarsimp
|
|
done
|
|
|
|
(* FIXME: move *)
|
|
lemma cap_to_H_PageCap_tag:
|
|
"\<lbrakk> cap_to_H cap = ArchObjectCap (FrameCap p R sz d A);
|
|
cap_lift C_cap = Some cap \<rbrakk> \<Longrightarrow>
|
|
cap_get_tag C_cap = scast cap_frame_cap"
|
|
apply (clarsimp simp: cap_to_H_def Let_def split: cap_CL.splits if_split_asm)
|
|
by (simp_all add: Let_def cap_lift_def split_def split: if_splits)
|
|
|
|
lemma ccap_relation_mapped_asid_0:
|
|
"\<lbrakk>ccap_relation (ArchObjectCap (FrameCap d v0 v1 v2 v3)) cap\<rbrakk>
|
|
\<Longrightarrow> (capFMappedASID_CL (cap_frame_cap_lift cap) \<noteq> 0 \<longrightarrow> v3 \<noteq> None) \<and>
|
|
(capFMappedASID_CL (cap_frame_cap_lift cap) = 0 \<longrightarrow> v3 = None)"
|
|
apply (frule cap_get_tag_PageCap_frame)
|
|
apply (frule cap_get_tag_isCap_unfolded_H_cap)
|
|
apply simp
|
|
done
|
|
|
|
lemma framesize_from_H_bounded:
|
|
"framesize_from_H x < 3"
|
|
by (clarsimp simp: framesize_from_H_def framesize_defs
|
|
split: vmpage_size.split)
|
|
|
|
lemma cap_to_H_Frame_unfold:
|
|
"cap_to_H capC = ArchObjectCap (FrameCap p R sz d m) \<Longrightarrow>
|
|
\<exists>asid_C sz_C vmrights_C device_C mappedAddr_C.
|
|
capC = Cap_frame_cap \<lparr>capFMappedASID_CL = asid_C, capFBasePtr_CL = p, capFSize_CL = sz_C,
|
|
capFVMRights_CL = vmrights_C, capFIsDevice_CL = device_C,
|
|
capFMappedAddress_CL = mappedAddr_C\<rparr> \<and>
|
|
sz = framesize_to_H sz_C \<and>
|
|
d = to_bool device_C \<and>
|
|
R = vmrights_to_H vmrights_C \<and>
|
|
m = (if asid_C = 0 then None else Some (asid_C, mappedAddr_C))"
|
|
supply if_cong[cong]
|
|
apply (clarsimp simp: cap_to_H_def Let_def split: cap_CL.splits)
|
|
apply (simp split: if_split_asm)
|
|
apply (rename_tac fcap, case_tac fcap, simp)
|
|
done
|
|
|
|
lemma performPageInvocationUnmap_ccorres:
|
|
notes Collect_const[simp del]
|
|
shows
|
|
"ccorres (K (K \<bottom>) \<currency> dc) (liftxf errstate id (K ()) ret__unsigned_long_')
|
|
(invs' and cte_wp_at' ((=) (ArchObjectCap cap) o cteCap) ctSlot and K (isFrameCap cap))
|
|
(UNIV \<inter> \<lbrace>ccap_relation (ArchObjectCap cap) \<acute>cap\<rbrace> \<inter> \<lbrace>\<acute>ctSlot = Ptr ctSlot\<rbrace>)
|
|
hs
|
|
(liftE (performPageInvocation (PageUnmap cap ctSlot)))
|
|
(Call performPageInvocationUnmap_'proc)"
|
|
apply (simp only: liftE_liftM ccorres_liftM_simp K_def)
|
|
apply (rule ccorres_gen_asm)
|
|
apply (clarsimp simp: isCap_simps)
|
|
apply (cinit' lift: cap_' ctSlot_' simp: performPageInvocation_def)
|
|
apply (rename_tac ctSlotC capC)
|
|
apply csymbr
|
|
apply (simp only: )
|
|
apply (frule ccap_relation_mapped_asid_0)
|
|
apply (rule_tac R'="\<lbrace> cap_get_tag capC = SCAST(32 signed \<rightarrow> 64) cap_frame_cap \<rbrace>"
|
|
in ccorres_split_nothrow)
|
|
apply (rule ccorres_Cond_rhs)
|
|
(* ASID present, unmap *)
|
|
apply (rule ccorres_rhs_assoc)+
|
|
apply csymbr
|
|
apply csymbr
|
|
apply csymbr
|
|
apply csymbr
|
|
apply clarsimp
|
|
apply (frule cap_get_tag_isCap_unfolded_H_cap)
|
|
apply (clarsimp simp: asidInvalid_def)
|
|
apply (rule ccorres_call[where xf'=xfdc])
|
|
apply datatype_schem
|
|
apply (rule unmapPage_ccorres)
|
|
apply simp
|
|
apply simp
|
|
apply simp
|
|
apply (simp add: asidInvalid_def flip: dc_def)
|
|
apply (rule ccorres_return_Skip)
|
|
apply ceqv
|
|
apply (simp add: liftM_def)
|
|
apply (rule_tac Q="\<lambda>slotCap. cte_wp_at' ((=) slotCap o cteCap) ctSlot and (\<lambda>_. isArchFrameCap slotCap)" and
|
|
Q'="\<lambda>slotCap slotCap_C. UNIV"
|
|
in ccorres_split_nothrow)
|
|
apply (ctac add: getSlotCap_h_val_ccorres)
|
|
apply ceqv
|
|
apply (rename_tac slotCap slotCap_C)
|
|
apply (rule ccorres_gen_asm)
|
|
apply (rule ccorres_guard_imp)
|
|
apply csymbr
|
|
apply csymbr
|
|
apply (rule ccorres_move_c_guard_cte)
|
|
apply (rule ccorres_add_return2)
|
|
apply (ctac add: ccorres_updateCap)
|
|
apply (rule ccorres_rel_imp[where xf'=ret__unsigned_long_' and
|
|
r'="\<lambda>_ x. x = SCAST(32 signed \<rightarrow> 64) EXCEPTION_NONE"])
|
|
apply (rule ccorres_return_C; simp)
|
|
apply simp
|
|
apply wp
|
|
apply vcg
|
|
apply (clarsimp simp: cte_wp_at_ctes_of)
|
|
apply (clarsimp simp: cap_get_tag_isCap asidInvalid_def)
|
|
apply (clarsimp simp: ccap_relation_def map_option_Some_eq2 c_valid_cap_def)
|
|
apply (clarsimp simp: cap_frame_cap_lift)
|
|
apply (rename_tac slotCap_CL)
|
|
apply (clarsimp simp: isCap_simps)
|
|
apply (simp (no_asm) add: cap_to_H_def cap_frame_cap_lift_def)
|
|
apply simp
|
|
apply (drule cap_to_H_Frame_unfold)+
|
|
apply (clarsimp simp: cl_valid_cap_def)
|
|
apply wp
|
|
apply (wpsimp simp: getSlotCap_def wp: getCTE_wp)
|
|
apply vcg
|
|
apply simp
|
|
apply (wpsimp wp: hoare_drop_imps hoare_vcg_ex_lift unmapPage_cte_wp_at')
|
|
apply (rule conseqPre, vcg exspec=unmapPage_modifies)
|
|
apply clarsimp
|
|
apply (clarsimp simp: asidInvalid_def cap_get_tag_isCap cte_wp_at_ctes_of)
|
|
apply (rename_tac p R sz d m cap' s s' cte)
|
|
apply (frule ctes_of_valid', fastforce)
|
|
apply (drule_tac t="cteCap cte" in sym)
|
|
apply (clarsimp simp: valid_cap'_def)
|
|
apply (clarsimp simp: ccap_relation_def map_option_Some_eq2)
|
|
apply (drule cap_to_H_Frame_unfold)
|
|
apply (clarsimp simp: cap_frame_cap_lift_def
|
|
c_valid_cap_def cl_valid_cap_def wellformed_mapdata'_def)
|
|
done
|
|
|
|
lemma RISCVGetWriteFromVMRights_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile> \<lbrace>s. \<acute>vm_rights < 4 \<and> \<acute>vm_rights \<noteq> 0\<rbrace> Call RISCVGetWriteFromVMRights_'proc
|
|
\<lbrace> \<acute>ret__unsigned_long = writable_from_vm_rights (vmrights_to_H \<^bsup>s\<^esup>vm_rights) \<rbrace>"
|
|
supply if_cong[cong]
|
|
apply vcg
|
|
apply (simp add: vmrights_to_H_def writable_from_vm_rights_def Kernel_C.VMKernelOnly_def
|
|
Kernel_C.VMReadOnly_def Kernel_C.VMReadWrite_def)
|
|
apply (drule word_less_cases, auto)+
|
|
done
|
|
|
|
lemma RISCVGetReadFromVMRights_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile> \<lbrace>s. \<acute>vm_rights < 4 \<and> \<acute>vm_rights \<noteq> 0\<rbrace> Call RISCVGetReadFromVMRights_'proc
|
|
\<lbrace> \<acute>ret__unsigned_long = readable_from_vm_rights (vmrights_to_H \<^bsup>s\<^esup>vm_rights) \<rbrace>"
|
|
supply if_cong[cong]
|
|
apply vcg
|
|
apply (simp add: vmrights_to_H_def readable_from_vm_rights_def Kernel_C.VMKernelOnly_def
|
|
Kernel_C.VMReadOnly_def Kernel_C.VMReadWrite_def)
|
|
apply (drule word_less_cases, auto)+
|
|
done
|
|
|
|
lemma writable_from_vm_rights_mask:
|
|
"(writable_from_vm_rights R) && 1 = (writable_from_vm_rights R :: machine_word)"
|
|
by (simp add: writable_from_vm_rights_def split: vmrights.splits)
|
|
|
|
lemma readable_from_vm_rights_mask:
|
|
"(readable_from_vm_rights R) && 1 = (readable_from_vm_rights R :: machine_word)"
|
|
by (simp add: readable_from_vm_rights_def split: vmrights.splits)
|
|
|
|
lemma user_from_vm_rights_mask:
|
|
"user_from_vm_rights R && 1 = (user_from_vm_rights R :: machine_word)"
|
|
by (simp add: user_from_vm_rights_def split: vmrights.splits)
|
|
|
|
lemma makeUserPTE_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile>
|
|
\<lbrace>s. \<acute>vm_rights < 4 \<and> \<acute>vm_rights \<noteq> 0\<rbrace>
|
|
Call makeUserPTE_'proc
|
|
\<lbrace> if \<^bsup>s\<^esup>executable = 0 \<and> vmrights_to_H \<^bsup>s\<^esup>vm_rights = VMKernelOnly
|
|
then
|
|
pte_lift \<acute>ret__struct_pte_C = \<lparr>
|
|
pte_CL.ppn_CL = 0,
|
|
pte_CL.sw_CL = 0,
|
|
pte_CL.dirty_CL = 0,
|
|
pte_CL.accessed_CL = 0,
|
|
pte_CL.global_CL = 0,
|
|
pte_CL.user_CL = 0,
|
|
pte_CL.execute_CL = 0,
|
|
pte_CL.write_CL = 0,
|
|
pte_CL.read_CL = 0,
|
|
pte_CL.valid_CL = 0\<rparr>
|
|
else
|
|
pte_lift \<acute>ret__struct_pte_C = \<lparr>
|
|
pte_CL.ppn_CL = (\<^bsup>s\<^esup>paddr >> 12) && mask 44,
|
|
pte_CL.sw_CL = 0,
|
|
pte_CL.dirty_CL = 1,
|
|
pte_CL.accessed_CL = 1,
|
|
pte_CL.global_CL = 0,
|
|
pte_CL.user_CL = 1,
|
|
pte_CL.execute_CL = \<^bsup>s\<^esup>executable && mask 1,
|
|
pte_CL.write_CL = writable_from_vm_rights (vmrights_to_H \<^bsup>s\<^esup>vm_rights),
|
|
pte_CL.read_CL = readable_from_vm_rights (vmrights_to_H \<^bsup>s\<^esup>vm_rights),
|
|
pte_CL.valid_CL = 1\<rparr> \<rbrace>"
|
|
supply if_cong[cong]
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (clarsimp simp: mask_def user_from_vm_rights_mask writable_from_vm_rights_mask
|
|
readable_from_vm_rights_mask)
|
|
apply (rule conjI; clarsimp simp: readable_from_vm_rights_def writable_from_vm_rights_def
|
|
split: if_split vmrights.splits)
|
|
done
|
|
|
|
lemma vmAttributesFromWord_spec:
|
|
"\<forall>s. \<Gamma> \<turnstile> \<lbrace>s. True\<rbrace> Call vmAttributesFromWord_'proc
|
|
\<lbrace> vm_attributes_lift \<acute>ret__struct_vm_attributes_C =
|
|
\<lparr> riscvExecuteNever_CL = \<^bsup>s\<^esup>w && 1 \<rparr> \<rbrace>"
|
|
by (vcg, simp add: vm_attributes_lift_def word_sless_def word_sle_def mask_def)
|
|
|
|
lemma cap_to_H_PTCap_tag:
|
|
"\<lbrakk> cap_to_H cap = ArchObjectCap (PageTableCap p A);
|
|
cap_lift C_cap = Some cap \<rbrakk> \<Longrightarrow>
|
|
cap_get_tag C_cap = scast cap_page_table_cap"
|
|
apply (clarsimp simp: cap_to_H_def Let_def split: cap_CL.splits if_split_asm)
|
|
apply (simp_all add: Let_def cap_lift_def split: if_splits)
|
|
done
|
|
|
|
lemma cap_to_H_PTCap:
|
|
"cap_to_H cap = ArchObjectCap (PageTableCap p asid) \<Longrightarrow>
|
|
\<exists>cap_CL. cap = Cap_page_table_cap cap_CL \<and>
|
|
to_bool (capPTIsMapped_CL cap_CL) = (asid \<noteq> None) \<and>
|
|
(asid \<noteq> None \<longrightarrow> capPTMappedASID_CL cap_CL = fst (the asid) \<and>
|
|
capPTMappedAddress_CL cap_CL = snd (the asid)) \<and>
|
|
capPTBasePtr_CL cap_CL = p"
|
|
by (auto simp add: cap_to_H_def Let_def split: cap_CL.splits if_splits)
|
|
|
|
lemma cap_lift_PTCap_Base:
|
|
"\<lbrakk> cap_to_H cap_cl = ArchObjectCap (PageTableCap p asid);
|
|
cap_lift cap_c = Some cap_cl \<rbrakk>
|
|
\<Longrightarrow> p = capPTBasePtr_CL (cap_page_table_cap_lift cap_c)"
|
|
apply (simp add: cap_page_table_cap_lift_def)
|
|
apply (clarsimp simp: cap_to_H_def Let_def split: cap_CL.splits if_splits)
|
|
done
|
|
|
|
declare mask_Suc_0[simp]
|
|
|
|
(* FIXME: move *)
|
|
lemma setCTE_asidpool':
|
|
"\<lbrace> ko_at' (ASIDPool pool) p \<rbrace> setCTE c p' \<lbrace>\<lambda>_. ko_at' (ASIDPool pool) p\<rbrace>"
|
|
apply (clarsimp simp: setCTE_def)
|
|
apply (simp add: setObject_def split_def)
|
|
apply (rule hoare_seq_ext [OF _ hoare_gets_post])
|
|
apply (clarsimp simp: valid_def in_monad)
|
|
apply (frule updateObject_type)
|
|
apply (clarsimp simp: obj_at'_def)
|
|
apply (rule conjI)
|
|
apply (clarsimp simp: lookupAround2_char1)
|
|
apply (clarsimp split: if_split)
|
|
apply (case_tac obj', auto)[1]
|
|
apply (rename_tac arch_kernel_object)
|
|
apply (case_tac arch_kernel_object, auto)[1]
|
|
apply (simp add: updateObject_cte)
|
|
apply (clarsimp simp: updateObject_cte typeError_def magnitudeCheck_def in_monad
|
|
split: kernel_object.splits if_splits option.splits)
|
|
apply (clarsimp simp: ps_clear_upd lookupAround2_char1)
|
|
done
|
|
|
|
lemmas udpateCap_asidpool' = updateCap_ko_at_ap_inv'
|
|
|
|
(* FIXME: move *)
|
|
lemma asid_pool_at_rf_sr:
|
|
"\<lbrakk>ko_at' (ASIDPool pool) p s; (s, s') \<in> rf_sr\<rbrakk> \<Longrightarrow>
|
|
\<exists>pool'. cslift s' (ap_Ptr p) = Some pool' \<and>
|
|
casid_pool_relation (ASIDPool pool) pool'"
|
|
apply (clarsimp simp: rf_sr_def cstate_relation_def Let_def cpspace_relation_def)
|
|
apply (erule (1) cmap_relation_ko_atE)
|
|
apply clarsimp
|
|
done
|
|
|
|
(* FIXME: move *)
|
|
lemma asid_pool_at_ko:
|
|
"asid_pool_at' p s \<Longrightarrow> \<exists>pool. ko_at' (ASIDPool pool) p s"
|
|
apply (clarsimp simp: typ_at'_def obj_at'_def ko_wp_at'_def)
|
|
apply (case_tac ko, auto)
|
|
apply (rename_tac arch_kernel_object)
|
|
apply (case_tac arch_kernel_object, auto)[1]
|
|
apply (rename_tac asidpool)
|
|
apply (case_tac asidpool, auto)[1]
|
|
done
|
|
|
|
(* FIXME: move *)
|
|
lemma asid_pool_at_c_guard:
|
|
"\<lbrakk>asid_pool_at' p s; (s, s') \<in> rf_sr\<rbrakk> \<Longrightarrow> c_guard (ap_Ptr p)"
|
|
by (fastforce intro: typ_heap_simps dest!: asid_pool_at_ko asid_pool_at_rf_sr)
|
|
|
|
(* FIXME: move *)
|
|
lemma setObjectASID_Basic_ccorres:
|
|
"ccorres dc xfdc \<top> {s. f s = p \<and> casid_pool_relation pool (asid_pool_C.asid_pool_C (pool' s))} hs
|
|
(setObject p pool)
|
|
((Basic (\<lambda>s. globals_update( t_hrs_'_update
|
|
(hrs_mem_update (heap_update (Ptr &(ap_Ptr (f s)\<rightarrow>[''array_C''])) (pool' s)))) s)))"
|
|
apply (rule setObject_ccorres_helper)
|
|
apply (simp_all add: objBits_simps pageBits_def)
|
|
apply (rule conseqPre, vcg)
|
|
apply (rule subsetI, clarsimp simp: Collect_const_mem)
|
|
apply (rule cmap_relationE1, erule rf_sr_cpspace_asidpool_relation,
|
|
erule ko_at_projectKO_opt)
|
|
apply (clarsimp simp: rf_sr_def cstate_relation_def Let_def)
|
|
apply (rule conjI)
|
|
apply (clarsimp simp: cpspace_relation_def typ_heap_simps
|
|
update_asidpool_map_to_asidpools
|
|
update_asidpool_map_tos)
|
|
apply (case_tac y')
|
|
apply clarsimp
|
|
apply (erule cmap_relation_updI,
|
|
erule ko_at_projectKO_opt, simp+)
|
|
apply (simp add: cready_queues_relation_def
|
|
carch_state_relation_def
|
|
cmachine_state_relation_def
|
|
Let_def typ_heap_simps
|
|
update_asidpool_map_tos)
|
|
done
|
|
|
|
lemma getObject_ap_inv [wp]: "\<lbrace>P\<rbrace> (getObject addr :: asidpool kernel) \<lbrace>\<lambda>rv. P\<rbrace>"
|
|
apply (rule getObject_inv)
|
|
apply simp
|
|
apply (rule loadObject_default_inv)
|
|
done
|
|
|
|
lemma getObject_ko_at_ap [wp]:
|
|
"\<lbrace>\<top>\<rbrace> getObject p \<lbrace>\<lambda>rv::asidpool. ko_at' rv p\<rbrace>"
|
|
by (rule getObject_ko_at | simp add: objBits_simps bit_simps)+
|
|
|
|
lemma canonical_address_page_table_at':
|
|
"\<lbrakk>page_table_at' p s; pspace_canonical' s\<rbrakk> \<Longrightarrow> canonical_address p"
|
|
apply (clarsimp simp: page_table_at'_def)
|
|
apply (drule_tac x=0 in spec, clarsimp simp: bit_simps typ_at_to_obj_at_arches)
|
|
apply (erule (1) obj_at'_is_canonical)
|
|
done
|
|
|
|
lemma page_table_at'_array_assertion:
|
|
assumes "(s,s') \<in> rf_sr"
|
|
assumes "page_table_at' pt s"
|
|
assumes "n \<le> 2^ptTranslationBits" "0 < n"
|
|
shows "array_assertion (pte_Ptr pt) n (hrs_htd (t_hrs_' (globals s')))"
|
|
using assms
|
|
by (fastforce simp: bit_simps
|
|
intro: array_assertion_abs_pt[where x="\<lambda>_. (1::nat)", simplified, rule_format])
|
|
|
|
lemma page_table_at'_array_assertion_weak[unfolded ptTranslationBits_def, simplified]:
|
|
assumes "(s,s') \<in> rf_sr"
|
|
assumes "page_table_at' pt s"
|
|
assumes "n < 2^(ptTranslationBits-1)"
|
|
shows "array_assertion (pte_Ptr pt) ((unat (2^(ptTranslationBits-1) + of_nat n::machine_word)))
|
|
(hrs_htd (t_hrs_' (globals s')))"
|
|
using assms
|
|
by (fastforce intro: page_table_at'_array_assertion
|
|
simp: unat_add_simple ptTranslationBits_def word_bits_def unat_of_nat)
|
|
|
|
lemma page_table_at'_array_assertion_strong[unfolded ptTranslationBits_def, simplified]:
|
|
assumes "(s,s') \<in> rf_sr"
|
|
assumes "page_table_at' pt s"
|
|
assumes "n < 2^(ptTranslationBits-1)"
|
|
shows "array_assertion (pte_Ptr pt) (Suc (unat (2^(ptTranslationBits-1) + of_nat n::machine_word)))
|
|
(hrs_htd (t_hrs_' (globals s')))"
|
|
using assms
|
|
using assms
|
|
by (fastforce intro: page_table_at'_array_assertion
|
|
simp: unat_add_simple ptTranslationBits_def word_bits_def unat_of_nat)
|
|
|
|
lemma copyGlobalMappings_ccorres:
|
|
"ccorres dc xfdc
|
|
(page_table_at' pt and valid_arch_state')
|
|
(UNIV \<inter> {s. newLvl1pt_' s = Ptr pt}) []
|
|
(copyGlobalMappings pt) (Call copyGlobalMappings_'proc)"
|
|
proof -
|
|
have ptIndex_maxPTLevel_pptrBase:
|
|
"ptIndex maxPTLevel RISCV64.pptrBase = 0x100"
|
|
by (simp add: ptIndex_def maxPTLevel_def ptBitsLeft_def pageBits_def ptTranslationBits_def
|
|
RISCV64.pptrBase_def canonical_bit_def mask_def)
|
|
let ?enum = "\<lambda>n. [0x100.e.0x1FF::machine_word] ! n << 3"
|
|
have enum_rewrite:
|
|
"\<And>n. n < 256 \<Longrightarrow> ?enum n = 0x800 + of_nat n * 8"
|
|
by (auto simp: upto_enum_word_nth word_shiftl_add_distrib shiftl_t2n)
|
|
show ?thesis
|
|
apply (cinit lift: newLvl1pt_' simp: ptIndex_maxPTLevel_pptrBase ptTranslationBits_def)
|
|
apply (rule ccorres_pre_gets_riscvKSGlobalPT_ksArchState, rename_tac globalPT)
|
|
apply (rule ccorres_rel_imp[where r=dc, OF _ dc_simp])
|
|
apply (clarsimp simp: whileAnno_def objBits_simps bit_simps RISCV64.pptrBase_def mask_def)
|
|
apply (rule ccorres_h_t_valid_riscvKSGlobalPT)
|
|
apply csymbr
|
|
apply csymbr
|
|
apply clarsimp
|
|
apply (rule_tac F="\<lambda>n s. globalPT = riscvKSGlobalPT (ksArchState s) \<and> page_table_at' pt s \<and>
|
|
page_table_at' globalPT s"
|
|
and i="0x100"
|
|
in ccorres_mapM_x_while'
|
|
; clarsimp simp: word_bits_def)
|
|
apply (rule ccorres_guard_imp2)
|
|
apply (rule ccorres_pre_getObject_pte, rename_tac pte)
|
|
apply (simp add: storePTE_def)
|
|
apply (rule_tac P="\<lambda>s. page_table_at' pt s \<and>
|
|
page_table_at' (riscvKSGlobalPT (ksArchState s)) s \<and>
|
|
ko_at' pte (riscvKSGlobalPT (ksArchState s) + ?enum n) s"
|
|
and P'="\<lbrace>\<acute>i = 0x100 + of_nat n \<rbrace>"
|
|
in setObject_ccorres_helper)
|
|
apply (rule conseqPre, vcg, clarsimp)
|
|
apply (prop_tac "(0x100::machine_word) + of_nat n \<noteq> 0")
|
|
apply unat_arith
|
|
apply (simp add: unat_of_nat)
|
|
apply clarsimp
|
|
apply (frule (2) page_table_at'_array_assertion_weak)
|
|
apply (frule (2) page_table_at'_array_assertion_strong)
|
|
apply (frule rf_sr_riscvKSGlobalPT, clarsimp)
|
|
apply (frule (2) page_table_at'_array_assertion_weak[where pt="symbol_table s" for s])
|
|
apply (frule (2) page_table_at'_array_assertion_strong[where pt="symbol_table s" for s])
|
|
apply simp
|
|
apply (rule cmap_relationE1[OF rf_sr_cpte_relation], assumption,
|
|
erule_tac ko=ko' in ko_at_projectKO_opt)
|
|
apply (rule cmap_relationE1[OF rf_sr_cpte_relation], assumption,
|
|
erule_tac ko=pte in ko_at_projectKO_opt)
|
|
apply (clarsimp simp: enum_rewrite typ_heap_simps' heap_access_Array_element)
|
|
apply (clarsimp simp: rf_sr_def cstate_relation_def Let_def)
|
|
apply (clarsimp simp: typ_heap_simps update_pte_map_tos)
|
|
apply (rule conjI)
|
|
apply (clarsimp simp: cpspace_relation_def typ_heap_simps
|
|
update_pte_map_tos update_pte_map_to_ptes
|
|
carray_map_relation_upd_triv)
|
|
subgoal by (erule (2) cmap_relation_updI; simp)
|
|
subgoal by (clarsimp simp: carch_state_relation_def cmachine_state_relation_def)
|
|
apply simp
|
|
apply (simp add: objBits_simps)
|
|
apply clarsimp
|
|
apply (rule conseqPre, vcg, clarsimp)
|
|
apply wp
|
|
apply (clarsimp simp: valid_arch_state'_def valid_global_pts'_def riscvKSGlobalPT_def)
|
|
apply (erule_tac x=maxPTLevel in allE, force)
|
|
done
|
|
qed
|
|
|
|
lemma performASIDPoolInvocation_ccorres:
|
|
notes option.case_cong_weak [cong]
|
|
shows
|
|
"ccorres (K (K \<bottom>) \<currency> dc) (liftxf errstate id (K ()) ret__unsigned_long_')
|
|
(invs' and cte_wp_at' (isPTCap' o cteCap) ctSlot and asid_pool_at' poolPtr
|
|
and K (asid_wf asid))
|
|
(UNIV \<inter> \<lbrace>\<acute>poolPtr = Ptr poolPtr\<rbrace> \<inter> \<lbrace>\<acute>asid___unsigned_long = asid\<rbrace> \<inter> \<lbrace>\<acute>vspaceCapSlot = Ptr ctSlot\<rbrace>)
|
|
[]
|
|
(liftE (performASIDPoolInvocation (Assign asid poolPtr ctSlot)))
|
|
(Call performASIDPoolInvocation_'proc)"
|
|
apply (simp only: liftE_liftM ccorres_liftM_simp K_def)
|
|
apply (rule ccorres_gen_asm)
|
|
apply (cinit lift: poolPtr_' asid___unsigned_long_' vspaceCapSlot_')
|
|
apply (rule_tac Q="\<lambda>slotCap. valid_arch_state' and valid_objs' and
|
|
cte_wp_at' ((=) slotCap o cteCap) ctSlot and
|
|
(\<lambda>_. isPTCap' slotCap \<and> capPTBasePtr (capCap slotCap) \<noteq> 0)" and
|
|
Q'="\<lambda>slotCap slotCap_C. UNIV"
|
|
in ccorres_split_nothrow)
|
|
apply (ctac add: getSlotCap_h_val_ccorres)
|
|
apply ceqv
|
|
apply (rule ccorres_gen_asm)
|
|
apply (rule ccorres_guard_imp)
|
|
apply csymbr
|
|
apply csymbr
|
|
apply csymbr
|
|
apply csymbr
|
|
apply csymbr
|
|
apply (ctac add: ccorres_updateCap)
|
|
apply (ctac (no_vcg) add: copyGlobalMappings_ccorres)
|
|
apply (simp add: liftM_def)
|
|
apply (rule ccorres_pre_getObject_asidpool)
|
|
apply (rule ccorres_move_c_guard_ap)
|
|
apply (rule ccorres_add_return2)
|
|
apply (ctac add: setObjectASID_Basic_ccorres)
|
|
apply (rule ccorres_rel_imp[where xf'=ret__unsigned_long_' and
|
|
r'="\<lambda>_ x. x = SCAST(32 signed \<rightarrow> 64) EXCEPTION_NONE"])
|
|
apply (rule ccorres_return_C; simp)
|
|
apply simp
|
|
apply wp
|
|
apply simp
|
|
apply vcg
|
|
apply (rule hoare_strengthen_post[where Q="\<lambda>_. \<top>"], wp)
|
|
apply (clarsimp simp: typ_at'_def ko_wp_at'_def obj_at'_def)
|
|
apply wp
|
|
apply simp
|
|
apply vcg
|
|
apply (clarsimp simp: cte_wp_at_ctes_of)
|
|
apply (drule (1) ctes_of_valid')
|
|
apply (clarsimp simp: valid_cap'_def isPTCap'_def)
|
|
apply (clarsimp simp: isPTCap'_def cap_get_tag_isCap_unfolded_H_cap asidInvalid_def)
|
|
apply (clarsimp split: if_split)
|
|
apply (erule ccap_relationE)
|
|
apply (rename_tac cap_CL)
|
|
apply (drule_tac t="cap_to_H cap_CL" in sym)
|
|
apply (clarsimp simp: cap_lift_PTCap_Base[symmetric])
|
|
apply (frule cap_to_H_PTCap, clarsimp)
|
|
apply (rule conjI; clarsimp)
|
|
apply (clarsimp simp: cap_page_table_cap_lift)
|
|
apply (clarsimp simp: ccap_relation_def cap_to_H_def)
|
|
apply (simp (no_asm) add: cap_page_table_cap_lift_def)
|
|
apply (clarsimp simp: asid_wf_eq_mask_eq asid_bits_def)
|
|
apply (simp add: c_valid_cap_def cl_valid_cap_def)
|
|
apply (erule notE[where P="casid_pool_relation a b" for a b])
|
|
apply (clarsimp simp: typ_heap_simps simp flip: fun_upd_def)
|
|
apply (clarsimp simp: casid_pool_relation_def
|
|
split: asidpool.splits asid_pool_C.splits)
|
|
apply (rule conjI)
|
|
apply (rule array_relation_update)
|
|
apply (simp add: inv_def)
|
|
apply (simp add: mask_2pm1)
|
|
apply simp
|
|
apply (simp add: asid_low_bits_def)
|
|
apply (clarsimp simp: word_and_le1 inv_def ran_def split: if_splits)
|
|
apply wp
|
|
apply (wpsimp simp: getSlotCap_def wp: getCTE_wp)
|
|
apply simp
|
|
apply vcg
|
|
apply (clarsimp simp: cte_wp_at_ctes_of isPTCap'_def)
|
|
apply (drule ctes_of_valid', fastforce)
|
|
apply (clarsimp simp: valid_cap'_def isPTCap'_def)
|
|
apply (rule conjI, fastforce)
|
|
apply (rule conjI, fastforce)
|
|
apply clarsimp
|
|
apply (drule page_table_pte_atI'[where x=0, simplified])
|
|
apply (erule no_0_typ_at', fastforce)
|
|
done
|
|
|
|
lemma pte_case_isInvalidPTE:
|
|
"(case pte of InvalidPTE \<Rightarrow> P | _ \<Rightarrow> Q)
|
|
= (if isInvalidPTE pte then P else Q)"
|
|
by (cases pte, simp_all add: isInvalidPTE_def)
|
|
|
|
lemma ccap_relation_page_table_mapped_asid:
|
|
"ccap_relation (ArchObjectCap (PageTableCap p (Some (asid, vspace)))) cap
|
|
\<Longrightarrow> asid = capPTMappedASID_CL (cap_page_table_cap_lift cap)"
|
|
by (frule cap_get_tag_isCap_unfolded_H_cap)
|
|
(clarsimp simp: cap_page_table_cap_lift ccap_relation_def cap_to_H_def split: if_splits)
|
|
|
|
lemma performPageTableInvocationMap_ccorres:
|
|
"ccorres (K (K \<bottom>) \<currency> dc) (liftxf errstate id (K ()) ret__unsigned_long_')
|
|
(cte_at' ctSlot)
|
|
(\<lbrace>ccap_relation cap \<acute>cap\<rbrace> \<inter> \<lbrace>\<acute>ctSlot = Ptr ctSlot\<rbrace>
|
|
\<inter> \<lbrace>cpte_relation pte \<acute>pte\<rbrace> \<inter> \<lbrace>\<acute>ptSlot = Ptr ptSlot\<rbrace>)
|
|
[]
|
|
(liftE (performPageTableInvocation (PageTableMap cap ctSlot pte ptSlot)))
|
|
(Call performPageTableInvocationMap_'proc)"
|
|
apply (simp only: liftE_liftM ccorres_liftM_simp)
|
|
apply (cinit lift: cap_' ctSlot_' pte_' ptSlot_')
|
|
apply (ctac (no_vcg))
|
|
apply (rule ccorres_split_nothrow)
|
|
apply simp
|
|
apply (erule storePTE_Basic_ccorres)
|
|
apply ceqv
|
|
apply (rule ccorres_cases[where P="\<exists>p a v. cap = ArchObjectCap (PageTableCap p (Some (a, v)))"
|
|
and H=\<top> and H'=UNIV];
|
|
clarsimp split: capability.splits arch_capability.splits simp: ccorres_fail)
|
|
apply (rule ccorres_add_return2)
|
|
apply (ctac (no_vcg) add: sfence_ccorres)
|
|
apply (rule_tac P=\<top> and P'=UNIV in ccorres_from_vcg_throws)
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (clarsimp simp: return_def)
|
|
apply wpsimp
|
|
apply (rule ccorres_guard_imp)
|
|
apply (rule ccorres_add_return2)
|
|
apply (ctac (no_vcg) add: sfence_ccorres)
|
|
apply (rule_tac P=\<top> and P'=UNIV in ccorres_from_vcg_throws)
|
|
apply (rule allI, rule conseqPre, vcg)
|
|
apply (clarsimp simp: return_def)
|
|
apply (wpsimp | vcg)+
|
|
done
|
|
|
|
end
|
|
|
|
end
|