(*
 * 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)
 *)

(*
Retype refinement
*)

theory Retype_AI
imports VSpace_AI
begin

abbreviation "up_aligned_area ptr sz \<equiv> {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)}"
abbreviation "down_aligned_area ptr sz \<equiv> {(ptr && ~~ mask sz) + (2 ^ sz - 1) .. ptr}"

context begin interpretation Arch .
requalify_facts
  global_refs_kheap
requalify_consts
  clearMemory
  clearMemoryVM
end

declare global_refs_kheap[simp]

locale Retype_AI_clearMemoryVM =
  assumes clearMemoryVM_return [simp]: "\<And> a b. clearMemoryVM a b = return ()"

context Retype_AI_clearMemoryVM begin
lemmas clearMemoryVM_return_raw = clearMemoryVM_return[abs_def]
end

lemma upto_enum_inc_1:
  "a < 2^word_bits - 1 \<Longrightarrow> [(0::machine_word).e.1 + a] = [0.e.a] @ [(1+a)]"
  apply (simp add:upto_enum_word)
  apply (subgoal_tac "unat (1 +a) = 1 + unat a")
    apply simp
   apply (subst unat_plus_simple[THEN iffD1])
   apply (rule word_plus_mono_right2[where b = "2^word_bits - 2"])
    apply (simp add:word_bits_def minus_one_norm)+
    apply unat_arith
   apply simp
 done

lemma unat_of_nat_minus_1:
  "\<lbrakk>n < 2^len_of TYPE('a);n\<noteq> 0\<rbrakk> \<Longrightarrow> (unat (((of_nat n):: 'a :: len word) - 1)) = n - 1"
  apply (subst unat_minus_one)
   apply (rule of_nat_neq_0)
     apply simp
   apply (simp add:of_nat_neq_0 word_bits_def)
   apply (simp add:unat_of_nat word_bits_def)
  done

lemma range_to_bl':
  "\<lbrakk> is_aligned (ptr :: 'a :: len word) bits; bits < len_of TYPE('a) \<rbrakk> \<Longrightarrow>
   {ptr .. ptr + (2 ^ bits) - 1} = {x. take (len_of TYPE('a) - bits) (to_bl x)
                                        = take (len_of TYPE('a) - bits) (to_bl ptr)}"
  apply (rule set_eqI, rule iffI)
   apply clarsimp
   apply (subgoal_tac "\<exists>y. x = ptr + y \<and> y < 2 ^ bits")
    apply clarsimp
    apply (subst is_aligned_add_conv)
       apply assumption
      apply simp
    apply simp
   apply (rule_tac x="x - ptr" in exI)
   apply (simp add: add_diff_eq[symmetric])
   apply (simp only: word_less_sub_le[symmetric])
   apply (rule word_diff_ls')
    apply (simp add: field_simps)
   apply assumption
  apply simp
  apply (subgoal_tac "\<exists>y. y < 2 ^ bits \<and> to_bl (ptr + y) = to_bl x")
   apply clarsimp
   apply (rule conjI)
    apply (erule(1) is_aligned_no_wrap')
   apply (simp only: add_diff_eq[symmetric])
   apply (rule word_plus_mono_right)
    apply simp
   apply (erule is_aligned_no_wrap')
   apply simp
  apply (rule_tac x="of_bl (drop (len_of TYPE('a) - bits) (to_bl x))" in exI)
  apply (rule context_conjI)
   apply (rule order_less_le_trans [OF of_bl_length])
    apply simp
   apply simp
  apply (subst is_aligned_add_conv)
     apply assumption
    apply simp
  apply (drule sym)
  apply (simp add: word_rep_drop)
  done

lemma range_to_bl:
  "is_aligned (ptr :: 'a :: len word) bits \<Longrightarrow>
   {ptr..ptr + 2 ^ bits - 1} =
     {x. take (len_of TYPE('a) - bits) (to_bl x) =
         take (len_of TYPE('a) - bits) (to_bl ptr)}"
  apply (erule is_aligned_get_word_bits)
   apply (erule(1) range_to_bl')
  apply (rule set_eqI)
  apply (simp add: power_overflow)
  done

lemma aligned_ranges_subset_or_disjoint:
  "\<lbrakk> is_aligned (p :: 'a :: len word) n; is_aligned (p' :: 'a :: len word) n' \<rbrakk>
     \<Longrightarrow> {p .. p + 2 ^ n - 1} \<inter> {p' .. p' + 2 ^ n' - 1} = {}
      \<or> {p .. p + 2 ^ n - 1} \<subseteq> {p' .. p' + 2 ^ n' - 1}
      \<or> {p .. p + 2 ^ n - 1} \<supseteq> {p' .. p' + 2 ^ n' - 1}"
  apply (simp add: range_to_bl)
  apply (rule disjCI2)
  apply (erule nonemptyE)
  apply simp
  apply (subgoal_tac "(\<exists>n''. len_of TYPE('a) - n = (len_of TYPE('a) - n') + n'')
                    \<or> (\<exists>n''. len_of TYPE('a) - n' = (len_of TYPE('a) - n) + n'')")
   apply (elim conjE disjE exE)
    apply (rule disjI1)
    apply (clarsimp simp: take_add)
   apply (rule disjI2)
   apply (clarsimp simp: take_add)
  apply arith
  done

lemma aligned_range_offset_subset:
  assumes al: "is_aligned (ptr :: 'a :: len word) sz" and al': "is_aligned x sz'"
  and     szv: "sz' \<le> sz" and xsz: "x < 2 ^ sz"
  shows       "{ptr + x .. (ptr + x) + 2 ^ sz' - 1} \<subseteq> {ptr .. ptr + 2 ^ sz - 1}"
  using al
proof (rule is_aligned_get_word_bits)
  assume p0: "ptr = 0" and szv': "len_of TYPE ('a) \<le> sz"
  hence "(2 :: 'a word) ^ sz = 0" by simp

  thus ?thesis using p0
    apply -
    apply (erule ssubst)
    apply simp
    done
next
  assume szv': "sz < len_of TYPE('a)"

  hence blah: "2 ^ (sz - sz') < (2 :: nat) ^ len_of TYPE('a)"
    using szv
    apply -
    apply (rule power_strict_increasing, simp+)
    done
  show ?thesis using szv szv'
    apply (intro range_subsetI)
     apply (rule is_aligned_no_wrap' [OF al xsz])
    apply (simp only: add_diff_eq[symmetric])
    apply (subst add.assoc, rule word_plus_mono_right)
    apply (subst iffD1 [OF le_m1_iff_lt])
    apply (simp add: p2_gt_0 word_bits_conv)
    apply (rule is_aligned_add_less_t2n[OF al' _ szv xsz])
    apply simp
    apply (simp add: field_simps szv al is_aligned_no_overflow)
    done
qed

lemma aligned_diff:
  "\<lbrakk>is_aligned (dest :: 'a :: len word) bits; is_aligned (ptr :: 'a :: len word) sz; bits \<le> sz; sz < len_of TYPE('a);
    dest < ptr\<rbrakk>
   \<Longrightarrow> (2^ bits - 1) + dest < ptr"
  apply (frule_tac p' = ptr in aligned_ranges_subset_or_disjoint)
   apply assumption
  apply (elim disjE)
    apply clarsimp
    apply (drule_tac ptr = dest in is_aligned_no_overflow)
     apply simp
    apply (drule is_aligned_no_overflow)
    apply clarsimp
    apply (erule impE)
     apply (erule order_trans[OF less_imp_le])
     apply (clarsimp simp:field_simps)
    apply (clarsimp simp:not_less field_simps not_le)
   apply clarsimp
   apply (drule_tac ptr = dest in is_aligned_no_overflow)
    apply simp
   apply fastforce
  apply clarsimp
  apply (frule is_aligned_no_overflow)
  apply (erule impE)
  apply (frule(1) is_aligned_no_overflow)
  apply (rule ccontr)
  apply (clarsimp simp:not_less p_assoc_help)
  apply (subst (asm) add.commute[where b = "(2^ sz - 1)"])
  apply (subst (asm) add.commute[where b = "(2^ bits - 1)"])+
  apply (drule word_sub_mono2)
   apply (rule word_le_minus_mono_left)
   apply (erule(1) two_power_increasing)
   apply (simp add:word_1_le_power)
   apply (simp add:field_simps is_aligned_no_overflow)+
  done

lemma default_object_tcbE:
  "\<lbrakk> default_object ty dev us = TCB tcb; ty \<noteq> Untyped;
   \<lbrakk> tcb = default_tcb; ty = Structures_A.TCBObject \<rbrakk> \<Longrightarrow> R \<rbrakk> \<Longrightarrow> R"
  unfolding default_object_def by (cases ty, auto)

locale Retype_AI_slot_bits =
  assumes slot_bits_def2: "slot_bits = cte_level_bits"
     and  arch_kobj_size_cong:
            "\<And>a a1 c c1. \<lbrakk>a = a1; c=c1\<rbrakk> \<Longrightarrow> arch_kobj_size (default_arch_object a b c)
                 = arch_kobj_size (default_arch_object a1 b1 c1)"

lemma (in Retype_AI_slot_bits) obj_bits_cong:
  "\<lbrakk>a = a1; c=c1\<rbrakk> \<Longrightarrow> obj_bits (default_object a b c)
    = obj_bits (default_object a1 b1 c1)"
  by (simp add: default_object_def arch_kobj_size_cong
         split: if_splits apiobject_type.splits)

lemma (in Retype_AI_slot_bits) obj_bits_api_default_object:
  "\<lbrakk> ty \<noteq> Untyped\<rbrakk> \<Longrightarrow> obj_bits_api ty us = obj_bits (default_object ty dev us)"
  unfolding obj_bits_api_def default_object_def
  by (cases ty)
     (simp_all add: slot_bits_def2 arch_kobj_size_cong wf_empty_bits cte_level_bits_def)

lemma obj_bits_api_default_CapTableObject:
  "obj_bits (default_object Structures_A.apiobject_type.CapTableObject dev us)
  = cte_level_bits + us"
  unfolding default_object_def
  by (simp add: cte_level_bits_def wf_empty_bits)

lemma empty_cnode_dom:
  "x \<in> dom (empty_cnode n) \<Longrightarrow> length x = n"
  unfolding dom_def empty_cnode_def by (simp split: if_split_asm)

context Retype_AI_slot_bits begin

lemma obj_bits_api_def2:
  "obj_bits_api type obj_size_bits =
   (case type of Structures_A.Untyped \<Rightarrow> obj_size_bits
           | _ \<Rightarrow> obj_bits (default_object type False obj_size_bits))"
  by (simp add: obj_bits_api_def default_object_def
                wf_empty_bits dom_empty_cnode ex_with_length
                slot_bits_def2 cte_level_bits_def
         split: apiobject_type.split)

lemma obj_bits_api_def3:
  "obj_bits_api type obj_size_bits =
   (if type = Structures_A.Untyped then obj_size_bits
     else obj_bits (default_object type False obj_size_bits))"
  by (simp add: obj_bits_api_def default_object_def
                wf_empty_bits dom_empty_cnode ex_with_length
                slot_bits_def2 cte_level_bits_def
         split: apiobject_type.split)

lemma obj_bits_api_def4:
  "obj_bits_api type obj_size_bits =
   (if type = Structures_A.Untyped then obj_size_bits
     else obj_bits (default_object type True obj_size_bits))"
  by (simp add: obj_bits_api_def default_object_def arch_kobj_size_cong
                wf_empty_bits dom_empty_cnode ex_with_length
                slot_bits_def2 cte_level_bits_def
         split: apiobject_type.split)

lemma obj_bits_dev_irr:
  "ty \<noteq> Untyped \<Longrightarrow> obj_bits (default_object ty dev us) = obj_bits_api ty us"
  by (simp add: obj_bits_api_def3 cong: obj_bits_cong)

lemma default_obj_range:
  "ty \<noteq> Untyped \<Longrightarrow> obj_range p (default_object ty dev us) = {p..p + 2 ^ (obj_bits_api ty us) - 1}"
  by (simp add: obj_range_def obj_bits_dev_irr)
end

definition
  "retype_addrs \<equiv> \<lambda>(ptr' :: obj_ref) ty n us. map (\<lambda>p. ptr_add ptr' (p * 2 ^ obj_bits_api ty us))
                                           [0..< n]"

lemma retype_addrs_base [simp]:
  "0 < n \<Longrightarrow> x \<in> set (retype_addrs x ty n us)"
  unfolding retype_addrs_def
  apply (simp add: ptr_add_def)
  apply (rule image_eqI [where x = 0])
   apply simp
  apply (simp add: power_sub[symmetric])
  done

lemma retype_addrs_aligned:
  assumes xin: "x \<in> set (retype_addrs ptr ty n us)"
  and      al: "is_aligned ptr (obj_bits_api ty us)"
  and      nv: "sz < word_bits"
  and     oav: "obj_bits_api ty us \<le> sz"
  shows   "is_aligned x (obj_bits_api ty us)"
  using xin unfolding retype_addrs_def ptr_add_def
  apply (clarsimp simp: word_unat_power [symmetric])
  apply (subst mult.commute, subst shiftl_t2n [symmetric])
  apply (rule aligned_add_aligned[OF al is_aligned_shift])
   apply (insert assms)
   apply simp+
  done

lemma (in pspace_update_eq) pspace_no_overlap_update [simp]:
  "pspace_no_overlap S (f s) = pspace_no_overlap S s"
  by (simp add: pspace_no_overlap_def pspace)

(* FIXME: move *)
lemma multi_lessD:
  "\<lbrakk>(a::nat)*b < c;0<a;0<b\<rbrakk> \<Longrightarrow> a < c \<and> b < c"
  by (cases a, simp_all,cases b,simp_all)

lemma unat_le_helper: "(x :: 'a :: len word) \<le> of_nat n \<Longrightarrow> unat x \<le> n"
  by (rule word_unat_less_le)

lemma word_of_nat_plus:
  "of_nat (a + b) = of_nat a + (of_nat b :: ('a :: len) word)"
  by (rule of_nat_add)

lemma word_of_nat_minus:
   "b<= a ==> of_nat (a - b) = of_nat a - (of_nat b :: ('a :: len) word)"
   by (rule of_nat_diff)

lemma unat_shiftl_absorb:
  "\<lbrakk>x \<le> 2^p ; p + k < len_of TYPE('a)\<rbrakk>
   \<Longrightarrow> unat (x :: 'a :: len word) * 2^k = unat (x * 2^k)"
  apply (simp add:unat_word_ariths)
  apply (subst mod_less)
   apply (rule le_less_trans[OF mult_le_mono1])
    apply (erule iffD1[OF word_le_nat_alt])
   apply (clarsimp simp: power_add[symmetric])+
  done

lemma word_up_bound:
  "(ptr::('a::len) word) \<le> 2^(len_of TYPE('a)) - 1 "
  by auto

lemma word_plus_mono_right_split:
  "\<lbrakk>unat ((x :: 'a :: len word) && mask sz) + unat z < 2 ^ sz ; sz < len_of TYPE('a)\<rbrakk>
   \<Longrightarrow>x \<le> x + z"
  (is "\<lbrakk>?bound;?len\<rbrakk> \<Longrightarrow>?rhs \<le> ?lhs")
  apply (subgoal_tac "(x && ~~ mask sz) + (x && mask sz) \<le> (x && ~~ mask sz) + ((x && mask sz) + z)")
   apply (simp add:word_plus_and_or_coroll2 field_simps)
  apply (rule word_plus_mono_right)
    apply (simp add:no_olen_add )
    apply (rule less_le_trans)
    apply (simp add:uint_nat)
    apply (subst of_nat_add[symmetric])
    apply (drule iffD2[OF of_nat_less_iff])
    apply simp
    apply (rule less_imp_le)
    apply (rule less_le_trans[where y = "2^len_of TYPE('a)"] )
    apply simp
   apply (simp add:word_bits_def)
  apply (rule word_plus_mono_right2)
    apply (rule is_aligned_no_overflow')
    apply (rule is_aligned_neg_mask[OF le_refl])
   apply (rule le_m1_iff_lt[THEN iffD1,THEN iffD2])
     apply (simp add:p2_gt_0 word_bits_def)
   apply (rule iffD2[OF word_less_nat_alt])
   apply (auto simp:unat_plus_if_size word_size word_bits_def not_less)
  done

lemmas machine_word_plus_mono_right_split = word_plus_mono_right_split[where 'a=machine_word_len, folded word_bits_def]

(* range_cover locale:
   proves properties when a small range is inside in a large range
 *)
locale range_cover =
  fixes ptr :: "'a :: len word"
  and   sz sbit n
  assumes aligned: "is_aligned ptr sbit"
  and sz:"sz< len_of TYPE('a)" "sbit \<le> sz" "n + unat (ptr && mask sz >> sbit) \<le> 2 ^ (sz - sbit)"

context range_cover begin

lemma range_cover_compare_bound:
 "n * 2 ^ sbit + unat (ptr && mask sz) \<le> 2 ^ sz"
proof -
  have mask_before_neg_mask: "(ptr && mask sz) && ~~ mask sbit = ptr && mask sz"
    using aligned sz
    by (simp add:mask_twice is_aligned_mask mask_out_sub_mask min_def)
  show ?thesis using aligned sz
  apply (drule_tac i = "a +b" for a b in Nat.mult_le_mono[where k = "2^sbit",OF _ le_refl])
  apply (subst (asm) add_mult_distrib)
  apply (clarsimp simp: power_add[symmetric])
  apply (subst (asm) unat_shiftl_absorb[where p = "sz - sbit"])
    apply (rule less_imp_le)
    apply (rule shiftr_less_t2n)
    apply (rule less_le_trans)
     apply (rule and_mask_less')
     apply (simp add:word_bits_def)
    apply (rule two_power_increasing)
      apply simp
    apply (simp add:word_bits_def field_simps)
   apply simp
  apply (subst (asm) mult.commute[where b = "2^sbit"],
         subst (asm) shiftl_t2n[symmetric])
  apply (subst (asm) and_not_mask[symmetric])
  apply (simp add:mask_before_neg_mask)
  done
qed

lemma range_cover_compare:
  assumes pointer:"p < n"
  shows "unat (ptr && mask sz) + unat (((of_nat p) :: 'a :: len word) * 2 ^ sbit) < 2 ^ sz"
proof -
  have mask_before_neg_mask: "(ptr && mask sz) && ~~ mask sbit = ptr && mask sz"
    using aligned sz
    by (simp add:mask_twice is_aligned_mask mask_out_sub_mask min_def)

  have absolute_compare:"n * 2 ^ sbit + unat (ptr && mask sz) \<le> 2 ^ sz"
    by (rule range_cover_compare_bound)

  have no_overflow_n:"n * 2^sbit < 2^len_of TYPE('a)"
    using aligned sz
    apply (clarsimp dest!:add_leD1)
    apply (rule le_less_trans)
    apply (drule Nat.mult_le_mono[where i = n and k = "2^sbit",OF _ le_refl])
    apply (clarsimp simp: power_add[symmetric])
     apply (assumption)
    apply clarsimp
    done

  have no_overflow_p:"p * 2^sbit < 2^len_of TYPE('a)"
    apply (rule le_less_trans[OF _ no_overflow_n])
    apply (simp add:pointer less_imp_le)
    done

  show ?thesis
  apply (rule less_le_trans[OF _ absolute_compare])
  apply (subst add.commute)
  apply clarsimp
  apply (case_tac "p = 0")
   apply (insert pointer)
   apply (clarsimp simp: range_cover_def pointer)
   apply (simp add:unat_word_ariths)
   apply (rule le_less_trans[OF mod_less_eq_dividend])
   apply (rule less_le_trans[OF mult_less_mono1[where j = n]])
   apply (cut_tac no_overflow_p)
     apply (drule multi_lessD[OF no_overflow_p],simp)
     apply (clarsimp simp:unat_of_nat word_bits_def)
   using sz
   apply (simp add:unat_gt_0 range_cover_def)
  apply (rule mult_le_mono2)
  apply (rule unat_le_helper)
  apply simp
  done
 qed

lemma no_overflow_n:"n * 2^sbit < 2^len_of TYPE('a)"
  using aligned sz
  apply (clarsimp dest!:add_leD1)
  apply (rule le_less_trans)
  apply (drule Nat.mult_le_mono[where i = n and k = "2^sbit",OF _ le_refl])
  apply (clarsimp simp: power_add[symmetric])
   apply (assumption)
  apply clarsimp
  done

lemma range_cover_n_le:
  "n \<le> 2 ^ (len_of TYPE('a) - sbit)"
  "n \<le> 2 ^ (sz - sbit)"
  using aligned sz
  by (auto elim: le_trans[OF add_leD1])

lemma range_cover_n_less:
  shows weak: "n < 2 ^ len_of TYPE('a)"
  and string: "n < 2 ^ (len_of TYPE('a) - sbit)"
proof -
  show str: "n < 2 ^ (len_of TYPE('a) - sbit)"
    using aligned sz
    by (auto intro: le_less_trans range_cover_n_le(2))

  show "n<2^len_of TYPE('a)"
    using str by (rule less_le_trans) simp
qed

lemma range_cover_le_n_less:
  "p \<le> n \<Longrightarrow> p < 2^ len_of TYPE('a)"
  "p \<le> n \<Longrightarrow> p < 2^ (len_of TYPE('a) - sbit)"
  apply (erule le_less_trans[OF _ range_cover_n_less(1)])
  apply (erule le_less_trans[OF _ range_cover_n_less(2)])
  done

lemma unat_of_nat_n :"unat ((of_nat n):: 'a :: len word) = n"
  using range_cover_n_less
  apply (simp add:unat_of_nat)
  done

lemma unat_of_nat_n_shift:
  "gbits \<le> sbit \<Longrightarrow> unat (((of_nat n):: 'a :: len word) << gbits) = (n * 2^ gbits)"
   apply (simp add:shiftl_t2n field_simps)
   apply (subst mult.commute)
   apply (subst unat_mult_power_lem)
     apply (case_tac "gbits = sbit")
      apply (rule le_less_trans[OF range_cover_n_le(2)])
      apply clarsimp
       apply (rule diff_less_mono)
      apply (rule sz)
     apply (rule sz)
    apply (rule le_less_trans[OF range_cover_n_le(1)])
    apply clarsimp
    apply (rule diff_less_mono2)
     apply simp
    using sz
    apply simp
   apply simp
   done

lemma unat_of_nat_shift:
  "\<lbrakk>gbits \<le> sbit;p\<le> n\<rbrakk> \<Longrightarrow> (unat (((of_nat p):: 'a :: len word) * 2 ^ gbits)) = (p * 2^ gbits)"
   apply (subst mult.commute[where a = "of_nat p"])
   apply (subst mult.commute[where a = "p "])
   apply (subst unat_mult_power_lem)
     apply (case_tac "gbits = sbit")
      apply simp
      apply (erule le_less_trans[OF _ range_cover_le_n_less(2) ])
       apply simp
       apply (erule le_less_trans)
     apply (rule less_le_trans[OF range_cover_n_less(2)])
     apply clarsimp
    apply (erule diff_le_mono2)
  apply (simp add:range_cover_def)+
 done

lemma range_cover_base_le:
  "(ptr && mask sz) \<le> (ptr && mask sz) + (of_nat n << sbit)"
  apply (clarsimp simp:no_olen_add_nat shiftl_t2n unat_of_nat_shift field_simps)
  apply (subst add.commute)
  apply (rule le_less_trans[OF range_cover_compare_bound])
  apply (rule less_le_trans[OF power_strict_increasing])
    using sz
    apply simp+
  done

end

lemma range_cover_subset:
  fixes ptr :: "'a :: len word"
  assumes cover:   "range_cover ptr sz sbit n"
  assumes pointer: "p<n"
  assumes not_0:   "n \<noteq> 0"
  shows  "{ptr + of_nat p * 2^sbit .. ptr + of_nat p * 2 ^ sbit + 2 ^ sbit - 1} \<subseteq> {ptr .. ptr + of_nat n * 2 ^ sbit - 1}"
  apply clarsimp
  apply (intro conjI)
  apply (rule word_plus_mono_right_split[OF range_cover.range_cover_compare[OF cover pointer]])
  using cover
  apply (simp add:range_cover_def)
  proof -
    note n_less = range_cover.range_cover_n_less[OF cover]
    have unat_of_nat_m1: "unat (of_nat n - (1 :: 'a :: len word)) < n"
      using not_0 n_less
       by (simp add:unat_of_nat_minus_1)
    have decomp:"of_nat n * 2 ^ sbit = of_nat (n - 1) * 2 ^ sbit + (2 :: 'a :: len word) ^ sbit"
      apply (simp add:distrib_right[where b = "1::'a word",simplified,symmetric])
      using not_0 n_less
      apply (simp add:unat_of_nat_minus_1)
      done
    show "ptr + of_nat p * 2 ^ sbit + 2 ^ sbit - 1 \<le> ptr + of_nat n * 2 ^ sbit - 1"
      apply (subst decomp)
      apply (simp add:add.assoc[symmetric])
      apply (simp add:p_assoc_help)
      apply (rule order_trans[OF word_plus_mono_left word_plus_mono_right])
         apply (rule word_plus_mono_right)
          apply (rule word_mult_le_mono1[OF word_of_nat_le])
          apply (insert n_less not_0 pointer)
            apply (simp add:unat_of_nat_minus_1)
           apply (rule p2_gt_0[THEN iffD2])
           using cover
           apply (simp add:word_bits_def range_cover_def)
          using cover
          apply (simp only: word_bits_def[symmetric] unat_power_lower range_cover_def)
          apply (clarsimp simp: unat_of_nat_minus_1 )
          apply (rule nat_less_power_trans2[OF range_cover.range_cover_le_n_less(2),OF cover])
          apply (simp add:unat_of_nat_m1 less_imp_le)
         using cover
         apply (simp add:range_cover_def)
        apply (rule word_plus_mono_right_split[where sz = sz])
        using range_cover.range_cover_compare[OF cover,where p = "unat (of_nat n - (1 :: 'a :: len word))"]
        apply (clarsimp simp:unat_of_nat_m1)
       using cover
       apply (simp add:range_cover_def)
      apply (rule olen_add_eqv[THEN iffD2])
      apply (subst add.commute[where a = "2^sbit - 1"])
     apply (subst p_assoc_help[symmetric])
     apply (rule is_aligned_no_overflow)
     apply (insert cover)
     apply (clarsimp simp:range_cover_def)
     apply (erule aligned_add_aligned[OF _  is_aligned_mult_triv2])
       apply (simp add:range_cover_def)+
   done
  qed

lemma range_cover_rel:
  assumes cover: "range_cover ptr sz sbit n"
  assumes le:"sbit' \<le> sbit"
  assumes num_r: "m = 2 ^ (sbit - sbit') * n"
  shows "range_cover ptr sz sbit' m"
  using cover
  apply (clarsimp simp:num_r range_cover_def)
  apply (intro conjI)
    apply (erule is_aligned_weaken[OF _ le])
    apply (erule le_trans[OF le])
    apply (drule is_aligned_weaken[OF _ le])+
    apply (drule mult_le_mono2[where j = "2^(sz-sbit)" and k = "2^(sbit-sbit')"])
    apply (subst (asm) power_add[symmetric])
    apply (clarsimp simp:field_simps le)
    apply (erule le_trans[rotated])
  apply clarsimp
  apply (rule unat_le_helper)
  apply clarsimp
  apply (insert le)
  apply (fold shiftl_t2n)
  apply (simp add: shiftr_shiftl1)
  apply (rule eq_refl[OF is_aligned_neg_mask_eq[symmetric]])
  apply (rule is_aligned_shiftr[OF is_aligned_weaken])
    apply (rule aligned_already_mask[where n = "sbit"])
    apply (insert cover)
    apply (simp add:range_cover_def)
  apply simp
done

lemma unat_plus_gt:
  "unat ((a::('a::len word)) + b) \<le>  (unat a + unat b)"
  by (clarsimp simp:unat_plus_if_size)

lemma retype_addrs_subset_ptr_bits:
  assumes cover: "range_cover ptr sz (obj_bits_api ty us) n"
  shows "set (retype_addrs ptr ty n us) \<subseteq> {ptr .. (ptr &&~~ mask sz) + (2 ^ sz - 1)}"
  apply (clarsimp simp:retype_addrs_def ptr_add_def)
  apply (intro conjI)
    apply (rule word_plus_mono_right_split)
    apply (erule range_cover.range_cover_compare[OF cover])
   using cover
   apply (simp add:range_cover_def)
  apply (subst word_plus_and_or_coroll2[symmetric,where w = "mask sz"])
  apply (subst add.commute)
  apply (subst add.assoc)
  apply (rule word_plus_mono_right)
  apply (insert cover)
  apply (drule(1) range_cover.range_cover_compare)
  apply (rule iffD1[OF le_m1_iff_lt,THEN iffD2])
    using cover
    apply (simp add: p2_gt_0 range_cover_def word_bits_def)
   apply (rule iffD2[OF word_less_nat_alt])
   apply (rule le_less_trans[OF unat_plus_gt])
    using cover
   apply (clarsimp simp:unat_power_lower range_cover_def)
  apply (insert cover)
  apply (rule is_aligned_no_wrap'[OF is_aligned_neg_mask,OF le_refl ])
   apply (simp add:range_cover_def)+
done

lemma pspace_no_overlapE:
  "\<lbrakk> pspace_no_overlap S s; kheap s x = Some ko;
  {x..x + (2 ^ obj_bits ko - 1)} \<inter> S = {} \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
  unfolding pspace_no_overlap_def by auto

lemma base_member_set:
  fixes x :: "'a :: len word"
  assumes al: "is_aligned x sz"
  and    szv: "sz < len_of TYPE('a)"
  shows "x \<in> {x .. x + (2 ^ sz - 1)}"
proof (simp, rule is_aligned_no_wrap')
  show "(2 :: 'a :: len word) ^ sz - 1 < 2 ^ sz" using szv
    by (simp add: word_less_nat_alt word_neq_0_conv unat_minus_one)
qed fact+

abbreviation(input)
  "pspace_no_overlap_range_cover ptr bits
    \<equiv> pspace_no_overlap {ptr .. (ptr && ~~ mask bits) + (2 ^ bits - 1)}"

lemma pspace_no_overlap_into_Int_none:
  assumes ps: "pspace_no_overlap_range_cover ptr sz s"
  and     vp: "valid_pspace s"
  and  cover: "range_cover ptr sz (obj_bits_api ty us) n"
  shows   "set (retype_addrs ptr ty n us) \<inter> dom (kheap s) = {}"
proof -
  {
    fix x ko
    assume ps': "kheap s x = Some ko"
    have "x \<notin> {ptr .. (ptr && ~~ mask sz) + (2 ^ sz - 1)}"
    proof (rule orthD1)
      show "x \<in> {x .. x + (2 ^ obj_bits ko - 1)}"
      proof (rule base_member_set)
        from vp show "is_aligned x (obj_bits ko)" using ps'
          by (auto elim!: valid_pspaceE pspace_alignedE)
        show "obj_bits ko < len_of TYPE(machine_word_len)"
          by (rule valid_pspace_obj_sizes [OF _ ranI, unfolded word_bits_def]) fact+
      qed

      show "{x..x + (2 ^ obj_bits ko - 1)} \<inter> {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)} = {}" using ps
        by (rule pspace_no_overlapE) fact+
    qed

    hence "x \<notin> set (retype_addrs ptr ty n us)"
      using assms subsetD[OF retype_addrs_subset_ptr_bits[OF cover]]
      by auto
  }
  thus ?thesis by auto
qed

lemma pspace_no_overlapD1:
  "\<lbrakk> pspace_no_overlap_range_cover ptr sz s; kheap s x = Some ko;
  range_cover ptr sz (obj_bits_api ty us) n;
  valid_pspace s\<rbrakk> \<Longrightarrow>
  x \<notin> set (retype_addrs ptr ty n us)"
  apply (drule(2) pspace_no_overlap_into_Int_none)
   apply (simp add:range_cover_def)
  apply (erule orthD2)
  apply (erule domI)
  done

lemma pspace_no_overlapD2:
  "\<lbrakk> pspace_no_overlap_range_cover ptr sz s; x \<in> set (retype_addrs ptr ty n us);
  range_cover ptr sz (obj_bits_api ty us) n;
   valid_pspace s \<rbrakk> \<Longrightarrow> x \<notin> dom (kheap s)"
  apply (drule(2) pspace_no_overlap_into_Int_none)
   apply (simp add:range_cover_def)
  apply (erule(1) orthD1)
done

lemma pspace_no_overlapC:
  "\<lbrakk> pspace_no_overlap_range_cover ptr sz s; x \<in> set (retype_addrs ptr ty n us); kheap s x = Some ko;
  range_cover ptr sz (obj_bits_api ty us) n;valid_pspace s \<rbrakk> \<Longrightarrow> P"
  by (auto dest: pspace_no_overlapD1)

lemma null_filterE:
  "\<lbrakk> null_filter cps x = Some cap;
      \<lbrakk> cps x = Some cap; cap \<noteq> cap.NullCap \<rbrakk> \<Longrightarrow> R \<rbrakk>
     \<Longrightarrow> R"
  by (simp add: null_filter_def split: if_split_asm)

lemma across_null_filter_eq:
  assumes eq: "null_filter xs = null_filter ys"
  shows "\<lbrakk> xs x = Some v; ys x = Some v \<Longrightarrow> R;
           \<lbrakk> v = cap.NullCap; ys x = None \<rbrakk> \<Longrightarrow> R \<rbrakk>
          \<Longrightarrow> R"
  apply (cases "null_filter xs x")
   apply (subgoal_tac "null_filter ys x = None")
    apply (simp add: null_filter_def split: if_split_asm)
   apply (simp add: eq)
  apply (subgoal_tac "null_filter ys x = Some a")
   apply (simp add: null_filter_def split: if_split_asm)
  apply (simp add: eq)
  done

lemma mdb_cte_at_no_descendants:
  "\<lbrakk> mdb_cte_at f m; \<not> f x \<rbrakk> \<Longrightarrow> descendants_of x m = {}"
  apply (clarsimp simp add: descendants_of_def)
  apply (erule tranclE2)
   apply (simp add: cdt_parent_of_def)
   apply (drule(1) mdb_cte_atD)
   apply simp
  apply (simp add: cdt_parent_of_def)
  apply (drule(1) mdb_cte_atD)
  apply simp
  done

lemma caps_of_state_foldr:
  assumes tyun: "ty \<noteq> Untyped"
  fixes s sz ptr us addrs dev
  defines "s' \<equiv> (s\<lparr>kheap := foldr (\<lambda>p ps. ps(p \<mapsto> default_object ty dev us))
                  addrs (kheap s)\<rparr>)"
  shows
  "caps_of_state s' =
  (\<lambda>(oref,cref). if oref \<in> set addrs
                 then (case ty of Structures_A.CapTableObject \<Rightarrow> empty_cnode us
                               | Structures_A.TCBObject \<Rightarrow> option_map (\<lambda>x. cap.NullCap) \<circ> tcb_cap_cases
                               | _ \<Rightarrow> empty) cref
                 else caps_of_state s (oref,cref))"
  apply (rule ext)+
  apply (case_tac x)
  apply (rename_tac oref cref)
  apply (simp add: caps_of_state_cte_wp_at split del: if_split)
  apply (case_tac "\<exists>cap. cte_wp_at (op = cap) (oref, cref) s'")
   apply clarsimp
   apply (simp add: s'_def cte_wp_at_cases)
   apply (erule disjE)
    apply (clarsimp simp add: foldr_upd_app_if default_object_def caps_of_state_cte_wp_at
                     cte_wp_at_cases tyun empty_cnode_def
           split: if_split_asm Structures_A.apiobject_type.splits)
   apply (clarsimp simp add: foldr_upd_app_if default_object_def caps_of_state_cte_wp_at
                             cte_wp_at_cases tyun empty_cnode_def default_tcb_def
          split: if_split_asm Structures_A.apiobject_type.splits)
   apply (clarsimp simp: tcb_cap_cases_def split: if_split_asm)
  apply simp
  apply (simp add: cte_wp_at_cases s'_def foldr_upd_app_if)
  apply (rule conjI)
   apply (clarsimp simp: default_object_def wf_empty_bits
                  split: Structures_A.apiobject_type.split_asm)
   apply (fastforce simp: tcb_cap_cases_def split: if_split_asm)
  apply clarsimp
  apply (simp add: caps_of_state_cte_wp_at)
  apply (simp add: cte_wp_at_cases)
  done

lemma null_filter_caps_of_state_foldr:
  fixes s sz ptr us addrs dev
  assumes tyun: "ty \<noteq> Untyped"
    and nondom: "\<forall>x \<in> set addrs. x \<notin> dom (kheap s)"
  defines "s' \<equiv> (s\<lparr>kheap := foldr (\<lambda>p ps. ps(p \<mapsto> default_object ty dev us))
                  addrs (kheap s)\<rparr>)"
  shows
  "null_filter (caps_of_state s') =
   null_filter (caps_of_state s)"
  unfolding s'_def
  apply (subst caps_of_state_foldr[OF tyun])
  apply (rule ext)
  apply (clarsimp simp add: null_filter_def split_def empty_cnode_def
                     split: Structures_A.apiobject_type.splits)
  apply (subgoal_tac "a \<in> set addrs \<longrightarrow> caps_of_state s (a, b) \<noteq> Some cap.NullCap
           \<longrightarrow> None = caps_of_state s (a, b)", simp)
   apply clarsimp
   apply (subgoal_tac "tcb_cap_cases b = None", simp)
   apply (rule ccontr, clarsimp)
  apply clarsimp
  apply (rule sym, rule ccontr, clarsimp)
  apply (drule bspec[OF nondom])
  apply (drule caps_of_state_cteD)
  apply (erule cte_wp_atE, fastforce+)
  done

lemma retype_addrs_fold:
  " map (\<lambda>p. ptr_add ptr' (p * 2 ^ obj_bits_api ty us)) [0..< n ]
  = retype_addrs ptr' ty n us"
  by (simp add: retype_addrs_def power_sub)

lemma mult_div_rearrange:
  "(b::nat) \<le> a \<Longrightarrow> (2::nat) ^ a * (p div 2 ^ b) =
   2 ^ (a - b) * (2 ^ b * (p div 2 ^ b))"
  by (auto simp:field_simps power_add[symmetric])

lemma shiftr_mask_cmp:
  "\<lbrakk>c \<le> n; n \<le> len_of TYPE('a)\<rbrakk>
   \<Longrightarrow> ((a::('a::len) word) \<le> mask n) = ((a >> c) \<le> mask (n - c))"
  apply (rule iffI)
    apply (drule le_shiftr[where n = c])
    apply (simp add:mask_2pm1[symmetric] shiftr_mask2)+
    apply (simp add:le_mask_iff shiftr_shiftr)
done

locale Retype_AI_no_gs_types =
  fixes no_gs_types :: "apiobject_type set"
  assumes no_gs_types_simps [simp]:
    "Untyped \<in> no_gs_types"
    "TCBObject \<in> no_gs_types"
    "EndpointObject \<in> no_gs_types"
    "NotificationObject \<in> no_gs_types"

lemma  measure_unat': "p \<noteq> 0 \<Longrightarrow> unat (p - 1) \<le>  unat p - 1"
  apply (insert measure_unat[where p = p])
  apply simp
done

(* FIXME: move *)
lemma range_cover_not_zero:
  "\<lbrakk>n \<noteq> 0; range_cover (ptr :: 'a :: len word) sz bits n\<rbrakk> \<Longrightarrow> ((of_nat n) :: 'a :: len word) \<noteq> 0"
    apply (rule of_nat_neq_0)
    apply simp
   apply (drule range_cover.range_cover_n_less)
   apply simp
  done

lemma range_cover_not_zero_shift:
  "\<lbrakk>n \<noteq> 0; range_cover (ptr :: 'a :: len word) sz bits n; gbits \<le> bits\<rbrakk>
   \<Longrightarrow> ((of_nat n) :: 'a :: len word) << gbits \<noteq> 0"
  apply (rule word_shift_nonzero[where m = "sz-gbits"])
     prefer 2
      apply (clarsimp simp:range_cover_def)
   apply (clarsimp simp:word_le_nat_alt)
   apply (subst unat_power_lower)
    apply (rule less_le_trans[OF diff_less_Suc])
    apply (simp add:range_cover_def)
   apply (simp add:range_cover.unat_of_nat_n)
   apply (erule le_trans[OF range_cover.range_cover_n_le(2)])
   apply (rule power_increasing)
     apply simp+
   using range_cover_not_zero
   apply auto
  done

lemma mult_plus_1: "(a::nat) + b * a = a * (b + 1)" by simp

lemma range_cover_cell_subset:
  "\<lbrakk>range_cover ptr sz us n;x < of_nat n\<rbrakk>
       \<Longrightarrow> {ptr + x * 2 ^ us..ptr + x * 2 ^ us + 2 ^ us - 1} \<subseteq> {ptr..(ptr && ~~ mask sz) + 2 ^ sz - 1}"
  proof -
  assume cover:"range_cover ptr sz us n"
  and      cmp:"x<of_nat n"
  have sh: "(2^us * (ptr && mask sz >> us)) = ptr && mask sz"
     apply (subst shiftl_t2n[symmetric])
     apply (subst and_not_mask[symmetric])
     apply (rule is_aligned_neg_mask_eq)
     using cover
     apply (simp add:is_aligned_mask mask_twice range_cover_def min_def)
     done
  show ?thesis
  using cover cmp
  apply clarsimp
  apply (intro conjI)
    apply (rule word_plus_mono_right_split)
    apply (drule range_cover.range_cover_compare[where p = "unat x"])
      apply (erule unat_less_helper)
      apply (simp add: range_cover.unat_of_nat_shift[where gbits = us])
   apply (simp add:range_cover_def)
  apply (subst word_plus_and_or_coroll2[symmetric,where w = "mask sz"])
  apply (subst add.commute)
  apply (simp add:p_assoc_help)
  apply (subst add.assoc)+
  apply (rule word_plus_mono_right)
   apply (cut_tac nasty_split_lt[where x="((ptr && mask sz) >> us) + x" and n=us and m=sz])
      apply (simp add: sh field_simps)
     apply (clarsimp simp:range_cover_def word_less_nat_alt)
     apply (rule le_less_trans[OF unat_plus_gt])
     apply (erule less_le_trans[rotated])
     apply (clarsimp simp:range_cover.unat_of_nat_n[OF cover])
    apply (simp add:range_cover_def p_assoc_help[symmetric])+
  apply (rule is_aligned_no_overflow[OF is_aligned_neg_mask ,OF le_refl])
  done
 qed

lemma is_aligned_ptr_add_helper:
  "\<lbrakk> is_aligned ptr d; d < word_bits; c \<le> d; c \<le> a + b;
     a + b < word_bits \<rbrakk> \<Longrightarrow> is_aligned (ptr_add ptr (x * 2 ^ a * 2 ^ b)) c"
  apply (simp add: ptr_add_def)
  apply (erule aligned_add_aligned)
    apply (rule is_aligned_weaken)
     apply (simp add: field_simps
                      power_add[symmetric])
     apply (rule is_aligned_mult_triv2)
     apply assumption+
  done

lemma range_cover_no_0:
  "\<lbrakk> ptr \<noteq> 0; range_cover (ptr :: 'a :: len word) sz sbit n;p < n\<rbrakk> \<Longrightarrow>
   ptr + of_nat p * 2 ^ sbit \<noteq> 0"
  apply (subst word_plus_and_or_coroll2[symmetric,where w = "mask sz"])
  apply (case_tac  "(ptr && ~~ mask sz) \<noteq> 0")
    apply (subst add.commute)
    apply (subst add.assoc)
    apply (rule aligned_offset_non_zero)
      apply (rule is_aligned_neg_mask[OF le_refl])
     apply (simp add:word_less_nat_alt)
     apply (rule le_less_trans[OF unat_plus_gt])
     apply (rule less_le_trans[OF range_cover.range_cover_compare])
       apply simp
    apply ((simp add:range_cover_def)+)[3]
  apply (subgoal_tac "(ptr && mask sz) \<noteq> 0")
   apply (rule unat_gt_0[THEN iffD1])
   apply (simp add:not_less)
   apply (subst iffD1[OF unat_add_lem])
     apply (rule less_le_trans[OF range_cover.range_cover_compare])
       apply simp+
     apply (simp add:range_cover_def word_bits_def)
   apply simp
  apply (rule disjI1)
    apply unat_arith
  apply (rule ccontr)
  apply (subst (asm) word_plus_and_or_coroll2[symmetric,where w = "mask sz" and t = ptr])
  apply (clarsimp simp:not_less)
done

lemma range_cover_mem:
  "\<lbrakk>x < n; range_cover ptr sz us n\<rbrakk>
       \<Longrightarrow> ptr + (of_nat x) * 2 ^ us \<in> {ptr..(ptr && ~~ mask sz) + 2 ^ sz - 1}"
  apply (clarsimp)
  apply (intro conjI)
    apply (rule word_plus_mono_right_split[where sz = sz])
       apply (erule range_cover.range_cover_compare)
     apply ((simp add:range_cover_def)+)[2]
    apply (subst p_assoc_help)
    apply (subst word_plus_and_or_coroll2[symmetric,where w = "mask sz"])
    apply (subst add.commute)
    apply (subst add.assoc)
    apply (rule word_plus_mono_right)
    apply (simp add:word_le_nat_alt)
    apply (rule le_trans[OF unat_plus_gt])
    apply (subst unat_minus_one[OF power_not_zero])
     apply (simp add:range_cover_def)
    apply (frule(1) range_cover.range_cover_compare)
    apply (clarsimp simp:range_cover_def le_m1_iff_lt power_not_zero nat_le_Suc_less_imp)
   apply (rule is_aligned_no_wrap'[OF is_aligned_neg_mask,OF le_refl ])
   apply (simp add:range_cover_def)
  done

lemma range_cover_mem':
  "\<lbrakk>x < of_nat n; range_cover ptr sz us n\<rbrakk>
   \<Longrightarrow> ptr + x * 2 ^ us \<in> {ptr..(ptr && ~~ mask sz) + 2 ^ sz - 1}"
  apply (drule range_cover_mem[where x = "unat x",rotated])
    apply (erule unat_less_helper)
  apply auto
  done

lemma range_cover_subset_not_empty:
  "\<lbrakk>x < of_nat n; range_cover ptr sz us n\<rbrakk>
   \<Longrightarrow> {ptr + x * 2 ^ us..ptr + x * 2 ^ us + 2 ^ us - 1} \<noteq> {}"
  apply (clarsimp simp:p_assoc_help)
  apply (rule is_aligned_no_overflow')
  apply (rule is_aligned_add_multI)
    apply (fastforce simp:range_cover_def)+
  done

crunch global_refs[wp]: retype_region "\<lambda>s. P (global_refs s)"
  (simp: crunch_simps)

locale Retype_AI_retype_region_ret =
  fixes state_ext_t :: "'state_ext :: state_ext itself"
  assumes retype_region_ret_folded:
    "\<And> y n bits ty dev.
      \<lbrace>\<top>\<rbrace> retype_region y n bits ty dev
      \<lbrace>\<lambda>r (s :: 'state_ext state). r = retype_addrs y ty n bits\<rbrace>"

context Retype_AI_retype_region_ret begin

lemmas retype_region_ret = retype_region_ret_folded[unfolded retype_addrs_def]

lemma retype_region_global_refs_disjoint:
  "\<lbrace>(\<lambda>s::'state_ext state. {ptr .. (ptr && ~~ mask sz) + 2 ^ sz - 1} \<inter> global_refs s = {})
            and K (range_cover ptr sz (obj_bits_api apiobject_type obits) n)\<rbrace>
     retype_region ptr n obits apiobject_type dev
   \<lbrace>\<lambda>r s. global_refs s \<inter> set r = {}\<rbrace>"
  apply (rule hoare_gen_asm)
  apply (rule hoare_lift_Pf3[where f=global_refs])
   apply (rule hoare_assume_pre)
   apply (clarsimp simp: Int_commute)
   apply (rule hoare_chain)  apply(rule retype_region_ret)
    apply simp
   apply (erule disjoint_subset2[rotated])
   apply (rule subsetI, simp only: mask_in_range[symmetric])
   apply (clarsimp simp: ptr_add_def)
   apply (intro conjI)
     apply (rule machine_word_plus_mono_right_split[where sz = sz])
       apply (erule(1) range_cover.range_cover_compare)
     apply (simp add:range_cover_def word_bits_def)
    apply (subst p_assoc_help)
    apply (subst word_plus_and_or_coroll2[symmetric,where w = "mask sz"])
    apply (subst add.commute)
    apply (subst add.assoc)
    apply (rule word_plus_mono_right)
    apply (simp add:word_le_nat_alt)
    apply (rule le_trans[OF unat_plus_gt])
    apply (subst unat_minus_one[OF power_not_zero])
     apply (simp add:range_cover_def)
    apply (frule(1) range_cover.range_cover_compare)
    apply (clarsimp simp:range_cover_def le_m1_iff_lt power_not_zero nat_le_Suc_less_imp)
   apply (rule is_aligned_no_wrap'[OF is_aligned_neg_mask,OF le_refl ])
    apply (simp add:range_cover_def)
   apply (simp add:range_cover_def)
  apply wp
done

end

crunch valid_pspace: do_machine_op "valid_pspace"

lemma do_machine_op_return_foo:
  "do_machine_op (do x\<leftarrow>a;return () od) = (do (do_machine_op a); return () od)"
  apply (clarsimp simp:do_machine_op_def bind_def gets_def
    get_def return_def select_f_def split_def simpler_modify_def)
  apply (rule ext)+
  apply (clarsimp simp:image_def)
  apply (rule set_eqI)
  apply clarsimp
  done

abbreviation(input)
 "all_invs_but_equal_kernel_mappings_restricted S
    \<equiv> (\<lambda>s. equal_kernel_mappings (s \<lparr> kheap := restrict_map (kheap s) (- S) \<rparr>))
       and valid_pspace and valid_mdb and valid_idle and only_idle
       and if_unsafe_then_cap and valid_reply_caps
       and valid_reply_masters and valid_global_refs and valid_arch_state
       and valid_irq_node and valid_irq_handlers and valid_arch_objs
       and valid_irq_states
       and valid_arch_caps and valid_global_objs and valid_kernel_mappings
       and valid_asid_map and valid_global_vspace_mappings
       and pspace_in_kernel_window and cap_refs_in_kernel_window
       and pspace_respects_device_region and cap_refs_respects_device_region
       and cur_tcb and valid_ioc and valid_machine_state"

lemma all_invs_but_equal_kernel_mappings_restricted_eq:
  "all_invs_but_equal_kernel_mappings_restricted {}
        = invs"
  by (rule ext, simp add: invs_def valid_state_def conj_comms restrict_map_def)

locale Retype_AI_dmo_eq_kernel_restricted =
  fixes
    state_ext_t :: "'state_ext::state_ext itself" and
    machine_op_t :: "'machine_op_t itself"
  assumes dmo_eq_kernel_restricted[wp]:
    "\<And> f m.
      \<lbrace>\<lambda>s::'state_ext state. equal_kernel_mappings (kheap_update (f (kheap s)) s)\<rbrace>
        do_machine_op m :: ('state_ext state, 'machine_op_t) nondet_monad
      \<lbrace>\<lambda>rv s. equal_kernel_mappings (kheap_update (f (kheap s)) s)\<rbrace>"

crunch only_idle[wp]: do_machine_op "only_idle"
crunch valid_global_refs[wp]: do_machine_op "valid_global_refs"
crunch valid_kernel_mappings[wp]: do_machine_op "valid_kernel_mappings"
crunch global_pd_mappings[wp]: do_machine_op "valid_global_vspace_mappings"
crunch cap_refs_in_kernel_window[wp]: do_machine_op "cap_refs_in_kernel_window"

locale Retype_AI_post_retype_invs =
  fixes state_ext_t :: "'state_ext::state_ext itself"
    and post_retype_invs_check :: "apiobject_type \<Rightarrow> bool"
    and post_retype_invs :: "apiobject_type \<Rightarrow> machine_word list \<Rightarrow> 'state_ext state \<Rightarrow> bool"
  assumes post_retype_invs_def':
    "post_retype_invs tp refs \<equiv>
      if post_retype_invs_check tp
        then all_invs_but_equal_kernel_mappings_restricted (set refs)
        else invs"

lemma  (in Retype_AI_retype_region_ret)  retype_region_aligned_for_init[wp]:
  "\<lbrace>\<lambda>s::'state_ext state. range_cover ptr sz (obj_bits_api new_type obj_sz) n\<rbrace>
     retype_region ptr n obj_sz new_type dev
   \<lbrace>\<lambda>rv s. \<forall>ref \<in> set rv. is_aligned ref (obj_bits_api new_type obj_sz)\<rbrace>"
  apply (rule hoare_assume_pre)
  apply (rule hoare_chain, rule retype_region_ret)
   apply simp
  apply (clarsimp simp: ptr_add_def
                 dest!: less_two_pow_divD)
  apply (rule aligned_add_aligned)
    apply (fastforce simp:range_cover_def)
    apply (subst mult.commute, subst shiftl_t2n[symmetric],
           rule is_aligned_shiftl)
    apply simp
   apply (simp add:range_cover_def)+
  done

lemma honestly_16_10:
  "is_aligned (p :: word32) 10 \<Longrightarrow> p + 16 \<in> {p .. p + 1023}"
  apply simp
  apply (intro conjI is_aligned_no_wrap' word_plus_mono_right,
         (assumption | simp add: word_bits_def)+)
  done

definition
  caps_no_overlap :: "machine_word \<Rightarrow> nat \<Rightarrow> 'z::state_ext state \<Rightarrow> bool"
where
 "caps_no_overlap ptr sz s \<equiv> \<forall>cap \<in> ran (caps_of_state s).
               untyped_range cap \<inter> {ptr .. (ptr && ~~ mask sz) + 2 ^ sz - 1} \<noteq> {}
               \<longrightarrow> {ptr .. (ptr && ~~ mask sz) + 2 ^ sz - 1} \<subseteq> untyped_range cap"

definition caps_overlap_reserved :: "machine_word set \<Rightarrow> ('z::state_ext) state \<Rightarrow> bool"
where
 "caps_overlap_reserved S (s :: ('z::state_ext) state) \<equiv> \<forall>cap \<in> ran (caps_of_state s).
  (is_untyped_cap cap \<longrightarrow> usable_untyped_range cap \<inter> S = {})"

lemma of_nat_2: "((of_nat (2::nat))::word32) = 2" by simp

lemma subset_le_imp_less: "\<not> A \<subseteq> B \<Longrightarrow> \<not> A \<subset> B" by auto

lemma non_disjoing_subset: "\<lbrakk>A \<subseteq> B; A \<inter> C \<noteq> {}\<rbrakk> \<Longrightarrow> B \<inter> C \<noteq> {}" by blast

lemma pspace_no_overlap_same_type:
  "\<lbrakk>pspace_no_overlap S s; ko_at k p s; a_type ko = a_type k\<rbrakk>
    \<Longrightarrow> pspace_no_overlap S (kheap_update (\<lambda>_. (kheap s(p \<mapsto> ko))) s)"
  unfolding pspace_no_overlap_def
  by (clarsimp simp: obj_at_def obj_bits_T)

lemma set_object_no_overlap:
  "\<lbrace>pspace_no_overlap S and obj_at (\<lambda>k. a_type ko = a_type k) p\<rbrace>
  set_object p ko \<lbrace>\<lambda>r. pspace_no_overlap S\<rbrace>"
  unfolding set_object_def
  apply simp
  apply wp
  apply (clarsimp simp del: fun_upd_apply)
  apply (drule obj_at_ko_atD, erule exE)
  apply (rule pspace_no_overlap_same_type)
  apply auto
  done

lemma set_cap_no_overlap:
  "\<lbrace>pspace_no_overlap S\<rbrace> set_cap cap cte \<lbrace>\<lambda>r. pspace_no_overlap S\<rbrace>"
  unfolding set_cap_def
  by (wpsimp wp: set_object_no_overlap get_object_wp
           simp: split_beta obj_at_def a_type_def wf_cs_upd [unfolded fun_upd_def])

definition
  if_unsafe_then_cap2 :: "(cslot_ptr \<rightharpoonup> cap) \<Rightarrow> (irq \<Rightarrow> obj_ref) \<Rightarrow> bool"
where
 "if_unsafe_then_cap2 f x \<equiv> \<forall>cref. (f cref \<noteq> None \<and> (the (f cref)) \<noteq> cap.NullCap)
                               \<longrightarrow> (\<exists>cref'. f cref' \<noteq> None \<and> cref \<in> cte_refs (the (f cref')) x
                                              \<and> appropriate_cte_cap (the (f cref)) (the (f cref')))"

lemma null_filter_same:
  "cps p \<noteq> Some cap.NullCap \<Longrightarrow> null_filter cps p = cps p"
  by (simp add: null_filter_def)

lemma cte_wp_at_not_Null:
  "cte_wp_at (\<lambda>cp. cp \<noteq> cap.NullCap) p s \<Longrightarrow> caps_of_state s p \<noteq> Some cap.NullCap"
  by (clarsimp simp: cte_wp_at_caps_of_state)

lemma unsafe_rep2:
  "if_unsafe_then_cap =
    (\<lambda>s. if_unsafe_then_cap2 (null_filter (caps_of_state s)) (interrupt_irq_node s))"
  apply (simp only: if_unsafe_then_cap2_def o_def)
  apply (subst P_null_filter_caps_of_cte_wp_at, simp)+
  apply (simp add: null_filter_same [where cps="caps_of_state s" for s, OF cte_wp_at_not_Null])
  apply (fastforce simp: if_unsafe_then_cap2_def cte_wp_at_caps_of_state
                        if_unsafe_then_cap_def ex_cte_cap_wp_to_def
                intro!: ext)
  done

lemma descendants_inc_null_filter:
  "\<lbrakk>mdb_cte_at (swp (cte_wp_at (op \<noteq> cap.NullCap)) s) (cdt s)\<rbrakk>
   \<Longrightarrow> descendants_inc (cdt s) (null_filter (caps_of_state s)) =
       descendants_inc (cdt s) (caps_of_state s)"
  apply (simp add:descendants_inc_def descendants_of_def del:split_paired_All)
  apply (intro iffI allI impI)
   apply (drule spec)+
   apply (erule(1) impE)
   apply (frule tranclD)
   apply (drule tranclD2)
   apply (simp add:cdt_parent_rel_def is_cdt_parent_def del:split_paired_All)
   apply (elim conjE exE)
   apply (drule(1) mdb_cte_atD)+
   apply (simp add:swp_def cte_wp_at_caps_of_state null_filter_def del:split_paired_All)
   apply (elim conjE exE)
   apply simp
  apply (drule spec)+
  apply (erule(1) impE)
  apply (frule tranclD)
  apply (drule tranclD2)
  apply (simp add:cdt_parent_rel_def is_cdt_parent_def del:split_paired_All)
  apply (elim conjE exE)
  apply (drule(1) mdb_cte_atD)+
  apply (simp add:swp_def cte_wp_at_caps_of_state null_filter_def del:split_paired_All)
  apply (elim conjE exE)
  apply simp
  done

definition
  valid_mdb2
    :: "[cslot_ptr \<rightharpoonup> cap, cslot_ptr \<rightharpoonup> cslot_ptr, cslot_ptr \<Rightarrow> bool] \<Rightarrow> bool"
where
 "valid_mdb2 cps m r \<equiv>
     (\<forall>p p'. m p' = Some p \<longrightarrow> {cps p, cps p'} \<inter> {None, Some cap.NullCap} = {})
   \<and> (\<forall>p p' c c'. cps p = Some c \<longrightarrow> is_untyped_cap c \<longrightarrow> cps p' = Some c'
               \<longrightarrow> obj_refs c' \<inter> untyped_range c \<noteq> {} \<longrightarrow> p' \<in> descendants_of p m)
   \<and> descendants_inc m cps
   \<and> (\<forall>p. \<not> m \<Turnstile> p \<rightarrow> p) \<and> untyped_inc m cps \<and> ut_revocable r cps
   \<and> irq_revocable r cps \<and> reply_master_revocable r cps \<and> reply_mdb m cps"

lemma conj_cong2: "\<lbrakk>P = P'; P \<Longrightarrow> Q = Q'\<rbrakk> \<Longrightarrow> (P \<and> Q) = (P' \<and> Q')" by auto

lemma valid_mdb_rep2:
  "valid_mdb = (\<lambda>s. valid_mdb2 (null_filter (caps_of_state s)) (cdt s) (is_original_cap s))"
  apply (simp add: valid_mdb_def valid_mdb2_def
                   untyped_mdb_def no_mloop_def untyped_inc_def)
  apply (rule ext)
  apply (rule conj_cong2)
   apply (simp add: mdb_cte_at_def)
   apply (rule arg_cong[where f=All, OF ext])+
   apply ((clarsimp simp: cte_wp_at_caps_of_state null_filter_def
                | rule conjI iffI
                | drule iffD1 [OF not_None_eq, OF not_sym])+)[1]
  apply (rule conj_cong)
   apply (rule arg_cong[where f=All, OF ext])+
   apply (clarsimp simp: null_filter_def)
  apply (rule conj_cong)
   apply (simp add:descendants_inc_null_filter)
  apply (rule arg_cong2 [where f="op \<and>"])
   apply (rule refl)
  apply (rule arg_cong2 [where f="op \<and>"])
   prefer 2
   apply (rule arg_cong2 [where f="op \<and>"])
    apply (simp add: ut_revocable_def null_filter_def del: split_paired_All)
    apply (auto simp: is_cap_simps)[1]
   apply (rule arg_cong2 [where f="op \<and>"])
    apply (simp add: irq_revocable_def null_filter_def del: split_paired_All)
    apply auto[1]
   apply (rule arg_cong2 [where f="op \<and>"])
    apply (simp add: reply_master_revocable_def null_filter_def del: split_paired_All)
    apply (auto simp: is_cap_simps)[1]
   apply (simp add: reply_mdb_def null_filter_def)
   apply (rule arg_cong2 [where f="op \<and>"])
    apply (simp add: reply_caps_mdb_def
                del: split_paired_Ex split_paired_All)
    apply (fastforce intro!: iffI elim!: allEI exEI
                  simp del: split_paired_Ex split_paired_All)
   apply (fastforce simp: reply_masters_mdb_def intro!: iffI elim!: allEI
               simp del: split_paired_All split: if_split_asm)
  apply (rule arg_cong[where f=All, OF ext])+
  apply ((clarsimp simp: cte_wp_at_caps_of_state null_filter_def
               | rule conjI iffI
               | drule iffD1 [OF not_None_eq, OF not_sym])+)[1]
  done

lemma valid_mdb_rep3:
  "valid_mdb = (\<lambda>s. \<exists>m r. cdt s = m \<and> is_original_cap s = r \<and> valid_mdb2 (null_filter (caps_of_state s)) m r)"
  by (simp add: valid_mdb_rep2)

lemma retype_region_mdb[wp]:
  "\<lbrace>\<lambda>s. P (cdt s)\<rbrace> retype_region ptr n us ty dev \<lbrace>\<lambda>rv s. P (cdt s)\<rbrace>"
  apply (simp add: retype_region_def split del: if_split cong: if_cong)
  apply (wp|clarsimp)+
  done

lemma retype_region_revokable[wp]:
  "\<lbrace>\<lambda>s. P (is_original_cap s)\<rbrace> retype_region ptr n us ty dev \<lbrace>\<lambda>rv s. P (is_original_cap s)\<rbrace>"
  apply (simp add: retype_region_def split del: if_split cong: if_cong)
  apply (wp|clarsimp)+
  done

lemma pspace_no_overlap_obj_not_in_range:
  "\<lbrakk> pspace_no_overlap S s; obj_at P ptr' s;
       pspace_aligned s; valid_objs s \<rbrakk>
     \<Longrightarrow> ptr' \<notin> S"
  apply (clarsimp simp add: pspace_no_overlap_def obj_at_def)
  apply (elim allE, drule(1) mp)
  apply (simp add: field_simps)
  apply (drule_tac x=ptr' in eqset_imp_iff)
  apply (erule pspace_alignedE, erule domI)
  apply (drule valid_obj_sizes, erule ranI)
  apply (clarsimp simp: add_diff_eq[symmetric])
  apply (simp add: is_aligned_no_wrap')
  done

lemma obj_at_kheap_trans_state[simp]:"obj_at P ptr (kheap_update f (trans_state f' s)) = obj_at P ptr (kheap_update f s)"
  apply (simp only: trans_state_update[symmetric] more_update.obj_at_update)
  done

lemma retype_region_obj_at:
  assumes tyunt: "ty \<noteq> Structures_A.apiobject_type.Untyped"
  shows "\<lbrace>\<top>\<rbrace> retype_region ptr n us ty dev
  \<lbrace>\<lambda>r s. \<forall>x \<in> set (retype_addrs ptr ty n us). obj_at (\<lambda>ko. ko = default_object ty dev us) x s\<rbrace>"
  using tyunt unfolding retype_region_def
  apply (simp only: return_bind bind_return foldr_upd_app_if fun_app_def K_bind_def)
  apply wp
  apply (simp only: obj_at_kheap_trans_state)
  apply wp
  apply (simp only: simp_thms if_True)
  apply (rule ballI)
  apply (subst retype_addrs_fold)
  apply simp
  apply (unfold obj_at_def)
  apply clarsimp
  done

lemma retype_region_obj_at_other:
  assumes ptrv: "ptr \<notin> set (retype_addrs ptr' ty n us)"
  shows "\<lbrace>obj_at P ptr\<rbrace> retype_region ptr' n us ty dev \<lbrace>\<lambda>r. obj_at P ptr\<rbrace>"
  using ptrv unfolding retype_region_def retype_addrs_def
  apply (simp only: foldr_upd_app_if fun_app_def K_bind_def)
  apply (wpsimp simp: obj_at_def)
  done

lemma retype_region_obj_at_other2:
  "\<lbrace>\<lambda>s. ptr \<notin> set (retype_addrs ptr' ty n us)
       \<and> obj_at P ptr s\<rbrace> retype_region ptr' n us ty dev \<lbrace>\<lambda>rv. obj_at P ptr\<rbrace>"
  by (rule hoare_assume_pre) (wpsimp wp: retype_region_obj_at_other)

lemma retype_region_obj_at_other3:
  "\<lbrace>\<lambda>s. pspace_no_overlap_range_cover ptr sz s \<and> obj_at P p s \<and> range_cover ptr sz (obj_bits_api ty us) n
           \<and> valid_objs s \<and> pspace_aligned s\<rbrace>
     retype_region ptr n us ty dev
   \<lbrace>\<lambda>rv. obj_at P p\<rbrace>"
  apply (rule hoare_pre)
   apply (rule retype_region_obj_at_other2)
  apply clarsimp
  apply (drule subsetD [rotated, OF _ retype_addrs_subset_ptr_bits])
   apply simp
  apply (drule(3) pspace_no_overlap_obj_not_in_range)
  apply (simp add: field_simps)
  done

lemma retype_region_st_tcb_at:
  "\<lbrace>\<lambda>(s::'state_ext::state_ext state). pspace_no_overlap_range_cover ptr' sz s \<and> pred_tcb_at proj P t s \<and> range_cover ptr' sz (obj_bits_api ty us) n
          \<and> valid_objs s \<and> pspace_aligned s\<rbrace>
     retype_region ptr' n us ty dev \<lbrace>\<lambda>rv. pred_tcb_at proj P t\<rbrace>"
  by (simp add: retype_region_obj_at_other3 pred_tcb_at_def)

lemma retype_region_cur_tcb[wp]:
  "\<lbrace>pspace_no_overlap_range_cover ptr sz and cur_tcb and K (range_cover ptr sz (obj_bits_api ty us) n)
     and K (is_aligned ptr sz \<and> sz < word_bits)
     and valid_objs and pspace_aligned\<rbrace>
     retype_region ptr n us ty dev
   \<lbrace>\<lambda>rv. cur_tcb\<rbrace>"
  apply (rule hoare_post_imp [where Q="\<lambda>rv s. \<exists>tp. tcb_at tp s \<and> cur_thread s = tp"])
   apply (simp add: cur_tcb_def)
  apply (wpsimp wp: hoare_vcg_ex_lift retype_region_obj_at_other3 simp: retype_region_def)
  apply (auto simp: cur_tcb_def cong: if_cong)
  done

lemma retype_addrs_mem_sz_0_is_ptr:
  assumes "x \<in> set (retype_addrs ptr ty n us)"
  and     "n = 0"
  shows   "x = ptr"
  using assms unfolding retype_addrs_def by (clarsimp simp: ptr_add_def)

locale Retype_AI_obj_bits_api_neq_0 =
  assumes obj_bits_api_neq_0: "\<And>ty us. ty \<noteq> Untyped \<Longrightarrow> 0 < obj_bits_api ty us"

lemma retype_addrs_range_subset:
  "\<lbrakk>  p \<in> set (retype_addrs ptr ty n us);
     range_cover ptr sz (obj_bits_api ty us) n \<rbrakk>
  \<Longrightarrow> {p .. p + 2 ^ obj_bits_api ty us - 1} \<subseteq> {ptr..(ptr && ~~ mask sz) + 2^sz - 1}"
  apply (clarsimp simp: retype_addrs_def ptr_add_def
              simp del: atLeastatMost_subset_iff atLeastAtMost_iff)
  apply (frule_tac x = "of_nat pa" in range_cover_cell_subset)
    apply (erule of_nat_mono_maybe[rotated])
    apply (drule range_cover.range_cover_n_less)
   apply (simp add:word_bits_def)
  apply fastforce
  done

context Retype_AI_slot_bits begin

lemma retype_addrs_obj_range_subset:
  "\<lbrakk>  p \<in> set (retype_addrs ptr ty n us);
      range_cover ptr sz (obj_bits (default_object ty dev us)) n;
  ty \<noteq> Untyped \<rbrakk>
  \<Longrightarrow> obj_range p (default_object ty dev us) \<subseteq> {ptr..(ptr && ~~ mask sz) + (2^sz - 1)}"
  by(simp add: obj_range_def obj_bits_api_default_object[symmetric]
                retype_addrs_range_subset p_assoc_help[symmetric]
           del: atLeastatMost_subset_iff)

lemma retype_addrs_obj_range_subset_strong:
  "\<lbrakk> p \<in> set (retype_addrs ptr ty n us);
    range_cover ptr sz (obj_bits_api ty us) n;
  ty \<noteq> Untyped \<rbrakk>
   \<Longrightarrow> obj_range p (default_object ty dev us) \<subseteq>  {ptr..ptr + of_nat n * 2 ^ obj_bits_api ty us - 1}"
  unfolding obj_range_def
  apply (frule retype_addrs_obj_range_subset)
   apply (simp add:obj_bits_dev_irr)
  apply (simp add:obj_range_def)+
  apply (intro conjI impI)
  apply (erule(1) impE)
  apply clarsimp
  apply (case_tac "n = 0")
   apply (clarsimp simp:retype_addrs_def)
  proof -
    assume cover:"range_cover ptr sz (obj_bits_api ty us) n"
      and  mem_p:"p \<in> set (retype_addrs ptr ty n us)"
      and  not_0:"n\<noteq> 0"
      and  tyunt:"ty\<noteq> Untyped"
    note n_less = range_cover.range_cover_n_less[OF cover]
    have unat_of_nat_m1: "unat (of_nat n - (1::machine_word)) < n"
      using not_0 n_less
       by (simp add:unat_of_nat_minus_1)
    have decomp:"of_nat n * 2 ^ obj_bits_api ty us = of_nat (n - 1) * 2 ^ (obj_bits (default_object ty dev us))
      + (2 :: machine_word) ^ obj_bits (default_object ty dev us)"
      apply (simp add:distrib_right[where b = "1::'a::len word",simplified,symmetric])
      using not_0 n_less
      apply (simp add: unat_of_nat_minus_1 obj_bits_api_def3 tyunt cong: obj_bits_cong)
      done
    show  "p + 2 ^ obj_bits (default_object ty dev us) - 1 \<le> ptr + of_nat n * 2 ^ obj_bits_api ty us - 1"
      apply (subst decomp)
      apply (simp add:add.assoc[symmetric])
      apply (simp add:p_assoc_help)
      apply (rule order_trans[OF word_plus_mono_left word_plus_mono_right])
       using mem_p not_0
         apply (clarsimp simp: retype_addrs_def ptr_add_def shiftl_t2n tyunt
                               obj_bits_dev_irr)
         apply (rule word_plus_mono_right)
          apply (rule word_mult_le_mono1[OF word_of_nat_le])
          using n_less not_0
            apply (simp add:unat_of_nat_minus_1)
           apply (rule p2_gt_0[THEN iffD2])
           using cover
           apply (simp add: word_bits_def range_cover_def obj_bits_dev_irr tyunt)
          apply (simp only: word_bits_def[symmetric])
          using not_0 n_less
          apply (clarsimp simp: unat_of_nat_minus_1 obj_bits_dev_irr tyunt)
          apply (subst unat_power_lower)
            using cover
            apply (simp add:range_cover_def)
          apply (rule nat_less_power_trans2[OF range_cover.range_cover_le_n_less(2),OF cover, folded word_bits_def])
          apply (simp add:unat_of_nat_m1 less_imp_le)
         using cover
         apply (simp add:range_cover_def word_bits_def)
        apply (rule machine_word_plus_mono_right_split[where sz = sz])
        using range_cover.range_cover_compare[OF cover,where p = "unat (of_nat n - (1::machine_word))"]
        apply (clarsimp simp:unat_of_nat_m1)
       using cover
       apply (simp add:range_cover_def word_bits_def)
      apply (rule olen_add_eqv[THEN iffD2])
      apply (subst add.commute[where a = "2^(obj_bits (default_object ty dev us)) - 1"])
     apply (subst p_assoc_help[symmetric])
     apply (rule is_aligned_no_overflow)
     apply (insert cover)
     apply (clarsimp simp:range_cover_def)
     apply (erule aligned_add_aligned[OF _  is_aligned_mult_triv2])
       apply (simp add: obj_bits_dev_irr range_cover_def tyunt)+
   done
  qed

lemma retype_addrs_mem_subset_ptr_bits:
  assumes cover:"range_cover ptr sz (obj_bits_api ty us) n"
  and tynunt: "ty \<noteq> Untyped"
  and     xv: "x \<in> set (retype_addrs ptr ty n us)"
  shows "{x .. x + (2 ^ obj_bits_api ty us - 1)} \<subseteq> {ptr .. (ptr && ~~ mask sz) + (2 ^ sz - 1)}"
  apply (insert cover)
  using retype_addrs_obj_range_subset [OF xv _ tynunt]
  by (simp add: obj_bits_dev_irr tynunt obj_range_def field_simps)

lemma pspace_no_overlap_retype_addrs_empty:
  assumes nptr: "pspace_no_overlap_range_cover ptr sz s"
  and xv: "x \<in> set (retype_addrs ptr ty n us)"
  and yv: "y \<notin> set (retype_addrs ptr ty n us)"
  and kov: "kheap s y = Some ko"
  and tyv: "ty \<noteq> Structures_A.apiobject_type.Untyped"
  and cover: "range_cover ptr sz (obj_bits_api ty us) n"
  and oab: "obj_bits_api ty us \<le> sz"
  shows "{x..x + (2 ^ obj_bits (default_object ty dev us) - 1)} \<inter> {y..y + (2 ^ obj_bits ko - 1)} = {}"
proof -
  have "{x..x + (2 ^ obj_bits (default_object ty dev us) - 1)} \<subseteq> {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)}"
   by (subst obj_bits_api_default_object [OF tyv, symmetric],
      rule retype_addrs_mem_subset_ptr_bits) fact+

  moreover have "{ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)} \<inter> {y..y + (2 ^ obj_bits ko - 1)} = {}"
    by (subst Int_commute, rule pspace_no_overlapE) fact+

  ultimately show ?thesis by auto
qed

end

lemma valid_obj_default_object:
  assumes tyunt: "ty \<noteq> Untyped"
  and      tyct: "ty = CapTableObject \<Longrightarrow> us < word_bits - cte_level_bits \<and> 0 < us"
  shows "valid_obj ptr (default_object ty dev us) s"
  unfolding valid_obj_def default_object_def
  apply (cases ty)
       apply (simp add: tyunt)
      apply (simp add: valid_tcb_def default_tcb_def valid_tcb_state_def
                       tcb_cap_cases_def valid_ipc_buffer_cap_def
                       word_bits_def)
     apply (simp add: valid_ep_def default_ep_def)
    apply (simp add: valid_ntfn_def default_notification_def default_ntfn_def valid_bound_tcb_def)
   apply (frule tyct)
   apply (clarsimp simp: valid_cs_def empty_cnode_def well_formed_cnode_n_def)
   apply safe
    apply (erule ranE)
    apply (simp split: if_split_asm)
   apply (simp add: valid_cs_size_def well_formed_cnode_n_def)
   apply safe
    apply (simp split: if_split_asm)
   apply (clarsimp split: if_split_asm)
  apply (clarsimp simp add: wellformed_arch_default)
  done

lemma valid_arch_obj_default:
  assumes tyunt: "ty \<noteq> Structures_A.apiobject_type.Untyped"
  shows "ArchObj ao = default_object ty dev us \<Longrightarrow> valid_arch_obj ao s'"
  apply (cases ty, simp_all add: default_object_def tyunt)
  apply (simp add: valid_arch_obj_default')
  done

lemma usable_range_subseteq:
  "\<lbrakk>cap_aligned cap;is_untyped_cap cap\<rbrakk> \<Longrightarrow> usable_untyped_range cap \<subseteq> untyped_range cap"
  apply (clarsimp simp:is_cap_simps cap_aligned_def split:if_splits)
  apply (erule order_trans[OF is_aligned_no_wrap'])
   apply (erule of_nat_power)
   apply (simp add:word_bits_def)+
 done

lemma usable_range_emptyD:
  "\<lbrakk>cap_aligned cap;is_untyped_cap cap ;usable_untyped_range cap = {}\<rbrakk> \<Longrightarrow> 2 ^ cap_bits cap \<le> free_index_of cap"
  apply (clarsimp simp:is_cap_simps not_le free_index_of_def cap_aligned_def split:if_splits)
  apply (drule(1) of_nat_power [where 'a=machine_word_len, folded word_bits_def])
  apply (drule word_plus_mono_right[OF _ is_aligned_no_overflow[unfolded p_assoc_help],rotated])
   apply simp
  apply (simp add:p_assoc_help)
  done

locale Retype_AI_valid_untyped_helper =
  fixes state_ext_t :: "'state_ext::state_ext itself"
  assumes valid_untyped_helper:
    "\<And>s c q ty ptr sz us n dev.
      \<lbrakk> (s :: 'state_ext state) \<turnstile> c;
        cte_wp_at (op = c) q s;
        ty \<noteq> Untyped;
        range_cover ptr sz (obj_bits_api ty us) n;
        is_untyped_cap c \<Longrightarrow>
          usable_untyped_range c \<inter> {ptr..ptr + of_nat (n * 2 ^ (obj_bits_api ty us)) - 1} = {};
        pspace_no_overlap_range_cover ptr sz s;
        caps_no_overlap ptr sz s;
        valid_pspace s \<rbrakk>
      \<Longrightarrow> valid_cap c
           (s\<lparr>kheap := \<lambda>x. if x \<in> set (retype_addrs ptr ty n us)
                             then Some (default_object ty dev us)
                             else kheap s x\<rparr>)"

lemma cap_refs_respects_device_region_cap_range:
  "\<lbrakk>cte_wp_at (\<lambda>c.  {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)} \<subseteq> cap_range c \<and> cap_is_device c = dev) slot s;
    cap_refs_respects_device_region s\<rbrakk>
    \<Longrightarrow> up_aligned_area ptr sz \<subseteq> (if dev then device_region s else - device_region s)"
  unfolding cap_refs_respects_device_region_def
  apply (drule spec[where x = slot])
  apply (clarsimp simp: cte_wp_at_caps_of_state cap_range_respects_device_region_def)
  apply fastforce
  done

locale retype_region_proofs =
  fixes s :: "'state_ext :: state_ext state"
    and ty us ptr sz n ps s' dev
  assumes    vp: "valid_pspace s"
      and    vm: "valid_mdb s"
      and   res: "caps_overlap_reserved {ptr..ptr + of_nat (n * 2 ^ (obj_bits_api ty us)) - 1} s"
      and tyunt: "ty \<noteq> Structures_A.apiobject_type.Untyped"
      and  tyct: "ty = CapTableObject \<Longrightarrow> us < word_bits - cte_level_bits \<and> 0 < us"
      and   orth: "pspace_no_overlap_range_cover ptr sz s"
      and  mem :  "caps_no_overlap ptr sz s"
      and cover: "range_cover ptr sz (obj_bits_api ty us) n"
      and dev: "\<exists>slot. cte_wp_at (\<lambda>c.  {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)} \<subseteq> cap_range c \<and> cap_is_device c = dev) slot s"
  defines "ps \<equiv> (\<lambda>x. if x \<in> set (retype_addrs ptr ty n us) then Some (default_object ty dev us)
                       else kheap s x)"
      and "s' \<equiv> kheap_update (\<lambda>y. ps) s"

locale retype_region_proofs_gen
  = retype_region_proofs s ty us ptr sz n ps s' dev
  + Retype_AI_slot_bits
  + Retype_AI_valid_untyped_helper "TYPE('state_ext)"
  for s :: "'state_ext :: state_ext state"
  and ty us ptr sz n ps s' dev

context retype_region_proofs begin

lemma obj_at_pres: "\<And>P x. obj_at P x s \<Longrightarrow> obj_at P x s'"
  by (clarsimp simp: obj_at_def s'_def ps_def dest: domI)
     (rule pspace_no_overlapC [OF orth _ _ cover vp])

lemma orthr:
  "\<And>x obj. kheap s x = Some obj \<Longrightarrow> x \<notin> set (retype_addrs ptr ty n us)"
  apply (rule ccontr)
  apply (frule pspace_no_overlapC[OF orth _ _ _ vp,rotated])
    apply (rule cover)
  apply auto
  done

lemma cte_at_pres: "\<And>p. cte_at p s \<Longrightarrow> cte_at p s'"
  unfolding cte_at_cases s'_def ps_def
  apply (erule disjE)
   apply (clarsimp simp: well_formed_cnode_n_def orthr)+
  done

lemma pred_tcb_at_pres: "\<And>P t. pred_tcb_at proj P t s \<Longrightarrow> pred_tcb_at proj P t s'"
  unfolding pred_tcb_at_def
  by (erule obj_at_pres)

end

context retype_region_proofs_gen begin

lemma psp_dist:
  shows         "pspace_distinct s'"
proof -
  have distinct:"pspace_distinct s"
    apply (rule valid_pspaceE)
    apply (rule vp)
    apply simp
   done
  moreover
  {
    fix x y
    assume xne: "x \<noteq> y" and xv: "x \<in> set (retype_addrs ptr ty n us)" and yv: "y \<in> set (retype_addrs ptr ty n us)"

    have "is_aligned x (obj_bits_api ty us)"
      apply (rule retype_addrs_aligned)
      apply fact+
      apply (insert cover)
        apply (auto simp: range_cover_def word_bits_def)
      done
    moreover
    have "is_aligned y (obj_bits_api ty us)"
      apply (rule retype_addrs_aligned)
      apply fact+
      apply (insert cover)
      apply (auto simp: range_cover_def word_bits_def)
      done
    ultimately have
      "{x..x + (2 ^ obj_bits (default_object ty dev us) - 1)} \<inter>
       {y..y + (2 ^ obj_bits (default_object ty dev us) - 1)} = {}"
      using xne tyunt cover
      apply -
      apply (rule aligned_neq_into_no_overlap)
      apply (simp_all add: range_cover_def word_bits_def obj_bits_dev_irr)
      done
  } note inter = this
  moreover
  {
    fix x y ko'
    assume xne: "x \<noteq> y" and xv: "x \<in> set (retype_addrs ptr ty n us)"
        and yv: "y \<notin> set (retype_addrs ptr ty n us)" and  "kheap s y = Some ko'"
    have "{x..x + (2 ^ obj_bits (default_object ty dev us) - 1)} \<inter> {y..y + (2 ^ obj_bits ko' - 1)} = {}"
      apply (rule pspace_no_overlap_retype_addrs_empty [OF orth])
      apply fact+
      apply (insert cover tyunt)
      apply (simp add: range_cover_def word_bits_def)+
      done
  }note inter' = this
  show ?thesis
    unfolding pspace_distinct_def s'_def ps_def
    apply (clarsimp split: if_split_asm option.splits
              simp del: Int_atLeastAtMost)
    apply (intro conjI impI allI)
      apply (erule(2) inter)
     apply clarify
     apply (erule(3) inter')
    apply clarify
    apply (subst Int_commute)
    apply (erule(3) inter'[OF neq_commute[THEN iffD1]])
   apply clarify
   apply (insert vp[unfolded valid_pspace_def pspace_distinct_def])
   apply clarify
   apply (drule_tac x = x in spec)
   apply (drule_tac x = y in spec)
   apply (erule allE impE)+
     apply fastforce
  apply simp
  done
qed

lemma psp_al:
  shows "pspace_aligned s'"
  unfolding pspace_aligned_def s'_def ps_def
proof (clarsimp split: if_split_asm)
  fix x
  assume "x \<in> set (retype_addrs ptr ty n us)"
  thus "is_aligned x (obj_bits (default_object ty dev us))"
    apply -
    apply (drule retype_addrs_aligned)
    apply (insert cover tyunt)
      apply (fastforce simp:range_cover_def word_bits_def)+
    apply (simp add: obj_bits_dev_irr
              split: Structures_A.apiobject_type.splits)
    done
next
  fix x y
  assume "x \<notin> set (retype_addrs ptr ty n us)" and px: "kheap s x = Some y"

  have "pspace_aligned s"
    by (rule valid_pspaceE[OF vp],simp)

  thus "is_aligned x (obj_bits y)"
  proof
    show "x \<in> dom (kheap s)" by (rule domI) fact+
  next
    assume "is_aligned x (obj_bits (the (kheap s x)))"
    thus "is_aligned x (obj_bits y)" using px by simp
  qed
qed

end

lemma le_subset: "\<lbrakk>(a::('g::len) word) \<le> c\<rbrakk> \<Longrightarrow> {c..b} \<subseteq> {a..b}" by clarsimp

context retype_region_proofs_gen begin

lemma valid_cap_pres:
  "\<lbrakk> s \<turnstile> c; cte_wp_at (op = c) (oref,cref) s \<rbrakk> \<Longrightarrow> s' \<turnstile> c"
  using cover mem orth
  apply (simp add:s'_def ps_def)
  apply (rule valid_untyped_helper[ OF _ _ tyunt cover _ _ _ vp ])
      apply simp+
     apply (simp add:cte_wp_at_caps_of_state)
     apply (drule res[unfolded caps_overlap_reserved_def,THEN bspec,OF ranI])
     apply simp
    apply simp+
  done

lemma valid_objs: "valid_objs s'"
  apply (clarsimp simp:valid_objs_def)
  apply (rule valid_pspaceE[OF vp])
  apply (clarsimp simp:valid_objs_def s'_def ps_def split:if_splits)
   apply (simp add:valid_obj_default_object[OF tyunt tyct])
  apply (simp (no_asm) add:valid_obj_def)
  apply (drule bspec)
   apply (erule domI)
  apply (clarsimp simp:valid_obj_def split:Structures_A.kernel_object.splits)
     apply (clarsimp simp: valid_cs_def)
     apply (drule (1) bspec)
     apply (clarsimp simp: ran_def)
     apply (erule valid_cap_pres[unfolded s'_def ps_def])
     apply (clarsimp simp add: cte_wp_at_cases valid_cs_size_def s'_def ps_def)
     apply fastforce
    apply (clarsimp simp: valid_tcb_def)
    apply (rule conjI)
     apply (rule ballI, drule(1) bspec, clarsimp elim!: ranE)
     apply (erule valid_cap_pres[unfolded s'_def ps_def])
     apply (rule cte_wp_at_tcbI, fastforce+)[1]
   apply (fastforce simp: valid_tcb_state_def valid_bound_ntfn_def
                   elim!: obj_at_pres[unfolded s'_def ps_def]
                   split: Structures_A.thread_state.splits option.splits)
    apply (fastforce simp: valid_ep_def
                  elim!: obj_at_pres[unfolded s'_def ps_def]
                  split: Structures_A.endpoint.splits)
  apply (fastforce simp: valid_ntfn_def valid_bound_tcb_def
                  elim!: obj_at_pres[unfolded s'_def ps_def]
                 split: Structures_A.ntfn.splits option.splits)
  done

end

context retype_region_proofs begin

lemma refs_eq:
  "state_refs_of s' = state_refs_of s"
  unfolding s'_def ps_def
  apply (clarsimp intro!: ext simp: state_refs_of_def
                    simp: orthr
                   split: option.splits)
  apply (cases ty, simp_all add: tyunt default_object_def
                                 default_tcb_def default_ep_def
                                 default_notification_def default_ntfn_def)
  done

lemma cte_retype:
    "\<And>P p. \<not> P cap.NullCap \<Longrightarrow>
     cte_wp_at P p s' = cte_wp_at P p s"
  unfolding s'_def ps_def
  apply (safe elim!: cte_wp_atE)
       apply (clarsimp split: if_split_asm
                              Structures_A.apiobject_type.split_asm
                        simp: default_object_def tyunt default_tcb_def
                              empty_cnode_def cte_wp_at_cases
                       dest!: orthr
                  | simp add: tcb_cap_cases_def)+
  done

lemma iflive_s: "if_live_then_nonz_cap s" by (rule valid_pspaceE [OF vp])

lemma iflive:
  "if_live_then_nonz_cap s'"
  using iflive_s unfolding if_live_then_nonz_cap_def s'_def ps_def
  apply -
  apply (clarsimp elim!: obj_atE split: if_split_asm)
   apply (cases ty, simp_all add: default_object_def tyunt
                                  default_tcb_def default_ep_def
                                  default_notification_def default_ntfn_def)
  apply (frule(1) if_live_then_nonz_capD2[OF iflive_s])
  apply (simp add: ex_nonz_cap_to_def
                   cte_retype[unfolded s'_def ps_def])
  done

lemma final_retype: "is_final_cap' cap s' = is_final_cap' cap s"
  by (simp add: is_final_cap'_def2 cte_retype)

lemma not_final_NullCap: "\<And>s. \<not> is_final_cap' cap.NullCap s"
  by (simp add: is_final_cap'_def)

lemma zombies_s: "zombies_final s" by (rule valid_pspaceE[OF vp])

lemma zombies: "zombies_final s'"
  unfolding zombies_final_def
  by (clarsimp simp: final_retype is_zombie_def cte_retype not_final_NullCap
              elim!: zombies_finalD [OF _ zombies_s])

end

lemma (in retype_region_proofs_gen) valid_pspace: "valid_pspace s'"
  using vp by (simp add: valid_pspace_def valid_objs psp_al psp_dist
                         iflive zombies refs_eq)

(* I have the feeling I'm making this unnecessarily hard,
   but I can't put my finger on where. *)

lemma F: "\<And>x c s. (caps_of_state s x = Some c) = (cte_wp_at (op = c) x s)"
  apply (simp add: caps_of_state_cte_wp_at)
  apply (fastforce simp: cte_wp_at_def)
  done

lemma F2: "\<And>x c s. (null_filter (caps_of_state s) x = Some c)
             = (cte_wp_at (\<lambda>cap. cap \<noteq> cap.NullCap \<and> cap = c) x s)"
  apply (simp add: null_filter_def F)
  apply (fastforce simp: cte_wp_at_def)
  done

lemma F3: "\<And>x s. (None = null_filter (caps_of_state s) x)
              = (\<forall>c. \<not> cte_wp_at (\<lambda>cap. cap \<noteq> cap.NullCap \<and> cap = c) x s)"
  apply safe
   apply (simp add: F2[symmetric])
  apply (rule sym, rule ccontr, clarsimp simp: F2)
  done

lemma (in retype_region_proofs) null_filter:
  "null_filter (caps_of_state s') = null_filter (caps_of_state s)"
  apply (rule ext)
  apply (case_tac "null_filter (caps_of_state s) x")
   apply (simp add: eq_commute)
   apply (simp add: F3 cte_retype)
  apply simp
  apply (simp add: F2 cte_retype)
  done

context retype_region_proofs begin

lemma idle_s':
  "idle_thread s' = idle_thread s"
  by (simp add: s'_def ps_def)

lemma valid_idle:
  "valid_idle s \<Longrightarrow> valid_idle s'"
  by (clarsimp simp add: valid_idle_def idle_s' refs_eq
                         pred_tcb_at_pres)

lemma arch_state [simp]:
  "arch_state s' = arch_state s"
  by (simp add: s'_def)

lemma irq_node [simp]:
  "interrupt_irq_node s' = interrupt_irq_node s"
  by (simp add: s'_def)

lemma caps_retype:
  assumes nonnull: "cap \<noteq> cap.NullCap"
  and      newcap: "caps_of_state s' p = Some cap"
  shows            "caps_of_state s p = Some cap"
proof -
  from newcap have "cte_wp_at (op = cap) p s'"
    by (simp add: cte_wp_at_caps_of_state)
  hence "cte_wp_at (op = cap) p s"
    by (rule_tac subst [OF cte_retype], rule_tac nonnull, assumption)
  thus ?thesis
    by (simp add: cte_wp_at_caps_of_state)
qed

lemma unique_reply_caps:
  "unique_reply_caps (caps_of_state s) \<Longrightarrow> unique_reply_caps (caps_of_state s')"
  using caps_retype
  by (fastforce simp add: is_cap_simps unique_reply_caps_def
               simp del: split_paired_All
                  elim!: allEI)

lemma valid_reply_caps:
  "valid_reply_caps s \<Longrightarrow> valid_reply_caps s'"
  by (clarsimp simp: valid_reply_caps_def unique_reply_caps has_reply_cap_def
                     pred_tcb_at_pres cte_retype)

lemma valid_reply_masters:
  "valid_reply_masters s \<Longrightarrow> valid_reply_masters s'"
  by (clarsimp simp: valid_reply_masters_def cte_retype is_cap_simps obj_at_pres)

end

lemma ran_null_filter:
  "ran (null_filter m) = (ran m - {cap.NullCap})"
  apply (simp add: null_filter_def ran_def cong: conj_cong)
  apply force
  done

lemma valid_irq_handlers_def2:
  "valid_irq_handlers =
     (\<lambda>s. \<forall>cap \<in> ran (null_filter (caps_of_state s)).
          \<forall>irq \<in> cap_irqs cap. interrupt_states s irq = irq_state.IRQSignal)"
  apply (rule ext)
  apply (simp add: valid_irq_handlers_def irq_issued_def
                   ran_null_filter)
  apply auto
  done

lemma p_in_obj_range:
  "\<lbrakk> kheap s p = Some ko; pspace_aligned s; valid_objs s \<rbrakk> \<Longrightarrow> p \<in> obj_range p ko"
  apply (simp add: pspace_aligned_def)
  apply (drule bspec, erule domI)
  apply (drule valid_obj_sizes, erule ranI)
  apply (simp add: obj_range_def add_diff_eq[symmetric])
  apply (erule is_aligned_no_wrap')
  apply (erule word_power_less_1[where 'a=machine_word_len, folded word_bits_def])
  done

lemma p_in_obj_range_internal:
  "\<lbrakk> kheap s (p && ~~ mask (obj_bits ko))= Some ko; pspace_aligned s; valid_objs s \<rbrakk>
  \<Longrightarrow> p \<in> obj_range (p && ~~ mask (obj_bits ko)) ko"
  apply (drule p_in_obj_range,simp+)
  apply (simp add: obj_range_def word_and_le2 word_neg_and_le p_assoc_help)
  done

context retype_region_proofs begin

lemma interrupt_states:
  "interrupt_states s' = interrupt_states s"
  by (simp add: s'_def)

lemma valid_irq_handlers:
  "valid_irq_handlers s \<Longrightarrow> valid_irq_handlers s'"
  by (simp add: valid_irq_handlers_def2 null_filter
                interrupt_states)

lemma mdb_and_revokable:
  "cdt s' = cdt s"
  "is_original_cap s' = is_original_cap s"
  by (simp add: s'_def)+

lemma cur_tcb:
  "cur_tcb s \<Longrightarrow> cur_tcb s'"
  apply (simp add: cur_tcb_def, rule obj_at_pres)
  apply (simp add: s'_def)
  done

lemma only_idle:
  "only_idle s \<Longrightarrow> only_idle s'"
  apply (clarsimp simp: only_idle_def)
  apply (clarsimp simp: s'_def pred_tcb_at_def obj_at_def ps_def split: if_split_asm)
  apply (simp add: default_object_def tyunt split: Structures_A.apiobject_type.splits)
  apply (simp add: default_tcb_def)
  done

lemma valid_irq_states:
  "valid_irq_states s \<Longrightarrow> valid_irq_states s'"
  apply(simp add: s'_def valid_irq_states_def)
  done

lemma cap_refs_in_kernel_window:
  "cap_refs_in_kernel_window s \<Longrightarrow> cap_refs_in_kernel_window s'"
  apply (simp add: cap_refs_in_kernel_window_def valid_refs_def)
  apply (simp add: cte_retype cap_range_def)
  done

lemma valid_ioc:
  "valid_ioc s \<Longrightarrow> valid_ioc s'"
  using cte_retype
  by (simp add: valid_ioc_def s'_def)

end

locale retype_region_proofs_invs
  = retype_region_proofs_gen s ty us ptr sz n ps s' dev
  + Retype_AI_post_retype_invs "TYPE('state_ext)" post_retype_invs_check post_retype_invs
  for s :: "'state_ext :: state_ext state"
  and ty us ptr sz n ps s' dev post_retype_invs_check
  and post_retype_invs :: "apiobject_type \<Rightarrow> machine_word list \<Rightarrow> 'state_ext state \<Rightarrow> bool" +
  fixes region_in_kernel_window :: "machine_word set \<Rightarrow> 'state_ext state \<Rightarrow> bool"
  assumes valid_global_refs: "valid_global_refs s \<Longrightarrow> valid_global_refs s'"
  assumes valid_arch_state: "valid_arch_state s \<Longrightarrow> valid_arch_state s'"
  assumes valid_arch_objs': "valid_arch_objs s \<Longrightarrow> valid_arch_objs s'"
  assumes valid_cap:
    "(s::'state_ext state) \<turnstile> cap \<and>
        untyped_range cap \<inter> {ptr .. (ptr && ~~ mask sz) + 2 ^ sz - 1} = {}
      \<Longrightarrow> s' \<turnstile> cap"
  assumes post_retype_invs:
    "\<lbrakk> invs (s :: 'state_ext state); region_in_kernel_window {ptr .. (ptr && ~~ mask sz) + 2 ^ sz - 1} s \<rbrakk>
        \<Longrightarrow> post_retype_invs ty (retype_addrs ptr ty n us) s'"

context Retype_AI_slot_bits begin

lemma use_retype_region_proofs':
  assumes x: "\<And>s. \<lbrakk> retype_region_proofs s ty us ptr sz n dev; P s \<rbrakk>
   \<Longrightarrow> Q (retype_addrs ptr ty n us) (s\<lparr>kheap :=
           \<lambda>x. if x \<in> set (retype_addrs ptr ty n us)
             then Some (default_object ty dev us)
             else kheap s x\<rparr>)"
  assumes y: "\<And>x s f. Q x (trans_state f s) = Q x s"
  shows
    "\<lbrakk> ty = CapTableObject \<Longrightarrow> 0 < us;
         \<And>s. P s \<longrightarrow> Q (retype_addrs ptr ty n us) s \<rbrakk> \<Longrightarrow>
    \<lbrace>\<lambda>s. valid_pspace s \<and> valid_mdb s \<and> range_cover ptr sz (obj_bits_api ty us) n
        \<and> caps_overlap_reserved {ptr..ptr + of_nat n * 2 ^ obj_bits_api ty us - 1} s
        \<and> caps_no_overlap ptr sz s \<and> pspace_no_overlap_range_cover ptr sz s
        \<and> (\<exists>slot. cte_wp_at (\<lambda>c.  {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)} \<subseteq> cap_range c \<and> cap_is_device c = dev) slot s)
        \<and> P s\<rbrace> retype_region ptr n us ty dev \<lbrace>Q\<rbrace>"
  apply (simp add: retype_region_def split del: if_split)
  apply (rule hoare_pre, (wp|simp add:y trans_state_update[symmetric] del: trans_state_update)+)
  apply (clarsimp simp: retype_addrs_fold
                        foldr_upd_app_if fun_upd_def[symmetric])
  apply safe
  apply (rule x)
   apply (rule retype_region_proofs.intro, simp_all)[1]

   apply (fastforce simp add: range_cover_def obj_bits_api_def
     slot_bits_def2 word_bits_def cte_level_bits_def)+
  done
end

locale Retype_AI
  = Retype_AI_clearMemoryVM
  + Retype_AI_slot_bits
  + Retype_AI_retype_region_ret state_ext_t
  + Retype_AI_post_retype_invs state_ext_t post_retype_invs_check post_retype_invs
  + Retype_AI_obj_bits_api_neq_0
  + Retype_AI_no_gs_types no_gs_types
  + Retype_AI_dmo_eq_kernel_restricted state_ext_t machine_op_t
  for state_ext_t :: "'state_ext::state_ext itself"
  and post_retype_invs_check
  and post_retype_invs :: "apiobject_type \<Rightarrow> machine_word list \<Rightarrow> 'state_ext state \<Rightarrow> bool"
  and no_gs_types
  and machine_op_t :: "'machine_op_t itself" +
  fixes state_ext'_t :: "'state_ext'::state_ext itself"
  fixes region_in_kernel_window :: "machine_word set \<Rightarrow> 'state_ext state \<Rightarrow> bool"
  assumes invs_post_retype_invs:
    "\<And>(s::'state_ext state) ty refs. invs s \<Longrightarrow> post_retype_invs ty refs s"
  assumes equal_kernel_mappings_trans_state[simp]:
    "\<And>(f::'state_ext \<Rightarrow> 'state_ext') (s::'state_ext state).
      equal_kernel_mappings (trans_state f s) = equal_kernel_mappings s"
  assumes retype_region_proofs_assms:
    "\<And>s ty us ptr sz n dev.
      retype_region_proofs (s::'state_ext state) ty us ptr sz n dev
        \<Longrightarrow> retype_region_proofs_invs s ty us ptr sz n dev
                                      post_retype_invs_check post_retype_invs
                                      region_in_kernel_window"

context Retype_AI begin

lemmas use_retype_region_proofs
    = use_retype_region_proofs'[where Q="\<lambda>_. Q" and P=Q, simplified]
      for Q

lemma retype_region_proofs_assms':
  assumes "retype_region_proofs (s::'state_ext state) ty us ptr sz n dev"
  shows "retype_region_proofs_gen s ty us ptr sz n dev"
  using assms retype_region_proofs_assms
  by (auto simp: retype_region_proofs_invs_def)

lemmas retype_region_valid_pspace = use_retype_region_proofs
  [where Q=valid_pspace,
         OF retype_region_proofs_gen.valid_pspace[OF retype_region_proofs_assms'],
         simplified]

lemmas retype_region_caps_of = use_retype_region_proofs
  [where Q="\<lambda>s. P (null_filter (caps_of_state s))",
         OF ssubst [where P=P, OF retype_region_proofs.null_filter],
         simplified] for P

lemma retype_region_valid_cap:
  "\<lbrakk>ty = Structures_A.apiobject_type.CapTableObject \<Longrightarrow> 0 < us\<rbrakk>
   \<Longrightarrow> \<lbrace>(\<lambda>s::'state_ext state. valid_pspace s \<and> caps_overlap_reserved {ptr..ptr + of_nat n * 2 ^ obj_bits_api ty us - 1} s \<and>
           valid_mdb s \<and> range_cover ptr sz (obj_bits_api ty us) n \<and>
           caps_no_overlap ptr sz s \<and> pspace_no_overlap_range_cover ptr sz s  \<and>
           (\<exists>slot. cte_wp_at (\<lambda>c.  {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)} \<subseteq> cap_range c \<and> cap_is_device c = dev) slot s) \<and>
           s \<turnstile> cap) and K (untyped_range cap \<inter> {ptr..(ptr &&~~ mask sz) + 2 ^ sz - 1} = {})\<rbrace>
        retype_region ptr n us ty dev
      \<lbrace>\<lambda>r s. s \<turnstile> cap\<rbrace>"
  apply (rule hoare_gen_asm)
  apply (rule hoare_pre)
  apply (rule use_retype_region_proofs)
    apply (erule retype_region_proofs_invs.valid_cap[OF retype_region_proofs_assms])
    apply simp+
  done

lemmas retype_region_aligned = use_retype_region_proofs
  [where Q=pspace_aligned,
         OF retype_region_proofs_gen.psp_al[OF retype_region_proofs_assms'],
         simplified]

lemmas retype_region_valid_idle = use_retype_region_proofs
  [where Q=valid_idle,
         OF retype_region_proofs.valid_idle,
         simplified]

lemmas retype_region_valid_arch = use_retype_region_proofs
  [where Q=valid_arch_state,
         OF retype_region_proofs_invs.valid_arch_state[OF retype_region_proofs_assms],
         simplified]

lemmas retype_region_valid_globals = use_retype_region_proofs
  [where Q=valid_global_refs,
         OF retype_region_proofs_invs.valid_global_refs[OF retype_region_proofs_assms],
         simplified]

lemmas retype_region_valid_reply_caps = use_retype_region_proofs
  [where Q=valid_reply_caps,
         OF retype_region_proofs.valid_reply_caps,
         simplified]

lemmas retype_region_valid_reply_masters = use_retype_region_proofs
  [where Q=valid_reply_masters,
         OF retype_region_proofs.valid_reply_masters,
         simplified]

lemmas retype_region_arch_objs = use_retype_region_proofs
  [where Q=valid_arch_objs,
         OF retype_region_proofs_invs.valid_arch_objs'[OF retype_region_proofs_assms],
         simplified]

crunch irq_node[wp]: retype_region "\<lambda>s. P (interrupt_irq_node s)"
  (simp: crunch_simps)

crunch interrupt_states[wp]: retype_region "\<lambda>s. P (interrupt_states s)"
  (simp: crunch_simps)

lemma invs_trans_state[simp]:
  "invs (trans_state f s) = invs s"
  apply (simp add: invs_def valid_state_def)
  done

lemma post_retype_invs_trans_state[simp]:
  "post_retype_invs ty refs (trans_state f s) = post_retype_invs ty refs s"
  apply (simp add: post_retype_invs_def')
  apply (simp add: trans_state_update[symmetric] del: trans_state_update)
  done

lemma retype_region_post_retype_invs:
  "\<lbrace>(invs::'state_ext state \<Rightarrow> bool) and caps_no_overlap ptr sz and pspace_no_overlap_range_cover ptr sz
      and caps_overlap_reserved {ptr..ptr + of_nat n * 2 ^ obj_bits_api ty us - 1}
      and region_in_kernel_window {ptr .. (ptr && ~~ mask sz) + 2 ^ sz - 1}
      and (\<lambda>s. \<exists>slot. cte_wp_at (\<lambda>c.  {ptr..(ptr && ~~ mask sz) + (2 ^ sz - 1)} \<subseteq> cap_range c \<and> cap_is_device c = dev) slot s)
      and K (ty = Structures_A.CapTableObject \<longrightarrow> 0 < us)
      and K (range_cover ptr sz (obj_bits_api ty us) n) \<rbrace>
      retype_region ptr n us ty dev\<lbrace>\<lambda>rv. post_retype_invs ty rv\<rbrace>"
  apply (rule hoare_gen_asm)+
  apply (rule hoare_pre,
         rule use_retype_region_proofs'[where sz = sz
      and P="invs and region_in_kernel_window {ptr .. (ptr &&~~ mask sz) + 2 ^ sz - 1}"])
      apply (rule retype_region_proofs_invs.post_retype_invs
                  [OF retype_region_proofs_assms], simp+)
   apply (simp add: invs_post_retype_invs)
  apply (clarsimp simp:invs_def valid_state_def)
  done

lemma subset_not_le_trans: "\<lbrakk>\<not> A \<subset> B; C \<subseteq> B\<rbrakk> \<Longrightarrow> \<not> A \<subset> C" by auto

lemma cte_wp_at_trans_state[simp]: "cte_wp_at P ptr (kheap_update f (trans_state f' s)) =
       cte_wp_at P ptr (kheap_update f s)"
  by (simp add: trans_state_update[symmetric] del: trans_state_update)

lemma retype_region_cte_at_other:
  assumes cover: "range_cover ptr' sz (obj_bits_api ty us) n"
  shows "\<lbrace>\<lambda>s. pspace_no_overlap_range_cover ptr' sz s \<and> cte_wp_at P ptr s \<and> valid_pspace s\<rbrace>
  retype_region ptr' n us ty dev \<lbrace>\<lambda>r. cte_wp_at P ptr\<rbrace>"
  unfolding retype_region_def
  apply (simp only: foldr_upd_app_if fun_app_def K_bind_def)
  apply wp
      apply (simp only: cte_wp_at_trans_state)
      apply wp+
  apply (subst retype_addrs_fold)
  apply clarsimp
  apply (clarsimp simp: cte_wp_at_cases del: disjCI)
  apply (erule disjEI)
   apply (auto dest!: pspace_no_overlapD1[OF _ _ cover])
done

lemma retype_cte_wp_at:
  "\<lbrace>\<lambda>s. cte_wp_at P ptr s \<and> pspace_no_overlap_range_cover ptr' sz s \<and>
       valid_pspace s \<and> range_cover ptr' sz (obj_bits_api ty us) n\<rbrace>
  retype_region ptr' n us ty dev
  \<lbrace>\<lambda>r. cte_wp_at P ptr\<rbrace>"
  apply (rule hoare_assume_pre)
  apply (rule hoare_pre)
   apply (rule retype_region_cte_at_other)
   apply fastforce
  apply simp
  done

lemma pspace_no_overlap_typ_at_def:
  "pspace_no_overlap S =
  (\<lambda>s. \<forall>T x. typ_at T x s \<longrightarrow> {x..x + (2 ^ obj_bits_type T - 1)} \<inter> S = {})"
  apply (simp add: pspace_no_overlap_def obj_at_def)
  apply (rule ext)
  apply (auto simp: obj_bits_T)
  done

lemma pspace_no_overlap_typ_at_lift:
  assumes f: "\<And>P T p. \<lbrace>\<lambda>s. P (typ_at T p s)\<rbrace> f \<lbrace>\<lambda>rv s. P (typ_at T p s)\<rbrace>"
  shows "\<lbrace>pspace_no_overlap S\<rbrace> f \<lbrace>\<lambda>rv. pspace_no_overlap S\<rbrace>"
  apply (clarsimp simp: pspace_no_overlap_typ_at_def)
  apply (wp hoare_vcg_all_lift f)
  done

lemma swp_clearMemoryVM [simp]:
  "swp clearMemoryVM x = (\<lambda>_. return ())"
  by (rule ext,simp)

(* FIXME: move *)
lemma bind_assoc_reverse:
  "(do x \<leftarrow> A; _ \<leftarrow> B x; C x od) =
   (do x \<leftarrow> do x \<leftarrow> A; _ \<leftarrow> B x; return x od; C x od)"
by (simp only: bind_assoc return_bind)

(* FIXME: move *)
lemmas do_machine_op_bind =
    submonad_bind [OF submonad_do_machine_op submonad_do_machine_op
                      submonad_do_machine_op]

(* FIXME: move *)
lemmas do_machine_op_return =
    submonad_do_machine_op.return

lemma ioc_more_swap[simp]: "
    s'\<lparr>exst := sa',
         is_original_cap := sa\<rparr> =
    s'\<lparr>is_original_cap := sa,
         exst := sa'\<rparr>"
  apply simp
  done

lemma is_final_cap'_more_update[simp]:
  "is_final_cap' cap (trans_state f s) = is_final_cap' cap s"
  by (simp add: is_final_cap'_def)

lemma no_cap_to_obj_with_diff_ref_more_update[simp]:
  "no_cap_to_obj_with_diff_ref cap sl (trans_state f s) =
   no_cap_to_obj_with_diff_ref cap sl s"
  by (simp add: no_cap_to_obj_with_diff_ref_def)

end

(* FIXME: irq_state stuff moved from CNodeInv_AI, not clear it makes sense here. *)

lemma cte_wp_at_irq_state_independent[intro!, simp]:
  "is_final_cap' x (s\<lparr>machine_state := machine_state s\<lparr>irq_state := f (irq_state (machine_state s))\<rparr>\<rparr>)
   = is_final_cap' x s"
  by (simp add: is_final_cap'_def)

lemma zombies_final_irq_state_independent[intro!, simp]:
  "zombies_final (s\<lparr>machine_state := machine_state s\<lparr>irq_state := f (irq_state (machine_state s))\<rparr>\<rparr>)
   = zombies_final s"
  by (simp add: zombies_final_def)

lemma ex_cte_cap_wp_to_irq_state_independent[intro!, simp]:
  "ex_cte_cap_wp_to x y (s\<lparr>machine_state := machine_state s\<lparr>irq_state := f (irq_state (machine_state s))\<rparr>\<rparr>)
   = ex_cte_cap_wp_to x y s"
  by (simp add: ex_cte_cap_wp_to_def)

end


(******************************************************************************
 * Orca: A Functional Correctness Verifier for Imperative Programs
 *       Based on Isabelle/UTP
 *
 * Copyright (c) 2016-2018 Virginia Tech, USA
 *               2016-2018 Technische Universität München, Germany
 *               2016-2018 University of York, UK
 *               2016-2018 Université Paris-Saclay, Univ. Paris-Sud, France
 *
 * This software may be distributed and modified according to the terms of
 * the GNU Lesser General Public License version 3.0 or any later version.
 * Note that NO WARRANTY is provided.
 *
 * See CONTRIBUTORS, LICENSE and CITATION files for details.
 ******************************************************************************)

subsection {* Relational Hoare calculus *}

theory utp_hoare_rel_helper
imports utp_hoare_rel_total
begin
named_theorems utp_hoare_hp

subsection {*Try Catch Laws*}

text{*In this section we introduce the algebraic laws of programming related to the assignment
      statement.*}

lemma try_catch_unfold_hoare: (*because seq is assoc*)
  "\<lbrace>p\<rbrace>try  R ;; P catch  Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R =
   \<lbrace>p\<rbrace>R ;; try  P catch Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
   apply pred_simp
   apply rel_simp
   apply auto
   apply smt+
done

lemma try_catch_abr_fold_hoare[utp_hoare_hp]: (*because seq is assoc*)
  "\<lbrace>p\<rbrace>R ;; try  P catch Q end \<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R =
   \<lbrace>p\<rbrace>try  R ;; P catch  Q end \<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
   apply pred_simp
   apply rel_simp
   apply auto
   apply smt+
done

lemma try_catch_abr_throw_abr_hoare [utp_hoare_hp]:
  "\<lbrace>p\<rbrace> try THROW\<^sub>A\<^sub>B\<^sub>R  catch Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R =
   \<lbrace>p\<rbrace> Q \<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
   apply pred_simp
   apply rel_simp
   apply auto
   apply smt+
done

lemma try_catch_abr_skip_abr_hoare [utp_hoare_hp]:
  "\<lbrace>p\<rbrace>try  SKIP\<^sub>A\<^sub>B\<^sub>R catch Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R =
   \<lbrace>p\<rbrace>SKIP\<^sub>A\<^sub>B\<^sub>R\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
   apply pred_simp
   apply rel_simp
   apply auto
   apply smt
done

lemma try_catch_abr_assigns_abr_hoare [utp_hoare_hp]:
  "\<lbrace>p\<rbrace>try   \<langle>\<sigma>\<rangle>\<^sub>A\<^sub>B\<^sub>R catch Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R = \<lbrace>p\<rbrace> \<langle>\<sigma>\<rangle>\<^sub>A\<^sub>B\<^sub>R\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
   apply pred_simp
   apply rel_simp
   apply auto
   apply smt+
done

subsection {*Examples*}

lemma
  "\<lbrace>p\<rbrace> try THROW\<^sub>A\<^sub>B\<^sub>R ;; SKIP\<^sub>A\<^sub>B\<^sub>R catch Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R = \<lbrace>p\<rbrace>Q\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
   by (simp only: utp_hoare_hp  uabr_comp)

lemma
  "\<lbrace>p\<rbrace>THROW\<^sub>A\<^sub>B\<^sub>R ;; try \<langle>\<sigma>\<rangle>\<^sub>A\<^sub>B\<^sub>R catch Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R =
   \<lbrace>p\<rbrace>Q \<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
  by (simp only: utp_hoare_hp  uabr_comp)

lemma
  "\<lbrace>p\<rbrace>THROW\<^sub>A\<^sub>B\<^sub>R ;; try Simpl\<^sub>A\<^sub>B\<^sub>R P catch Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R = \<lbrace>p\<rbrace>Q\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
  by (simp only: utp_hoare_hp  uabr_comp)

lemma
  "\<lbrace>p\<rbrace> try THROW\<^sub>A\<^sub>B\<^sub>R;; Simpl\<^sub>A\<^sub>B\<^sub>R P catch Simpl\<^sub>A\<^sub>B\<^sub>R Q end\<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R =
   \<lbrace>p\<rbrace>Simpl\<^sub>A\<^sub>B\<^sub>R Q \<lbrace>q\<rbrace>\<^sub>A\<^sub>B\<^sub>R"
   by (simp only: utp_hoare_hp  uabr_comp)

end