(* * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) * * SPDX-License-Identifier: GPL-2.0-only *) theory Substitute imports "CKernel.Kernel_C" "AsmRefine.GlobalsSwap" begin ML \ structure SubstituteSpecs = struct val list_abs = uncurry (fold_rev (fn (x, T) => fn t => Abs (x, T, t))); fun get_rhs thm = snd (Logic.dest_equals (Thm.concl_of thm)) handle TYPE _ => snd (HOLogic.dest_eq (Thm.concl_of thm)); fun get_lhs thm = fst (Logic.dest_equals (Thm.concl_of thm)) handle TYPE _ => fst (HOLogic.dest_eq (Thm.concl_of thm)); fun term_convert prefix convs (tm as Const (name, _)) = if not (String.isPrefix prefix name) then tm else the (Termtab.lookup convs tm) | term_convert _ _ tm = tm; fun suspicious_term ctxt s t = if Term.add_var_names t [] = [] then () else (tracing ("suspicious " ^ s); Syntax.pretty_term ctxt t |> Pretty.string_of |> tracing; ()) val debug_trace = ref (Bound 0); fun convert prefix src_ctxt proc (tm as Const (name, _)) (convs, ctxt) = ((term_convert prefix convs tm; (convs, ctxt)) handle Option => let val cname = unprefix prefix name; val def_thm = Proof_Context.get_thm src_ctxt (cname ^ "_def") val rhs = get_rhs def_thm; val _ = suspicious_term ctxt "init rhs" rhs; val consts = Term.add_consts rhs []; val (convs, ctxt) = fold (convert prefix src_ctxt proc o Const) consts (convs, ctxt); val rhs' = map_aterms (term_convert prefix convs) rhs; val rhs'' = proc ctxt cname rhs'; val _ = suspicious_term ctxt "adjusted rhs" rhs''; in if rhs'' aconv rhs then (Termtab.insert (K true) (tm, tm) convs, ctxt |> Local_Theory.open_target |> snd |> Local_Theory.abbrev Syntax.mode_default ((Binding.name cname, NoSyn), get_lhs def_thm) |> snd |> Local_Theory.note ((Binding.name (cname ^ "_def"), []), [def_thm]) |> snd |> Local_Theory.close_target ) else let val _ = tracing ("Defining " ^ cname); val pre_def_ctxt = ctxt val b = Binding.name cname val ctxt = Local_Theory.open_target ctxt |> snd val ((tm', _), ctxt) = Local_Theory.define ((b, NoSyn), ((Thm.def_binding b, []), rhs'')) ctxt val tm'' = Morphism.term (Proof_Context.export_morphism ctxt pre_def_ctxt) tm' val ctxt = Local_Theory.close_target ctxt val lhs_argTs = get_lhs def_thm |> strip_comb |> snd |> map fastype_of; val abs_tm = list_abs (map (pair "_") lhs_argTs, tm'') in (Termtab.insert (K true) (tm, abs_tm) convs, ctxt) end end) | convert _ _ _ (tm) _ = raise TERM ("convert: not Const", [tm]) fun prove_impl_tac ctxt ss = SUBGOAL (fn (t, n) => let val lhs = t |> HOLogic.dest_Trueprop |> HOLogic.dest_eq |> fst; val cnames = Term.add_const_names lhs [] |> filter (String.isSuffix "_'proc"); val unfolds = map (Proof_Context.get_thm ctxt o suffix "_def" o Long_Name.base_name) cnames; in simp_tac (put_simpset ss ctxt addsimps unfolds) n end); fun convert_impls ctxt = let val thm = Proof_Context.get_thm ctxt "\_def" val proc_defs = (Term.add_const_names (Thm.concl_of thm) []) |> filter (String.isSuffix Hoare.proc_deco) |> map (suffix "_def" #> Proof_Context.get_thm ctxt) val tree_lemmata = StaticFun.prove_partial_map_thms thm (ctxt addsimps proc_defs) fun impl_name_from_proc (Const (s, _)) = s |> Long_Name.base_name |> unsuffix Hoare.proc_deco |> suffix HoarePackage.implementationN | impl_name_from_proc t = raise TERM ("impl_name_from_proc", [t]) val saves = tree_lemmata |> map (apfst (fst #> impl_name_from_proc)) in Local_Theory.notes (map (fn (n, t) => ((Binding.name n, []), [([t], [])])) saves) ctxt |> snd end fun take_all_actions prefix src_ctxt proc tm csenv styargs ctxt = let val (_, ctxt) = convert prefix src_ctxt proc tm (Termtab.empty, ctxt); in ctxt |> convert_impls |> Modifies_Proofs.prove_all_modifies_goals_local csenv (fn _ => true) styargs end end \ ML \ fun com_rewrite f t = case fastype_of t of (comT as Type (@{type_name com}, [s, _, ft])) => let val gd = Const (@{const_name Guard}, ft --> (HOLogic.mk_setT s) --> comT --> comT) fun add_guard ((f, gd_s), c) = gd $ f $ gd_s $ c; val seq = Const (@{const_name Seq}, comT --> comT --> comT); val skip = Const (@{const_name Skip}, comT); fun add_guards_to_seq gs (Const (@{const_name Seq}, _) $ a $ b) = seq $ add_guards_to_seq gs a $ b | add_guards_to_seq gs c = seq $ foldr add_guard skip gs $ c; fun add_guards c [] = c | add_guards ((w as Const (@{const_name While}, _)) $ S $ c) gs = seq $ (w $ S $ add_guards_to_seq gs c) $ foldr add_guard skip gs | add_guards (call as (Const (@{const_name call}, _) $ _ $ _ $ _ $ _)) gs = foldr add_guard (seq $ call $ foldr add_guard skip gs) gs | add_guards c gs = foldr add_guard c gs; fun inner t = case t of (Const (@{const_name "switch"}, T) $ v $ set_com_list) => let val (ss, cs) = map_split HOLogic.dest_prod (HOLogic.dest_list set_com_list); val cs' = map inner cs; val (v', gs) = f v; val (ss', gss) = map_split f ss; val listT = HOLogic.mk_prodT (HOLogic.mk_setT (range_type (domain_type T)), comT); in foldr add_guard (head_of t $ v' $ HOLogic.mk_list listT (map HOLogic.mk_prod (ss' ~~ cs'))) (gs @ flat gss) end | _ => let val (h, xs) = strip_comb t; (* assumption: we can only get into the com type with one of the constructors or pseudo-constructors, which don't need rewriting, so we can ignore h *) val xTs = xs ~~ (fastype_of h |> strip_type |> fst); fun upd_arg (x, T) = if T = comT then (inner x, []) else f x; val (ys, gss) = map_split upd_arg xTs; in add_guards (list_comb (h, ys)) (flat gss) end in inner (Envir.beta_eta_contract t) end | _ => t; \ setup \DefineGlobalsList.define_globals_list_i "../c/build/$L4V_ARCH/kernel_all.c_pp" @{typ globals}\ locale substitute_pre = fixes symbol_table :: "string \ addr" and domain :: "addr set" begin abbreviation "globals_list \ kernel_all_global_addresses.global_data_list" end locale kernel_all_substitute = substitute_pre begin ML \ fun mk_rew (t as Abs (s, T, _)) = mk_rew (betapply (t, Var ((s, 0), T))) | mk_rew t = HOLogic.dest_eq t val mk_varifyT = Term.map_types Logic.varifyT_global local val c_guard_rew = @{term "\p b. Guard C_Guard {s. c_guard (p s)} b = Guard C_Guard {s. h_t_valid (hrs_htd (t_hrs_' (globals s))) c_guard (p s)} b"} |> mk_varifyT |> mk_rew val c_guard_rew_weak = @{term "\p b. Guard C_Guard {s. c_guard (p s)} b = Guard C_Guard {s. ptr_safe (p s) (hrs_htd (t_hrs_' (globals s))) \ c_guard (p s)} b"} |> mk_varifyT |> mk_rew in fun strengthen_c_guards ss thy s = if (exists (curry (=) s) ss) then Pattern.rewrite_term thy [c_guard_rew_weak] [] else Pattern.rewrite_term thy [c_guard_rew] [] end; \ lemmas global_data_defs = kernel_all_global_addresses.global_data_defs lemmas globals_list_def = kernel_all_global_addresses.global_data_list_def ML \ (* the unvarify sets ?symbol_table back to symbol_table. be careful *) val global_datas = @{thms global_data_defs} |> map (Thm.concl_of #> Logic.unvarify_global #> Logic.dest_equals #> snd #> Envir.beta_eta_contract) val const_globals = map_filter (fn (Const (@{const_name const_global_data}, _) $ nm $ t) => SOME (HOLogic.dest_string nm, t) | _ => NONE) global_datas local val hrs_htd_update_guard_rew1 = @{term "\u. Basic (\s. globals_update (t_hrs_'_update (hrs_htd_update (u s))) s) = Guard C_Guard {s. globals_list_distinct (fst ` dom_s (u s (hrs_htd (t_hrs_' (globals s))))) symbol_table globals_list} (Basic (\s. globals_update (t_hrs_'_update (id hrs_htd_update (u s))) s))"} |> mk_rew val hrs_htd_update_guard_rew2 = @{term "t_hrs_'_update (id hrs_htd_update f) = t_hrs_'_update (hrs_htd_update f)"} |> Logic.varify_global |> HOLogic.dest_eq; val consts = map snd const_globals val index_eq_set_helper = Syntax.parse_term @{context} (String.concat ["\str t n c. {s :: globals myvars. c \", "h_val (hrs_mem (t_hrs_' (globals s)))", " (CTypesDefs.ptr_add (Ptr (symbol_table str)) (of_nat (n s)))", " = t s}"]) val eq_set_helper = Syntax.parse_term @{context} (String.concat ["\str t c. {s :: globals myvars. c \", "h_val (hrs_mem (t_hrs_' (globals s)))", " (Ptr (symbol_table str)) = t}"]) val s = @{term "s :: globals myvars"} val grab_name_str = head_of #> dest_Const #> fst #> Long_Name.base_name #> HOLogic.mk_string in fun const_global_asserts ctxt cond (t as (Const (@{const_name index}, _) $ arr $ n)) = if member (=) consts arr then [(index_eq_set_helper $ grab_name_str arr $ lambda s t $ lambda s n $ cond) |> Syntax.check_term ctxt] else [] | const_global_asserts ctxt cond (Const c) = if member (=) consts (Const c) then [(eq_set_helper $ grab_name_str (Const c) $ Const c $ cond) |> Syntax.check_term ctxt] else [] | const_global_asserts ctxt cond (f $ x) = if member (=) consts (f $ x) then [(eq_set_helper $ grab_name_str (f $ x) $ (f $ x) $ cond) |> Syntax.check_term ctxt] else const_global_asserts ctxt cond f @ const_global_asserts ctxt cond x | const_global_asserts ctxt cond (a as Abs (_, @{typ "globals myvars"}, _)) = const_global_asserts ctxt cond (betapply (a, s)) | const_global_asserts ctxt cond (Abs (_, _, t)) = const_global_asserts ctxt cond t | const_global_asserts _ _ _ = [] fun guard_rewritable_globals const_cond ctxt = Pattern.rewrite_term @{theory} [hrs_htd_update_guard_rew2] [] o Pattern.rewrite_term @{theory} [hrs_htd_update_guard_rew1] [] o com_rewrite (fn t => (t, map (pair @{term C_Guard}) (case const_cond of SOME cond => const_global_asserts ctxt cond t | NONE => []))) val guard_htd_updates_with_domain = com_rewrite (fn t => if fastype_of t = @{typ "globals myvars \ globals myvars"} andalso Term.exists_Const (fn (s, _) => s = @{const_name "hrs_htd_update"}) t then (t, [(@{term MemorySafety}, betapply (@{term "\f :: globals myvars \ globals myvars. {s. htd_safe domain (hrs_htd (t_hrs_' (globals s))) \ htd_safe domain (hrs_htd (t_hrs_' (globals (f s))))}"}, t))]) else (t, [])) val guard_halt = com_rewrite (fn t => if t = @{term "halt_'proc"} then (t, [(@{term DontReach}, @{term "{} :: globals myvars set"})]) else (t, [])) fun acc_ptr_adds (Const (@{const_name h_val}, _) $ m $ (Const (@{const_name ptr_add}, _) $ p $ n)) = [(p, n, true)] @ maps acc_ptr_adds [m, p, n] | acc_ptr_adds (Const (@{const_name heap_update}, _) $ (Const (@{const_name ptr_add}, _) $ p $ n)) = [(p, n, true)] @ maps acc_ptr_adds [p, n] | acc_ptr_adds (Const (@{const_name ptr_add}, _) $ p $ n) = [(p, n, false)] @ maps acc_ptr_adds [p, n] | acc_ptr_adds (f $ x) = maps acc_ptr_adds [f, x] | acc_ptr_adds (abs as Abs (_, T, t)) = if T = @{typ "globals myvars"} then acc_ptr_adds (betapply (abs, @{term "s :: globals myvars"})) else acc_ptr_adds t | acc_ptr_adds _ = [] fun mk_bool true = @{term True} | mk_bool false = @{term False} val guard_acc_ptr_adds = com_rewrite (fn t => (t, acc_ptr_adds t |> map (fn (p, n, strong) => let val assn = Const (@{const_name ptr_add_assertion'}, fastype_of p --> @{typ "int \ bool \ heap_typ_desc \ bool"}) $ p $ n $ mk_bool strong $ @{term "hrs_htd (t_hrs_' (globals (s :: globals myvars)))"} val gd = HOLogic.mk_Collect ("s", @{typ "globals myvars"}, assn) in (@{term MemorySafety}, gd) end))) end \ cond_sorry_modifies_proofs SORRY_MODIFIES_PROOFS local_setup \ SubstituteSpecs.take_all_actions "Kernel_C.kernel_all_global_addresses." (Locale.init "Kernel_C.kernel_all_global_addresses" @{theory}) (fn ctxt => fn s => guard_rewritable_globals NONE ctxt o (strengthen_c_guards ["memset_body", "memcpy_body", "memzero_body"] (Proof_Context.theory_of ctxt) s) o guard_halt o guard_htd_updates_with_domain o guard_acc_ptr_adds) @{term kernel_all_global_addresses.\} (CalculateState.get_csenv @{theory} "../c/build/$L4V_ARCH/kernel_all.c_pp" |> the) [@{typ "globals myvars"}, @{typ int}, @{typ strictc_errortype}] \ end end