(*
 * Copyright 2014, NICTA
 *
 * 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(NICTA_GPL)
 *)

(*
 * The layout of the capability space and other parts of the system-initialiser.
 *)
theory RootTask_SI
imports WellFormed_SI
begin

(******************************************************************
 * Definition of the CSpace of the root task.                     *
 * This requires a default cap to all of the objects created,     *
 * and a copy of caps to all of the CNodes (for installing caps). *
 ******************************************************************)

consts
  si_cnode_id      :: cdl_object_id
  si_asidpool_id   :: cdl_object_id
  si_asidpool_base :: nat

definition
  si_cnode_size :: cdl_size_bits
where
  "si_cnode_size = 12"

(* If we axioimise this size, we need it to be smaller than the word size.
 * We need this to prove that:
   - word_bits - si_cnode_size + si_cnode_size = word_bits.
   - offset (of_nat slot) si_cnode_size = slot
 *)
lemma si_cnode_size_less_than_word_size [simp]:
  "si_cnode_size < word_bits"
  by (clarsimp simp: si_cnode_size_def word_bits_def)

lemma si_cnode_size_less_than_eq_word_size [simp]:
  "si_cnode_size \<le> word_bits"
  by (rule less_imp_le_nat, simp)

lemma si_cnode_size_greater_than_1 [simp]:
  "1 < si_cnode_size"
  by (clarsimp simp: si_cnode_size_def)

lemma si_cnode_size_greater_than_2 [simp]:
  "2 < si_cnode_size"
  by (clarsimp simp: si_cnode_size_def)

lemma unat_less_2_si_cnode_size:
  "unat (cptr::32 word) < 2 ^ si_cnode_size
  \<Longrightarrow> cptr < 2 ^ si_cnode_size"
  by (metis si_cnode_size_less_than_word_size unat_power_lower32 word_less_nat_alt)

lemma unat_less_2_si_cnode_size':
  "(cptr::32 word) < 2 ^ si_cnode_size
  \<Longrightarrow> unat cptr < 2 ^ si_cnode_size"
  by (metis unat_less_helper word_unat_power)

(* This is stored in the root TCB. *)
definition
  si_cspace_cap :: cdl_cap
where
  "si_cspace_cap = CNodeCap si_cnode_id 0 (word_bits - si_cnode_size) si_cnode_size"

(* This is the cap the root TCB has to its own root cnode (stored in its root CNode). *)
definition
  si_cnode_cap :: cdl_cap
where
  "si_cnode_cap = CNodeCap si_cnode_id 0 (word_bits - si_cnode_size) si_cnode_size"

definition
  root_tcb :: cdl_object
where
  "root_tcb = update_slots [tcb_cspace_slot \<mapsto> si_cspace_cap,
                            tcb_vspace_slot \<mapsto> undefined,
                            tcb_replycap_slot \<mapsto> undefined,
                            tcb_caller_slot \<mapsto> undefined,
                            tcb_ipcbuffer_slot \<mapsto> undefined,
                            tcb_pending_op_slot \<mapsto> undefined] (Tcb (default_tcb minBound))"

definition
  empty_asid :: cdl_asid_pool
where
  "empty_asid = \<lparr>cdl_asid_pool_caps = empty_cap_map asid_low_bits\<rparr>"

definition
  si_asid :: "sep_state \<Rightarrow> bool"
where
  "si_asid \<equiv>
  (si_cnode_id, unat seL4_CapInitThreadASIDPool) \<mapsto>c AsidPoolCap si_asidpool_id si_asidpool_base \<and>*
    si_asidpool_id \<mapsto>f AsidPool empty_asid \<and>*
   (\<And>* offset\<in>{offset. offset < 2 ^ asid_low_bits}.
               (si_asidpool_id, offset) \<mapsto>c -)"

abbreviation "si_tcb_id \<equiv> root_tcb_id"

definition si_objects :: "sep_state \<Rightarrow> bool"
where
  "si_objects \<equiv>
   si_tcb_id \<mapsto>f root_tcb \<and>*
   si_cnode_id \<mapsto>f CNode (empty_cnode si_cnode_size) \<and>*
  (si_tcb_id, tcb_cspace_slot) \<mapsto>c si_cspace_cap \<and>*
  (si_tcb_id, tcb_pending_op_slot) \<mapsto>c RunningCap \<and>*
  (si_cnode_id, unat seL4_CapInitThreadCNode) \<mapsto>c si_cnode_cap \<and>*
  (si_cnode_id, unat seL4_CapIRQControl) \<mapsto>c IrqControlCap \<and>*
   si_asid"

definition
  si_objects_extra_caps' :: "cdl_object_id set \<Rightarrow> cdl_cptr list \<Rightarrow> cdl_cptr list \<Rightarrow> sep_state \<Rightarrow> bool"
where
  "si_objects_extra_caps' obj_ids free_cptrs untyped_cptrs \<equiv> \<lambda>s.
   \<exists>untyped_caps all_available_ids.
    ((\<And>* (cptr, cap) \<in> set (zip untyped_cptrs untyped_caps). (si_cnode_id, unat cptr) \<mapsto>c cap) \<and>*
     (\<And>* cptr \<in> set (drop (card obj_ids) free_cptrs). (si_cnode_id, unat cptr) \<mapsto>c NullCap) \<and>*
     (\<And>* obj_id\<in>all_available_ids. obj_id \<mapsto>o Untyped)) s"

definition
  si_objects_extra_caps :: "cdl_object_id set \<Rightarrow> cdl_cptr list \<Rightarrow> cdl_cptr list
                          \<Rightarrow> cdl_state \<Rightarrow> sep_state \<Rightarrow> bool"
where
  "si_objects_extra_caps obj_ids free_cptrs untyped_cptrs spec \<equiv> \<lambda>s.
   \<exists>untyped_caps all_available_ids.
    ((\<And>* (cptr, cap) \<in> set (zip untyped_cptrs untyped_caps). (si_cnode_id, unat cptr) \<mapsto>c cap) \<and>*
     (\<And>* cptr \<in> set (drop (card obj_ids + card {obj_id \<in> obj_ids. cnode_or_tcb_at obj_id spec}) free_cptrs).
         (si_cnode_id, unat cptr) \<mapsto>c NullCap) \<and>*
     (\<And>* obj_id\<in>all_available_ids. obj_id \<mapsto>o Untyped)) s"


lemma distinct_take_drop_append:
  "distinct xs \<Longrightarrow> set (take b (drop a xs)) \<inter> set (drop (a + b) xs) = {}"
  by (metis distinct_append distinct_drop take_drop_append)

lemma si_objects_extra_caps'_si_objects_extra_caps:
  "distinct free_slots \<Longrightarrow>
     si_objects_extra_caps' obj_ids free_slots untyped_cptrs =
    (si_objects_extra_caps obj_ids free_slots untyped_cptrs spec \<and>*
    (\<And>* cptr \<in> set (take (card {obj_id \<in> obj_ids. cnode_or_tcb_at obj_id spec})
                       (drop (card obj_ids) free_slots)).
           (si_cnode_id, unat cptr) \<mapsto>c NullCap))"
  apply (rule ext)
  apply (clarsimp simp: si_objects_extra_caps'_def si_objects_extra_caps_def sep_conj_exists)
  apply (rule ex_eqI)+
  apply (subst take_drop_append [where a="card obj_ids" and
               b="card {obj_id \<in> obj_ids. cnode_or_tcb_at obj_id spec}"])
  apply clarsimp
  apply (subst sep.prod.union_disjoint, (simp add: distinct_take_drop_append)+)+
  apply (clarsimp simp: sep_conj_ac)
  done

definition
  si_irq_nodes :: "cdl_state \<Rightarrow> sep_state \<Rightarrow> bool"
where
  "si_irq_nodes spec \<equiv>
     (\<lambda>s. \<exists>k_irq_table. (\<And>* irq\<in>used_irqs spec. irq \<mapsto>irq k_irq_table irq \<and>*
                                                 k_irq_table irq \<mapsto>o IRQNode empty_irq_node) s)"


(***************************************
 * Lemmas about the root task objects. *
 ***************************************)

lemma is_cnode_cap_si_cspace_cap [simp]:
  "is_cnode_cap si_cspace_cap"
  by (clarsimp simp: si_cspace_cap_def)

lemma is_cnode_cap_si_cnode_cap [simp]:
  "is_cnode_cap si_cnode_cap"
  by (clarsimp simp: si_cnode_cap_def)

lemma is_tcb_root_tcb [simp]:
  "is_tcb root_tcb"
  by (clarsimp simp: root_tcb_def)

lemma cap_guard_size_si_cnode_cap_plus_si_cnode_size [simp]:
  "cap_guard_size si_cnode_cap + si_cnode_size = word_bits"
  by (clarsimp simp: si_cnode_cap_def)

lemma cap_object_si_cspace_cap [simp]:
  "cap_object si_cspace_cap = si_cnode_id"
  by (clarsimp simp: cap_object_def cap_has_object_def si_cspace_cap_def)

lemma cap_object_si_cnode_cap [simp]:
  "cap_object si_cnode_cap = si_cnode_id"
  by (clarsimp simp: cap_object_def cap_has_object_def si_cnode_cap_def)


lemma offset_slot_si_cnode_size:
  "slot < 2^si_cnode_size \<Longrightarrow> offset (of_nat slot) si_cnode_size = slot"
  by (clarsimp simp: offset_slot)

lemma offset_slot_si_cnode_size':
  "slot < 2^si_cnode_size \<Longrightarrow> offset slot si_cnode_size = unat slot"
  by (clarsimp simp: offset_slot')

lemma guard_equal_si_cspace_cap:
  "src_index < 2 ^ si_cnode_size \<Longrightarrow> guard_equal si_cspace_cap src_index 32"
  apply (clarsimp simp: si_cspace_cap_def guard_equal_def Let_unfold)
  apply (subst and_mask_eq_iff_shiftr_0 [THEN iffD1])
   apply (clarsimp simp: word_bits_def)
   apply (erule less_mask_eq)
  apply (clarsimp simp: mask_def)
  done

lemma guard_equal_si_cspace_cap':
  "src_index < 2 ^ si_cnode_size \<Longrightarrow> guard_equal si_cspace_cap src_index word_bits"
  by (drule guard_equal_si_cspace_cap, simp add: word_bits_def)

lemma guard_equal_si_cnode_cap:
  "src_index < 2 ^ si_cnode_size \<Longrightarrow> guard_equal si_cnode_cap src_index 32"
  apply (clarsimp simp: si_cnode_cap_def guard_equal_def Let_unfold)
  apply (subst and_mask_eq_iff_shiftr_0 [THEN iffD1])
   apply (clarsimp simp: word_bits_def)
   apply (erule less_mask_eq)
  apply (clarsimp simp: mask_def)
  done

lemma seL4_CapInitThreadASIDPool_si_cnode_size [simp]:
  "seL4_CapInitThreadASIDPool < 2 ^ si_cnode_size"
  by (clarsimp simp: seL4_CapInitThreadASIDPool_def si_cnode_size_def)

lemma guard_equal_si_cspace_cap_seL4_CapInitThreadASIDPool [simp]:
  "guard_equal si_cspace_cap seL4_CapInitThreadASIDPool word_bits"
  by (rule guard_equal_si_cspace_cap', simp)

lemma si_cspace_cap_guard_equal:
  "guard_equal si_cnode_cap src_index 32 \<Longrightarrow> src_index < 2 ^ si_cnode_size"
  apply (clarsimp simp: si_cnode_cap_def guard_equal_def
                        Let_unfold si_cnode_size_def)
  apply (subst (asm) shiftr_mask_eq')
   apply (simp add: word_bits_size word_bits_def)
  apply (subst (asm) le_mask_iff [symmetric])
  apply (clarsimp simp: mask_def)
  apply (insert word32_less_sub_le [where x=src_index and n=12])
  apply (clarsimp simp: word_bits_def)
  done

lemma one_lvl_lookup_si_cspace_cap [simp]:
  "one_lvl_lookup si_cspace_cap word_bits si_cnode_size"
  by (clarsimp simp: one_lvl_lookup_def si_cspace_cap_def)

lemmas one_lvl_lookup_si_cspace_cap' [simp] =
       one_lvl_lookup_si_cspace_cap [simplified word_bits_def, simplified]

lemma one_lvl_lookup_si_cnode_cap [simp]:
  "one_lvl_lookup si_cnode_cap word_bits si_cnode_size"
  by (clarsimp simp: one_lvl_lookup_def si_cnode_cap_def)

lemmas one_lvl_lookup_si_cnode_cap' [simp] =
       one_lvl_lookup_si_cnode_cap [simplified word_bits_def, simplified]

lemma obj_tcb_root_tcb [simp]:
  "Tcb (obj_tcb root_tcb) = root_tcb"
  by (clarsimp simp: obj_tcb_def root_tcb_def update_slots_def)

(***************************
 * Lemmas about word size. *
 ***************************)
lemma seL4_CapInitThreadCNode_less_than_si_cnode_size [simp]:
  "seL4_CapInitThreadCNode < 2 ^ si_cnode_size"
  apply (insert si_cnode_size_greater_than_1)
  apply (insert power_strict_increasing [where n=1 and a="(2::nat)" and N=si_cnode_size, simplified])
  apply (clarsimp)
  apply (drule  of_nat_less_pow_32)
   apply (clarsimp simp: seL4_CapInitThreadCNode_def)+
  done

lemma offset_seL4_CapInitThreadCNode [simp]:
  "offset seL4_CapInitThreadCNode si_cnode_size = unat seL4_CapInitThreadCNode"
  by (rule offset_slot', simp)

lemma seL4_CapIRQControl_less_than_si_cnode_size [simp]:
  "seL4_CapIRQControl < 2 ^ si_cnode_size"
  apply (simp add: seL4_CapIRQControl_def)
  apply (insert si_cnode_size_greater_than_2)
  apply (insert power_strict_increasing [where n=2 and a="(2::nat)" and N=si_cnode_size, simplified])
  apply (drule  of_nat_less_pow_32, simp_all)
  done

lemma offset_seL4_CapIRQControl [simp]:
  "offset seL4_CapIRQControl si_cnode_size = unat seL4_CapIRQControl"
  by (rule offset_slot', simp)

(* There is a cap in the root cnode that points to the obj_id specified.
 * This cap should be the default cap to that object.
 *
 * This predicate can be used for spec objects, or the duplicated cnode caps.
 *)
definition si_cap_at :: "(cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                           (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow> bool \<Rightarrow>
                            cdl_object_id \<Rightarrow> sep_pred"
where
  "si_cap_at t si_caps spec dev obj_id \<equiv> \<lambda>s.
    \<exists>cap_ptr slot obj kobj_id.
     ((si_cnode_id, slot) \<mapsto>c default_cap (object_type obj) {kobj_id} (object_size_bits obj) dev) s \<and>
     si_caps obj_id = Some cap_ptr \<and>
     unat cap_ptr = slot \<and>
     cap_ptr < 2 ^ si_cnode_size \<and>
     cdl_objects spec obj_id = Some obj \<and>
     t obj_id = Some kobj_id"

definition si_irq_cap_at :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                cdl_irq \<Rightarrow> sep_pred"
where
  "si_irq_cap_at si_irq_caps spec irq \<equiv> \<lambda>s.
    \<exists>cap_ptr slot.
     ((si_cnode_id, slot) \<mapsto>c IrqHandlerCap irq) s \<and>
     si_irq_caps irq = Some cap_ptr \<and>
     unat cap_ptr = slot \<and>
     cap_ptr < 2 ^ si_cnode_size"

definition si_caps_at :: "(cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                           (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow> bool \<Rightarrow>
                            cdl_object_id set \<Rightarrow> sep_pred"
where
  "si_caps_at t si_caps spec dev obj_ids \<equiv>
  \<And>* obj_id \<in> obj_ids. (si_cap_at t si_caps spec) dev obj_id"

definition si_irq_caps_at :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                cdl_irq set \<Rightarrow> sep_pred"
where
  "si_irq_caps_at si_irq_caps spec irqs \<equiv>
  \<And>* irq \<in> irqs. si_irq_cap_at si_irq_caps spec irq"

definition
  si_obj_cap_at' :: " (cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                        (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow> bool \<Rightarrow>
                         cdl_object_id \<Rightarrow> cdl_cnode_index \<Rightarrow> sep_pred"
where
  "si_obj_cap_at' t si_caps spec dev obj_id slot \<equiv> \<lambda>s. \<exists> spec_cap.
   si_cap_at t si_caps spec dev (cap_object spec_cap) s \<and>
   opt_cap (obj_id, slot) spec = Some spec_cap"

definition si_obj_cap_at where
  "si_obj_cap_at t si_caps spec dev obj_id slot \<equiv>
     if original_cap_at (obj_id, slot) spec \<and> cap_at cap_has_object (obj_id, slot) spec
     then si_obj_cap_at' t si_caps spec dev obj_id slot
     else \<box>"

definition
  si_obj_caps_at :: "(cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                            (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow> bool \<Rightarrow>
                             cdl_object_id \<Rightarrow> sep_pred"
where
  "si_obj_caps_at t si_caps spec dev obj_id \<equiv>
   \<And>* slot \<in> dom (slots_of obj_id spec). si_obj_cap_at t si_caps spec dev obj_id slot"

definition
  si_objs_caps_at :: "(cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                             (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow> bool \<Rightarrow>
                              cdl_object_id set \<Rightarrow> sep_pred"
where
  "si_objs_caps_at t si_caps spec dev obj_ids \<equiv>
   \<And>* obj_id \<in> obj_ids. (si_obj_caps_at t si_caps spec) dev obj_id"

definition
  si_spec_irq_cap_at' :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                             cdl_object_id \<Rightarrow> cdl_cnode_index \<Rightarrow> sep_pred"
where
  "si_spec_irq_cap_at' si_irq_caps spec obj_id slot \<equiv> \<lambda>s. \<exists> spec_cap.
   si_irq_cap_at si_irq_caps spec (cap_irq spec_cap) s \<and>
   opt_cap (obj_id, slot) spec = Some spec_cap"

definition si_spec_irq_cap_at where
  "si_spec_irq_cap_at si_irq_caps spec obj_id slot \<equiv>
     if irqhandler_cap_at (obj_id, slot) spec
     then si_spec_irq_cap_at' si_irq_caps spec obj_id slot
     else \<box>"

definition
  si_spec_irq_caps_at :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                             cdl_object_id \<Rightarrow> sep_pred"
where
  "si_spec_irq_caps_at si_irq_caps spec obj_id \<equiv>
   \<And>* slot \<in> dom (slots_of obj_id spec). si_spec_irq_cap_at si_irq_caps spec obj_id slot"

definition
  si_spec_irqs_caps_at :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                              cdl_object_id set \<Rightarrow> sep_pred"
where
  "si_spec_irqs_caps_at si_irq_caps spec obj_ids \<equiv>
   \<And>* obj_id \<in> obj_ids. si_spec_irq_caps_at si_irq_caps spec obj_id"

definition
  "si_null_cap_at t si_irq_caps spec obj_id \<equiv>
    \<lambda>s. \<exists>cap_ptr slot obj kobj_id.
       ((si_cnode_id, slot) \<mapsto>c NullCap) s \<and>
       si_irq_caps obj_id = Some cap_ptr \<and>
       unat cap_ptr = slot \<and>
       cap_ptr < 2 ^ si_cnode_size \<and>
       cdl_objects spec obj_id = Some obj \<and> t obj_id = Some kobj_id"

definition
  "si_null_irq_cap_at si_irq_caps spec irq \<equiv>
    \<lambda>s. \<exists>cap_ptr slot.
       ((si_cnode_id, slot) \<mapsto>c NullCap) s \<and>
       si_irq_caps irq = Some cap_ptr \<and>
       unat cap_ptr = slot \<and>
       cap_ptr < 2 ^ si_cnode_size"

definition
  si_spec_obj_null_cap_at' :: " (cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                                  (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                   cdl_object_id \<Rightarrow> cdl_cnode_index \<Rightarrow> sep_pred"
where
  "si_spec_obj_null_cap_at' t si_irq_caps spec obj_id slot \<equiv> \<lambda>s. \<exists> spec_cap.
   si_null_cap_at t si_irq_caps spec (cap_object spec_cap) s \<and>
   opt_cap (obj_id, slot) spec = Some spec_cap"

definition si_spec_obj_null_cap_at where
  "si_spec_obj_null_cap_at t si_irq_caps spec obj_id slot \<equiv>
     if original_cap_at (obj_id, slot) spec \<and> cap_at cap_has_object (obj_id, slot) spec
     then si_spec_obj_null_cap_at' t si_irq_caps spec obj_id slot
     else \<box>"

definition
  si_spec_obj_null_caps_at :: "(cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                                 (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                  cdl_object_id \<Rightarrow> sep_pred"
where
  "si_spec_obj_null_caps_at t si_irq_caps spec obj_id \<equiv>
   \<And>* slot \<in> dom (slots_of obj_id spec). si_spec_obj_null_cap_at t si_irq_caps spec obj_id slot"

definition
  si_spec_objs_null_caps_at :: "(cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                                  (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                   cdl_object_id set \<Rightarrow> sep_pred"
where
  "si_spec_objs_null_caps_at t si_irq_caps spec obj_ids \<equiv>
   \<And>* obj_id \<in> obj_ids. si_spec_obj_null_caps_at t si_irq_caps spec obj_id"

definition
  si_spec_irq_null_cap_at' :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                  cdl_object_id \<Rightarrow> cdl_cnode_index \<Rightarrow> sep_pred"
where
  "si_spec_irq_null_cap_at' si_irq_caps spec obj_id slot \<equiv> \<lambda>s. \<exists> spec_cap.
   si_null_irq_cap_at si_irq_caps spec (cap_irq spec_cap) s \<and>
   opt_cap (obj_id, slot) spec = Some spec_cap \<and> \<not>is_untyped_cap spec_cap"

definition si_spec_irq_null_cap_at where
  "si_spec_irq_null_cap_at si_irq_caps spec obj_id slot \<equiv>
     if irqhandler_cap_at (obj_id, slot) spec
     then si_spec_irq_null_cap_at' si_irq_caps spec obj_id slot
     else \<box>"

definition
  si_spec_irq_null_caps_at :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                  cdl_object_id \<Rightarrow> sep_pred"
where
  "si_spec_irq_null_caps_at si_irq_caps spec obj_id \<equiv>
   \<And>* slot \<in> dom (slots_of obj_id spec). si_spec_irq_null_cap_at si_irq_caps spec obj_id slot"

definition
  si_spec_irqs_null_caps_at :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                   cdl_object_id set \<Rightarrow> sep_pred"
where
  "si_spec_irqs_null_caps_at si_irq_caps spec obj_ids \<equiv>
   \<And>* obj_id \<in> obj_ids. si_spec_irq_null_caps_at si_irq_caps spec obj_id"

definition si_null_caps_at :: "(cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow>
                           (cdl_object_id \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                            cdl_object_id set \<Rightarrow> sep_pred"
where
  "si_null_caps_at t si_caps spec obj_ids \<equiv>
  \<And>* obj_id \<in> obj_ids. si_null_cap_at t si_caps spec obj_id"


lemma si_cap_at_less_si_cnode_size:
  "\<lbrakk>\<guillemotleft>si_cap_at t opt_sel4_cap spec dev obj_id \<and>* R\<guillemotright> s;
    Some cap_ptr = opt_sel4_cap obj_id\<rbrakk>
  \<Longrightarrow> cap_ptr < 2 ^ si_cnode_size"
  by (clarsimp simp: si_cap_at_def sep_conj_exists)

lemma si_irq_cap_at_less_si_cnode_size:
  "\<lbrakk>\<guillemotleft>si_irq_cap_at opt_sel4_cap spec obj_id \<and>* R\<guillemotright> s;
    Some cap_ptr = opt_sel4_cap obj_id\<rbrakk>
  \<Longrightarrow> cap_ptr < 2 ^ si_cnode_size"
  by (clarsimp simp: si_irq_cap_at_def sep_conj_exists)

lemma si_cap_at_has_k_obj_id:
  "\<lbrakk>\<guillemotleft>si_cap_at t opt_sel4_cap spec dev obj_id \<and>* R\<guillemotright> s\<rbrakk>
  \<Longrightarrow> \<exists>cap_object_id. t obj_id = Some cap_object_id"
  by (clarsimp simp: si_cap_at_def sep_conj_exists)

(******************************************************
 * Using just si_cap_at when you have si_caps_at. *
 ******************************************************)

lemma valid_si_caps_at_si_cap_at:
  "\<lbrakk>finite obj_ids; obj_id \<in> obj_ids;
   (\<And>R. \<lbrace>\<guillemotleft>si_cap_at t orig_caps spec dev obj_id \<and>* P \<and>* R\<guillemotright>\<rbrace>
   f
   \<lbrace>\<lambda>_.\<guillemotleft>si_cap_at t orig_caps spec dev obj_id \<and>* Q \<and>* R\<guillemotright>\<rbrace>)\<rbrakk>
   \<Longrightarrow>
   \<lbrace>\<guillemotleft>si_caps_at t orig_caps spec dev obj_ids \<and>* P \<and>* R\<guillemotright>\<rbrace>
   f
   \<lbrace>\<lambda>_.\<guillemotleft>si_caps_at t orig_caps spec dev obj_ids \<and>* Q \<and>* R\<guillemotright>\<rbrace>"
  apply (clarsimp simp: si_caps_at_def)
  apply (drule sep_set_conj_map_singleton_wp [where f=f and
                   I="si_cap_at t orig_caps spec dev" and  P=P and Q=Q and R=R, rotated])
    apply (clarsimp simp: sep_conj_ac)+
  done

(**********************************************************
 * The pre and post conditions of the system initialiser. *
 **********************************************************)

(* That the boot info is valid, and that there are enough free slots to initialise a system. *)
definition
  valid_boot_info
where
  "valid_boot_info bootinfo spec \<equiv> \<lambda>s.
  \<exists>untyped_caps fstart fend ustart uend.
  ((\<And>*(cptr, cap) \<in> set (zip [ustart .e. uend - 1] untyped_caps). (si_cnode_id, unat cptr) \<mapsto>c cap)  \<and>*
   (\<And>* cptr \<in> set [fstart .e. fend - 1]. (si_cnode_id, unat cptr) \<mapsto>c NullCap) \<and>*
   (\<And>* obj_id\<in>(\<Union>cap\<in>set untyped_caps. cap_free_ids cap). obj_id \<mapsto>o Untyped) \<and>*
    si_objects \<and>* si_irq_nodes spec) s \<and>
   card (dom (cdl_objects spec)) +
   card {obj_id. cnode_or_tcb_at obj_id spec} \<le> unat fend - unat fstart \<and>
   length untyped_caps = unat uend - unat ustart \<and>
   distinct_sets (map cap_free_ids untyped_caps) \<and>
   list_all is_full_untyped_cap untyped_caps \<and>
   list_all well_formed_untyped_cap untyped_caps \<and>
   list_all (\<lambda>c. \<not> is_device_cap c) untyped_caps \<and>
   bi_untypes bootinfo = (ustart, uend) \<and>
   bi_free_slots bootinfo = (fstart, fend) \<and>
   ustart < 2 ^ si_cnode_size \<and>
  (uend - 1) < 2 ^ si_cnode_size \<and>
   fstart < 2 ^ si_cnode_size \<and>
  (fend - 1) < 2 ^ si_cnode_size \<and>
   uend \<noteq> 0 \<and> fend \<noteq> 0"

definition
  si_final_objects :: "cdl_state \<Rightarrow> (cdl_object_id \<Rightarrow> cdl_object_id option) \<Rightarrow> sep_pred"
where
  "si_final_objects spec t \<equiv> \<lambda>s.
   \<exists>dup_caps (untyped_cptrs::32 word list) (free_cptrs::32 word list) untyped_caps all_available_ids.
    ((\<And>*  cptr \<in> set (take (card (dom (cdl_objects spec))) free_cptrs).
          (si_cnode_id, unat cptr) \<mapsto>c NullCap) \<and>*
     (\<And>*  cptr \<in> set (drop (card (dom (cdl_objects spec)) +
                             card ({obj_id. cnode_or_tcb_at obj_id spec})) free_cptrs).
          (si_cnode_id, unat cptr) \<mapsto>c NullCap) \<and>*
     (\<And>* (cptr, untyped_cap) \<in> set (zip untyped_cptrs untyped_caps).
          (si_cnode_id, unat cptr) \<mapsto>c untyped_cap) \<and>*
     (\<And>*  obj_id \<in> all_available_ids. obj_id \<mapsto>o Untyped) \<and>*
     (\<And>*  obj_id \<in> {obj_id. cnode_or_tcb_at obj_id spec}. (si_cap_at t dup_caps spec False obj_id)) \<and>*
      si_objects) s"

(********************************************************
 * Conversion of si_objs_caps_at to si_caps_at *
 ********************************************************)

lemma orig_cap_rewrite:
  "Set.filter (\<lambda>cap_ref. original_cap_at cap_ref spec \<and> cap_at cap_has_object cap_ref spec)
               (SIGMA obj_id:{obj_id. cnode_at obj_id spec}.
                      dom (slots_of obj_id spec)) =
   {cap_ref. original_cap_at cap_ref spec \<and> object_cap_ref cap_ref spec}"
  by (auto simp: object_cap_ref_def opt_cap_def object_at_def cap_at_def real_object_at_def
          split: option.splits)

lemma slots_tcb:
  "\<lbrakk>well_formed spec; opt_cap (obj_id, slot) spec = Some cap;
    cdl_objects spec obj_id = Some obj; obj = Tcb tcb\<rbrakk> \<Longrightarrow>
   slot = 0 \<or>
   slot = 1 \<or>
   slot = 2 \<or>
   slot = 3 \<or>
   slot = 4 \<or>
   slot = 5 \<or>
   slot = 6"
  apply (frule (1) well_formed_object_slots)
  apply (drule (1) well_formed_well_formed_tcb)
  apply (clarsimp simp: well_formed_tcb_def opt_cap_def slots_of_def opt_object_def)
  apply (drule (1) dom_eqD)
  apply (clarsimp simp: object_default_state_def2 dom_object_slots_default_tcb
                        tcb_pending_op_slot_def tcb_boundntfn_slot_def)
  done

lemma object_at_dom_cdl_objects:
  "object_at P obj_id s \<Longrightarrow> obj_id \<in> dom (cdl_objects s)"
  by (clarsimp simp: object_at_def)

lemma foo:
  "\<lbrakk>well_formed spec; irq_node_at obj_id spec\<rbrakk>
  \<Longrightarrow> obj_id \<in> irq_nodes spec"
  by (metis irq_nodes_def mem_Collect_eq)

lemma well_formed_irqhandler_cap_in_cnode:
  "\<lbrakk>well_formed spec; opt_cap (obj_id, slot) spec = Some cap;
    is_irqhandler_cap cap; cdl_objects spec obj_id = Some obj\<rbrakk>
    \<Longrightarrow> is_cnode obj"
  apply (case_tac obj)
          apply (fastforce simp: opt_cap_def slots_of_def object_slots_def opt_object_def
                                 is_cnode_def object_at_def is_asidpool_def)+
        apply (frule (3) slots_tcb)
        apply (drule (1) well_formed_well_formed_tcb)
        apply (clarsimp simp: well_formed_tcb_def opt_cap_def slots_of_def opt_object_def)
        apply (erule allE [where x=slot])
        apply (simp add: tcb_slot_defs cap_type_def split: cdl_cap.splits)
       apply (fastforce simp: opt_cap_def slots_of_def object_slots_def opt_object_def
                              is_cnode_def object_at_def is_asidpool_def)
      apply (frule_tac obj_id=obj_id in well_formed_asidpool_at, simp add: object_at_def)
     apply (frule (1) well_formed_pt, simp add: object_at_def, simp+)
    apply (frule (1) well_formed_pd, simp add: object_at_def, simp+)
    apply (clarsimp simp: is_fake_pt_cap_def split: cdl_cap.splits)
   apply (fastforce simp: opt_cap_def slots_of_def object_slots_def opt_object_def
                         is_cnode_def object_at_def is_asidpool_def)+
   apply (frule (1) well_formed_well_formed_irq_node)
   apply (fastforce simp: well_formed_irq_node_def opt_cap_def slots_of_def opt_object_def
                          object_at_def irq_nodes_def is_irq_node_def)
  done

lemma well_formed_irqhandler_cap_in_cnode_at:
  "\<lbrakk>well_formed spec; opt_cap (obj_id, slot) spec = Some cap; is_irqhandler_cap cap\<rbrakk>
  \<Longrightarrow> cnode_at obj_id spec"
  apply (frule opt_cap_cdl_objects, clarsimp)
  apply (drule (3) well_formed_irqhandler_cap_in_cnode)
  apply (clarsimp simp: object_at_def)
  done

lemma irqhandler_cap_rewrite:
   "well_formed spec \<Longrightarrow>
    Set.filter (\<lambda>irq. irqhandler_cap_at irq spec)
                (SIGMA obj_id:{obj_id. cnode_at obj_id spec}.
                       dom (slots_of obj_id spec)) =
    {cap_ref. irqhandler_cap_at cap_ref spec}"
   apply (clarsimp simp: object_cap_ref_def object_at_def cap_at_def
          split: option.splits)
   apply rule
    apply clarsimp
   apply clarsimp
   apply (frule opt_cap_dom_cdl_objects)
   apply (frule opt_cap_dom_slots_of, clarsimp)
   apply (frule (3) well_formed_irqhandler_cap_in_cnode)
   apply (frule (1) well_formed_well_formed_irq_node)
   apply (clarsimp simp: well_formed_irq_node_def object_at_def
                         opt_cap_def slots_of_def opt_object_def dom_def)
   done

lemma well_formed_object_cap_real:
  "well_formed spec
  \<Longrightarrow> object_cap_ref cap_ref spec =
     (cap_at_to_real_object cap_ref spec \<and>
      cnode_at (fst cap_ref) spec)"
  apply (clarsimp simp: cap_at_def cap_at_to_real_object_def object_cap_ref_def)
  apply (rule iffI)
   apply clarsimp
   apply (drule (1) well_formed_well_formed_cap_to_real_object', simp)
   apply (clarsimp simp: well_formed_cap_to_real_object_def real_object_at_def)
  apply (clarsimp simp: real_object_at_def opt_cap_dom_cdl_objects)
  done

(* This lemma converts between the two represenatations of the fact that the
 * root task has orig caps to each of the objects.
 *
 * This can be specified either:
 * - on the objects themselves.
 * - on the cap slots of CNodes that have a orig cap in them.
 *
 * This relies on the bijection between orig capabilities and objects in the spec.
 *)

lemma si_caps_at_conversion:
  "\<lbrakk>well_formed spec;
    real_ids = {obj_id. real_object_at obj_id spec};
    cnode_ids = {obj_id. cnode_at obj_id spec}\<rbrakk>
  \<Longrightarrow> si_objs_caps_at t si_caps spec dev cnode_ids =
      si_caps_at t si_caps spec dev real_ids"
  apply (clarsimp simp: si_objs_caps_at_def si_obj_caps_at_def [abs_def]
                        si_obj_cap_at_def [abs_def] si_caps_at_def)
  apply (subst sep.prod.Sigma, clarsimp+)
  apply (clarsimp simp: split_def)
  apply (subst sep_map_set_conj_restrict_predicate)
   apply (rule finite_SigmaI, clarsimp+)
  apply (subst orig_cap_rewrite)
  apply (frule well_formed_bij)
  apply (clarsimp simp: bij_betw_def)
  apply (rule sep_map_set_conj_reindex_cong [where f="\<lambda>cap_ref. cap_ref_object cap_ref spec", symmetric])
    apply (subst well_formed_object_cap_real, simp+)
   apply (simp add: real_objects_def real_object_at_def)
   apply (subst well_formed_object_cap_real, simp+)
  apply (clarsimp simp: cap_ref_object_def object_cap_ref_def si_obj_cap_at'_def)
  done


lemma si_null_caps_at_conversion:
  "\<lbrakk>well_formed spec;
    real_ids = {obj_id. real_object_at obj_id spec};
    cnode_ids = {obj_id. cnode_at obj_id spec}\<rbrakk>
  \<Longrightarrow> si_spec_objs_null_caps_at t si_caps spec cnode_ids =
      si_null_caps_at t si_caps spec real_ids"
  apply (clarsimp simp: si_spec_objs_null_caps_at_def si_spec_obj_null_caps_at_def [abs_def]
                        si_spec_obj_null_cap_at_def [abs_def] si_null_caps_at_def)
  apply (subst sep.prod.Sigma, clarsimp+)
  apply (clarsimp simp: split_def)
  apply (subst sep_map_set_conj_restrict_predicate)
   apply (rule finite_SigmaI, clarsimp+)
  apply (subst orig_cap_rewrite)
  apply (frule well_formed_bij)
  apply (clarsimp simp: bij_betw_def)
  apply (rule sep_map_set_conj_reindex_cong [where f="\<lambda>cap_ref. cap_ref_object cap_ref spec"
    and h="(si_null_cap_at t si_caps spec)"
    and B="{obj_id. real_object_at obj_id spec}", symmetric])
    apply (subst well_formed_object_cap_real, simp+)
   apply (simp add: real_objects_def real_object_at_def)
   apply (subst well_formed_object_cap_real, simp+)
  apply (clarsimp simp: cap_ref_object_def object_cap_ref_def si_spec_obj_null_cap_at'_def)
  done

lemma si_null_caps_at_reindex:
  "\<lbrakk>distinct (obj_ids::32 word list); distinct (free_cptrs);
     orig_caps = map_of (zip obj_ids free_cptrs);
     length obj_ids \<le> length free_cptrs\<rbrakk>
  \<Longrightarrow> (\<And>* obj_id\<in>set obj_ids.
       (\<lambda>s. \<exists>cap_ptr. ((si_cnode_id, unat cap_ptr) \<mapsto>c NullCap) s \<and>
                       orig_caps obj_id = Some cap_ptr))
   = (\<And>* cptr\<in>set (take (length obj_ids) free_cptrs).
                   (si_cnode_id, unat cptr) \<mapsto>c NullCap)"
  apply (rule sep_map_set_conj_reindex_cong [symmetric, where
      f="\<lambda>obj_id. the (orig_caps obj_id)"
      and h="\<lambda>cptr. (si_cnode_id, unat cptr) \<mapsto>c NullCap"
      and B="set (take (length obj_ids) free_cptrs)"])
    apply clarsimp
    apply (erule (2) map_of_zip_inj')
   apply clarsimp
   apply (subst zip_take_length[symmetric])
   apply (subst map_of_zip_range)
     apply (clarsimp simp: min_def)
    apply assumption
   apply simp
  apply clarsimp
  apply (rule ext)
  apply rule
   apply clarsimp
  apply (rule_tac x="the (map_of (zip obj_ids free_cptrs) a)" in exI)
  apply clarsimp
  apply (frule_tac x=a in map_of_zip_is_Some', clarsimp)
  done

lemma si_null_caps_at_simplified_helper:
  "\<lbrakk>(si_null_caps_at t orig_caps spec obj_ids) s\<rbrakk> \<Longrightarrow>
     (\<And>* obj_id \<in> obj_ids. (\<lambda>s. \<exists>cap_ptr. ((si_cnode_id, unat cap_ptr) \<mapsto>c NullCap) s \<and>
                                   orig_caps obj_id = Some cap_ptr)) s"
  apply (clarsimp simp: si_null_caps_at_def si_null_cap_at_def [abs_def])
  apply (erule sep_map_set_conj_impl)
   apply blast
  apply clarsimp
  done

lemma si_null_caps_at_simplified:
  "\<lbrakk>(si_spec_objs_null_caps_at t si_caps spec cnode_ids) s;
    well_formed spec;
    cnode_ids = {obj_id. cnode_at obj_id spec};
    real_ids = {obj_id. real_object_at obj_id spec};
    real_ids = set obj_ids;
    distinct obj_ids; distinct free_cptrs;
    si_caps = map_of (zip obj_ids free_cptrs);
    length obj_ids \<le> length free_cptrs\<rbrakk> \<Longrightarrow>
   (\<And>* cptr \<in> set (take (length obj_ids) free_cptrs). ((si_cnode_id, unat cptr) \<mapsto>c NullCap)) s"
  apply (subst (asm) si_null_caps_at_conversion, assumption+)
  apply (drule si_null_caps_at_simplified_helper)
  apply (subst si_null_caps_at_reindex [symmetric], simp+)
  done

lemma map_of_zip_range':
  "\<lbrakk>length xs = length ys; distinct xs; set xs = X\<rbrakk>
  \<Longrightarrow> (\<lambda>x. (the (map_of (zip xs ys) x))) ` X = set ys"
  by (metis map_of_zip_range)




lemma si_irq_caps_at_conversion:
  "\<lbrakk>well_formed spec;
    cnode_ids = {obj_id. cnode_at obj_id spec};
    irqs = used_irqs spec\<rbrakk>
  \<Longrightarrow> si_spec_irqs_caps_at irq_caps spec cnode_ids =
      si_irq_caps_at irq_caps spec irqs"
  apply (clarsimp simp: si_spec_irqs_caps_at_def si_irq_caps_at_def
                        si_spec_irq_caps_at_def [abs_def]
                        si_spec_irq_cap_at_def [abs_def])
  apply (subst sep.prod.Sigma, clarsimp+)
  apply (clarsimp simp: split_def)
  apply (subst sep_map_set_conj_restrict_predicate)
   apply (rule finite_SigmaI, clarsimp+)
  apply (subst irqhandler_cap_rewrite, assumption)
  apply (frule well_formed_irqhandler_bij)
  apply (clarsimp simp: bij_betw_def)
  apply (rule sep_map_set_conj_reindex_cong [where f="\<lambda>cap_ref. cap_ref_irq cap_ref spec", symmetric], simp+)
  apply (clarsimp simp: si_spec_irq_cap_at'_def cap_ref_irq_def cap_at_def)
  done

definition si_null_irq_caps_at :: "(cdl_irq \<Rightarrow> cdl_cptr option) \<Rightarrow> cdl_state \<Rightarrow>
                                      cdl_irq set \<Rightarrow> sep_pred"
where
  "si_null_irq_caps_at si_irq_caps spec irqs \<equiv>
  \<And>* irq \<in> irqs. si_null_irq_cap_at si_irq_caps spec irq"

lemma si_null_irq_caps_at_simplified_helper:
  "\<lbrakk>(si_null_irq_caps_at si_irq_caps spec irqs) s\<rbrakk> \<Longrightarrow>
     (\<And>* irq \<in> irqs. (\<lambda>s. \<exists>cap_ptr. ((si_cnode_id, unat cap_ptr) \<mapsto>c NullCap) s \<and>
                                   si_irq_caps irq = Some cap_ptr)) s"
  apply (clarsimp simp: si_null_irq_caps_at_def si_null_irq_cap_at_def)
  apply (erule sep_map_set_conj_impl)
   apply blast
  apply clarsimp
  done

lemma map_of_zip_inj2:
  "\<lbrakk>distinct xs; distinct ys; length xs \<le> length ys; set xs = X\<rbrakk>
  \<Longrightarrow> inj_on (\<lambda>x. the (map_of (zip xs ys) x)) X"
  by (metis map_of_zip_inj')

lemma opt_cap_has_slots:
  "\<lbrakk>opt_cap (obj_id, slot) spec = Some cap\<rbrakk>
  \<Longrightarrow> object_at has_slots obj_id spec"
  by (auto simp: object_at_def has_slots_def opt_cap_def slots_of_def opt_object_def object_slots_def
          split: option.splits cdl_object.splits)

lemma well_formed_non_ntfn_in_real_object:
  "\<lbrakk>well_formed spec; opt_cap (obj_id, slot) spec = Some cap; \<not>is_ntfn_cap cap; cap \<noteq> NullCap\<rbrakk>
  \<Longrightarrow> real_object_at obj_id spec"
  apply (frule opt_cap_cdl_objects, clarsimp)
  apply (frule (1) well_formed_well_formed_irq_node)
  apply (clarsimp simp: well_formed_irq_node_def real_object_at_def
                         opt_cap_def slots_of_def opt_object_def opt_cap_dom_cdl_objects)
  done


lemma irqhandler_cap_at_simp:
  "well_formed spec \<Longrightarrow>
   {(obj_id, slot). cnode_at obj_id spec \<and> irqhandler_cap_at (obj_id, slot) spec} =
   {(obj_id, slot). irqhandler_cap_at (obj_id, slot) spec}"
  apply (safe)
  apply (clarsimp simp: cap_at_def)
  apply (frule (2) well_formed_irqhandler_cap_in_cnode_at)
  apply (frule (1) well_formed_non_ntfn_in_real_object, simp+)
  done

lemma orig_cap_rewrite_v2:
  "(SIGMA obj_id:{obj_id. cnode_at obj_id spec}. dom (slots_of obj_id spec)) =
   {(obj_id, slot). cnode_at obj_id spec \<and> slots_of obj_id spec slot \<noteq> None}"
  by auto

lemma rewrite_irqhandler_cap_at:
  "well_formed spec \<Longrightarrow>
  Set.filter (\<lambda>cap_ref. irqhandler_cap_at cap_ref spec)
             (SIGMA obj_id:{obj_id. cnode_at obj_id spec}. dom (slots_of obj_id spec)) =
  {(obj_id, slot). irqhandler_cap_at (obj_id, slot) spec}"
  apply (subst irqhandler_cap_at_simp [symmetric])
  by (auto simp: opt_cap_def cap_at_def)

lemma well_formed_used_irqs_rewrite:
  "well_formed spec \<Longrightarrow>
   (\<lambda>cap_ref. cap_ref_irq cap_ref spec) ` {(obj_id, slot). irqhandler_cap_at (obj_id, slot) spec} =
   used_irqs spec"
  apply (drule well_formed_irqhandler_bij)
  apply (auto simp: bij_betw_def)
  done


lemma si_irq_null_caps_at_simplified:
  "\<lbrakk>(si_spec_irqs_null_caps_at irq_caps spec {obj_id. cnode_at obj_id spec}) s;
    well_formed spec;
    distinct irqs; distinct free_cptrs;
    set irqs = used_irqs spec;
    irq_caps = map_of (zip irqs free_cptrs);
    length irqs \<le> length free_cptrs\<rbrakk> \<Longrightarrow>
   (\<And>* cptr \<in> set (take (length irqs) free_cptrs). ((si_cnode_id, unat cptr) \<mapsto>c NullCap)) s"
  apply (clarsimp simp: si_spec_irqs_null_caps_at_def si_spec_irq_null_caps_at_def
                        si_spec_irq_null_cap_at_def si_spec_irqs_caps_at_def)
  apply (subst (asm) sep.prod.Sigma, clarsimp+)
  apply (clarsimp simp: split_def)
  apply (subst (asm) sep_map_set_conj_restrict_predicate, rule finite_SigmaI, clarsimp+)
  apply (subst (asm) rewrite_irqhandler_cap_at, simp)
  apply (subst (asm) sep_map_set_conj_reindex_cong [where
                    f = "\<lambda>cap_ref. cap_ref_irq cap_ref spec"
                and h = "si_null_irq_cap_at (map_of (zip irqs free_cptrs)) spec", symmetric])
     apply (drule well_formed_irqhandler_bij)
     apply (clarsimp simp: bij_betw_def cond_case_prod_eta)
    apply simp
   apply (clarsimp simp: si_spec_irq_null_cap_at'_def cap_at_def cap_ref_irq_def)
  apply clarsimp
  apply (drule si_null_irq_caps_at_simplified_helper [simplified si_null_irq_caps_at_def])
  apply (subst (asm) sep_map_set_conj_reindex_cong [symmetric, where
                    f = "\<lambda>irq. the ( map_of (zip irqs free_cptrs) irq)"
                and h = "\<lambda>cptr. (si_cnode_id, unat cptr) \<mapsto>c NullCap"
                and B = "set (take (length irqs) free_cptrs)"])
     apply (subst well_formed_used_irqs_rewrite, assumption)
     apply (metis map_of_zip_inj')
    apply (subst well_formed_used_irqs_rewrite, assumption)
    apply (subst zip_take_length[symmetric], subst map_of_zip_range', simp+)
   apply (rule ext)
   apply rule
    apply clarsimp
   apply (rule_tac x="the (map_of (zip irqs free_cptrs) a)" in exI)
   apply clarsimp
   apply (frule_tac x1="(cap_irq (the (opt_cap (aa, b) spec)))" in map_of_zip_is_Some'[THEN iffD1], clarsimp)
    apply (fastforce simp: cap_at_def used_irqs_def all_caps_def)
   apply (clarsimp simp: cap_ref_irq_def)
  apply simp
  done

end
