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

(*
 * State translation.
 *
 * Takes a state of the system as defined in the abstract seL4
 * specification, and returns an equivalent state of the system
 * defined in terms of the CapDL specification.
 *)

theory StateTranslation_D
imports Lemmas_D
begin

context begin interpretation Arch . (*FIXME: arch_split*)

type_synonym kernel_object = Structures_A.kernel_object
type_synonym tcb = Structures_A.tcb
type_synonym pte = ARM_A.pte

(* Transform an abstract-spec cap ptr to a capDL one. This is currently
 * a no-(;) however, it is conceivable that the capDL cptr representation could
 * be changed. Allowing for this potential change is the purpose of this
 * definition.
 *)
definition
  transform_cptr :: "word32 \<Rightarrow> cdl_cptr" where
  "transform_cptr w \<equiv> w"

(* transform an abstract-spec recv_slot description to a capDL one *)
definition
  transform_recv_slot :: "(word32 \<times> word32 \<times> word8) \<Rightarrow>
                          (cdl_cptr \<times> word32 \<times> word8)"
where
  "transform_recv_slot x \<equiv> let (cap,w32,w8) = x in (transform_cptr cap,w32,w8)"

(*
 * Convert a user value to a CDL type.
 *
 * We repeat "FrameType" multiple times because CapDL doesn't
 * treat the different frame sizes as different types.
 *)
definition
  transform_type :: "word32 \<Rightarrow> cdl_object_type option"
where
  "transform_type x \<equiv>
         if x = 0  then Some UntypedType
    else if x = 1  then Some TcbType
    else if x = 2  then Some EndpointType
    else if x = 3  then Some NotificationType
    else if x = 4  then Some CNodeType
    else if x = 5  then Some (FrameType 12)
    else if x = 6  then Some (FrameType 16)
    else if x = 7  then Some (FrameType 20)
    else if x = 8  then Some (FrameType 24)
    else if x = 9  then Some PageTableType
    else if x = 10 then Some PageDirectoryType
    else None"

definition
  transform_intent_untyped_retype :: "word32 list \<Rightarrow> cdl_untyped_intent option"
where
  "transform_intent_untyped_retype args =
    (case args of
      type#size_bits#index#depth#offset#window#_ \<Rightarrow>
        (case transform_type type of
             Some x \<Rightarrow>
               Some (UntypedRetypeIntent x size_bits index depth offset window)
           | _ \<Rightarrow>
               None)
      | _ \<Rightarrow> None)"

(* Arch flags always set to 0 here as they have no meaning on ARM. *)
definition
  transform_intent_tcb_read_registers :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_read_registers args =
  (case args of flags#n#_ \<Rightarrow>
    Some (TcbReadRegistersIntent (flags !! 0) 0 n)
   | _ \<Rightarrow> None)"

(* Arch flags always set to 0 here as they have no meaning on ARM. *)
definition
  transform_intent_tcb_write_registers :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_write_registers args =
  (case args of flags#n#values \<Rightarrow>
    Some (TcbWriteRegistersIntent (flags !! 0) 0 n values)
   | _ \<Rightarrow> None)"

(* Arch flags always set to 0 here as they have no meaning on ARM. *)
definition
  transform_intent_tcb_copy_registers :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_copy_registers args =
  (case args of flags#_ \<Rightarrow>
    Some (TcbCopyRegistersIntent (flags !! 0) (flags !! 1) (flags !! 2) (flags !! 3) 0)
   | _ \<Rightarrow> None)"

(* Priority always set to 0 here. This should change if priorities
 * are ever added to the capDL spec.
 *)
definition
  prio_from_arg :: "word32 \<Rightarrow> word8"
where
  "prio_from_arg _ = 0"

definition
  transform_intent_tcb_configure :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_configure args =
  (case args of fault_ep#croot_data#vroot_data#buffer#_ \<Rightarrow>
    Some (TcbConfigureIntent fault_ep
                             croot_data vroot_data buffer)
   | _ \<Rightarrow> None)"

definition
  transform_intent_tcb_set_priority :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_set_priority args =
  (case args of prio#_ \<Rightarrow>
    Some (TcbSetPriorityIntent (prio_from_arg prio))
   | _ \<Rightarrow> None)"

definition
  transform_intent_tcb_set_mcpriority :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_set_mcpriority args =
  (case args of mcp#_ \<Rightarrow>
    Some (TcbSetMCPriorityIntent (prio_from_arg mcp))
   | _ \<Rightarrow> None)"

definition
  transform_intent_tcb_set_sched_params :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_set_sched_params args =
  (case args of mcp#priority#_ \<Rightarrow>
    Some (TcbSetSchedParamsIntent (prio_from_arg mcp) (prio_from_arg priority))
   | _ \<Rightarrow> None)"

definition
  transform_intent_tcb_set_ipc_buffer :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_set_ipc_buffer args =
  (case args of buffer#_ \<Rightarrow>
    Some (TcbSetIPCBufferIntent buffer)
   | _ \<Rightarrow> None)"


definition
  transform_intent_tcb_set_space :: "word32 list \<Rightarrow> cdl_tcb_intent option"
where
  "transform_intent_tcb_set_space args =
  (case args of fault_ep#croot_data#vroot_data#_ \<Rightarrow>
    Some (TcbSetSpaceIntent fault_ep croot_data vroot_data)
   | _ \<Rightarrow> None)"

definition
  transform_cnode_index_and_depth :: "(word32 \<Rightarrow> word32 \<Rightarrow> 'a) \<Rightarrow> word32 list \<Rightarrow> 'a option"
where
  "transform_cnode_index_and_depth func args \<equiv>
  case args of index#depth#_ \<Rightarrow>
    Some (func index depth)
   | _ \<Rightarrow> None"


definition
  transform_intent_cnode_copy :: "word32 list \<Rightarrow> cdl_cnode_intent option"
where
  "transform_intent_cnode_copy args \<equiv>
  case args of destindex#destdepth#srcindex#srcdepth#rightsWord#_ \<Rightarrow>
     Some (CNodeCopyIntent destindex destdepth
                           srcindex srcdepth (data_to_rights rightsWord))
    | _ \<Rightarrow> Nothing"

definition
  transform_intent_cnode_mint :: "word32 list \<Rightarrow> cdl_cnode_intent option"
where
  "transform_intent_cnode_mint args \<equiv>
  case args of destindex#destdepth#srcindex#srcdepth#rightsWord#capData#_ \<Rightarrow>
     Some (CNodeMintIntent destindex destdepth
             srcindex srcdepth (data_to_rights rightsWord) capData)
    | _ \<Rightarrow> Nothing"

definition
  transform_intent_cnode_move :: "word32 list \<Rightarrow> cdl_cnode_intent option"
where
  "transform_intent_cnode_move args \<equiv>
  case args of destindex#destdepth#srcindex#srcdepth#rest \<Rightarrow>
     Some (CNodeMoveIntent destindex destdepth
                           srcindex srcdepth)
    | _ \<Rightarrow> Nothing"

definition
  transform_intent_cnode_mutate :: "word32 list \<Rightarrow> cdl_cnode_intent option"
where
  "transform_intent_cnode_mutate args \<equiv>
  case args of destindex#destdepth#srcindex#srcdepth#capData#_ \<Rightarrow>
     Some (CNodeMutateIntent destindex destdepth
                             srcindex srcdepth capData)
    | _ \<Rightarrow> Nothing"

definition
  transform_intent_cnode_rotate :: "word32 list \<Rightarrow> cdl_cnode_intent option"
where
  "transform_intent_cnode_rotate args \<equiv>
  case args of destindex#destdepth#pivotbadge#pivotindex#
               pivotdepth#srcbadge#srcindex#srcdepth#_ \<Rightarrow>
     Some (CNodeRotateIntent destindex destdepth
                             pivotindex pivotdepth pivotbadge
                             srcindex srcdepth srcbadge)
    | _ \<Rightarrow> Nothing"


definition
  transform_intent_issue_irq_handler :: "word32 list \<Rightarrow> cdl_irq_control_intent option"
where
  "transform_intent_issue_irq_handler args \<equiv>
   case args of
      irqW#index#depth#_ \<Rightarrow>
         Some (IrqControlIssueIrqHandlerIntent ((ucast irqW)::10 word) index depth)
    | _ \<Rightarrow> Nothing"

definition
  arch_transform_intent_issue_irq_handler :: "word32 list \<Rightarrow> cdl_irq_control_intent option"
where
  "arch_transform_intent_issue_irq_handler args \<equiv>
   case args of
      irqW#trigger#index#depth#_ \<Rightarrow>
         Some (IrqControlIssueIrqHandlerIntent ((ucast irqW)::10 word) index depth)
    | _ \<Rightarrow> Nothing"

definition
  transform_intent_page_table_map :: "word32 list \<Rightarrow> cdl_page_table_intent option"
where
  "transform_intent_page_table_map args =
    (case args of
      vaddr#attr#_ \<Rightarrow>
         Some (PageTableMapIntent vaddr attr)
    | _ \<Rightarrow> Nothing)"

definition
  transform_intent_page_map :: "word32 list \<Rightarrow> cdl_page_intent option"
where
  "transform_intent_page_map args =
    (case args of
      vaddr#rightsW#attr#_ \<Rightarrow>
         Some (PageMapIntent vaddr (data_to_rights rightsW) attr)
    | _ \<Rightarrow> Nothing)"

definition
  transform_intent_page_remap :: "word32 list \<Rightarrow> cdl_page_intent option"
where
  "transform_intent_page_remap args =
    (case args of
      rightsW#attr#_ \<Rightarrow> Some (PageRemapIntent (data_to_rights rightsW) attr)
    | _ \<Rightarrow> Nothing)"

definition
  transform_intent_domain :: "word32 list \<Rightarrow> cdl_domain_intent option"
where
  "transform_intent_domain args =
     (case args of
         d#_ \<Rightarrow> Some (DomainSetIntent (ucast d :: word8))
       | _   \<Rightarrow> Nothing)"

(* Added for IOAPIC patch *)
definition
  to_bool :: "word32 \<Rightarrow> bool"
where
  "to_bool w \<equiv> w \<noteq> 0"

(* A dispatch function that converts the user's message label
 * and IPC buffer into an intent by dispatching on the message label.
 * For malformed messages etc., we return None.
*)

definition
  transform_intent :: "invocation_label \<Rightarrow> word32 list \<Rightarrow> cdl_intent option" where
  "transform_intent label args \<equiv>
    case label of
      InvalidInvocation \<Rightarrow> None
    | UntypedRetype \<Rightarrow>
        map_option UntypedIntent (transform_intent_untyped_retype args)
    | TCBReadRegisters \<Rightarrow>
        map_option TcbIntent
                   (transform_intent_tcb_read_registers args)
    | TCBWriteRegisters \<Rightarrow>
        map_option TcbIntent
                   (transform_intent_tcb_write_registers args)
    | TCBCopyRegisters \<Rightarrow>
         map_option TcbIntent
                   (transform_intent_tcb_copy_registers args)
    | TCBConfigure \<Rightarrow>
         map_option TcbIntent
                   (transform_intent_tcb_configure args)
    | TCBSetPriority \<Rightarrow>
         map_option TcbIntent
                   (transform_intent_tcb_set_priority args)
    | TCBSetMCPriority \<Rightarrow>
         map_option TcbIntent
                   (transform_intent_tcb_set_mcpriority args)
    | TCBSetSchedParams \<Rightarrow>
         map_option TcbIntent
                   (transform_intent_tcb_set_sched_params args)
    | TCBSetIPCBuffer \<Rightarrow>
          map_option TcbIntent
                   (transform_intent_tcb_set_ipc_buffer args)
    | TCBSetSpace \<Rightarrow>
          map_option TcbIntent
                   (transform_intent_tcb_set_space args)
    | TCBSuspend \<Rightarrow> Some (TcbIntent TcbSuspendIntent)
    | TCBResume \<Rightarrow> Some (TcbIntent TcbResumeIntent)
    | TCBBindNotification \<Rightarrow> Some (TcbIntent TcbBindNTFNIntent)
    | TCBUnbindNotification \<Rightarrow> Some (TcbIntent TcbUnbindNTFNIntent)
    | TCBSetTLSBase \<Rightarrow> Some (TcbIntent TcbSetTLSBaseIntent)
    | CNodeRevoke \<Rightarrow>
          map_option CNodeIntent
                   (transform_cnode_index_and_depth CNodeRevokeIntent args)
    | CNodeDelete \<Rightarrow>
          map_option CNodeIntent
                   (transform_cnode_index_and_depth CNodeDeleteIntent args)
    | CNodeCancelBadgedSends \<Rightarrow>
          map_option CNodeIntent
                   (transform_cnode_index_and_depth CNodeCancelBadgedSendsIntent args)
    | CNodeCopy \<Rightarrow>
          map_option CNodeIntent
                   (transform_intent_cnode_copy args)
    | CNodeMint \<Rightarrow>
          map_option CNodeIntent
                   (transform_intent_cnode_mint args)
    | CNodeMove \<Rightarrow>
          map_option CNodeIntent
                   (transform_intent_cnode_move args)
    | CNodeMutate \<Rightarrow>
          map_option CNodeIntent
                   (transform_intent_cnode_mutate args)
    | CNodeRotate \<Rightarrow>
          map_option CNodeIntent
                   (transform_intent_cnode_rotate args)
    | CNodeSaveCaller \<Rightarrow>
          map_option CNodeIntent
                   (transform_cnode_index_and_depth CNodeSaveCallerIntent args)
    | IRQIssueIRQHandler \<Rightarrow>
          map_option IrqControlIntent
                   (transform_intent_issue_irq_handler args)
    | IRQAckIRQ \<Rightarrow> Some (IrqHandlerIntent IrqHandlerAckIntent)
    | IRQSetIRQHandler \<Rightarrow> Some (IrqHandlerIntent IrqHandlerSetEndpointIntent)
    | IRQClearIRQHandler \<Rightarrow> Some (IrqHandlerIntent IrqHandlerClearIntent)
    | ArchInvocationLabel ARMPageTableMap \<Rightarrow>
                          map_option PageTableIntent
                                   (transform_intent_page_table_map args)
    | ArchInvocationLabel ARMPageTableUnmap \<Rightarrow> Some (PageTableIntent PageTableUnmapIntent)
    | ArchInvocationLabel ARMPageMap \<Rightarrow>
                          map_option PageIntent
                                   (transform_intent_page_map args)
    | ArchInvocationLabel ARMPageRemap \<Rightarrow>
                          map_option PageIntent
                                   (transform_intent_page_remap args)
    | ArchInvocationLabel ARMPageUnmap \<Rightarrow> Some (PageIntent PageUnmapIntent)
    | ArchInvocationLabel ARMPageClean_Data \<Rightarrow> Some (PageIntent PageFlushCachesIntent )
    | ArchInvocationLabel ARMPageInvalidate_Data  \<Rightarrow> Some (PageIntent PageFlushCachesIntent )
    | ArchInvocationLabel ARMPageCleanInvalidate_Data \<Rightarrow> Some (PageIntent PageFlushCachesIntent )
    | ArchInvocationLabel ARMPageUnify_Instruction \<Rightarrow> Some (PageIntent PageFlushCachesIntent )
    | ArchInvocationLabel ARMPageGetAddress \<Rightarrow> Some (PageIntent PageGetAddressIntent )
    | ArchInvocationLabel ARMPDClean_Data \<Rightarrow> Some (PageDirectoryIntent PageDirectoryFlushIntent )
    | ArchInvocationLabel ARMPDInvalidate_Data \<Rightarrow>  Some (PageDirectoryIntent PageDirectoryFlushIntent )
    | ArchInvocationLabel ARMPDCleanInvalidate_Data \<Rightarrow>  Some (PageDirectoryIntent PageDirectoryFlushIntent)
    | ArchInvocationLabel ARMPDUnify_Instruction \<Rightarrow>  Some (PageDirectoryIntent PageDirectoryFlushIntent )
    | ArchInvocationLabel ARMASIDControlMakePool \<Rightarrow>
                          map_option AsidControlIntent
                                  (transform_cnode_index_and_depth AsidControlMakePoolIntent args)
    | ArchInvocationLabel ARMASIDPoolAssign \<Rightarrow> Some (AsidPoolIntent AsidPoolAssignIntent )
    | ArchInvocationLabel ARMIRQIssueIRQHandler \<Rightarrow>
                          map_option IrqControlIntent
                                   (arch_transform_intent_issue_irq_handler args)
    | DomainSetSet \<Rightarrow> map_option DomainIntent (transform_intent_domain args)"

lemmas transform_intent_tcb_defs =
  transform_intent_tcb_read_registers_def
  transform_intent_tcb_write_registers_def
  transform_intent_tcb_copy_registers_def
  transform_intent_tcb_configure_def
  transform_intent_tcb_set_priority_def
  transform_intent_tcb_set_mcpriority_def
  transform_intent_tcb_set_sched_params_def
  transform_intent_tcb_set_ipc_buffer_def
  transform_intent_tcb_set_space_def

lemma transform_tcb_intent_invocation:
  "transform_intent label args = Some (TcbIntent ti)
   \<Longrightarrow>
   (
   ((label = TCBReadRegisters) = (ti = (TcbReadRegistersIntent ((args ! 0)!!0) 0 (args ! 1)) \<and> length args \<ge> 2)) \<and>
   ((label = TCBWriteRegisters) = (ti = (TcbWriteRegistersIntent ((args ! 0)!!0) 0 (args ! 1) (drop 2 args)) \<and> length args \<ge> 2)) \<and>
   ((label = TCBCopyRegisters) = (ti = (TcbCopyRegistersIntent ((args ! 0)!!0) ((args ! 0)!!1) ((args ! 0)!!2) ((args ! 0)!!3) 0) \<and> length args \<ge> 1)) \<and>
   ((label = TCBConfigure) = (ti = (TcbConfigureIntent (args ! 0) (args ! 1) (args ! 2) (args ! 3)) \<and> length args \<ge> 4)) \<and>
   ((label = TCBSetPriority) = (ti = (TcbSetPriorityIntent (prio_from_arg (args ! 0))) \<and> length args \<ge> 1)) \<and>
   ((label = TCBSetMCPriority) = (ti = (TcbSetMCPriorityIntent (prio_from_arg (args ! 0))) \<and> length args \<ge> 1)) \<and>
   ((label = TCBSetSchedParams) = (ti = (TcbSetSchedParamsIntent (prio_from_arg (args ! 0)) (prio_from_arg (args ! 1))) \<and> length args \<ge> 2)) \<and>
   ((label = TCBSetSpace) = (ti = (TcbSetSpaceIntent (args ! 0) (args ! 1) (args ! 2)) \<and> length args \<ge> 3)) \<and>
   ((label = TCBSuspend) = (ti = TcbSuspendIntent)) \<and>
   ((label = TCBResume) = (ti = TcbResumeIntent)) \<and>
   ((label = TCBBindNotification) = (ti = TcbBindNTFNIntent)) \<and>
   ((label = TCBUnbindNotification) = (ti = TcbUnbindNTFNIntent)) \<and>
   ((label = TCBSetTLSBase) = (ti = TcbSetTLSBaseIntent))
   ) \<and>
   (
    label \<noteq> InvalidInvocation \<and>
    label \<noteq> UntypedRetype \<and>
    label \<noteq> CNodeRevoke \<and>
    label \<noteq> CNodeDelete \<and>
    label \<noteq> CNodeCancelBadgedSends \<and>
    label \<noteq> CNodeCopy \<and>
    label \<noteq> CNodeMint \<and>
    label \<noteq> CNodeMove \<and>
    label \<noteq> CNodeMutate \<and>
    label \<noteq> CNodeRotate \<and>
    label \<noteq> CNodeSaveCaller \<and>
    label \<noteq> IRQIssueIRQHandler \<and>
    label \<noteq> IRQAckIRQ \<and>
    label \<noteq> IRQSetIRQHandler \<and>
    label \<noteq> IRQClearIRQHandler \<and>
    label \<noteq> ArchInvocationLabel ARMPageTableMap \<and>
    label \<noteq> ArchInvocationLabel ARMPageTableUnmap \<and>
    label \<noteq> ArchInvocationLabel ARMPageMap \<and>
    label \<noteq> ArchInvocationLabel ARMPageUnmap \<and>
    label \<noteq> ArchInvocationLabel ARMPageClean_Data \<and>
    label \<noteq> ArchInvocationLabel ARMPageInvalidate_Data \<and>
    label \<noteq> ArchInvocationLabel ARMPageCleanInvalidate_Data \<and>
    label \<noteq> ArchInvocationLabel ARMPageUnify_Instruction \<and>
    label \<noteq> ArchInvocationLabel ARMPageGetAddress \<and>
    label \<noteq> ArchInvocationLabel ARMPDClean_Data \<and>
    label \<noteq> ArchInvocationLabel ARMPDInvalidate_Data \<and>
    label \<noteq> ArchInvocationLabel ARMPDCleanInvalidate_Data \<and>
    label \<noteq> ArchInvocationLabel ARMPDUnify_Instruction \<and>
    label \<noteq> ArchInvocationLabel ARMASIDControlMakePool \<and>
    label \<noteq> DomainSetSet)"
  apply(intro conjI)
   apply(rule iffI,
         simp add: transform_intent_def transform_intent_tcb_defs split: list.split_asm,
         simp add: transform_intent_def transform_intent_tcb_defs split: invocation_label.split_asm arch_invocation_label.split_asm list.split_asm)+
  apply(simp add: transform_intent_def transform_intent_tcb_defs split: invocation_label.split_asm arch_invocation_label.split_asm)+
done

lemma transform_intent_isnot_UntypedIntent:
      "(\<not> (\<exists> ui. Some (UntypedIntent ui) = transform_intent label args))
       = ((label \<noteq> UntypedRetype) \<or>
           (label = UntypedRetype \<and> length args < 6) \<or>
           (label = UntypedRetype \<and> length args \<ge> 6 \<and> args ! 0 > 10))"
  apply(rule iffI)
   apply(erule contrapos_np)
   apply(clarsimp)
   apply(simp add: transform_intent_def)
   apply(unfold transform_intent_untyped_retype_def)
   apply (clarsimp split: list.split, safe, simp_all)[1]
   apply (clarsimp simp: transform_type_def)
   apply (simp add: linorder_not_less eval_nat_numeral le_Suc_eq unat_arith_simps)
  apply(erule disjE)
   apply(auto simp: transform_intent_def option_map_def split: invocation_label.split arch_invocation_label.split option.split_asm)[1]
  apply (erule disjE)
   apply (auto simp: transform_intent_def transform_intent_untyped_retype_def
         option_map_def split: invocation_label.split option.split_asm list.split)[1]
  apply clarsimp
  apply (clarsimp simp: transform_intent_def transform_type_def transform_intent_untyped_retype_def)
  apply (clarsimp simp: option_map_def split: invocation_label.splits arch_invocation_label.splits option.splits list.splits)
  apply (clarsimp simp: transform_type_def split: if_split_asm)
  done

lemma transform_cnode_index_and_depth_success:
       "(\<exists>ci. Some (C ci) =
            map_option C
             (transform_cnode_index_and_depth C2 args)) =
       (\<not> length args < 2)"
apply(rule iffI)
 apply(unfold option_map_def transform_cnode_index_and_depth_def)
 apply(case_tac args)
 apply(auto split: list.split)
done

lemmas transform_intent_cnode_defs =
  transform_cnode_index_and_depth_def
  transform_intent_cnode_copy_def
  transform_intent_cnode_mint_def
  transform_intent_cnode_move_def
  transform_intent_cnode_mutate_def
  transform_intent_cnode_rotate_def

method case_labels for label :: invocation_label =
  (cases label, find_goal \<open>match premises in "label = ArchInvocationLabel x" for x \<Rightarrow> \<open>cases x\<close>\<close>)

lemma transform_intent_isnot_CNodeIntent:
      "(\<not> (\<exists> ui. Some (CNodeIntent ui) = transform_intent label args))
       = ((label = CNodeRevoke \<longrightarrow> length args < 2) \<and>
          (label = CNodeDelete \<longrightarrow> length args < 2) \<and>
          (label = CNodeCancelBadgedSends \<longrightarrow> length args < 2) \<and>
          (label = CNodeCopy \<longrightarrow> length args < 5) \<and>
          (label = CNodeMint \<longrightarrow> length args < 6) \<and>
          (label = CNodeMove \<longrightarrow> length args < 4) \<and>
          (label = CNodeMutate \<longrightarrow> length args < 5) \<and>
          (label = CNodeRotate \<longrightarrow> length args < 8) \<and>
          (label = CNodeSaveCaller \<longrightarrow> length args < 2))"
  apply(rule iffI)
   apply(erule contrapos_np)
   apply(clarsimp simp: transform_intent_def)
   apply(case_tac label)
                                  apply(simp_all)
        apply(simp_all add: transform_intent_cnode_defs
                            option_map_def
                            split: list.split)
           prefer 10
           apply(clarify)
           apply(case_labels label)
           apply(clarsimp simp: transform_intent_def
                      option_map_def transform_intent_cnode_defs
                      split: list.split_asm option.split_asm)+
  apply(auto)
done

lemma transform_intent_isnot_TcbIntent:
      "(\<not> (\<exists> ti. Some (TcbIntent ti) = transform_intent label args))
       = ((label = TCBReadRegisters \<longrightarrow> length args < 2) \<and>
          (label = TCBWriteRegisters \<longrightarrow> length args < 2) \<and>
          (label = TCBCopyRegisters \<longrightarrow> length args < 1) \<and>
          (label = TCBConfigure \<longrightarrow> length args < 4) \<and>
          (label = TCBSetPriority \<longrightarrow> length args < 1) \<and>
          (label = TCBSetMCPriority \<longrightarrow> length args < 1) \<and>
          (label = TCBSetSchedParams \<longrightarrow> length args < 2) \<and>
          (label = TCBSetIPCBuffer \<longrightarrow> length args < 1) \<and>
          (label = TCBSetSpace \<longrightarrow> length args < 3) \<and>
          (label \<noteq> TCBSuspend) \<and>
          (label \<noteq> TCBResume) \<and>
          (label \<noteq> TCBBindNotification) \<and>
          (label \<noteq> TCBUnbindNotification) \<and>
          (label \<noteq> TCBSetTLSBase))"
  apply(rule iffI)
   apply(erule contrapos_np)
   apply(clarsimp simp: transform_intent_def)
   apply(case_labels label)
                                    apply(simp_all)
          apply(fastforce simp: transform_intent_tcb_defs
                                option_map_def
                         split: list.split)+
  apply(unfold transform_intent_def)
  apply(case_labels label, simp_all add: option_map_def split: option.split)
  apply (auto simp: transform_intent_tcb_defs
                 split:  list.splits arch_invocation_label.splits)
done

(*
 * Convert a partial function of type "word \<Rightarrow> 'b" into
 * a partial function of type "nat \<Rightarrow> 'b".
 *
 * It would be nice if we could just use the original
 * partial function as "p (unat x)". Unfortunately, this
 * would mean that "p ((unat x) + 2^32)" would return
 * some non-None value, which isn't what we want.
 *
 * Instead, return a new function that performs a range
 * check prior to calling the original function.
 *)
definition
  unat_map :: "(('a :: len) word \<rightharpoonup> 'b) \<Rightarrow> (nat \<rightharpoonup> 'b)"
where
  "unat_map x z \<equiv>
    if z < 2^len_of(TYPE('a)) then
      x (of_nat z)
    else
      None"

lemma unat_map_unat [simp]: "(unat_map p) (unat x) = p x"
  by (clarsimp simp: unat_map_def)

(*
 * Convert a cslot_ptr into a cdl_cap_ref.
 *)
definition
  transform_cslot_ptr :: "cslot_ptr \<Rightarrow> cdl_cap_ref"
where
  "transform_cslot_ptr \<equiv>
       \<lambda> (a, b). (a, nat (bl_to_bin b))"

(*
 * Convert an asid into a cdl_asid with asid_low_bits
 * hardcoded.
 *)
definition
  transform_asid :: "asid \<Rightarrow> cdl_asid"
where
  "transform_asid asid = (unat (asid_high_bits_of asid), unat (ucast asid :: 10 word))"

definition
  transform_mapping :: "(asid \<times> vspace_ref) option \<Rightarrow> cdl_mapped_addr option"
where
  " transform_mapping mp = option_map (\<lambda>x. (transform_asid (fst x),snd x)) mp"

(*
 * Transform a cap in the abstract spec to an equivalent
 * CapDL cap.
 *)

definition "free_range_of_untyped \<equiv> (\<lambda>idx size_bits ptr.
  (if (idx \<le> 2^size_bits - 1) then {ptr + of_nat idx .. ptr + 2^size_bits - 1} else {}))"
definition
  transform_cap :: "cap \<Rightarrow> cdl_cap"
where
  "transform_cap c \<equiv> case c of
      Structures_A.NullCap \<Rightarrow>
        Types_D.NullCap
    | Structures_A.UntypedCap dev ptr size_bits idx \<Rightarrow>
        Types_D.UntypedCap dev {ptr .. ptr + 2^ size_bits - 1}
        (free_range_of_untyped idx size_bits ptr)
    | Structures_A.EndpointCap ptr badge cap_rights_ \<Rightarrow>
        Types_D.EndpointCap ptr badge cap_rights_
    | Structures_A.NotificationCap ptr badge cap_rights_ \<Rightarrow>
        Types_D.NotificationCap ptr badge cap_rights_
    | Structures_A.ReplyCap ptr is_master \<Rightarrow>
        if is_master then Types_D.MasterReplyCap ptr else Types_D.ReplyCap ptr
    | Structures_A.CNodeCap ptr size_bits guard \<Rightarrow>
        Types_D.CNodeCap ptr (of_bl guard) (length guard) size_bits
    | Structures_A.ThreadCap ptr \<Rightarrow>
        Types_D.TcbCap ptr
    | Structures_A.DomainCap \<Rightarrow>
        Types_D.DomainCap
    | Structures_A.IRQControlCap \<Rightarrow>
        Types_D.IrqControlCap
    | Structures_A.IRQHandlerCap irq \<Rightarrow>
        Types_D.IrqHandlerCap irq
    | Structures_A.Zombie ptr _ _ \<Rightarrow>
        Types_D.ZombieCap ptr
    | Structures_A.ArchObjectCap arch_cap \<Rightarrow> (case arch_cap of
          ARM_A.ASIDControlCap \<Rightarrow>
            Types_D.AsidControlCap
        | ARM_A.ASIDPoolCap ptr asid \<Rightarrow>
            Types_D.AsidPoolCap ptr (fst $ (transform_asid asid))
        | ARM_A.PageCap dev ptr cap_rights_ sz mp \<Rightarrow>
            Types_D.FrameCap dev ptr cap_rights_ (pageBitsForSize sz) Real (transform_mapping mp)
        | ARM_A.PageTableCap ptr mp \<Rightarrow>
            Types_D.PageTableCap ptr Real (transform_mapping mp)
        | ARM_A.PageDirectoryCap ptr mp \<Rightarrow>
            Types_D.PageDirectoryCap ptr Real (option_map transform_asid mp)
        )
  "

(* Transform a list of (caps, refs) into CDL equivalents. *)
definition
  transform_cap_list :: "(cap \<times> cslot_ptr) list
      \<Rightarrow> (cdl_cap \<times> cdl_cap_ref) list"
where
  "transform_cap_list \<equiv>
     map (\<lambda>(cap, slot). (transform_cap cap, transform_cslot_ptr slot))"


\<comment> \<open>Convert a nat into a bool list of the given size.\<close>
definition
  nat_to_bl :: "nat \<Rightarrow> nat \<Rightarrow> bool list option"
where
  "nat_to_bl bits n \<equiv>
    if n \<ge> 2^bits then
      None
    else
      Some $ bin_to_bl bits (of_nat n)"

lemma nat_to_bl_id [simp]: "nat_to_bl (size (x :: (('a::len) word))) (unat x) = Some (to_bl x)"
  apply (clarsimp simp: nat_to_bl_def to_bl_def)
  apply (auto simp: uint_nat le_def word_size)
  done

(* FIXME: MOVE *)
definition
  option_join :: "'a option option \<Rightarrow> 'a option"
where
  "option_join x \<equiv> case x of
                      Some (Some y) \<Rightarrow> Some y
                    | _             \<Rightarrow> None"

definition
  option_map_join :: "('a \<Rightarrow> 'b option) \<Rightarrow> 'a option \<Rightarrow> 'b option"
where
  "option_map_join f x \<equiv> case x of
                      Some y        \<Rightarrow> f y
                    | _             \<Rightarrow> None"

lemmas option_map_join_simps = option_map_join_def [split_simps option.split]

(* Transform a CNode. *)

definition
  transform_cnode_contents :: "nat \<Rightarrow> cnode_contents \<Rightarrow> cdl_cap_map"
where
  "transform_cnode_contents sz c \<equiv> \<lambda>n. option_map transform_cap (option_map_join c (nat_to_bl sz n))"


(* Create a "TCB pending operation" cap based on the given thread's
 * current state. *)

definition
  infer_tcb_pending_op :: "obj_ref \<Rightarrow> Structures_A.thread_state \<Rightarrow> cdl_cap"
where
  "infer_tcb_pending_op ptr t \<equiv>
    case t of
        Structures_A.BlockedOnReceive ptr \<Rightarrow>
          PendingSyncRecvCap ptr False

      |Structures_A.BlockedOnReply \<Rightarrow>
          PendingSyncRecvCap ptr True

      | Structures_A.BlockedOnSend ptr payload \<Rightarrow>
          PendingSyncSendCap ptr
              (sender_badge payload) (sender_is_call payload)
              (sender_can_grant payload) False

      | Structures_A.BlockedOnNotification ptr \<Rightarrow>
          PendingNtfnRecvCap ptr

      | Structures_A.Restart \<Rightarrow> RestartCap

      | Structures_A.Running \<Rightarrow> RunningCap

      | _ \<Rightarrow> Types_D.NullCap
   "

(* Create a "Bound NTFN" cap based on the given thread's
 * current state. *)

definition
  infer_tcb_bound_notification :: "obj_ref option \<Rightarrow> cdl_cap"
where
  "infer_tcb_bound_notification a \<equiv> case a of
      Some ntfn \<Rightarrow> BoundNotificationCap ntfn
    | _ \<Rightarrow> Types_D.NullCap"

definition
  evalMonad :: "('s, 'a) nondet_monad \<Rightarrow> 's \<Rightarrow> 'a option"
where
  "evalMonad m s = (if fst (m s) = {} then None else Some (SOME x. x \<in> fst ` (fst (m s))))"

(* The monad here avoids repeating the def of loadWord *)
definition
  get_ipc_buffer_words :: "machine_state \<Rightarrow> tcb \<Rightarrow> nat list \<Rightarrow> word32 list"
where
  "get_ipc_buffer_words ms tcb ns \<equiv>
    let
      p = tcb_ipc_buffer tcb;
      cap = tcb_ipcframe tcb;
      wordsM = case cap of
               cap.ArchObjectCap (arch_cap.PageCap dev buf rights sz mapdata) \<Rightarrow> if AllowRead \<in> rights then
                   mapM loadWord (map (\<lambda>n. buf + (p && mask(pageBitsForSize sz)) + (of_nat (n * word_size))) ns)
                   else return []
              | _ \<Rightarrow> return []
    in
      the (evalMonad wordsM ms)"

definition
  get_tcb_message_info :: "tcb \<Rightarrow> Structures_A.message_info"
where
  "get_tcb_message_info t \<equiv> data_to_message_info ((arch_tcb_context_get (tcb_arch t)) msg_info_register)"

definition
  get_tcb_mrs :: "machine_state \<Rightarrow> tcb \<Rightarrow> word32 list"
where
  "get_tcb_mrs ms tcb \<equiv>
    let
      info = get_tcb_message_info tcb;
      cpu_mrs = map (arch_tcb_context_get (tcb_arch tcb)) msg_registers;
      mem_mrs = get_ipc_buffer_words ms tcb [length msg_registers + 1 ..< Suc msg_max_length]
    in
      (take (unat (mi_length info)) (cpu_mrs @ mem_mrs))"

(* Convert contents of the user's IPC buffer into an intent. *)
definition "guess_error \<equiv> \<lambda>x. x \<noteq> (0::word32)"

definition
  transform_full_intent :: "machine_state \<Rightarrow> obj_ref \<Rightarrow> tcb \<Rightarrow> cdl_full_intent"
where
  "transform_full_intent ms r tcb \<equiv>
  let mi = get_tcb_message_info tcb;
      offset = msg_max_length + msg_max_extra_caps + 2
  in
  \<lparr> cdl_intent_op = (transform_intent
                     (invocation_type (mi_label mi))
                     (get_tcb_mrs ms tcb)),
    cdl_intent_error = guess_error (mi_label mi),
    cdl_intent_cap = arch_tcb_context_get (tcb_arch tcb) cap_register,
    cdl_intent_extras = get_ipc_buffer_words ms tcb [buffer_cptr_index ..< buffer_cptr_index + (unat (mi_extra_caps mi))],
    cdl_intent_recv_slot = case (get_ipc_buffer_words ms tcb [offset ..< offset + 3]) of
                                [croot, index, depth] \<Rightarrow> Some (croot, index, unat depth)
                              | _                    \<Rightarrow> None
  \<rparr>"

lemma invocation_type0:
 "invocation_type 0 = InvalidInvocation"
   by (clarsimp simp:invocation_type_def
     toEnum_def enum_invocation_label)

(* Transform a TCB object. *)
abbreviation
  "tcb_has_fault \<equiv> \<lambda>tcb. tcb_fault tcb \<noteq> None"

definition
  transform_tcb :: "machine_state \<Rightarrow> obj_ref \<Rightarrow> tcb \<Rightarrow> etcb \<Rightarrow> cdl_object"
where
  "transform_tcb ms ptr tcb etcb \<equiv>
    Types_D.Tcb \<lparr> cdl_tcb_caps = [
                   tcb_cspace_slot \<mapsto> (transform_cap $ tcb_ctable tcb),
                   tcb_vspace_slot \<mapsto> (transform_cap $ tcb_vtable tcb),
                   tcb_replycap_slot \<mapsto> (transform_cap $ tcb_reply tcb),
                   tcb_caller_slot \<mapsto> (transform_cap $ tcb_caller tcb),
                   tcb_ipcbuffer_slot \<mapsto> (transform_cap $ tcb_ipcframe tcb),
                   tcb_pending_op_slot \<mapsto> (infer_tcb_pending_op ptr (tcb_state tcb)),
                   tcb_boundntfn_slot \<mapsto> (infer_tcb_bound_notification (tcb_bound_notification tcb))
                 ],

                 cdl_tcb_fault_endpoint = (of_bl (tcb_fault_handler tcb)),

                 \<comment> \<open>Decode the thread's intent.\<close>
                 cdl_tcb_intent = transform_full_intent ms ptr tcb,
                 cdl_tcb_has_fault = (tcb_has_fault tcb),
                 cdl_tcb_domain = tcb_domain etcb
                \<rparr>"

definition
  transform_asid_pool_entry :: "obj_ref option \<Rightarrow> cdl_cap"
where
  "transform_asid_pool_entry p \<equiv> case p of
       None \<Rightarrow> Types_D.NullCap
     | Some p \<Rightarrow> Types_D.PageDirectoryCap p Fake None"

(*
 * Transform an AsidPool.
 *
 * This converts the object references into PageDirectory caps.
 *)
definition
  transform_asid_pool_contents :: "(10 word \<Rightarrow> obj_ref option) \<Rightarrow> cdl_cap_map"
where
  "transform_asid_pool_contents M \<equiv> unat_map (Some \<circ> transform_asid_pool_entry \<circ> M)"

definition
  transform_paddr :: "paddr \<Rightarrow> cdl_object_id"
where
 "transform_paddr = ptrFromPAddr"

declare transform_paddr_def[simp]

(*
 * Transform a PageTable, one entry(PTE) at a time.
 *
 * This transforms the references to frames into frame caps.
 *)
definition
  transform_pte :: "ARM_A.pte \<Rightarrow> cdl_cap"
where
  "transform_pte pte \<equiv> case pte of
           ARM_A.InvalidPTE \<Rightarrow> cdl_cap.NullCap
         | ARM_A.LargePagePTE ref _ rights_ \<Rightarrow>
             Types_D.FrameCap False (transform_paddr ref) rights_
                              (pageBitsForSize ARMLargePage) Fake None
         | ARM_A.SmallPagePTE ref _ rights_ \<Rightarrow>
             Types_D.FrameCap False (transform_paddr ref) rights_
                              (pageBitsForSize ARMSmallPage) Fake None"

definition
  transform_page_table_contents :: "(word8 \<Rightarrow> ARM_A.pte) \<Rightarrow> (nat \<Rightarrow> cdl_cap option)"
where
  "transform_page_table_contents M \<equiv> unat_map (Some o transform_pte o M)"

(*
 * Transform a PageDirectory, one entry(PDE) at a time.
 *
 * This transforms the references to frames into PageTable or Frame caps.
 *)
definition
  transform_pde :: "ARM_A.pde \<Rightarrow> cdl_cap"
where
  "transform_pde pde \<equiv> case pde of
           ARM_A.InvalidPDE \<Rightarrow> cdl_cap.NullCap
         | ARM_A.PageTablePDE ref _ _ \<Rightarrow>
             Types_D.PageTableCap (transform_paddr ref) Fake None
         | ARM_A.SectionPDE ref _ _ rights_ \<Rightarrow>
             Types_D.FrameCap False (transform_paddr ref) rights_
                              (pageBitsForSize ARMSection) Fake None
         | ARM_A.SuperSectionPDE ref _ rights_ \<Rightarrow>
             Types_D.FrameCap False (transform_paddr ref) rights_
                              (pageBitsForSize ARMSuperSection) Fake None"

definition
  kernel_pde_mask ::  "(12 word \<Rightarrow> ARM_A.pde) \<Rightarrow> (12 word \<Rightarrow> ARM_A.pde)"
where
  "kernel_pde_mask M \<equiv> \<lambda>x.
  if (ucast (kernel_base >> 20)) \<le> x then ARM_A.InvalidPDE else M x"

definition
  transform_page_directory_contents :: "(12 word \<Rightarrow> ARM_A.pde) \<Rightarrow> (nat \<Rightarrow> cdl_cap option)"
where
  "transform_page_directory_contents M \<equiv> unat_map (Some o transform_pde o kernel_pde_mask M)"

(* sseefried: The 'undefined' case below will never occur as long as this function is invoked in an environment
   where the invariant 'valid_etcbs s' holds *)
(* Transform a kernel object. *)
definition
  transform_object :: "machine_state \<Rightarrow> obj_ref \<Rightarrow> etcb option \<Rightarrow> kernel_object \<Rightarrow> cdl_object"
  where
  "transform_object ms ref opt_etcb ko \<equiv> case ko of
           Structures_A.CNode 0 c \<Rightarrow>
              Types_D.IRQNode \<lparr>cdl_irq_node_caps = transform_cnode_contents 0 c\<rparr>
         | Structures_A.CNode sz c \<Rightarrow>
              Types_D.CNode \<lparr>
                cdl_cnode_caps = transform_cnode_contents sz c,
                cdl_cnode_size_bits = sz
                \<rparr>
         | Structures_A.TCB tcb \<Rightarrow> (case opt_etcb of Some etcb \<Rightarrow> transform_tcb ms ref tcb etcb | None \<Rightarrow> undefined)
         | Structures_A.Endpoint _ \<Rightarrow> Types_D.Endpoint
         | Structures_A.Notification _ \<Rightarrow> Types_D.Notification
         | Structures_A.ArchObj (ARM_A.ASIDPool ap) \<Rightarrow>
                Types_D.AsidPool \<lparr>cdl_asid_pool_caps = (transform_asid_pool_contents ap)\<rparr>
         | Structures_A.ArchObj (ARM_A.PageTable ptx) \<Rightarrow>
                Types_D.PageTable \<lparr>cdl_page_table_caps = (transform_page_table_contents ptx)\<rparr>
         | Structures_A.ArchObj (ARM_A.PageDirectory pd) \<Rightarrow>
                Types_D.PageDirectory \<lparr>cdl_page_directory_caps = (transform_page_directory_contents pd)\<rparr>
         | Structures_A.ArchObj (ARM_A.DataPage dev sz) \<Rightarrow>
                Types_D.Frame \<lparr>cdl_frame_size_bits = pageBitsForSize sz\<rparr>"

lemmas transform_object_simps [simp] =
  transform_object_def [split_simps Structures_A.kernel_object.split ARM_A.arch_kernel_obj.split]

(* Lifts a map over a function, returning the empty map if that
   function would be insufficiently injective *)
definition
  map_lift_over :: "('a \<Rightarrow> 'b) \<Rightarrow> ('a \<rightharpoonup> 'a) \<Rightarrow> ('b \<rightharpoonup> 'b)"
where
 "map_lift_over f m = (if inj_on f (dom m \<union> ran m)
    then (\<lambda>x. if \<exists>y. f y = x \<and> y \<in> dom m
              then map_option f (m (inv_into (dom m) f x)) else None)
    else Map.empty)"

(* Transform the CDT. *)
definition
  transform_cdt :: "'z::state_ext state \<Rightarrow> cdl_cdt"
where
  "transform_cdt s =
     map_lift_over transform_cslot_ptr (cdt s)"

definition
  get_obj :: "'z::state_ext state \<Rightarrow> obj_ref \<Rightarrow> kernel_object option"
where
  "get_obj s r \<equiv> (kheap s) r"

definition
  cap_installed_at_irq :: "irq \<Rightarrow> 'z::state_ext state \<Rightarrow> cap option"
where
  "cap_installed_at_irq irq s \<equiv> caps_of_state s (interrupt_irq_node s irq, [])"

abbreviation
  option_map2 :: "('a \<Rightarrow> 'b \<Rightarrow> 'c) \<Rightarrow> 'a option \<Rightarrow> 'b option \<Rightarrow> 'c option"
where
  "option_map2 f opt_a opt_b \<equiv> case opt_a of
                                   None \<Rightarrow> None
                                 | Some a \<Rightarrow> (case opt_b of
                                                 None \<Rightarrow> None
                                               | Some b \<Rightarrow> Some (f a b))"





(* Transform objects in the abstract spec to CapDL.
   Empty memory is transformed into Untyped objects. *)
definition
  transform_objects :: "det_ext state \<Rightarrow> (cdl_object_id \<Rightarrow> cdl_object option)"
where
   "transform_objects s = (\<lambda>ptr. Some Types_D.Untyped) |` (- {idle_thread s}) ++
                           (\<lambda>ptr. map_option (transform_object (machine_state s) ptr ((ekheap s |` (- {idle_thread s})) ptr))
                                ((kheap s  |` (- {idle_thread s})) ptr))"

lemma evalMonad_return [simp]:
  "evalMonad (return x) s = Some x"
  by (simp add: evalMonad_def return_def)

definition
  "det_or_fail f \<equiv> \<forall>s. fst (f s) = {} \<or> (\<exists>r. fst (f s) = {r})"

lemma evalMonad_bind:
  assumes f: "\<And>P. \<lbrace>P\<rbrace> f \<lbrace>\<lambda>_. P\<rbrace>"
  assumes det: "det_or_fail f"
  shows "evalMonad (f >>= g) s = (if evalMonad f s = None then None else evalMonad (g (the (evalMonad f s))) s)"
  apply (case_tac "evalMonad f s")
   apply (simp add: evalMonad_def split: if_split_asm)
   apply (simp add: bind_def)
  apply simp
  apply (simp add: evalMonad_def)
  apply (clarsimp simp: bind_def)
  apply (insert det)
  apply (clarsimp simp: det_or_fail_def split: if_split_asm)
  apply (erule_tac x=s in allE)
  apply clarsimp
  apply (subgoal_tac "b = s")
   apply simp
  apply (subgoal_tac "(a,b) \<in> fst (f s)")
   apply (drule use_valid, rule f [where P="(=) s"])
    apply (rule refl)
   apply simp
  apply simp
  done

lemma bind_dfI:
  "\<lbrakk> det_or_fail f; \<And>x. det_or_fail (g x) \<rbrakk> \<Longrightarrow> det_or_fail (f >>= g)"
  apply (auto simp: det_or_fail_def bind_def split_def)
  apply force
  done

lemma return_df:
  "det_or_fail (return x)"
  by (simp add: det_or_fail_def return_def)

lemma assert_df:
  "det_or_fail (assert P)"
  by (simp add: assert_def fail_def det_or_fail_def return_def)

lemma mapM_df:
  "(\<And>x. det_or_fail (f x)) \<Longrightarrow> det_or_fail (mapM f xs)"
  apply (induct xs)
   apply (simp add: mapM_Nil return_df)
  apply (simp add: mapM_Cons)
  apply (rule bind_dfI, assumption)
  apply (rule bind_dfI, assumption)
  apply (rule return_df)
  done

lemma df_loadWord: "det_or_fail (loadWord x)"
  apply (unfold loadWord_def)
  apply (rule bind_dfI)
   apply (simp add: simpler_gets_def det_or_fail_def)
  apply clarsimp
  apply (rule bind_dfI)
   apply (rule assert_df)
  apply (rule return_df)
  done

lemma evalMonad_loadWord_cong:
  "underlying_memory ms = underlying_memory ms' \<Longrightarrow>
  evalMonad (loadWord x) ms = evalMonad (loadWord x) ms'"
  by (simp add: loadWord_def bind_def simpler_gets_def assert_def
                return_def fail_def evalMonad_def)

lemma evalMonad_mapM_cong:
  assumes f: "\<And>x. evalMonad (f x) ms = evalMonad (f x) ms'"
  assumes P: "\<And>P x. \<lbrace>P\<rbrace> f x \<lbrace>\<lambda>_. P\<rbrace>"
  assumes det: "\<And>x. det_or_fail (f x)"
  shows "evalMonad (mapM f xs) ms = evalMonad (mapM f xs) ms'"
  apply (induct xs)
   apply (simp add: mapM_Nil)
  apply (simp add: mapM_Cons)
  apply (subst evalMonad_bind [OF P det])
  apply (subst evalMonad_bind [OF P det])
  apply (clarsimp simp: f)
  apply (subst evalMonad_bind)
    apply (wp mapM_wp' P)
   apply (rule mapM_df, rule det)
  apply (subst evalMonad_bind)
    apply (wp mapM_wp' P)
   apply (rule mapM_df, rule det)
  apply simp
  done

lemma evalMonad_mapM_loadWord_cong:
  "underlying_memory ms = underlying_memory ms' \<Longrightarrow>
   evalMonad (mapM loadWord xs) ms = evalMonad (mapM loadWord xs) ms'"
  apply (rule evalMonad_mapM_cong)
    apply (simp cong: evalMonad_loadWord_cong)
   apply (wp loadWord_inv)
  apply (rule df_loadWord)
  done

lemma get_ipc_buffer_words_cong:
  "underlying_memory ms = underlying_memory ms' \<Longrightarrow>
   get_ipc_buffer_words ms = get_ipc_buffer_words ms'"
  apply (rule ext)+
  apply (simp add: get_ipc_buffer_words_def Let_def cong: evalMonad_mapM_loadWord_cong
              split: cap.splits arch_cap.splits)
  done

lemma get_tcb_mrs_cong:
  "underlying_memory ms = underlying_memory ms' \<Longrightarrow> get_tcb_mrs ms = get_tcb_mrs ms'"
  apply (rule ext)
  apply (simp add: get_tcb_mrs_def Let_def cong: get_ipc_buffer_words_cong)
  done

lemma transform_objects_ms_underlying_mem:
  "transform_objects s =
   transform_objects (s \<lparr> machine_state :=
     undefined \<lparr> underlying_memory := underlying_memory (machine_state s) \<rparr> \<rparr>)"
  apply (rule ext)
  apply (simp add: transform_objects_def map_add_def option_map_def
            split: option.split)
  apply (simp add: transform_object_def transform_tcb_def
                   transform_full_intent_def Let_def
            split: Structures_A.kernel_object.split)
  apply (clarsimp simp: transform_intent_def cong: get_tcb_mrs_cong get_ipc_buffer_words_cong)
  done

lemmas transform_objects_def2
    = trans [OF transform_objects_ms_underlying_mem
                transform_objects_def,
             simplified]

(*
 * Transform the current thread in the abstract spec to CapDL.
 *
 * We just return the thread's memory address, unless it happens
 * to be the idle thread, which CapDL maps as "None".
 *)
definition
  transform_current_thread :: "'z::state_ext state \<Rightarrow> cdl_object_id option"
where
  "transform_current_thread s \<equiv>
    if (cur_thread s \<noteq> idle_thread s) then
      Some (cur_thread s)
    else
      None"

definition
  transform_asid_table_entry :: "obj_ref option \<Rightarrow> cdl_cap"
where
  "transform_asid_table_entry p \<equiv> case p of
       None \<Rightarrow> Types_D.NullCap
     | Some p \<Rightarrow> Types_D.AsidPoolCap p 0"

definition
  transform_asid_table :: "'z::state_ext state \<Rightarrow> cdl_cap_map"
where
  "transform_asid_table s \<equiv>
    let asid_table = arm_asid_table $ arch_state s
    in unat_map (Some \<circ> transform_asid_table_entry \<circ> asid_table)"

definition
  transform_current_domain :: "det_ext state \<Rightarrow> word8"
where
  "transform_current_domain s = cur_domain s"

(*
 * Transform an abstract spec state into the corresponding
 * CDL state.
 *)
definition
  transform :: "det_ext state \<Rightarrow> cdl_state"
where
  "transform s \<equiv> \<lparr>
    cdl_arch           = ARM11,
    cdl_objects        = transform_objects s,
    cdl_cdt            = transform_cdt s,
    cdl_current_thread = transform_current_thread s,
    cdl_irq_node       = interrupt_irq_node s,
    cdl_asid_table     = transform_asid_table s,
    cdl_current_domain = transform_current_domain s
    \<rparr>"

end

end

