diff --git a/_CoqProject b/_CoqProject index 502c7b66..118bcb2d 100644 --- a/_CoqProject +++ b/_CoqProject @@ -7,13 +7,6 @@ case_study/MinimalCaps/Base.v case_study/MinimalCaps/Contracts.v case_study/MinimalCaps/Machine.v case_study/MinimalCaps/Model.v --Q case_study/RiscvPmp Katamaran.RiscvPmp -case_study/RiscvPmp/Base.v -case_study/RiscvPmp/Contracts.v -case_study/RiscvPmp/Machine.v -case_study/RiscvPmp/Model.v -case_study/RiscvPmp/LoopVerification.v -case_study/RiscvPmp/BlockVerification.v -R theories Katamaran test/Example.v test/LinkedList.v diff --git a/case_study/.gitattributes b/case_study/.gitattributes deleted file mode 100644 index ca1d4079..00000000 --- a/case_study/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -RiscvPmp export-ignore diff --git a/case_study/RiscvPmp/Base.v b/case_study/RiscvPmp/Base.v deleted file mode 100644 index 1b61e71f..00000000 --- a/case_study/RiscvPmp/Base.v +++ /dev/null @@ -1,792 +0,0 @@ -(******************************************************************************) -(* Copyright (c) 2020 Steven Keuchel, Dominique Devriese, Sander Huyghebaert *) -(* All rights reserved. *) -(* *) -(* Redistribution and use in source and binary forms, with or without *) -(* modification, are permitted provided that the following conditions are *) -(* met: *) -(* *) -(* 1. Redistributions of source code must retain the above copyright notice, *) -(* this list of conditions and the following disclaimer. *) -(* *) -(* 2. Redistributions in binary form must reproduce the above copyright *) -(* notice, this list of conditions and the following disclaimer in the *) -(* documentation and/or other materials provided with the distribution. *) -(* *) -(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) -(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) -(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *) -(* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR *) -(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *) -(* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *) -(* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *) -(* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *) -(* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *) -(* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *) -(* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) -(******************************************************************************) - -From Coq Require Import - Strings.String - ZArith.ZArith. -From Equations Require Import - Equations. -From stdpp Require - finite. -From Katamaran Require Import - Base - Syntax.TypeDecl. - -Local Unset Equations Derive Equations. -Local Set Implicit Arguments. - -(* Taken from Coq >= 8.15 SigTNotations *) -Local Notation "( x ; y )" := (existT x y) (only parsing). - -Definition Xlenbits : Set := Z. -Definition Addr : Set := Z. -Definition Word : Set := Z. - -(* Parameter minAddr : Addr. *) -(* Parameter maxAddr : Addr. *) -Definition minAddr : Addr := 0%Z. -Definition maxAddr : Addr := 10%Z. - -Inductive Privilege : Set := -| User -| Machine -. - -(* Enum for available CRSs' *) -Inductive CSRIdx : Set := -| MStatus -| MTvec -| MCause -| MEpc -| MPMP0CFG -| MPMP1CFG -| MPMPADDR0 -| MPMPADDR1 -. - -(* NOTE: PMP CSRs limited to 1 for now *) -Inductive PmpCfgIdx : Set := -| PMP0CFG -| PMP1CFG -. - -Inductive PmpAddrIdx : Set := -| PMPADDR0 -| PMPADDR1 -. - -(* NOTE: PMP Addr Match Type limited to OFF and TOR for now *) -Inductive PmpAddrMatchType : Set := -| OFF -| TOR -. - -Inductive PmpMatch : Set := -| PMP_Success -| PMP_Continue -| PMP_Fail -. - -Inductive PmpAddrMatch : Set := -| PMP_NoMatch -| PMP_PartialMatch -| PMP_Match -. - -Inductive ROP : Set := -| RISCV_ADD -| RISCV_SUB -. - -Inductive IOP : Set := -| RISCV_ADDI -. - -Inductive UOP : Set := -| RISCV_LUI -| RISCV_AUIPC -. - -Inductive BOP : Set := -| RISCV_BEQ -| RISCV_BNE -| RISCV_BLT -| RISCV_BGE -| RISCV_BLTU -| RISCV_BGEU -. - -(* Zicsr extension, only support for Read-Write (no set or clear) *) -Inductive CSROP : Set := -| CSRRW -. - -Inductive Retired : Set := -| RETIRE_SUCCESS -| RETIRE_FAIL. - -Inductive Enums : Set := -| privilege -| csridx -| pmpcfgidx -| pmpaddridx -| pmpaddrmatchtype -| pmpmatch -| pmpaddrmatch -| rop -| iop -| uop -| bop -| csrop -| retired -. - -Definition RegIdx := bv 3. -Bind Scope bv_scope with RegIdx. - -Inductive AST : Set := -| RTYPE (rs2 rs1 rd : RegIdx) (op : ROP) -| ITYPE (imm : Z) (rs1 rd : RegIdx) (op : IOP) -| UTYPE (imm : Z) (rd : RegIdx) (op : UOP) -| BTYPE (imm : Z) (rs2 rs1 : RegIdx) (op : BOP) -| RISCV_JAL (imm : Z) (rd : RegIdx) -| RISCV_JALR (imm : Z) (rs1 rd : RegIdx) -| LOAD (imm : Z) (rs1 rd : RegIdx) -| STORE (imm : Z) (rs2 rs1 : RegIdx) -| ECALL -| MRET -(* Ziscr extension, excluding immediate variants *) -| CSR (csr : CSRIdx) (rs1 rd : RegIdx) (csrop : CSROP) -. - -Inductive AccessType : Set := -| Read -| Write -| ReadWrite -| Execute -. - -Inductive ExceptionType : Set := -| E_Fetch_Access_Fault -| E_Load_Access_Fault -| E_SAMO_Access_Fault -| E_U_EnvCall -| E_M_EnvCall -| E_Illegal_Instr -. - -Inductive MemoryOpResult : Set := -| MemValue (v : Word) -| MemException (e : ExceptionType) -. - -Inductive FetchResult : Set := -| F_Base (v : Word) -| F_Error (e : ExceptionType) (v : Xlenbits) -. - -(* NOTE: simplified to only take the ctl_trap constructor into account - (other constructors are for mret, sret and uret, not considered atm) *) -Inductive CtlResult : Set := -| CTL_TRAP (e : ExceptionType) -| CTL_MRET -. - -Inductive ASTConstructor : Set := -| KRTYPE -| KITYPE -| KUTYPE -| KBTYPE -| KRISCV_JAL -| KRISCV_JALR -| KLOAD -| KSTORE -| KECALL -| KMRET -| KCSR -. - -Inductive AccessTypeConstructor : Set := -| KRead -| KWrite -| KReadWrite -| KExecute -. - -Inductive ExceptionTypeConstructor : Set := -| KE_Fetch_Access_Fault -| KE_Load_Access_Fault -| KE_SAMO_Access_Fault -| KE_U_EnvCall -| KE_M_EnvCall -| KE_Illegal_Instr -. - -Inductive MemoryOpResultConstructor : Set := -| KMemValue -| KMemException -. - -Inductive FetchResultConstructor : Set := -| KF_Base -| KF_Error -. - -Inductive CtlResultConstructor : Set := -| KCTL_TRAP -| KCTL_MRET -. - -Inductive Unions : Set := -| ast -| access_type -| exception_type -| memory_op_result -| fetch_result -| ctl_result -(* | pmp_entries *) -. - -Record Pmpcfg_ent : Set := - MkPmpcfg_ent - { L : bool; - A : PmpAddrMatchType; - X : bool; - W : bool; - R : bool; - }. - -Record Mstatus : Set := - MkMstatus - { MPP : Privilege - }. - -Inductive Records : Set := -| rpmpcfg_ent -| rmstatus -. - -Section TransparentObligations. - Local Set Transparent Obligations. - - Derive NoConfusion for Enums. - Derive NoConfusion for Privilege. - Derive NoConfusion for CSRIdx. - Derive NoConfusion for PmpCfgIdx. - Derive NoConfusion for PmpAddrIdx. - Derive NoConfusion for PmpAddrMatchType. - Derive NoConfusion for PmpMatch. - Derive NoConfusion for PmpAddrMatch. - Derive NoConfusion for ROP. - Derive NoConfusion for IOP. - Derive NoConfusion for UOP. - Derive NoConfusion for BOP. - Derive NoConfusion for CSROP. - Derive NoConfusion for Retired. - Derive NoConfusion for Unions. - Derive NoConfusion for AST. - Derive NoConfusion for ASTConstructor. - Derive NoConfusion for AccessType. - Derive NoConfusion for AccessTypeConstructor. - Derive NoConfusion for ExceptionType. - Derive NoConfusion for ExceptionTypeConstructor. - Derive NoConfusion for MemoryOpResult. - Derive NoConfusion for MemoryOpResultConstructor. - Derive NoConfusion for FetchResult. - Derive NoConfusion for FetchResultConstructor. - Derive NoConfusion for CtlResult. - Derive NoConfusion for CtlResultConstructor. - Derive NoConfusion for Records. - Derive NoConfusion for Pmpcfg_ent. - Derive NoConfusion for Mstatus. -End TransparentObligations. - -Derive EqDec for Enums. -Derive EqDec for Privilege. -Derive EqDec for CSRIdx. -Derive EqDec for PmpCfgIdx. -Derive EqDec for PmpAddrIdx. -Derive EqDec for PmpAddrMatchType. -Derive EqDec for PmpMatch. -Derive EqDec for PmpAddrMatch. -Derive EqDec for ROP. -Derive EqDec for IOP. -Derive EqDec for UOP. -Derive EqDec for BOP. -Derive EqDec for CSROP. -Derive EqDec for Retired. -Derive EqDec for Unions. -Derive EqDec for AST. -Derive EqDec for ASTConstructor. -Derive EqDec for AccessType. -Derive EqDec for AccessTypeConstructor. -Derive EqDec for ExceptionType. -Derive EqDec for ExceptionTypeConstructor. -Derive EqDec for MemoryOpResult. -Derive EqDec for MemoryOpResultConstructor. -Derive EqDec for FetchResult. -Derive EqDec for FetchResultConstructor. -Derive EqDec for CtlResult. -Derive EqDec for CtlResultConstructor. -Derive EqDec for Records. -Derive EqDec for Pmpcfg_ent. -Derive EqDec for Mstatus. - -Section Finite. - Import stdpp.finite. - - Local Obligation Tactic := - finite_from_eqdec. - - #[export,program] Instance Privilege_finite : Finite Privilege := - {| enum := [User;Machine] |}. - - #[export,program] Instance CSRIdx_finite : Finite CSRIdx := - {| enum := [MStatus;MTvec;MCause;MEpc;MPMP0CFG;MPMP1CFG;MPMPADDR0;MPMPADDR1] |}. - - #[export,program] Instance PmpCfgIdx_finite : Finite PmpCfgIdx := - {| enum := [PMP0CFG;PMP1CFG] |}. - - #[export,program] Instance PmpAddrIdx_finite : Finite PmpAddrIdx := - {| enum := [PMPADDR0;PMPADDR1] |}. - - #[export,program] Instance PmpAddrMatchType_finite : Finite PmpAddrMatchType := - {| enum := [OFF;TOR] |}. - - #[export,program] Instance PmpMatch_finite : Finite PmpMatch := - {| enum := [PMP_Success;PMP_Continue;PMP_Fail] |}. - - #[export,program] Instance PmpAddrMatch_finite : Finite PmpAddrMatch := - {| enum := [PMP_NoMatch;PMP_PartialMatch;PMP_Match] |}. - - #[export,program] Instance ROP_finite : - Finite ROP := - {| enum := [RISCV_ADD;RISCV_SUB] |}. - - #[export,program] Instance IOP_finite : - Finite IOP := - {| enum := [RISCV_ADDI] |}. - - #[export,program] Instance UOP_finite : - Finite UOP := - {| enum := [RISCV_LUI;RISCV_AUIPC] |}. - - #[export,program] Instance BOP_finite : - Finite BOP := - {| enum := [RISCV_BEQ;RISCV_BNE;RISCV_BLT;RISCV_BGE;RISCV_BLTU;RISCV_BGEU] |}. - - #[export,program] Instance CSROP_finite : - Finite CSROP := - {| enum := [CSRRW] |}. - - #[export,program] Instance Retired_finite : - Finite Retired := - {| enum := [RETIRE_SUCCESS; RETIRE_FAIL] |}. - - #[export,program] Instance ASTConstructor_finite : - Finite ASTConstructor := - {| enum := [KRTYPE;KITYPE;KUTYPE;KBTYPE;KRISCV_JAL;KRISCV_JALR;KLOAD;KSTORE;KECALL;KMRET;KCSR] |}. - - #[export,program] Instance AccessType_finite : - Finite AccessType := - {| enum := [Read; Write; ReadWrite; Execute] |}. - - #[export,program] Instance AccessTypeConstructor_finite : - Finite AccessTypeConstructor := - {| enum := [KRead;KWrite;KReadWrite;KExecute] |}. - - #[export,program] Instance ExceptionTypeConstructor_finite : - Finite ExceptionTypeConstructor := - {| enum := [KE_Fetch_Access_Fault;KE_Load_Access_Fault;KE_SAMO_Access_Fault; - KE_U_EnvCall;KE_M_EnvCall;KE_Illegal_Instr] |}. - - #[export,program] Instance MemoryOpResultConstructor_finite : - Finite MemoryOpResultConstructor := - {| enum := [KMemValue;KMemException] |}. - - #[export,program] Instance FetchResultConstructor_finite : - Finite FetchResultConstructor := - {| enum := [KF_Base;KF_Error] |}. - - #[export,program] Instance CtlResultConstructor_finite : - Finite CtlResultConstructor := - {| enum := [KCTL_TRAP;KCTL_MRET] |}. - -End Finite. - -Module Export RiscvPmpBase <: Base. - - Import ctx.notations. - Import ctx.resolution. - Import env.notations. - Import stdpp.finite. - - #[export] Instance typedeclkit : TypeDeclKit := - {| enumi := Enums; - unioni := Unions; - recordi := Records; - |}. - - (* Override notations of bindigns to put the variable x into string_scope. *) - Notation "x ∷ t" := (MkB x%string t) : ctx_scope. - - Notation ty_xlenbits := (ty.int). - Notation ty_word := (ty.int). - Notation ty_regno := (ty.bvec 3). - Notation ty_privilege := (ty.enum privilege). - Notation ty_csridx := (ty.enum csridx). - Notation ty_pmpcfgidx := (ty.enum pmpcfgidx). - Notation ty_pmpaddridx := (ty.enum pmpaddridx). - Notation ty_pmpaddrmatchtype := (ty.enum pmpaddrmatchtype). - Notation ty_pmpmatch := (ty.enum pmpmatch). - Notation ty_pmpaddrmatch := (ty.enum pmpaddrmatch). - Notation ty_pmp_addr_range := (ty.option (ty.prod ty_xlenbits ty_xlenbits)). - Notation ty_rop := (ty.enum rop). - Notation ty_iop := (ty.enum iop). - Notation ty_uop := (ty.enum uop). - Notation ty_bop := (ty.enum bop). - Notation ty_csrop := (ty.enum csrop). - Notation ty_retired := (ty.enum retired). - Notation ty_mcause := (ty_xlenbits). - Notation ty_exc_code := (ty.int). - Notation ty_ast := (ty.union ast). - Notation ty_access_type := (ty.union access_type). - Notation ty_exception_type := (ty.union exception_type). - Notation ty_memory_op_result := (ty.union memory_op_result). - Notation ty_fetch_result := (ty.union fetch_result). - Notation ty_ctl_result := (ty.union ctl_result). - Notation ty_pmpcfg_ent := (ty.record rpmpcfg_ent). - Notation ty_mstatus := (ty.record rmstatus). - Notation ty_pmpentry := (ty.prod ty_pmpcfg_ent ty_xlenbits). - - Definition enum_denote (e : Enums) : Set := - match e with - | privilege => Privilege - | csridx => CSRIdx - | pmpcfgidx => PmpCfgIdx - | pmpaddridx => PmpAddrIdx - | pmpaddrmatchtype => PmpAddrMatchType - | pmpmatch => PmpMatch - | pmpaddrmatch => PmpAddrMatch - | rop => ROP - | iop => IOP - | uop => UOP - | bop => BOP - | csrop => CSROP - | retired => Retired - end. - - Definition union_denote (U : Unions) : Set := - match U with - | ast => AST - | access_type => AccessType - | exception_type => ExceptionType - | memory_op_result => MemoryOpResult - | fetch_result => FetchResult - | ctl_result => CtlResult - (* | pmp_entries => Coq type in the model for pmp_entries *) - end. - - Definition record_denote (R : Records) : Set := - match R with - | rpmpcfg_ent => Pmpcfg_ent - | rmstatus => Mstatus - end. - - #[export] Instance typedenotekit : TypeDenoteKit typedeclkit := - {| enumt := enum_denote; - uniont := union_denote; - recordt := record_denote; - |}. - - Definition union_constructor (U : Unions) : Set := - match U with - | ast => ASTConstructor - | access_type => AccessTypeConstructor - | exception_type => ExceptionTypeConstructor - | memory_op_result => MemoryOpResultConstructor - | fetch_result => FetchResultConstructor - | ctl_result => CtlResultConstructor - (* | pmp_entries => PmpEntriesConstructor *) - end. - - Definition union_constructor_type (U : Unions) : union_constructor U -> Ty := - match U with - | ast => fun K => - match K with - | KRTYPE => ty.tuple [ty_regno; ty_regno; ty_regno; ty_rop] - | KITYPE => ty.tuple [ty.int; ty_regno; ty_regno; ty_iop] - | KUTYPE => ty.tuple [ty.int; ty_regno; ty_uop] - | KBTYPE => ty.tuple [ty.int; ty_regno; ty_regno; ty_bop] - | KRISCV_JAL => ty.tuple [ty.int; ty_regno] - | KRISCV_JALR => ty.tuple [ty.int; ty_regno; ty_regno] - | KLOAD => ty.tuple [ty.int; ty_regno; ty_regno] - | KSTORE => ty.tuple [ty.int; ty_regno; ty_regno] - | KECALL => ty.unit - | KMRET => ty.unit - | KCSR => ty.tuple [ty_csridx; ty_regno; ty_regno; ty_csrop] - end - | access_type => fun _ => ty.unit - | exception_type => fun _ => ty.unit - | memory_op_result => fun K => - match K with - | KMemValue => ty_word - | KMemException => ty_exception_type - end - | fetch_result => fun K => - match K with - | KF_Base => ty_word - | KF_Error => ty.prod ty_exception_type ty_word - end - | ctl_result => fun K => - match K with - | KCTL_TRAP => ty_exception_type - | KCTL_MRET => ty.unit - end - end. - - #[export] Instance eqdec_enum_denote E : EqDec (enum_denote E) := - ltac:(destruct E; auto with typeclass_instances). - #[export] Instance finite_enum_denote E : finite.Finite (enum_denote E) := - ltac:(destruct E; auto with typeclass_instances). - #[export] Instance eqdec_union_denote U : EqDec (union_denote U) := - ltac:(destruct U; cbn; auto with typeclass_instances). - #[export] Instance eqdec_union_constructor U : EqDec (union_constructor U) := - ltac:(destruct U; cbn; auto with typeclass_instances). - #[export] Instance finite_union_constructor U : finite.Finite (union_constructor U) := - ltac:(destruct U; cbn; auto with typeclass_instances). - #[export] Instance eqdec_record_denote R : EqDec (record_denote R) := - ltac:(destruct R; auto with typeclass_instances). - - Definition union_unfold (U : unioni) : uniont U -> { K & Val (union_constructor_type U K) } := - match U with - | ast => fun Kv => - match Kv with - | RTYPE rs2 rs1 rd op => existT KRTYPE (tt , rs2 , rs1 , rd , op) - | ITYPE imm rs1 rd op => existT KITYPE (tt , imm , rs1 , rd , op) - | UTYPE imm rd op => existT KUTYPE (tt , imm , rd , op) - | BTYPE imm rs2 rs1 op => existT KBTYPE (tt , imm , rs2 , rs1 , op) - | RISCV_JAL imm rd => existT KRISCV_JAL (tt , imm , rd) - | RISCV_JALR imm rs1 rd => existT KRISCV_JALR (tt , imm , rs1 , rd) - | LOAD imm rs1 rd => existT KLOAD (tt , imm , rs1 , rd) - | STORE imm rs2 rs1 => existT KSTORE (tt , imm , rs2 , rs1) - | ECALL => existT KECALL tt - | MRET => existT KMRET tt - | CSR csr rs1 rd op => existT KCSR (tt , csr , rs1 , rd , op) - end - | access_type => fun Kv => - match Kv with - | Read => existT KRead tt - | Write => existT KWrite tt - | ReadWrite => existT KReadWrite tt - | Execute => existT KExecute tt - end - | exception_type => fun Kv => - match Kv with - | E_Fetch_Access_Fault => existT KE_Fetch_Access_Fault tt - | E_Load_Access_Fault => existT KE_Load_Access_Fault tt - | E_SAMO_Access_Fault => existT KE_SAMO_Access_Fault tt - | E_U_EnvCall => existT KE_U_EnvCall tt - | E_M_EnvCall => existT KE_M_EnvCall tt - | E_Illegal_Instr => existT KE_Illegal_Instr tt - end - | memory_op_result => fun Kv => - match Kv with - | MemValue v => existT KMemValue v - | MemException e => existT KMemException e - end - | fetch_result => fun Kv => - match Kv with - | F_Base v => existT KF_Base v - | F_Error e v => existT KF_Error (e , v) - end - | ctl_result => fun Kv => - match Kv with - | CTL_TRAP e => existT KCTL_TRAP e - | CTL_MRET => existT KCTL_MRET tt - end - end. - - Definition union_fold (U : unioni) : { K & Val (union_constructor_type U K) } -> uniont U := - match U with - | ast => fun Kv => - match Kv with - | existT KRTYPE (tt , rs2 , rs1 , rd , op) => RTYPE rs2 rs1 rd op - | existT KITYPE (tt , imm , rs1 , rd , op) => ITYPE imm rs1 rd op - | existT KUTYPE (tt , imm , rd , op) => UTYPE imm rd op - | existT KBTYPE (tt , imm , rs2 , rs1 , op) => BTYPE imm rs2 rs1 op - | existT KRISCV_JAL (tt , imm , rd) => RISCV_JAL imm rd - | existT KRISCV_JALR (tt , imm , rs1 , rd) => RISCV_JALR imm rs1 rd - | existT KLOAD (tt , imm , rs1 , rd) => LOAD imm rs1 rd - | existT KSTORE (tt , imm , rs2 , rs1) => STORE imm rs2 rs1 - | existT KECALL tt => ECALL - | existT KMRET tt => MRET - | existT KCSR (tt , csr , rs1 , rd , op) => CSR csr rs1 rd op - end - | access_type => fun Kv => - match Kv with - | existT KRead tt => Read - | existT KWrite tt => Write - | existT KReadWrite tt => ReadWrite - | existT KExecute tt => Execute - end - | exception_type => fun Kv => - match Kv with - | existT KE_Fetch_Access_Fault tt => E_Fetch_Access_Fault - | existT KE_Load_Access_Fault tt => E_Load_Access_Fault - | existT KE_SAMO_Access_Fault tt => E_SAMO_Access_Fault - | existT KE_U_EnvCall tt => E_U_EnvCall - | existT KE_M_EnvCall tt => E_M_EnvCall - | existT KE_Illegal_Instr tt => E_Illegal_Instr - end - | memory_op_result => fun Kv => - match Kv with - | existT KMemValue v => MemValue v - | existT KMemException e => MemException e - end - | fetch_result => fun Kv => - match Kv with - | existT KF_Base v => F_Base v - | existT KF_Error (e , v) => F_Error e v - end - | ctl_result => fun Kv => - match Kv with - | existT KCTL_TRAP e => CTL_TRAP e - | existT KCTL_MRET tt => CTL_MRET - end - end. - - Definition record_field_type (R : recordi) : NCtx string Ty := - match R with - | rpmpcfg_ent => [ "L" ∷ ty.bool; - "A" ∷ ty_pmpaddrmatchtype; - "X" ∷ ty.bool; - "W" ∷ ty.bool; - "R" ∷ ty.bool - ] - | rmstatus => ["MPP" ∷ ty_privilege - ] - end. - - Equations record_fold (R : recordi) : NamedEnv Val (record_field_type R) -> recordt R := - | rpmpcfg_ent | [l;a;x;w;r]%env := MkPmpcfg_ent l a x w r - | rmstatus | [mpp]%env := MkMstatus mpp. - - Equations record_unfold (R : recordi) : recordt R -> NamedEnv Val (record_field_type R) := - | rpmpcfg_ent | p => [kv (_ ∷ ty.bool ; L p); - (_ ∷ ty_pmpaddrmatchtype ; A p); - (_ ∷ ty.bool ; X p); - (_ ∷ ty.bool ; W p); - (_ ∷ ty.bool ; R p) ]; - | rmstatus | m => [kv ("MPP" ∷ ty_privilege; MPP m) ]. - - #[export,refine] Instance typedefkit : TypeDefKit typedenotekit := - {| unionk := union_constructor; - unionk_ty := union_constructor_type; - recordf := string; - recordf_ty := record_field_type; - unionv_fold := union_fold; - unionv_unfold := union_unfold; - recordv_fold := record_fold; - recordv_unfold := record_unfold; - |}. - Proof. - - abstract (now intros [] []). - - abstract (intros [] [[] x]; cbn in x; - repeat - match goal with - | x: unit |- _ => destruct x - | x: prod _ _ |- _ => destruct x - end; auto). - - abstract (now intros [] []). - - abstract (intros []; now apply env.Forall_forall). - Defined. - - Canonical typedeclkit. - Canonical typedenotekit. - Canonical typedefkit. - - #[export] Instance varkit : VarKit := DefaultVarKit. - - Section RegDeclKit. - - Inductive Reg : Ty -> Set := - | pc : Reg ty_xlenbits - | nextpc : Reg ty_xlenbits - | mstatus : Reg ty_mstatus - | mtvec : Reg ty_xlenbits - | mcause : Reg ty_exc_code - | mepc : Reg ty_xlenbits - | cur_privilege : Reg ty_privilege - | x1 : Reg ty_xlenbits - | x2 : Reg ty_xlenbits - | x3 : Reg ty_xlenbits - | x4 : Reg ty_xlenbits - | x5 : Reg ty_xlenbits - | x6 : Reg ty_xlenbits - | x7 : Reg ty_xlenbits - | pmp0cfg : Reg ty_pmpcfg_ent - | pmp1cfg : Reg ty_pmpcfg_ent - | pmpaddr0 : Reg ty_xlenbits - | pmpaddr1 : Reg ty_xlenbits - . - - Import bv.notations. - Definition reg_convert (idx : RegIdx) : option (Reg ty_xlenbits) := - match bv.to_bitstring idx with - | 000 => None - | 001 => Some x1 - | 010 => Some x2 - | 011 => Some x3 - | 100 => Some x4 - | 101 => Some x5 - | 110 => Some x6 - | 111 => Some x7 - end. - - Section TransparentObligations. - Local Set Transparent Obligations. - Derive Signature NoConfusion NoConfusionHom EqDec for Reg. - End TransparentObligations. - - Definition 𝑹𝑬𝑮 : Ty -> Set := Reg. - - Instance 𝑹𝑬𝑮_eq_dec : EqDec (sigT Reg) := - sigma_eqdec _ _. - - Local Obligation Tactic := - finite_from_eqdec. - - Program Instance 𝑹𝑬𝑮_finite : Finite (sigT Reg) := - {| enum := - [ existT _ pc; - existT _ nextpc; - existT _ mstatus; - existT _ mtvec; - existT _ mcause; - existT _ mepc; - existT _ cur_privilege; - existT _ x1; - existT _ x2; - existT _ x3; - existT _ x4; - existT _ x5; - existT _ x6; - existT _ x7; - existT _ pmp0cfg; - existT _ pmp1cfg; - existT _ pmpaddr0; - existT _ pmpaddr1 - ]%list - |}. - - End RegDeclKit. - - Include BaseMixin. - -End RiscvPmpBase. diff --git a/case_study/RiscvPmp/BlockVerification.v b/case_study/RiscvPmp/BlockVerification.v deleted file mode 100644 index 841aeac9..00000000 --- a/case_study/RiscvPmp/BlockVerification.v +++ /dev/null @@ -1,2348 +0,0 @@ -(******************************************************************************) -(* Copyright (c) 2020 Steven Keuchel, Dominique Devriese, Sander Huyghebaert *) -(* All rights reserved. *) -(* *) -(* Redistribution and use in source and binary forms, with or without *) -(* modification, are permitted provided that the following conditions are *) -(* met: *) -(* *) -(* 1. Redistributions of source code must retain the above copyright notice, *) -(* this list of conditions and the following disclaimer. *) -(* *) -(* 2. Redistributions in binary form must reproduce the above copyright *) -(* notice, this list of conditions and the following disclaimer in the *) -(* documentation and/or other materials provided with the distribution. *) -(* *) -(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) -(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) -(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *) -(* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR *) -(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *) -(* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *) -(* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *) -(* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *) -(* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *) -(* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *) -(* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) -(******************************************************************************) - -From Coq Require Import - ZArith.ZArith - Lists.List - micromega.Lia - Strings.String. -From Equations Require Import - Equations. -From Katamaran Require Import - Iris.Logic - Iris.Model - Notations - Semantics - Sep.Hoare - Sep.Logic - Shallow.Executor - Shallow.Soundness - Specification - Symbolic.Executor - Symbolic.Propositions - Symbolic.Solver - Symbolic.Soundness - Symbolic.Worlds - RiscvPmp.Machine. -From Katamaran Require - RiscvPmp.Model - RiscvPmp.Contracts - RiscvPmp.LoopVerification. -From iris.base_logic Require lib.gen_heap lib.iprop invariants. -From iris.bi Require interface big_op. -From iris.algebra Require dfrac. -From iris.program_logic Require weakestpre adequacy. -From iris.proofmode Require string_ident tactics. -From stdpp Require namespaces. - -Import RiscvPmpProgram. - -Set Implicit Arguments. -Import ctx.resolution. -Import ctx.notations. -Import env.notations. -Import ListNotations. -Open Scope string_scope. -Open Scope ctx_scope. -Open Scope Z_scope. - -Module ns := stdpp.namespaces. - -(* Definition pmp_entry_cfg := ty_prod ty_pmpcfg_ent ty_xlenbits. *) - -Module RiscvPmpBlockVerifSpec <: Specification RiscvPmpBase RiscvPmpProgram Contracts.RiscvPmpSignature. - Include SpecificationMixin RiscvPmpBase RiscvPmpProgram Contracts.RiscvPmpSignature. - Import Contracts.RiscvPmpSignature. - Import Contracts. - Section ContractDefKit. - - Notation "a '↦ₘ' t" := (asn_chunk (chunk_user ptsto [a; t])) (at level 70). - Notation "a '↦ᵢ' t" := (asn_chunk (chunk_user ptstoinstr [a; t])) (at level 70). - Notation "p '∗' q" := (asn_sep p q). - Notation "a '=' b" := (asn_eq a b). - Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - Notation "a '∨' b" := (asn_or a b). - Notation "a <ₜ b" := (term_binop bop.lt a b) (at level 60). - Notation "a <=ₜ b" := (term_binop bop.le a b) (at level 60). - Notation "a &&ₜ b" := (term_binop bop.and a b) (at level 80). - Notation "a ||ₜ b" := (term_binop bop.or a b) (at level 85). - Notation asn_match_option T opt xl alt_inl alt_inr := (asn_match_sum T ty.unit opt xl alt_inl "_" alt_inr). - Notation asn_pmp_entries l := (asn_chunk (chunk_user pmp_entries [l])). - - Definition term_eqb {Σ} (e1 e2 : Term Σ ty_regno) : Term Σ ty.bool := - term_binop bop.eq e1 e2. - - Local Notation "e1 '=?' e2" := (term_eqb e1 e2). - - Definition z_term {Σ} : Z -> Term Σ ty.int := term_val ty.int. - - Definition sep_contract_logvars (Δ : PCtx) (Σ : LCtx) : LCtx := - ctx.map (fun '(x::σ) => x::σ) Δ ▻▻ Σ. - - Definition create_localstore (Δ : PCtx) (Σ : LCtx) : SStore Δ (sep_contract_logvars Δ Σ) := - (env.tabulate (fun '(x::σ) xIn => - @term_var - (sep_contract_logvars Δ Σ) - x - σ - (ctx.in_cat_left Σ (ctx.in_map (fun '(y::τ) => y::τ) xIn)))). - - Definition SepContractFun {Δ τ} (f : Fun Δ τ) : Type := - SepContract Δ τ. - - Definition SepContractFunX {Δ τ} (f : FunX Δ τ) : Type := - SepContract Δ τ. - - Definition SepLemma {Δ} (f : Lem Δ) : Type := - Lemma Δ. - - Fixpoint asn_exists {Σ} (Γ : NCtx string Ty) : Assertion (Σ ▻▻ Γ) -> Assertion Σ := - match Γ return Assertion (Σ ▻▻ Γ) -> Assertion Σ with - | ctx.nil => fun asn => asn - | ctx.snoc Γ (x :: τ) => - fun asn => - @asn_exists Σ Γ (asn_exist x τ asn) - end. - - Definition asn_with_reg {Σ} (r : Term Σ ty_regno) (asn : Reg ty_xlenbits -> Assertion Σ) (asn_default : Assertion Σ) : Assertion Σ := - asn_if (r =? term_val ty_regno (bv.of_N 0)) (asn_default) - (asn_if (r =? term_val ty_regno (bv.of_N 1)) (asn x1) - (asn_if (r =? term_val ty_regno (bv.of_N 2)) (asn x2) - (asn_if (r =? term_val ty_regno (bv.of_N 3)) (asn x3) - (asn_if (r =? term_val ty_regno (bv.of_N 4)) (asn x4) - (asn_if (r =? term_val ty_regno (bv.of_N 5)) (asn x5) - (asn_if (r =? term_val ty_regno (bv.of_N 6)) (asn x6) - (asn_if (r =? term_val ty_regno (bv.of_N 7)) (asn x7) - asn_false))))))). - - Definition asn_reg_ptsto {Σ} (r : Term Σ ty_regno) (w : Term Σ ty_word) : Assertion Σ := - asn_with_reg r (fun r => asn_chunk (chunk_ptsreg r w)) (asn_eq w (term_val ty.int 0%Z)). - - Local Notation "e1 ',ₜ' e2" := (term_binop bop.pair e1 e2) (at level 100). - - Notation "r '↦' val" := (asn_chunk (asn_reg_ptsto [r; val])) (at level 79). - (* TODO: abstract away the concrete type, look into unions for that *) - (* TODO: length of list should be 16, no duplicates *) - Definition pmp_entries {Σ} : Term Σ (ty.list (ty.prod ty_pmpcfgidx ty_pmpaddridx)) := - term_list - (cons (term_val ty_pmpcfgidx PMP0CFG ,ₜ term_val ty_pmpaddridx PMPADDR0) - (cons (term_val ty_pmpcfgidx PMP1CFG ,ₜ term_val ty_pmpaddridx PMPADDR1) nil)). - - End ContractDefKit. - - Local Notation "r '↦' val" := (asn_reg_ptsto r val) (at level 79). - Local Notation "a '↦ₘ' t" := (asn_chunk (chunk_user ptsto [a; t])) (at level 70). - Local Notation "a '↦ᵢ' t" := (asn_chunk (chunk_user ptstoinstr [a; t])) (at level 70). - Local Notation "p '∗' q" := (asn_sep p q). - Local Notation "a '=' b" := (asn_eq a b). - Local Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - Local Notation "a '∨' b" := (asn_or a b). - Local Notation "a <ₜ b" := (term_binop bop.lt a b) (at level 60). - Local Notation "a <=ₜ b" := (term_binop bop.le a b) (at level 60). - Local Notation "a &&ₜ b" := (term_binop bop.and a b) (at level 80). - Local Notation "a ||ₜ b" := (term_binop bop.or a b) (at level 85). - Local Notation asn_match_option T opt xl alt_inl alt_inr := (asn_match_sum T ty.unit opt xl alt_inl "_" alt_inr). - Local Notation asn_pmp_entries l := (asn_chunk (chunk_user pmp_entries [l])). - Local Notation "e1 ',ₜ' e2" := (term_binop bop.pair e1 e2) (at level 100). - Import bv.notations. - - - Definition sep_contract_rX : SepContractFun rX := - {| sep_contract_logic_variables := ["rs" :: ty_regno; "w" :: ty_word]; - sep_contract_localstore := [term_var "rs"]; - sep_contract_precondition := term_var "rs" ↦ term_var "w"; - sep_contract_result := "result_rX"; - sep_contract_postcondition := term_var "result_rX" = term_var "w" ∗ - term_var "rs" ↦ term_var "w"; - |}. - - Definition sep_contract_wX : SepContractFun wX := - {| sep_contract_logic_variables := ["rs" :: ty_regno; "v" :: ty_xlenbits; "w" :: ty_xlenbits]; - sep_contract_localstore := [term_var "rs"; term_var "v"]; - sep_contract_precondition := term_var "rs" ↦ term_var "w"; - sep_contract_result := "result_wX"; - sep_contract_postcondition := term_var "result_wX" = term_val ty.unit tt ∗ - asn_if (term_eqb (term_var "rs") (term_val ty_regno [bv 0])) - (term_var "rs" ↦ term_val ty.int 0%Z) - (term_var "rs" ↦ term_var "v") - |}. - - Definition sep_contract_fetch : SepContractFun fetch := - {| sep_contract_logic_variables := ["a" :: ty_xlenbits; "w" :: ty.int]; - sep_contract_localstore := []; - sep_contract_precondition := asn_chunk (chunk_ptsreg pc (term_var "a")) ∗ - term_var "a" ↦ₘ term_var "w"; - sep_contract_result := "result_fetch"; - sep_contract_postcondition := asn_chunk (chunk_ptsreg pc (term_var "a")) ∗ - term_var "a" ↦ₘ term_var "w" ∗ - term_var "result_fetch" = term_union fetch_result KF_Base (term_var "w"); - |}. - - Definition sep_contract_fetch_instr : SepContractFun fetch := - {| sep_contract_logic_variables := ["a" :: ty_xlenbits; "i" :: ty_ast]; - sep_contract_localstore := []; - sep_contract_precondition := asn_chunk (chunk_ptsreg pc (term_var "a")) ∗ - term_var "a" ↦ᵢ term_var "i"; - sep_contract_result := "result_fetch"; - sep_contract_postcondition := - asn_chunk (chunk_ptsreg pc (term_var "a")) ∗ term_var "a" ↦ᵢ term_var "i" ∗ - asn_exist "w" _ - (term_var "result_fetch" = term_union fetch_result KF_Base (term_var "w") ∗ - asn_chunk (chunk_user encodes_instr [term_var "w"; term_var "i"])); - |}. - - Definition sep_contract_mem_read : SepContractFun mem_read := - {| sep_contract_logic_variables := ["typ" :: ty_access_type; "paddr" :: ty_xlenbits; "w" :: ty_xlenbits]; - sep_contract_localstore := [term_var "typ"; term_var "paddr"]; - sep_contract_precondition := term_var "paddr" ↦ₘ term_var "w"; - sep_contract_result := "result_mem_read"; - sep_contract_postcondition := - term_var "result_mem_read" = term_union memory_op_result KMemValue (term_var "w") ∗ - term_var "paddr" ↦ₘ term_var "w"; - |}. - - Definition sep_contract_tick_pc : SepContractFun tick_pc := - {| sep_contract_logic_variables := ["ao" :: ty_xlenbits; "an" :: ty_xlenbits]; - sep_contract_localstore := []; - sep_contract_precondition := asn_chunk (chunk_ptsreg pc (term_var "ao")) ∗ - asn_chunk (chunk_ptsreg nextpc (term_var "an")); - sep_contract_result := "result_tick_pc"; - sep_contract_postcondition := asn_chunk (chunk_ptsreg pc (term_var "an")) ∗ - asn_chunk (chunk_ptsreg nextpc (term_var "an")) ∗ - term_var "result_tick_pc" = term_val ty.unit tt; - |}. - - Definition CEnv : SepContractEnv := - fun Δ τ f => - match f with - | rX => Some sep_contract_rX - | wX => Some sep_contract_wX - | fetch => Some sep_contract_fetch_instr - | mem_read => Some sep_contract_mem_read - | tick_pc => Some sep_contract_tick_pc - | _ => None - end. - - Lemma linted_cenv : - forall Δ τ (f : Fun Δ τ), - match CEnv f with - | Some c => Linted c - | None => True - end. - Proof. intros ? ? []; try constructor. Qed. - - Definition sep_contract_read_ram : SepContractFunX read_ram := - {| sep_contract_logic_variables := ["paddr" :: ty_xlenbits; "w" :: ty_xlenbits]; - sep_contract_localstore := [term_var "paddr"]; - sep_contract_precondition := term_var "paddr" ↦ₘ term_var "w"; - sep_contract_result := "result_read_ram"; - sep_contract_postcondition := term_var "paddr" ↦ₘ term_var "w" ∗ - term_var "result_read_ram" = term_var "w"; - |}. - - Definition sep_contract_write_ram : SepContractFunX write_ram := - {| sep_contract_logic_variables := ["paddr" :: ty.int; "data" :: ty_word]; - sep_contract_localstore := [term_var "paddr"; term_var "data"]; - sep_contract_precondition := ∃ "w", (term_var "paddr" ↦ₘ term_var "w"); - sep_contract_result := "result_write_ram"; - sep_contract_postcondition := term_var "paddr" ↦ₘ term_var "data" ∗ - term_var "result_write_ram" = term_val ty.int 1%Z; - |}. - - Definition sep_contract_decode : SepContractFunX decode := - {| sep_contract_logic_variables := ["code" :: ty.int; "instr" :: ty_ast]; - sep_contract_localstore := [term_var "code"]; - sep_contract_precondition := asn_chunk (chunk_user encodes_instr [term_var "code"; term_var "instr"]); - sep_contract_result := "result_decode"; - sep_contract_postcondition := term_var "result_decode" = term_var "instr"; - |}. - - Definition CEnvEx : SepContractEnvEx := - fun Δ τ f => - match f with - | read_ram => sep_contract_read_ram - | write_ram => sep_contract_write_ram - | decode => sep_contract_decode - end. - - Lemma linted_cenvex : - forall Δ τ (f : FunX Δ τ), - Linted (CEnvEx f). - Proof. - intros ? ? []; try constructor. - Qed. - - Definition lemma_open_gprs : SepLemma open_gprs := - {| lemma_logic_variables := ctx.nil; - lemma_patterns := env.nil; - lemma_precondition := asn_true; - lemma_postcondition := asn_true; - |}. - - Definition lemma_close_gprs : SepLemma close_gprs := - {| lemma_logic_variables := ctx.nil; - lemma_patterns := env.nil; - lemma_precondition := asn_true; - lemma_postcondition := asn_true; - |}. - - Definition lemma_open_pmp_entries : SepLemma open_pmp_entries := - {| lemma_logic_variables := ctx.nil; - lemma_patterns := env.nil; - lemma_precondition := asn_true; - lemma_postcondition := asn_true; - |}. - - Definition lemma_close_pmp_entries : SepLemma close_pmp_entries := - {| lemma_logic_variables := ctx.nil; - lemma_patterns := env.nil; - lemma_precondition := asn_true; - lemma_postcondition := asn_true; - |}. - - Definition lemma_update_pmp_entries : SepLemma update_pmp_entries := - {| lemma_logic_variables := ctx.nil; - lemma_patterns := env.nil; - lemma_precondition := asn_true; - lemma_postcondition := asn_true; - |}. - - Definition lemma_extract_pmp_ptsto : SepLemma extract_pmp_ptsto := - {| lemma_logic_variables := ["paddr" :: ty_xlenbits]; - lemma_patterns := [term_var "paddr"]; - lemma_precondition := asn_true; - lemma_postcondition := asn_true; - |}. - - Definition lemma_return_pmp_ptsto : SepLemma return_pmp_ptsto := - {| lemma_logic_variables := ["paddr" :: ty_xlenbits]; - lemma_patterns := [term_var "paddr"]; - lemma_precondition := asn_true; - lemma_postcondition := asn_true; - |}. - - Definition LEnv : LemmaEnv := - fun Δ l => - match l with - | open_gprs => lemma_open_gprs - | close_gprs => lemma_close_gprs - | open_pmp_entries => lemma_open_pmp_entries - | close_pmp_entries => lemma_close_pmp_entries - | update_pmp_entries => lemma_update_pmp_entries - | extract_pmp_ptsto => lemma_extract_pmp_ptsto - | return_pmp_ptsto => lemma_return_pmp_ptsto - end. -End RiscvPmpBlockVerifSpec. - -Module RiscvPmpBlockVerifShalExecutor := - MakeShallowExecutor RiscvPmpBase RiscvPmpProgram Contracts.RiscvPmpSignature RiscvPmpBlockVerifSpec. -Module RiscvPmpBlockVerifExecutor := - MakeExecutor RiscvPmpBase RiscvPmpProgram Contracts.RiscvPmpSignature RiscvPmpBlockVerifSpec Contracts.RiscvPmpSolver. - -Module RiscvPmpSpecVerif. - Import Contracts.RiscvPmpSignature. - Import RiscvPmpBlockVerifSpec. - Import RiscvPmpBlockVerifExecutor.Symbolic. - - Notation "r '↦' val" := (chunk_ptsreg r val) (at level 79). - - Import ModalNotations. - - Definition ValidContract {Δ τ} (f : Fun Δ τ) : Prop := - match CEnv f with - | Some c => ValidContractReflect c (FunDef f) - | None => False - end. - - Lemma valid_execute_rX : ValidContract rX. - Proof. reflexivity. Qed. - - Lemma valid_execute_wX : ValidContract wX. - Proof. reflexivity. Qed. - - Lemma valid_execute_fetch : ValidContract fetch. - Proof. Admitted. - - (* Lemma valid_execute_fetch_instr : SMut.ValidContract sep_contract_fetch_instr (FunDef fetch). *) - (* Proof. compute. Admitted. *) - - Lemma valid_execute_tick_pc : ValidContract tick_pc. - Proof. reflexivity. Qed. - - Lemma defined_contracts_valid : forall {Δ τ} (f : Fun Δ τ), - match CEnv f with - | Some c => ValidContract f - | None => True - end. - Proof. - destruct f; try now cbv. - Admitted. - -End RiscvPmpSpecVerif. - -Module RiscvPmpIrisInstanceWithContracts. - Include ProgramLogicOn RiscvPmpBase RiscvPmpProgram Contracts.RiscvPmpSignature RiscvPmpBlockVerifSpec. - Include IrisInstanceWithContracts RiscvPmpBase RiscvPmpProgram Model.RiscvPmpSemantics - Contracts.RiscvPmpSignature RiscvPmpBlockVerifSpec Model.RiscvPmpIrisBase Model.RiscvPmpIrisInstance. - Include Shallow.Soundness.Soundness RiscvPmpBase RiscvPmpProgram Contracts.RiscvPmpSignature - RiscvPmpBlockVerifSpec RiscvPmpBlockVerifShalExecutor. - Include Symbolic.Soundness.Soundness RiscvPmpBase RiscvPmpProgram Contracts.RiscvPmpSignature - RiscvPmpBlockVerifSpec Contracts.RiscvPmpSolver RiscvPmpBlockVerifShalExecutor RiscvPmpBlockVerifExecutor. -End RiscvPmpIrisInstanceWithContracts. - - -Module BlockVerification. - Import Contracts.RiscvPmpSignature. - Import RiscvPmpBlockVerifSpec. - Import RiscvPmpBlockVerifExecutor. - - Notation "r '↦' val" := (chunk_ptsreg r val) (at level 79). - - Import ModalNotations. - Import bv.notations. - - Definition M : TYPE -> TYPE := SHeapSpecM [] []. - - Definition pure {A} : ⊢ A -> M A := SHeapSpecM.pure. - Definition bind {A B} : ⊢ M A -> □(A -> M B) -> M B := SHeapSpecM.bind. - Definition angelic {σ} : ⊢ M (STerm σ) := @SHeapSpecM.angelic [] None σ. - Definition assert : ⊢ Formula -> M Unit := SHeapSpecM.assert_formula. - Definition assume : ⊢ Formula -> M Unit := SHeapSpecM.assume_formula. - - Definition produce_chunk : ⊢ Chunk -> M Unit := SHeapSpecM.produce_chunk. - Definition consume_chunk : ⊢ Chunk -> M Unit := SHeapSpecM.consume_chunk. - - Definition produce : ⊢ Assertion -> □(M Unit) := SHeapSpecM.produce. - Definition consume : ⊢ Assertion -> □(M Unit) := SHeapSpecM.consume. - - Notation "ω ∣ x <- ma ;; mb" := - (bind ma (fun _ ω x => mb)) - (at level 80, x at next level, - ma at next level, mb at level 200, - right associativity). - - Definition rX (r : Reg ty_xlenbits) : ⊢ M (STerm ty_xlenbits) := - fun _ => - ω01 ∣ v1 <- @angelic ty_xlenbits _ ;; - ω12 ∣ _ <- consume_chunk (r ↦ v1) ;; - let v2 := persist__term v1 ω12 in - ω23 ∣ _ <- produce_chunk (r ↦ v2) ;; - let v3 := persist__term v2 ω23 in - pure v3. - - Definition wX (r : Reg ty_xlenbits) : ⊢ STerm ty_xlenbits -> M Unit := - fun _ u0 => - ω01 ∣ v1 <- @angelic ty_xlenbits _ ;; - ω12 ∣ _ <- consume_chunk (r ↦ v1) ;; - let u2 := persist__term u0 (acc_trans ω01 ω12) in - produce_chunk (r ↦ u2). - - Definition exec_rtype (rs2 rs1 rd : Reg ty_xlenbits) (op : ROP) : ⊢ M Unit := - fun _ => - ω01 ∣ v11 <- @rX rs1 _ ;; - ω12 ∣ v22 <- @rX rs2 _ ;; - let v12 := persist__term v11 ω12 in - let bop := match op with - | RISCV_ADD => bop.plus - | RISCV_SUB => bop.minus - end in - wX rd (peval_binop bop v12 v22). - - Definition exec_instruction (i : AST) : ⊢ M Unit := - match i with - | RTYPE rs2 rs1 rd op => - match reg_convert rs2, reg_convert rs1, reg_convert rd with - | Some rs2, Some rs1, Some rd => exec_rtype rs2 rs1 rd op - | _, _, _ => fun _ => pure tt - end - | _ => fun _ => pure tt - end. - - (* Ideally, a block should be a list of non-branching - instruction plus one final branching instruction *) - Fixpoint exec_block (b : list AST) : ⊢ M Unit := - fun _ => - match b with - | nil => pure tt - | cons i b' => - _ ∣ _ <- @exec_instruction i _ ;; - @exec_block b' _ - end. - - Definition ADD (rd rs1 rs2 : RegIdx) : AST := - RTYPE rs2 rs1 rd RISCV_ADD. - Definition SUB (rd rs1 rs2 : RegIdx) : AST := - RTYPE rs2 rs1 rd RISCV_SUB. - Definition BEQ (rs1 rs2 : RegIdx) (imm : Z) : AST := - BTYPE imm rs2 rs1 RISCV_BEQ. - Definition BNE (rs1 rs2 : RegIdx) (imm : Z) : AST := - BTYPE imm rs2 rs1 RISCV_BNE. - Definition ADDI (rd rs1 : RegIdx) (imm : Z) : AST := - ITYPE imm rs1 rd RISCV_ADDI. - Definition JALR (rd rs1 : RegIdx) (imm : Z) : AST := - RISCV_JALR imm rs1 rd. - Definition RET : AST := - JALR [bv 0] [bv 1] 0%Z. - Definition MV (rd rs1 : RegIdx) : AST := - ADDI rd rs1 0%Z. - - Definition exec_double {Σ : World} - (req : Assertion Σ) (b : list AST) : M Unit Σ := - ω1 ∣ _ <- T (produce req) ;; - @exec_block b _. - - Definition exec_triple {Σ : World} - (req : Assertion Σ) (b : list AST) (ens : Assertion Σ) : M Unit Σ := - ω ∣ _ <- exec_double req b ;; - consume ens ω. - - Module Post := Postprocessing. - (* This is a VC for triples, for doubles we probably need to talk - about the continuation of a block. *) - Definition VC {Σ : LCtx} (req : Assertion Σ) (b : list AST) (ens : Assertion Σ) : 𝕊 Σ := - Post.prune (Post.solve_uvars (Post.prune (Post.solve_evars (Post.prune - (@exec_triple - {| wctx := Σ; wco := nil |} - req b ens - (* Could include leakcheck here *) - (fun _ _ _ _ h => SymProp.block) - []%env []%list))))). - - Section Example. - - Import ListNotations. - Notation "p '∗' q" := (asn_sep p q). - - Example block1 : list AST := - [ ADD [bv 1] [bv 1] [bv 2] - ; SUB [bv 2] [bv 1] [bv 2] - ; SUB [bv 1] [bv 1] [bv 2] - ]. - - Let Σ1 : LCtx := ["x" :: ty_xlenbits; "y" :: ty_xlenbits]. - - Local Notation "r '↦' val" := (asn_chunk (chunk_ptsreg r val)) (at level 79). - - Example pre1 : Assertion Σ1 := - x1 ↦ term_var "x" ∗ - x2 ↦ term_var "y". - - Example post1 : Assertion Σ1 := - x1 ↦ term_var "y" ∗ - x2 ↦ term_var "x". - - Example VC1 : 𝕊 Σ1 := VC pre1 block1 post1. - - Eval compute in VC1. - - End Example. - - Module SUM. - - Definition zero : RegIdx := [bv 0]. - Definition ra : RegIdx := [bv 1]. - Definition a0 : RegIdx := [bv 2]. - Definition a4 : RegIdx := [bv 3]. - Definition a5 : RegIdx := [bv 4]. - Definition rra := x1. - Definition ra0 := x2. - Definition ra4 := x3. - Definition ra5 := x4. - - (* C SOURCE *) - (* int sum(int n) { *) - (* int s = 0; *) - (* for (int i = 0; i != n; ++i) { *) - (* s = s + i; *) - (* } *) - (* return s; *) - (* } *) - - (* 0000000000000000 : *) - (* 0: 00050713 addi a4,a0,0 *) - (* 4: 00050e63 beq a0,zero,20 <.L4> *) - (* 8: 00000793 addi a5,zero,0 *) - (* c: 00000513 addi a0,zero,0 *) - (* 0000000000000010 <.L3>: *) - (* 10: 00f5053b addw a0,a0,a5 *) - (* 14: 0017879b addiw a5,a5,1 *) - (* 18: fef71ce3 bne a4,a5,10 <.L3> *) - (* 1c: 00008067 jalr zero,0(ra) *) - (* 0000000000000020 <.L4>: *) - (* 20: 00008067 jalr zero,0(ra) *) - - Example block_sum : list AST := - [ ADDI a4 a0 0 - ; BEQ a0 zero 0x20 - ; ADDI a5 zero 0 - ; ADDI a0 zero 0 - ]. - - Example block_l3 : list AST := - [ ADD a0 a0 a5 - ; ADDI a5 a5 1 - ; BNE a4 a5 (-0x8) - ]. - - Example block_l4 : list AST := - [ RET - ]. - - Example sum : list AST := - block_sum ++ block_l3 ++ block_l4. - - Local Notation "p '∗' q" := (asn_sep p q). - Local Notation "r '↦' val" := (asn_chunk (chunk_ptsreg r val)) (at level 79). - Local Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - Local Notation "x - y" := (term_binop bop.minus x y) : exp_scope. - Local Notation "x + y" := (term_binop bop.plus x y) : exp_scope. - Local Notation "x * y" := (term_binop bop.times x y) : exp_scope. - - Section BlockSum. - - Let Σ1 : LCtx := ["n" ∷ ty.int]. - - Example sum_pre : Assertion Σ1 := - asn_exist "s" _ (ra0 ↦ term_var "s") ∗ - ra4 ↦ term_var "n" ∗ - asn_exist "i" _ (ra5 ↦ term_var "i") ∗ - asn_bool (term_binop bop.le (term_val ty.int 0%Z) (term_var "n")). - - Example sum_post : Assertion Σ1 := - ra0 ↦ term_val ty.int 0%Z ∗ - ra4 ↦ term_var "n" ∗ - ra5 ↦ term_val ty.int 0%Z ∗ - asn_bool (term_binop bop.le (term_val ty.int 0%Z) (term_var "n")). - - Example vc_sum : 𝕊 Σ1 := - VC sum_pre block_sum sum_post. - - Eval compute in vc_sum. - - End BlockSum. - - Let Σ1 : LCtx := ["n" ∷ ty.int; "s" ∷ ty.int; "i" ∷ ty.int]. - - (* Example sum_pre : Assertion Σ1 := *) - (* ra0 ↦ term_var "s" ∗ *) - (* ra4 ↦ term_var "n" ∗ *) - (* ra5 ↦ term_var "i" ∗ *) - (* asn_bool (term_binop bop.le (term_val ty.int 0%Z) (term_var "n")) ∗ *) - (* asn_eq (term_val ty.int 0%Z) (term_var "s") ∗ *) - (* asn_eq (term_val ty.int 0%Z) (term_var "i"). *) - - (* Example sum_loop : Assertion Σ1 := *) - (* ra0 ↦ term_var "s" ∗ *) - (* ra4 ↦ term_var "n" ∗ *) - (* ra5 ↦ term_var "i" ∗ *) - (* asn_eq *) - (* (term_val ty.int 2%Z * term_var "s") *) - (* (term_var "i" * (term_var "i" - term_val ty.int 1%Z)). *) - - (* Example sum_post : Assertion Σ1 := *) - (* ra0 ↦ term_var "s" ∗ *) - (* ra4 ↦ term_var "n" ∗ *) - (* ra5 ↦ term_var "i" ∗ *) - (* asn_eq (term_var "i") (term_var "n") ∗ *) - (* asn_eq *) - (* (term_val ty.int 2%Z * term_var "s") *) - (* (term_var "n" * (term_var "n" - term_val ty.int 1%Z)). *) - - End SUM. - - Section MemCopy. - - Import ListNotations. - Open Scope hex_Z_scope. - - (* C SOURCE *) - (* #include *) - (* void mcpy(char* dst, char* src, size_t size) { *) - (* for (; size != 0; --size) { *) - (* *dst = *src; *) - (* ++dst; *) - (* ++src; *) - (* } *) - (* } *) - - (* ASSEMBLY SOURCE (modified) *) - (* mcpy: *) - (* beq a2,zero,.L2 *) - (* .L1: *) - (* lb a3,0(a1) *) - (* sb a3,0(a0) *) - (* addi a0,a0,1 *) - (* addi a1,a1,1 *) - (* addi a2,a2,-1 *) - (* bne a2,zero,.L1 *) - (* .L2: *) - (* ret *) - - (* DISASSEMBLY *) - (* 0000000000000000 : *) - (* 0: 00060e63 beqz a2,1c <.L2> *) - (* 0000000000000004 <.L1>: *) - (* 4: 00058683 lb a3,0(a1) *) - (* 8: 00d50023 sb a3,0(a0) *) - (* c: 00150513 addi a0,a0,1 *) - (* 10: 00158593 addi a1,a1,1 *) - (* 14: fff60613 addi a2,a2,-1 *) - (* 18: fe0616e3 bnez a2,4 <.L1> *) - (* 000000000000001c <.L2>: *) - (* 1c: 00008067 ret *) - - Definition zero : RegIdx := [bv 0]. - Definition ra : RegIdx := [bv 1]. - Definition a0 : RegIdx := [bv 2]. - Definition a1 : RegIdx := [bv 3]. - Definition a2 : RegIdx := [bv 4]. - Definition a3 : RegIdx := [bv 5]. - Definition rra := x1. - Definition ra0 := x2. - Definition ra1 := x3. - Definition ra2 := x4. - Definition ra3 := x5. - - Example memcpy : list AST := - [ BEQ a2 zero 0x1c - ; LOAD 0 a1 a3 - ; STORE 0 a3 a0 - ; ADDI a0 a0 1 - ; ADDI a1 a1 1 - ; ADDI a2 a2 (-1) - ; BNE a2 zero (-0x14) - ; RET - ]. - - Let Σ1 : LCtx := - ["dst" :: ty_xlenbits; "src" :: ty_xlenbits; "size" :: ty.int; - "srcval" :: ty.list ty_word; "ret" :: ty_xlenbits]. - - Local Notation "p '∗' q" := (asn_sep p q). - Local Notation "r '↦' val" := (asn_chunk (chunk_ptsreg r val)) (at level 79). - Local Notation "a '↦[' n ']' xs" := (asn_chunk (chunk_user Contracts.ptstomem [a; n; xs])) (at level 79). - Local Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - - Example memcpy_pre : Assertion Σ1 := - pc ↦ term_val ty_xlenbits 0%Z ∗ - rra ↦ term_var "ret" ∗ - ra0 ↦ term_var "dst" ∗ - ra1 ↦ term_var "src" ∗ - ra2 ↦ term_var "size" ∗ - term_var "src" ↦[ term_var "size" ] term_var "srcval" ∗ - (∃ "dstval", term_var "dst" ↦[ term_var "size" ] term_var "dstval"). - - Example memcpy_post : Assertion Σ1 := - pc ↦ term_var "ret" ∗ - rra ↦ term_var "ret" ∗ - (∃ "v", ra0 ↦ term_var "v") ∗ - (∃ "v", ra1 ↦ term_var "v") ∗ - (∃ "v", ra2 ↦ term_var "v") ∗ - term_var "src" ↦[ term_var "size" ] term_var "srcval" ∗ - term_var "dst" ↦[ term_var "size" ] term_var "srcval". - - Example memcpy_loop : Assertion Σ1 := - pc ↦ term_val ty_xlenbits 0%Z ∗ - rra ↦ term_var "ret" ∗ - ra0 ↦ term_var "dst" ∗ - ra1 ↦ term_var "src" ∗ - ra2 ↦ term_var "size" ∗ - asn_formula (formula_neq (term_var "size") (term_val ty.int 0)) ∗ - term_var "src" ↦[ term_var "size" ] term_var "srcval" ∗ - (∃ "dstval", term_var "dst" ↦[ term_var "size" ] term_var "dstval"). - - End MemCopy. - -End BlockVerification. - -Module BlockVerificationDerived. - - Import Contracts. - Import RiscvPmpSignature. - Import RiscvPmpBlockVerifSpec. - Import RiscvPmpBlockVerifExecutor. - Import Symbolic. - - Import ModalNotations. - - Definition M : TYPE -> TYPE := SHeapSpecM [] []. - - Definition pure {A} : ⊢ A -> M A := SHeapSpecM.pure. - Definition bind {A B} : ⊢ M A -> □(A -> M B) -> M B := SHeapSpecM.bind. - Definition angelic {σ} : ⊢ M (STerm σ) := @SHeapSpecM.angelic [] None σ. - Definition demonic {σ} : ⊢ M (STerm σ) := @SHeapSpecM.demonic [] None σ. - Definition assert : ⊢ Formula -> M Unit := SHeapSpecM.assert_formula. - Definition assume : ⊢ Formula -> M Unit := SHeapSpecM.assume_formula. - - Definition produce_chunk : ⊢ Chunk -> M Unit := SHeapSpecM.produce_chunk. - Definition consume_chunk : ⊢ Chunk -> M Unit := SHeapSpecM.consume_chunk. - - Definition produce : ⊢ Assertion -> □(M Unit) := SHeapSpecM.produce. - Definition consume : ⊢ Assertion -> □(M Unit) := SHeapSpecM.consume. - - Notation "ω ∣ x <- ma ;; mb" := - (bind ma (fun _ ω x => mb)) - (at level 80, x at next level, - ma at next level, mb at level 200, - right associativity). - - Definition exec_instruction' (i : AST) : ⊢ M (STerm ty_retired) := - let inline_fuel := 3%nat in - fun w0 POST _ => - SHeapSpecM.exec - default_config inline_fuel (FunDef execute) - (fun w1 ω01 res _ => POST w1 ω01 res []%env) - [term_val (type ("ast" :: ty_ast)) i]%env. - - Definition exec_instruction (i : AST) : ⊢ M Unit := - fun _ => - _ ∣ msg <- @exec_instruction' i _ ;; - assert (formula_eq msg (term_val ty_retired RETIRE_SUCCESS)). - - (* Ideally, a block should be a list of non-branching - instruction plus one final branching instruction *) - Fixpoint exec_block (b : list AST) : ⊢ M Unit := - fun _ => - match b with - | nil => pure tt - | cons i b' => - _ ∣ _ <- @exec_instruction i _ ;; - @exec_block b' _ - end. - - - Definition exec_double {Σ : World} - (req : Assertion Σ) (b : list AST) : M Unit Σ := - ω1 ∣ _ <- T (produce req) ;; - @exec_block b _. - - Definition exec_triple {Σ : World} - (req : Assertion Σ) (b : list AST) (ens : Assertion Σ) : M Unit Σ := - ω ∣ _ <- exec_double req b ;; - consume ens ω. - - (* This is a VC for triples, for doubles we probably need to talk - about the continuation of a block. *) - Definition VC {Σ : LCtx} (req : Assertion Σ) (b : list AST) (ens : Assertion Σ) : 𝕊 ε := - SymProp.demonic_close - (@exec_triple - {| wctx := Σ; wco := nil |} - req b ens - (* Could include leakcheck here *) - (fun _ _ _ _ h => SymProp.block) - []%env []%list). - Section Example. - - Import ListNotations. - Import bv.notations. - - Notation "p '∗' q" := (asn_sep p q). - Notation "r '↦r' val" := - (asn_chunk - (chunk_ptsreg r val)) - (at level 79). - - Definition ADD (rd rs1 rs2 : RegIdx) : AST := - RTYPE rs2 rs1 rd RISCV_ADD. - Definition SUB (rd rs1 rs2 : RegIdx) : AST := - RTYPE rs2 rs1 rd RISCV_SUB. - - Example block1 : list AST := - [ ADD [bv 1] [bv 1] [bv 2] - ; SUB [bv 2] [bv 1] [bv 2] - ; SUB [bv 1] [bv 1] [bv 2] - ]. - - Section Contract. - - Let Σ1 : LCtx := ["x" :: ty_xlenbits; "y" :: ty_xlenbits]. - - Example pre1 : Assertion Σ1 := - x1 ↦r term_var "x" ∗ - x2 ↦r term_var "y". - - Example post1 : Assertion Σ1 := - x1 ↦r term_var "y" ∗ - x2 ↦r term_var "x". - - End Contract. - - Example vc1 : 𝕊 ε := - let vc1 := BlockVerificationDerived.VC pre1 block1 post1 in - let vc2 := Postprocessing.prune vc1 in - let vc3 := Postprocessing.solve_evars vc2 in - let vc4 := Postprocessing.solve_uvars vc3 in - vc4. - - Notation "x" := (@term_var _ x%string _ (@ctx.MkIn _ (x%string :: _) _ _ _)) (at level 1, only printing). - Notation "s = t" := (@formula_eq _ _ s t) (only printing). - Notation "' t" := (@formula_bool _ t) (at level 0, only printing, format "' t"). - Notation "F ∧ P" := (@SymProp.assertk _ F _ P) (at level 80, right associativity, only printing). - (* Notation "F → P" := (@SymProp.assumek _ F P) (at level 99, right associativity, only printing). *) - Notation "'∃' x '∷' σ , P" := (SymProp.angelicv (x,σ) P) (at level 200, right associativity, only printing, format "'∃' x '∷' σ , '/' P"). - Notation "'∀' x '∷' σ , P" := (SymProp.demonicv (x,σ) P) (at level 200, right associativity, only printing, format "'∀' x '∷' σ , '/' P"). - Notation "⊤" := (@SymProp.block _). - Notation "x - y" := (term_binop bop.minus x y) : exp_scope. - Notation "x + y" := (term_binop bop.plus x y) : exp_scope. - - Lemma sat_vc1 : VerificationConditionWithErasure (Erasure.erase_symprop vc1). - Proof. - compute. constructor. cbv - [Z.sub Z.add]. lia. - Qed. - - End Example. - -End BlockVerificationDerived. - -Module BlockVerificationDerived2. - - Import Contracts. - Import RiscvPmpSignature. - Import RiscvPmpBlockVerifSpec. - Import RiscvPmpBlockVerifExecutor. - Import Symbolic. - - Import ModalNotations. - - Definition M : TYPE -> TYPE := SHeapSpecM [] []. - - Definition pure {A} : ⊢ A -> M A := SHeapSpecM.pure. - Definition bind {A B} : ⊢ M A -> □(A -> M B) -> M B := SHeapSpecM.bind. - Definition angelic {σ} : ⊢ M (STerm σ) := @SHeapSpecM.angelic [] None σ. - Definition demonic {σ} : ⊢ M (STerm σ) := @SHeapSpecM.demonic [] None σ. - Definition assert : ⊢ Formula -> M Unit := SHeapSpecM.assert_formula. - Definition assume : ⊢ Formula -> M Unit := SHeapSpecM.assume_formula. - - Definition produce_chunk : ⊢ Chunk -> M Unit := SHeapSpecM.produce_chunk. - Definition consume_chunk : ⊢ Chunk -> M Unit := SHeapSpecM.consume_chunk. - - Definition produce : ⊢ Assertion -> □(M Unit) := SHeapSpecM.produce. - Definition consume : ⊢ Assertion -> □(M Unit) := SHeapSpecM.consume. - - Notation "ω ∣ x <- ma ;; mb" := - (bind ma (fun _ ω x => mb)) - (at level 80, x at next level, - ma at next level, mb at level 200, - right associativity). - - Definition exec_instruction_any (i : AST) : ⊢ STerm ty_xlenbits -> M (STerm ty_xlenbits) := - let inline_fuel := 10%nat in - fun _ a => - ω2 ∣ _ <- produce_chunk (chunk_ptsreg pc a) ;; - ω4 ∣ _ <- produce_chunk (chunk_user ptstoinstr [persist__term a ω2; term_val ty_ast i]) ;; - ω6 ∣ an <- @demonic _ _ ;; - ω7 ∣ _ <- produce_chunk (chunk_ptsreg nextpc an) ;; - ω8 ∣ _ <- SHeapSpecM.exec default_config inline_fuel (FunDef step) ;; - ω9 ∣ _ <- consume_chunk (chunk_user ptstoinstr [persist__term a (ω2 ∘ ω4 ∘ ω6 ∘ ω7 ∘ ω8); term_val ty_ast i]) ;; - ω10 ∣ na <- @angelic _ _ ;; - ω11 ∣ _ <- consume_chunk (chunk_ptsreg nextpc na) ;; - ω12 ∣ _ <- consume_chunk (chunk_ptsreg pc (persist__term na ω11)) ;; - pure (persist__term na (ω11 ∘ ω12)). - - Definition exec_instruction (i : AST) : ⊢ M Unit := - let inline_fuel := 10%nat in - fun _ => - ω1 ∣ a <- @demonic _ _ ;; - ω2 ∣ na <- exec_instruction_any i a ;; - assert (formula_eq na (term_binop bop.plus (persist__term a ω2) (term_val ty_exc_code 4))). - - - Fixpoint exec_block_addr (b : list AST) : ⊢ STerm ty_xlenbits -> STerm ty_xlenbits -> M (STerm ty_xlenbits) := - fun _ ainstr apc => - match b with - | nil => pure apc - | cons i b' => - ω1 ∣ _ <- assert (formula_eq ainstr apc) ;; - ω2 ∣ apc' <- exec_instruction_any i (persist__term apc ω1) ;; - @exec_block_addr b' _ (term_binop bop.plus (persist__term ainstr (ω1 ∘ ω2)) (term_val ty_xlenbits 4)) apc' - end. - - Definition exec_double_addr {Σ : World} - (req : Assertion (Σ ▻ ("a":: ty_xlenbits))) (b : list AST) : M (STerm ty_xlenbits) Σ := - ω1 ∣ an <- @demonic _ _ ;; - ω2 ∣ _ <- produce (w := wsnoc _ _) req (acc_snoc_left ω1 _ an);; - @exec_block_addr b _ (persist__term an ω2) (persist__term an ω2). - - Definition exec_triple_addr {Σ : World} - (req : Assertion (Σ ▻ ("a"::ty_xlenbits))) (b : list AST) - (ens : Assertion (Σ ▻ ("a"::ty_xlenbits) ▻ ("an"::ty_xlenbits))) : M Unit Σ := - ω1 ∣ a <- @demonic _ _ ;; - ω2 ∣ _ <- produce (w := wsnoc _ _) req (acc_snoc_left ω1 _ a) ;; - ω3 ∣ na <- @exec_block_addr b _ (persist__term a ω2) (persist__term a ω2) ;; - consume (w := wsnoc (wsnoc _ ("a"::ty_xlenbits)) ("an"::ty_xlenbits)) ens - (acc_snoc_left (acc_snoc_left (ω1 ∘ ω2 ∘ ω3) _ (persist__term a (ω2 ∘ ω3))) ("an"::ty_xlenbits) na). - - (* This is a VC for triples, for doubles we probably need to talk - about the continuation of a block. *) - Definition VC__addr {Σ : LCtx} (req : Assertion {| wctx := Σ ▻ ("a":: ty_xlenbits); wco := nil |}) (b : list AST) - (ens : Assertion {| wctx := Σ ▻ ("a"::ty_xlenbits) ▻ ("an"::ty_xlenbits); wco := nil |}) : 𝕊 ε := - SymProp.demonic_close - (@exec_triple_addr - {| wctx := Σ; wco := nil |} - req b ens - (* Could include leakcheck here *) - (fun _ _ _ _ h => SymProp.block) - []%env []%list). - - Definition simplify {Σ} : 𝕊 Σ -> 𝕊 Σ := - fun P => let P2 := Postprocessing.prune P in - let P3 := Postprocessing.solve_evars P2 in - let P4 := Postprocessing.solve_uvars P3 in - P4. - - Lemma simplify_sound {Σ} (p : 𝕊 Σ) (ι : Valuation Σ) : SymProp.safe (simplify p) ι -> SymProp.safe p ι. - Proof. - unfold simplify. - intros Hs. - now apply (Postprocessing.prune_sound p), Postprocessing.solve_evars_sound, Postprocessing.solve_uvars_sound. - Qed. - - Definition safeE {Σ} : 𝕊 Σ -> Prop := - fun P => VerificationConditionWithErasure (Erasure.erase_symprop P). - - Definition safeE_safe (p : 𝕊 wnil) (ι : Valuation wnil) : safeE p -> SymProp.safe p []. - Proof. - unfold safeE. - destruct 1 as [H]. - now eapply Erasure.erase_safe'. - Qed. - - Section Example. - - Import ListNotations. - Import bv.notations. - - Notation "p '∗' q" := (asn_sep p q). - Notation "r '↦r' val" := - (asn_chunk - (chunk_ptsreg r val)) - (at level 79). - - Definition ADD (rd rs1 rs2 : RegIdx) : AST := - RTYPE rs2 rs1 rd RISCV_ADD. - Definition SUB (rd rs1 rs2 : RegIdx) : AST := - RTYPE rs2 rs1 rd RISCV_SUB. - - Example block1 : list AST := - [ ADD [bv 1] [bv 1] [bv 2] - ; SUB [bv 2] [bv 1] [bv 2] - ; SUB [bv 1] [bv 1] [bv 2] - ]. - - Section Contract. - - Let Σ1 : LCtx := ["x" :: ty_xlenbits; "y" :: ty_xlenbits]. - - Example pre1 : Assertion Σ1 := - x1 ↦r term_var "x" ∗ - x2 ↦r term_var "y". - - Example post1 : Assertion Σ1 := - x1 ↦r term_var "y" ∗ - x2 ↦r term_var "x". - - End Contract. - - Notation "x" := (@term_var _ x%string _ (@ctx.MkIn _ (x%string :: _) _ _ _)) (at level 1, only printing). - Notation "s = t" := (@formula_eq _ _ s t) (only printing). - Notation "' t" := (@formula_bool _ t) (at level 0, only printing, format "' t"). - Notation "F ∧ P" := (@SymProp.assertk _ F _ P) (at level 80, right associativity, only printing). - (* Notation "F → P" := (@SymProp.assumek _ F P) (at level 99, right associativity, only printing). *) - Notation "'∃' x '∷' σ , P" := (SymProp.angelicv (x,σ) P) (at level 200, right associativity, only printing, format "'∃' x '∷' σ , '/' P"). - Notation "'∀' x '∷' σ , P" := (SymProp.demonicv (x,σ) P) (at level 200, right associativity, only printing, format "'∀' x '∷' σ , '/' P"). - Notation "⊤" := (@SymProp.block _). - Notation "x - y" := (term_binop bop.minus x y) : exp_scope. - Notation "x + y" := (term_binop bop.plus x y) : exp_scope. - - Section ContractAddr. - - Let Σ1 : LCtx := ["x" :: ty_xlenbits; "y" :: ty_xlenbits]. - - Example pre1' : Assertion {| wctx := Σ1 ▻ ("a"::ty_xlenbits) ; wco := nil |} := - (x1 ↦r term_var "x") ∗ x2 ↦r term_var "y". - - Example post1' : Assertion {| wctx := Σ1 ▻ ("a"::ty_xlenbits) ▻ ("an"::ty_xlenbits) ; wco := nil |} := - x1 ↦r term_var "y" ∗ - x2 ↦r term_var "x" ∗ - asn_formula (formula_eq (term_var "an") (term_binop bop.plus (term_var "a") (term_val _ (Z.of_nat 12 : Val ty.int)))). - - End ContractAddr. - - Example vc1 : 𝕊 ε := simplify (BlockVerificationDerived2.VC__addr pre1' block1 post1'). - (* let vc1 := BlockVerificationDerived2.VC__addr pre1' block1 post1' in *) - (* let vc2 := Postprocessing.prune vc1 in *) - (* let vc3 := Postprocessing.solve_evars vc2 in *) - (* let vc4 := Postprocessing.solve_uvars vc3 in *) - (* vc4. *) - - Lemma sat_vc1' : safeE vc1. - Proof. - compute. constructor. cbv - [Z.sub Z.add]. lia. - Qed. - - End Example. - - Section FemtoKernel. - Import bv.notations. - Import ListNotations. - Open Scope hex_Z_scope. - - Definition zero : RegIdx := [bv 0]. - Definition ra : RegIdx := [bv 1]. -(* MAX := 2^30; *) -(* (* assembly source: *) *) -(* CODE: UTYPE #HERE ra RISCV_AUIPC *) (* 0 *) -(* ADDI RA, RA, (ADV - #PREVHERE) *) (* 4 *) -(* CSR pmpaddr0 ra r0 CSRRW; *) (* 8 *) -(* UTYPE MAX ra RISCV_LUI; *) (* 12 *) -(* CSR pmpaddr1 ra r0 CSRRW; *) (* 16 *) -(* UTYPE (pure_pmpcfg_ent_to_bits { L := false; A := OFF; X := false; W := false; R := false }) ra RISCV_LUI; *) (* 20 *) -(* CSR pmp0cfg ra r0 CSRRW; *) (* 24 *) -(* UTYPE (pure_pmpcfg_ent_to_bits { L := false; A := TOR; X := true; W := true; R := true }) ra RISCV_LUI; *) (* 28 *) -(* CSR pmp1cfg ra r0 CSRRW; *) (* 32 *) -(* UTYPE #HERE ra RISCV_AUIPC *) (* 36 *) -(* ADDI RA, RA, (ADV - #PREVHERE) *) (* 40 *) -(* CSR epc ra r0 CSRRW; *) (* 44 *) -(* UTYPE #HERE ra RISCV_AUIPC *) (* 48 *) -(* ADDI RA, RA, (IH - #PREVHERE) *) (* 52 *) -(* CSR Tvec ra r0 CSRRW; *) (* 56 *) -(* UTYPE (pure_mstatus_to_bits { MPP := User }) ra RISCV_LUI; *) (* 60 *) -(* CSR Mstatus ra r0 CSRRW; *) (* 64 *) -(* MRET *) (* 68 *) - -(* IH: UTYPE 0 ra RISCV_AUIPC *) (* 72 *) -(* load (#HERE - 4 - DATA) ra ra; *) (* 76 *) -(* MRET *) (* 80 *) -(* DATA: 42 *) (* 84 *) -(* ADV: ... (anything) *) (* 88 *) -(* } *) - - Definition pure_privilege_to_bits : Privilege -> Xlenbits := - fun p => match p with | Machine => 3%Z | User => 0%Z end. - - Definition pure_mstatus_to_bits : Mstatus -> Xlenbits := - fun '(MkMstatus mpp) => Z.shiftl (pure_privilege_to_bits mpp) 11. - - Definition pure_pmpAddrMatchType_to_bits : PmpAddrMatchType -> Z:= - fun mt => match mt with - | OFF => 0%Z - | TOR => 1%Z - end. - - Definition pure_pmpcfg_ent_to_bits : Pmpcfg_ent -> Xlenbits := - fun ent => - match ent with - | MkPmpcfg_ent L A X W R => - let l := Z.shiftl (if L then 1 else 0) 7 in - let a := Z.shiftl (pure_pmpAddrMatchType_to_bits A) 3 in - let x := Z.shiftl (if X then 1 else 0) 2 in - let w := Z.shiftl (if W then 1 else 0) 1 in - let r := Z.shiftl (if R then 1 else 0) 0 in - Z.lor l (Z.lor a (Z.lor x (Z.lor w r))) - end%Z. - - Definition femto_address_max := 2^30. - Definition femto_pmpcfg_ent0 : Pmpcfg_ent := MkPmpcfg_ent false OFF false false false. - Definition femto_pmpcfg_ent0_bits : Val ty_xlenbits := pure_pmpcfg_ent_to_bits femto_pmpcfg_ent0. - Definition femto_pmpcfg_ent1 : Pmpcfg_ent := MkPmpcfg_ent false TOR true true true. - Definition femto_pmpcfg_ent1_bits : Val ty_xlenbits := pure_pmpcfg_ent_to_bits femto_pmpcfg_ent1. - Definition femto_pmpentries : list PmpEntryCfg := [(femto_pmpcfg_ent0, 88); (femto_pmpcfg_ent1, femto_address_max)]%list. - - Definition femto_mstatus := pure_mstatus_to_bits (MkMstatus User ). - - Example femtokernel_init : list AST := - [ - UTYPE 0 ra RISCV_AUIPC - ; ITYPE 88 ra ra RISCV_ADDI - ; CSR MPMPADDR0 ra zero CSRRW - ; UTYPE femto_address_max ra RISCV_LUI - ; CSR MPMPADDR1 ra zero CSRRW - ; UTYPE femto_pmpcfg_ent0_bits ra RISCV_LUI - ; CSR MPMP0CFG ra zero CSRRW - ; UTYPE femto_pmpcfg_ent1_bits ra RISCV_LUI - ; CSR MPMP1CFG ra zero CSRRW - ; UTYPE 0 ra RISCV_AUIPC - ; ITYPE 52 ra ra RISCV_ADDI - ; CSR MEpc ra zero CSRRW - ; UTYPE 0 ra RISCV_AUIPC - ; ITYPE 24 ra ra RISCV_ADDI - ; CSR MTvec ra zero CSRRW - ; UTYPE femto_mstatus ra RISCV_LUI - ; CSR MStatus ra zero CSRRW - ; MRET - ]. - - Example femtokernel_handler : list AST := - [ UTYPE 0 ra RISCV_AUIPC - ; LOAD 12 ra ra - ; MRET - ]. - - Local Notation "p '∗' q" := (asn_sep p q). - Local Notation "r '↦' val" := (asn_chunk (chunk_ptsreg r val)) (at level 79). - Local Notation "a '↦[' n ']' xs" := (asn_chunk (chunk_user ptstomem [a; n; xs])) (at level 79). - Local Notation "a '↦ₘ' t" := (asn_chunk (chunk_user ptsto [a; t])) (at level 70). - Local Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - Local Notation "x + y" := (term_binop bop.plus x y) : exp_scope. - Local Notation "a '=' b" := (asn_eq a b). - - Let Σ__femtoinit : LCtx := []. - Let W__femtoinit : World := MkWorld Σ__femtoinit []. - - Example femtokernel_default_pmpcfg : Pmpcfg_ent := - {| L := false; A := OFF; X := false; W := false; R := false |}. - - (* DOMI: TODO: replace the pointsto chunk for 84 ↦ 42 with a corresponding invariant *) - Example femtokernel_init_pre : Assertion {| wctx := [] ▻ ("a"::ty_xlenbits) ; wco := nil |} := - (term_var "a" = term_val ty_word 0) ∗ - (∃ "v", mstatus ↦ term_var "v") ∗ - (∃ "v", mtvec ↦ term_var "v") ∗ - (∃ "v", mcause ↦ term_var "v") ∗ - (∃ "v", mepc ↦ term_var "v") ∗ - cur_privilege ↦ term_val ty_privilege Machine ∗ - (∃ "v", x1 ↦ term_var "v") ∗ - (∃ "v", x2 ↦ term_var "v") ∗ - (∃ "v", x3 ↦ term_var "v") ∗ - (∃ "v", x4 ↦ term_var "v") ∗ - (∃ "v", x5 ↦ term_var "v") ∗ - (∃ "v", x6 ↦ term_var "v") ∗ - (∃ "v", x7 ↦ term_var "v") ∗ - (pmp0cfg ↦ term_val ty_pmpcfg_ent femtokernel_default_pmpcfg) ∗ - (pmp1cfg ↦ term_val ty_pmpcfg_ent femtokernel_default_pmpcfg) ∗ - (∃ "v", pmpaddr0 ↦ term_var "v") ∗ - (∃ "v", pmpaddr1 ↦ term_var "v") ∗ - (term_var "a" + (term_val ty_xlenbits 84) ↦ₘ term_val ty_xlenbits 42)%exp. - - Example femtokernel_init_post : Assertion {| wctx := [] ▻ ("a"::ty_xlenbits) ▻ ("an"::ty_xlenbits) ; wco := nil |} := - ( - asn_formula (formula_eq (term_var "an") (term_var "a" + term_val ty_xlenbits 88)) ∗ - (∃ "v", mstatus ↦ term_var "v") ∗ - (mtvec ↦ (term_var "a" + term_val ty_xlenbits 72)) ∗ - (∃ "v", mcause ↦ term_var "v") ∗ - (∃ "v", mepc ↦ term_var "v") ∗ - cur_privilege ↦ term_val ty_privilege User ∗ - (∃ "v", x1 ↦ term_var "v") ∗ - (∃ "v", x2 ↦ term_var "v") ∗ - (∃ "v", x3 ↦ term_var "v") ∗ - (∃ "v", x4 ↦ term_var "v") ∗ - (∃ "v", x5 ↦ term_var "v") ∗ - (∃ "v", x6 ↦ term_var "v") ∗ - (∃ "v", x7 ↦ term_var "v") ∗ - (pmp0cfg ↦ term_val (ty.record rpmpcfg_ent) femto_pmpcfg_ent0) ∗ - (pmp1cfg ↦ term_val (ty.record rpmpcfg_ent) femto_pmpcfg_ent1) ∗ - (pmpaddr0 ↦ term_var "a" + term_val ty_xlenbits 88) ∗ - (pmpaddr1 ↦ term_val ty_xlenbits femto_address_max) ∗ - (term_var "a" + (term_val ty_xlenbits 84) ↦ₘ term_val ty_xlenbits 42) - )%exp. - - (* note that this computation takes longer than directly proving sat__femtoinit below *) - Time Example t_vc__femtoinit : 𝕊 Σ__femtoinit := - Eval vm_compute in - simplify (VC__addr femtokernel_init_pre femtokernel_init femtokernel_init_post). - - Definition vc__femtoinit : 𝕊 Σ__femtoinit := - simplify (VC__addr femtokernel_init_pre femtokernel_init femtokernel_init_post). - (* let vc1 := VC__addr femtokernel_init_pre femtokernel_init femtokernel_init_post in *) - (* let vc2 := Postprocessing.prune vc1 in *) - (* let vc3 := Postprocessing.solve_evars vc2 in *) - (* let vc4 := Postprocessing.solve_uvars vc3 in *) - (* let vc5 := Postprocessing.prune vc4 in *) - (* vc5. *) - (* Import SymProp.notations. *) - (* Set Printing Depth 200. *) - (* Print vc__femtoinit. *) - - Lemma sat__femtoinit : safeE vc__femtoinit. - Proof. - constructor. vm_compute. intros. auto. - Qed. - - (* Even admitting this goes OOM :-) *) - (* Lemma sat__femtoinit2 : SymProp.safe vc__femtoinit env.nil. *) - (* Admitted. *) - (* (* Proof. *) *) - (* (* destruct sat__femtoinit as [se]. *) *) - (* (* exact (proj1 (Erasure.erase_safe vc__femtoinit env.nil) se). *) *) - (* (* Qed. *) *) - - - Let Σ__femtohandler : LCtx := ["epc"::ty_exc_code; "mpp"::ty_privilege]. - Let W__femtohandler : World := MkWorld Σ__femtohandler []. - - Example femtokernel_handler_pre : Assertion {| wctx := ["epc"::ty_exc_code; "a" :: ty_xlenbits]; wco := nil |} := - (asn_eq (term_var "a") (term_val ty_word 72)) ∗ - (mstatus ↦ term_val (ty.record rmstatus) {| MPP := User |}) ∗ - (mtvec ↦ term_val ty_word 72) ∗ - (∃ "v", mcause ↦ term_var "v") ∗ - (mepc ↦ term_var "epc") ∗ - cur_privilege ↦ term_val ty_privilege Machine ∗ - (∃ "v", x1 ↦ term_var "v") ∗ - (∃ "v", x2 ↦ term_var "v") ∗ - (∃ "v", x3 ↦ term_var "v") ∗ - (∃ "v", x4 ↦ term_var "v") ∗ - (∃ "v", x5 ↦ term_var "v") ∗ - (∃ "v", x6 ↦ term_var "v") ∗ - (∃ "v", x7 ↦ term_var "v") ∗ - (pmp0cfg ↦ term_val (ty.record rpmpcfg_ent) femto_pmpcfg_ent0) ∗ - (pmp1cfg ↦ term_val (ty.record rpmpcfg_ent) femto_pmpcfg_ent1) ∗ - (pmpaddr0 ↦ term_var "a" + term_val ty_xlenbits 16) ∗ - (pmpaddr1 ↦ term_val ty_xlenbits femto_address_max) ∗ - (term_var "a" + (term_val ty_xlenbits 12) ↦ₘ term_val ty_xlenbits 42)%exp. - - Example femtokernel_handler_post : Assertion {| wctx := ["epc"::ty_exc_code; "a" :: ty_xlenbits; "an"::ty_xlenbits]; wco := nil |} := - ( - (mstatus ↦ term_val (ty.record rmstatus) {| MPP := User |}) ∗ - (mtvec ↦ term_val ty_word 72) ∗ - (∃ "v", mcause ↦ term_var "v") ∗ - (mepc ↦ term_var "epc") ∗ - cur_privilege ↦ term_val ty_privilege User ∗ - (∃ "v", x1 ↦ term_var "v") ∗ - (∃ "v", x2 ↦ term_var "v") ∗ - (∃ "v", x3 ↦ term_var "v") ∗ - (∃ "v", x4 ↦ term_var "v") ∗ - (∃ "v", x5 ↦ term_var "v") ∗ - (∃ "v", x6 ↦ term_var "v") ∗ - (∃ "v", x7 ↦ term_var "v") ∗ - (pmp0cfg ↦ term_val (ty.record rpmpcfg_ent) femto_pmpcfg_ent0) ∗ - (pmp1cfg ↦ term_val (ty.record rpmpcfg_ent) femto_pmpcfg_ent1) ∗ - (pmpaddr0 ↦ term_var "a" + term_val ty_xlenbits 16) ∗ - (pmpaddr1 ↦ term_val ty_xlenbits femto_address_max) ∗ - (term_var "a" + (term_val ty_xlenbits 12) ↦ₘ term_val ty_xlenbits 42) ∗ - asn_formula (formula_eq (term_var "an") (term_var "epc")) - )%exp. - - Time Example t_vc__femtohandler : 𝕊 [] := - Eval vm_compute in - simplify (VC__addr femtokernel_handler_pre femtokernel_handler femtokernel_handler_post). - Definition vc__femtohandler : 𝕊 [] := - simplify (VC__addr femtokernel_handler_pre femtokernel_handler femtokernel_handler_post). - - (* let vc1 := VC__addr femtokernel_handler_pre femtokernel_handler femtokernel_handler_post in *) - (* let vc2 := Postprocessing.prune vc1 in *) - (* let vc3 := Postprocessing.solve_evars vc2 in *) - (* let vc4 := Postprocessing.solve_uvars vc3 in *) - (* let vc5 := Postprocessing.prune vc4 in *) - (* vc5. *) - (* Import SymProp.notations. *) - (* Set Printing Depth 200. *) - (* Print vc__femtohandler. *) - - Lemma sat__femtohandler : safeE vc__femtohandler. - Proof. - constructor. vm_compute. intros. auto. - Qed. - - End FemtoKernel. - -End BlockVerificationDerived2. - -Module BlockVerificationDerivedSem. - Import Contracts. - Import Model.RiscvPmpIrisBase. - Import Model.RiscvPmpIrisInstance. - Import RiscvPmpBlockVerifSpec. - Import weakestpre. - Import tactics. - Import BlockVerificationDerived. - Import RiscvPmpIrisInstanceWithContracts. - - Lemma read_ram_sound `{sailGS Σ} {Γ} (es : NamedEnv (Exp Γ) ["paddr"∷ty_exc_code]) (δ : CStore Γ) : - ∀ paddr w, - evals es δ = [env].["paddr"∷ty_exc_code ↦ paddr] - → ⊢ semTriple δ (interp_ptsto paddr w) (stm_foreign read_ram es) - (λ (v : Z) (δ' : NamedEnv Val Γ), (interp_ptsto paddr w ∗ ⌜v = w⌝ ∧ emp) ∗ ⌜δ' = δ⌝). - Proof. - iIntros (paddr w Heq) "ptsto_addr_w". - rewrite wp_unfold. cbn. - iIntros (σ' ns ks1 ks nt) "[Hregs Hmem]". - iDestruct "Hmem" as (memmap) "[Hmem' %]". - iMod (fupd_mask_subseteq empty) as "Hclose"; first set_solver. - iModIntro. - iSplitR; first easy. - iIntros (e2 σ'' efs Hstep). - dependent elimination Hstep. - dependent elimination s. - rewrite Heq in f1. cbv in f1. - dependent elimination f1. cbn. - do 3 iModIntro. - unfold interp_ptsto. - iAssert (⌜ memmap !! paddr = Some w ⌝)%I with "[ptsto_addr_w Hmem']" as "%". - { iApply (gen_heap.gen_heap_valid with "Hmem' ptsto_addr_w"). } - iMod "Hclose" as "_". - iModIntro. - iSplitL "Hmem' Hregs". - iSplitL "Hregs"; first iFrame. - iExists memmap. - iSplitL "Hmem'"; first iFrame. - iPureIntro; assumption. - iSplitL; last easy. - apply map_Forall_lookup_1 with (i := paddr) (x := w) in H0; auto. - cbn in H0. subst. - iApply wp_value. - iSplitL; last easy. - iSplitL; last easy. - iAssumption. - Qed. - - Lemma write_ram_sound `{sailGS Σ} {Γ} - (es : NamedEnv (Exp Γ) ["paddr"∷ty_exc_code; "data"∷ty_exc_code]) (δ : CStore Γ) : - ∀ paddr data : Z, - evals es δ = [env].["paddr"∷ty_exc_code ↦ paddr].["data"∷ty_exc_code ↦ data] - → ⊢ semTriple δ (∃ v : Z, interp_ptsto paddr v) - (stm_foreign write_ram es) - (λ (v : Z) (δ' : NamedEnv Val Γ), - (interp_ptsto paddr data ∗ ⌜v = 1%Z⌝ ∧ emp) ∗ ⌜δ' = δ⌝). - Proof. - iIntros (paddr data Heq) "[% ptsto_addr]". - rewrite wp_unfold. cbn. - iIntros (σ' ns ks1 ks nt) "[Hregs Hmem]". - iDestruct "Hmem" as (memmap) "[Hmem' %]". - iMod (fupd_mask_subseteq empty) as "Hclose"; first set_solver. - iModIntro. - iSplitR; first easy. - iIntros (e2 σ'' efs Hstep). - dependent elimination Hstep. - dependent elimination s. - rewrite Heq in f1. cbn in f1. - dependent elimination f1. cbn. - do 3 iModIntro. - unfold interp_ptsto. - iMod (gen_heap.gen_heap_update _ _ _ data with "Hmem' ptsto_addr") as "[Hmem' ptsto_addr]". - iMod "Hclose" as "_". - iModIntro. - iSplitL "Hmem' Hregs". - iSplitL "Hregs"; first iFrame. - iExists (<[paddr:=data]> memmap). - iSplitL "Hmem'"; first iFrame. - iPureIntro. - { apply map_Forall_lookup. - intros i x Hl. - unfold fun_write_ram. - destruct (Z.eqb_spec paddr i). - + subst. apply (lookup_insert_rev memmap i); assumption. - + rewrite -> map_Forall_lookup in H0. - rewrite -> lookup_insert_ne in Hl; auto. - } - iSplitL; last easy. - iApply wp_value. - iSplitL; trivial. - iSplitL; trivial. - Qed. - - Lemma foreignSemBlockVerif `{sailGS Σ} : ForeignSem. - Proof. - intros Γ τ Δ f es δ. - destruct f; cbn. - - intros *; apply read_ram_sound. - - intros *; apply write_ram_sound. - - admit. - Admitted. - - Lemma lemSemBlockVerif `{sailGS Σ} : LemmaSem. - Proof. - intros Δ []. - - intros ι. now iIntros "_". - - intros ι. now iIntros "_". - - intros ι. now iIntros "_". - - intros ι. now iIntros "_". - - intros ι. now iIntros "_". - - intros ι. now iIntros "_". - - intros ι. now iIntros "_". - Qed. - - Import ctx.resolution. - Import ctx.notations. - Import env.notations. - - Definition semTripleOneInstr `{sailGS Σ} (PRE : iProp Σ) (a : AST) (POST : iProp Σ) : iProp Σ := - semTriple [a : Val (type ("ast" :: ty_ast))]%env PRE (FunDef execute) (fun ret _ => ⌜ret = RETIRE_SUCCESS⌝ ∗ POST)%I. - - Module ValidContractsBlockVerif. - Import Contracts.RiscvPmpSignature. - Import RiscvPmpBlockVerifExecutor. - Import Symbolic. - - Lemma contractsVerified `{sailGS Σ} : ProgramLogic.ValidContractCEnv (PI := PredicateDefIProp). - Proof. - intros Γ τ f. - destruct f; intros c eq; inversion eq; subst; clear eq. - - eapply shallow_vcgen_soundness. - eapply symbolic_vcgen_soundness. - eapply Symbolic.validcontract_reflect_sound. - eapply RiscvPmpSpecVerif.valid_execute_rX. - - eapply shallow_vcgen_soundness. - eapply symbolic_vcgen_soundness. - eapply Symbolic.validcontract_reflect_sound. - eapply RiscvPmpSpecVerif.valid_execute_wX. - Admitted. - - Lemma contractsSound `{sailGS Σ} : ⊢ ValidContractEnvSem CEnv. - Proof. - eauto using sound, foreignSemBlockVerif, lemSemBlockVerif, contractsVerified. - Admitted. - - (* Lemma sound_exec_instruction {ast} `{sailGS Σ} : *) - (* SymProp.safe (exec_instruction (w := wnil) ast (fun _ _ res _ h => SymProp.block) env.nil []%list) env.nil -> *) - (* ⊢ semTripleOneInstr emp%I ast emp%I. *) - (* Proof. *) - (* unfold exec_instruction, exec_instruction', assert. *) - (* iIntros (safe_exec) "". *) - (* rewrite <-SymProp.safe_debug_safe in safe_exec. *) - (* rewrite <-SymProp.wsafe_safe in safe_exec. *) - (* iApply (sound_stm foreignSemBlockVerif lemSemBlockVerif). *) - (* Admitted. *) - (* - refine (exec_sound 3 _ _ _ []%list _). *) - (* enough (CMut.bind (CMut.exec 3 (FunDef execute)) (fun v => CMut.assert_formula (v = RETIRE_SUCCESS)) (fun _ _ _ => True) [ast] []%list). *) - (* + unfold CMut.bind, CMut.assert_formula, CMut.dijkstra, CDijk.assert_formula in H0. *) - (* refine (exec_monotonic _ _ _ _ _ _ _ H0). *) - (* intros ret δ h [-> _]; cbn. *) - (* iIntros "_". iPureIntro. now split. *) - (* + refine (approx_exec _ _ _ _ _ safe_exec); cbn; try trivial; try reflexivity. *) - (* intros w ω ι _ Hpc tr ? -> δ δ' Hδ h h' Hh. *) - (* refine (approx_assert_formula _ _ _ (a := fun _ _ _ => True) _ _ _); *) - (* try assumption; try reflexivity. *) - (* constructor. *) - (* - do 2 iModIntro. *) - (* iApply contractsSound. *) - (* Qed. *) - End ValidContractsBlockVerif. - -End BlockVerificationDerivedSem. - -Module BlockVerificationDerived2Sound. - Import Contracts. - Import RiscvPmpSignature. - Import RiscvPmpBlockVerifSpec. - Import RiscvPmpBlockVerifShalExecutor. - Import RiscvPmpIrisInstanceWithContracts. - - Definition M : Type -> Type := CHeapSpecM [] []. - - Definition pure {A} : A -> M A := CHeapSpecM.pure. - Definition bind {A B} : M A -> (A -> M B) -> M B := CHeapSpecM.bind. - Definition angelic {σ} : M (Val σ) := @CHeapSpecM.angelic [] σ. - Definition demonic {σ} : M (Val σ) := @CHeapSpecM.demonic [] σ. - Definition assert : Prop -> M unit := CHeapSpecM.assert_formula. - Definition assume : Prop -> M unit := CHeapSpecM.assume_formula. - - Definition produce_chunk : SCChunk -> M unit := CHeapSpecM.produce_chunk. - Definition consume_chunk : SCChunk -> M unit := CHeapSpecM.consume_chunk. - - Definition produce {Σ} : Valuation Σ -> Assertion Σ -> M unit := CHeapSpecM.produce. - Definition consume {Σ} : Valuation Σ -> Assertion Σ -> M unit := CHeapSpecM.consume. - - Local Notation "x <- ma ;; mb" := - (bind ma (fun x => mb)) - (at level 80, ma at level 90, mb at level 200, right associativity). - - Definition exec_instruction_any__c (i : AST) : Val ty_xlenbits -> M (Val ty_xlenbits) := - let inline_fuel := 10%nat in - fun a => - _ <- produce_chunk (scchunk_ptsreg pc a) ;; - _ <- produce_chunk (scchunk_user ptstoinstr [a; i]) ;; - an <- @demonic _ ;; - _ <- produce_chunk (scchunk_ptsreg nextpc an) ;; - _ <- CHeapSpecM.exec inline_fuel (FunDef step) ;; - _ <- consume_chunk (scchunk_user ptstoinstr [a ; i]) ;; - na <- @angelic _ ;; - _ <- consume_chunk (scchunk_ptsreg nextpc na) ;; - _ <- consume_chunk (scchunk_ptsreg pc na) ;; (* TODO: a + 4! *) - pure na. - - Lemma refine_exec_instruction_any (i : AST) : - forall {w0 : World} {ι0 : Valuation w0} (Hpc0 : instpc (wco w0) ι0), - refine ι0 (@BlockVerificationDerived2.exec_instruction_any i w0) - (exec_instruction_any__c i). - Proof. - unfold BlockVerificationDerived2.exec_instruction_any, exec_instruction_any__c. - intros w0 ι0 Hpc0 a a0 ->. - apply refine_bind. - apply refine_produce_chunk; auto. - { reflexivity. } - intros w1 ω1 ι1 -> Hpc1 [] [] _. - apply refine_bind. - apply refine_produce_chunk; auto. - { now rewrite H, <-inst_persist. } - intros w2 ω2 ι2 -> Hpc2 [] [] _. - apply refine_bind. - apply refine_demonic; auto. - intros w3 ω3 ι3 -> Hpc3 an anv ->. - apply refine_bind. - apply refine_produce_chunk; auto. - { reflexivity. } - intros w4 ω4 ι4 -> Hpc4 [] [] _. - apply refine_bind. - { apply refine_exec; auto. } - intros w5 ω5 ι5 -> Hpc5 res ? ->. - apply refine_bind. - apply refine_consume_chunk; auto. - { rewrite H. - unfold refine, RefineInst. cbn. repeat f_equal. - rewrite (inst_persist (H := inst_term) _ _ a). - now rewrite ?sub_acc_trans, ?inst_subst. - } - intros w6 ω6 ι6 -> Hpc6 [] ? ->. - apply refine_bind. - apply refine_angelic; auto. - intros w7 ω7 ι7 -> Hpc7 na ? ->. - apply refine_bind. - apply refine_consume_chunk; auto. - { reflexivity. } - intros w8 ω8 ι8 -> Hpc8 [] [] _. - apply refine_bind. - apply refine_consume_chunk; auto. - { unfold refine, RefineInst. cbn. repeat f_equal. - now rewrite (inst_persist (H := inst_term) _ _ na). - } - intros w9 ω9 ι9 -> Hpc9 [] [] _. - apply refine_pure; auto. - unfold refine, RefineTermVal, RefineInst. - rewrite (inst_persist (H := inst_term) _ _ na). - now rewrite ?sub_acc_trans, ?inst_subst. - Qed. - - Fixpoint exec_block_addr__c (b : list AST) : Val ty_xlenbits -> Val ty_xlenbits -> M (Val ty_xlenbits) := - fun ainstr apc => - match b with - | nil => pure apc - | cons i b' => - _ <- assert (ainstr = apc) ;; - apc' <- exec_instruction_any__c i apc ;; - @exec_block_addr__c b' (ainstr + 4) apc' - end. - - Lemma refine_exec_block_addr (b : list AST) : - forall {w0 : World} {ι0 : Valuation w0} (Hpc0 : instpc (wco w0) ι0), - refine ι0 (@BlockVerificationDerived2.exec_block_addr b w0) - (exec_block_addr__c b). - Proof. - induction b. - - intros w0 ι0 Hpc0 a ? ->. - now apply refine_pure. - - intros w0 ι0 Hpc0 ainstr ? -> apc ? ->. - cbn. - apply refine_bind. - apply refine_assert_formula; auto. - intros w1 ω1 ι1 -> Hpc1 [] [] _. - apply refine_bind. - apply refine_exec_instruction_any; auto. - unfold refine, RefineTermVal, RefineInst. - now rewrite (inst_persist (H := inst_term)). - intros w2 ω2 ι2 -> Hpc2 napc ? ->. - apply IHb; auto. - {unfold refine, RefineTermVal, RefineInst. - cbn. f_equal. - change (inst_term ?t ?ι) with (inst t ι). - rewrite (inst_persist (H := inst_term) (acc_trans ω1 ω2) _ ainstr). - now rewrite ?sub_acc_trans, ?inst_subst. - } - { reflexivity. } - Qed. - - Definition exec_double_addr__c {Σ : World} (ι : Valuation Σ) - (req : Assertion (wsnoc Σ ("a"::ty_xlenbits))) (b : list AST) : M (Val ty_xlenbits) := - an <- @demonic _ ;; - _ <- produce (env.snoc ι ("a"::ty_xlenbits) an) req ;; - @exec_block_addr__c b an an. - - Definition exec_triple_addr__c {Σ : World} (ι : Valuation Σ) - (req : Assertion (Σ ▻ ("a"::ty_xlenbits))) (b : list AST) - (ens : Assertion (Σ ▻ ("a"::ty_xlenbits) ▻ ("an"::ty_xlenbits))) : M unit := - a <- @demonic _ ;; - _ <- produce (ι ► ( _ ↦ a )) req ;; - na <- @exec_block_addr__c b a a ;; - consume (ι ► ( ("a"::ty_xlenbits) ↦ a ) ► ( ("an"::ty_xlenbits) ↦ na )) ens. - - Import ModalNotations. - - Lemma refine_exec_triple_addr {Σ : World} - (req : Assertion (Σ ▻ ("a"::ty_xlenbits))) (b : list AST) - (ens : Assertion (Σ ▻ ("a"::ty_xlenbits) ▻ ("an"::ty_xlenbits))) : - forall {ι0 : Valuation Σ} (Hpc0 : instpc (wco Σ) ι0), - refine ι0 (@BlockVerificationDerived2.exec_triple_addr Σ req b ens) - (exec_triple_addr__c ι0 req b ens). - Proof. - intros ι0 Hpc0. - unfold BlockVerificationDerived2.exec_triple_addr, exec_triple_addr__c. - eapply refine_bind. - { eapply refine_demonic; auto. } - intros w1 ω1 ι1 -> Hpc1 a ? ->. - eapply refine_bind. - { eapply refine_produce; auto. - cbn. - now rewrite inst_subst, inst_sub_wk1. - } - intros w2 ω2 ι2 -> Hpc2 [] [] _. - eapply refine_bind. - {eapply refine_exec_block_addr; auto; - unfold refine, RefineTermVal, RefineInst in *; - change (persist__term a ω2) with (persist a ω2); - now rewrite inst_persist. - } - intros w3 ω3 ι3 -> Hpc3 na ? ->. - eapply refine_consume; auto. - cbn -[sub_wk1]. - now rewrite ?inst_subst, ?inst_sub_wk1. - cbn [acc_snoc_left sub_acc]. - refine (eq_trans _ (eq_sym (inst_sub_snoc ι3 (sub_snoc (sub_acc (ω1 ∘ ω2 ∘ ω3)) ("a"∷ty_exc_code) (persist__term a (ω2 ∘ ω3))) ("an"::ty_exc_code) na))). - f_equal. - rewrite inst_sub_snoc. - rewrite <-?inst_subst. - rewrite H, ?sub_acc_trans. - repeat f_equal. - change (persist__term a (ω2 ∘ ω3)) with (persist a (ω2 ∘ ω3)). - now rewrite (inst_persist (ω2 ∘ ω3) ι3 a), sub_acc_trans, inst_subst. - Qed. - -End BlockVerificationDerived2Sound. - -Module BlockVerificationDerived2Sem. - Import Contracts. - Import RiscvPmpSignature. - Import RiscvPmpBlockVerifSpec. - Import weakestpre. - Import tactics. - Import BlockVerificationDerived2. - Import Shallow.Executor. - Import ctx.resolution. - Import ctx.notations. - Import env.notations. - Import Model.RiscvPmpIrisBase. - Import Model.RiscvPmpIrisInstance. - Import RiscvPmpIrisInstanceWithContracts. - Import RiscvPmpBlockVerifShalExecutor. - (* Import Model.RiscvPmpModel. *) - (* Import Model.RiscvPmpModel2. *) - (* Import RiscvPmpIrisParams. *) - (* Import RiscvPmpIrisPredicates. *) - (* Import RiscvPmpIrisPrelims. *) - (* Import RiscvPmpIrisResources. *) - Import BlockVerificationDerived2Sound. - (* Import RiscvPmpModelBlockVerif.PLOG. *) - (* Import Sound. *) - - Definition semTripleOneInstrStep `{sailGS Σ} (PRE : iProp Σ) (instr : AST) (POST : Z -> iProp Σ) (a : Z) : iProp Σ := - semTriple [] (PRE ∗ (∃ v, lptsreg nextpc v) ∗ lptsreg pc a ∗ interp_ptsto_instr a instr) - (FunDef RiscvPmpProgram.step) - (fun ret _ => (∃ an, lptsreg nextpc an ∗ lptsreg pc an ∗ POST an) ∗ interp_ptsto_instr a instr)%I. - - Lemma mono_exec_instruction_any__c {i a} : Monotonic' (exec_instruction_any__c i a). - cbv [Monotonic' exec_instruction_any__c bind CHeapSpecM.bind produce_chunk CHeapSpecM.produce_chunk demonic CHeapSpecM.demonic angelic CHeapSpecM.angelic pure CHeapSpecM.pure]. - intros δ P Q PQ h eP v. - destruct (env.nilView δ). - specialize (eP v); revert eP. - apply exec_monotonic. - clear -PQ. intros _ δ h. - destruct (env.nilView δ). - apply consume_chunk_monotonic. - clear -PQ. intros _ h. - intros [v H]; exists v; revert H. - apply consume_chunk_monotonic. - clear -PQ; intros _ h. - apply consume_chunk_monotonic. - clear -PQ; intros _ h. - now apply PQ. - Qed. - - - Lemma sound_exec_instruction_any `{sailGS Σ} {instr} (h : SCHeap) (POST : Val ty_xlenbits -> CStore [ctx] -> iProp Σ) : - forall a, - exec_instruction_any__c instr a (fun res => liftP (POST res)) [] h -> - ⊢ semTripleOneInstrStep (interpret_scheap h)%I instr (fun an => POST an [])%I a. - Proof. - intros a. - intros Hverif. - iIntros "(Hheap & [%npc Hnpc] & Hpc & Hinstrs)". - unfold exec_instruction_any__c, bind, CHeapSpecM.bind, produce_chunk, CHeapSpecM.produce_chunk, demonic, CHeapSpecM.demonic, consume_chunk in Hverif. - specialize (Hverif npc). - assert (ProgramLogic.Triple [] (interpret_scheap (scchunk_ptsreg nextpc npc :: scchunk_user ptstoinstr [a; instr] :: scchunk_ptsreg pc a :: h)%list) (FunDef RiscvPmpProgram.step) (fun res => (fun δ' => interp_ptsto_instr a instr ∗ (∃ v, lptsreg nextpc v ∗ lptsreg pc v ∗ POST v δ'))%I)) as Htriple. - { apply (exec_sound 10). - refine (exec_monotonic 10 _ _ _ _ _ _ Hverif). - intros [] δ0 h0 HYP. - cbn. - refine (consume_chunk_sound (scchunk_user ptstoinstr [a; instr]) (fun δ' => (∃ v, lptsreg nextpc v ∗ lptsreg pc v ∗ POST v δ'))%I δ0 h0 _). - refine (consume_chunk_monotonic _ _ _ _ _ HYP). - intros [] h1 [an Hrest]; revert Hrest. - cbn. - iIntros (HYP') "Hh1". - iExists an. - iStopProof. - refine (consume_chunk_sound (scchunk_ptsreg nextpc an) (fun δ' => lptsreg pc an ∗ POST an δ')%I δ0 h1 _). - refine (consume_chunk_monotonic _ _ _ _ _ HYP'). - intros [] h2 HYP2. - refine (consume_chunk_sound (scchunk_ptsreg pc an) (fun δ' => POST an δ')%I δ0 h2 _). - refine (consume_chunk_monotonic _ _ _ _ _ HYP2). - now intros [] h3 HYP3. - } - apply sound_stm in Htriple. - unfold semTriple in Htriple. - iApply wp_mono. - all: cycle 1. - { iApply Htriple. - iApply BlockVerificationDerivedSem.ValidContractsBlockVerif.contractsSound. - { cbn. now iFrame. } - } - apply BlockVerificationDerivedSem.foreignSemBlockVerif. - apply BlockVerificationDerivedSem.lemSemBlockVerif. - { iIntros ([[] store]) "[Hinstr [%an (Hnextpc & Hpc & HPOST)]]". - destruct (env.nilView store). - iFrame. - iExists an. - iFrame. - } - Qed. - - Local Notation "a '↦' t" := (reg_pointsTo a t) (at level 79). - Local Notation "a '↦ₘ' t" := (interp_ptsto a t) (at level 79). - - Fixpoint ptsto_instrs `{sailGS Σ} (a : Z) (instrs : list AST) : iProp Σ := - match instrs with - | cons inst insts => (interp_ptsto_instr a inst ∗ ptsto_instrs (a + 4) insts)%I - | nil => True%I - end. - Arguments ptsto_instrs {Σ H} a%Z_scope instrs%list_scope : simpl never. - - Lemma mono_exec_block_addr {instrs ainstr apc} : Monotonic' (exec_block_addr__c instrs ainstr apc). - Proof. - revert ainstr apc. - induction instrs; cbn. - - intros ainstr apc δ P Q PQ h. - cbv [pure CHeapSpecM.pure]. - eapply PQ. - - intros ainstr apc. - cbv [Monotonic' bind CHeapSpecM.bind assert CHeapSpecM.assert_formula CHeapSpecM.lift_purem CPureSpecM.assert_formula]. - intros δ P Q PQ h [<- Hverif]. - split; [reflexivity|]. - revert Hverif. - eapply mono_exec_instruction_any__c. - intros res h2. - eapply IHinstrs. - intros res2 h3. - now eapply PQ. - Qed. - - Lemma sound_exec_block_addr `{sailGS Σ} {instrs ainstr apc} (h : SCHeap) (POST : Val ty_xlenbits -> CStore [ctx] -> iProp Σ) : - exec_block_addr__c instrs ainstr apc (fun res => liftP (POST res)) [] h -> - ⊢ ((interpret_scheap h ∗ lptsreg pc apc ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs ainstr instrs) -∗ - (∀ an, lptsreg pc an ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs ainstr instrs ∗ POST an [] -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop)%I. - Proof. - revert ainstr apc h POST. - induction instrs as [|instr instrs]; cbn; intros ainstr apc h POST. - - iIntros (Hverif) "(Hpre & Hpc & Hnpc & _) Hk". - iApply "Hk"; iFrame. - iSplitR; auto. - now iApply Hverif. - - unfold bind, CHeapSpecM.bind, assert, CHeapSpecM.assert_formula. - unfold CHeapSpecM.lift_purem, CPureSpecM.assert_formula. - intros [-> Hverif]. - unfold LoopVerification.WP_loop at 2, FunDef, fun_loop. - assert (⊢ semTripleOneInstrStep (interpret_scheap h)%I instr - (fun an => - lptsreg pc an ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs (apc + 4) instrs -∗ - (∀ an2 : Z, pc ↦ an2 ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs (apc + 4) instrs ∗ POST an2 [env] -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop) apc)%I as Hverif2. - { apply (sound_exec_instruction_any (fun an δ => (lptsreg pc an : iProp Σ) ∗ (∃ v, lptsreg nextpc v : iProp Σ) ∗ ptsto_instrs (apc + 4) instrs -∗ (∀ an2 : Z, pc ↦ an2 ∗ (∃ v, nextpc ↦ v) ∗ ptsto_instrs (apc + 4) instrs ∗ POST an2 [env] -∗ LoopVerification.WP_loop) -∗ LoopVerification.WP_loop)%I). - revert Hverif. - eapply mono_exec_instruction_any__c. - intros an h2. - unfold liftP; cbn. - iIntros (Hverif) "Hh2 (Hpc & Hnpc & Hinstrs) Hk". - iApply (IHinstrs (apc + 4)%Z an _ _ Hverif with "[$]"). - iIntros (an2) "(Hpc & Hinstrs & HPOST)". - iApply "Hk"; now iFrame. - } - iIntros "(Hh & Hpc & Hnpc & Hinstr & Hinstrs) Hk". - iApply (iris_rule_stm_seq _ _ _ _ _ (fun _ _ => True%I) with "[] [Hk Hinstrs] [Hinstr Hpc Hh Hnpc]"). - + iPoseProof Hverif2 as "Hverif2". - unfold semTripleOneInstrStep. - iApply (iris_rule_stm_call_inline env.nil RiscvPmpProgram.step env.nil with "Hverif2"). - + iIntros (δ) "(([%an (Hnpc & Hpc & Hk2)] & Hinstr) & <-)". - iSpecialize ("Hk2" with "[Hpc Hnpc Hinstrs]"). - iFrame. now iExists an. - iApply (wp_mono _ _ _ (fun v => True ∧ _)%I (fun v => True%I)). - all: cycle 1. - iApply (iris_rule_stm_call_inline env.nil RiscvPmpProgram.loop env.nil True%I (fun v => True%I) with "[Hk Hk2 Hinstr] [$]"). - iIntros "_". - iApply "Hk2". - iIntros (an2) "(Hpc & Hnpc & Hinstrs & HPOST)". - iApply "Hk". - iFrame. - now iIntros. - + iFrame. - Qed. - - Definition semTripleBlock `{sailGS Σ} (PRE : Z -> iProp Σ) (instrs : list AST) (POST : Z -> Z -> iProp Σ) : iProp Σ := - (∀ a, - (PRE a ∗ pc ↦ a ∗ (∃ v, nextpc ↦ v) ∗ ptsto_instrs a instrs) -∗ - (∀ an, pc ↦ an ∗ (∃ v, nextpc ↦ v) ∗ ptsto_instrs a instrs ∗ POST a an -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop)%I. - - Lemma sound_exec_triple_addr__c `{sailGS Σ} {W : World} {pre post instrs} {ι : Valuation W} : - (exec_triple_addr__c ι pre instrs post (λ _ _ _ , True) [env] []%list) -> - ⊢ semTripleBlock (λ a : Z, interpret_assertion pre (ι.[("a"::ty_xlenbits) ↦ a])) instrs - (λ a na : Z, interpret_assertion post (ι.[("a"::ty_xlenbits) ↦ a].[("an"::ty_xlenbits) ↦ na])). - Proof. - intros Hexec. - iIntros (a) "(Hpre & Hpc & Hnpc & Hinstrs) Hk". - specialize (Hexec a). - unfold bind, CHeapSpecM.bind, produce in Hexec. - assert (interpret_scheap []%list ∗ interpret_assertion pre ι.[("a"::ty_exc_code) ↦ a] ⊢ - (True ∗ lptsreg pc a ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs a instrs) -∗ - (∀ an, lptsreg pc an ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs a instrs ∗ interpret_assertion post (ι.[("a"::ty_xlenbits) ↦ a].[("an"::ty_xlenbits) ↦ an]) -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop)%I as Hverif. - { refine (@produce_sound _ _ _ _ (ι.[("a"::ty_exc_code) ↦ a]) pre (fun _ => - (True ∗ lptsreg pc a ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs a instrs) -∗ - (∀ an, lptsreg pc an ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs a instrs ∗ interpret_assertion post (ι.[("a"::ty_xlenbits) ↦ a].[("an"::ty_xlenbits) ↦ an]) -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop)%I [env] []%list _). - revert Hexec. - apply produce_monotonic. - unfold consume. - intros _ h Hexec. - cbn. - assert ( - ⊢ ((interpret_scheap h ∗ lptsreg pc a ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs a instrs) -∗ - (∀ an, lptsreg pc an ∗ (∃ v, lptsreg nextpc v) ∗ ptsto_instrs a instrs ∗ - interpret_assertion post ι.["a"∷ty_exc_code ↦ a].["an"∷ty_exc_code ↦ an] - -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop)%I) as Hverifblock. - { eapply (sound_exec_block_addr h - (fun an δ => interpret_assertion post ι.["a"∷ty_exc_code ↦ a].["an"∷ty_exc_code ↦ an])%I). - refine (mono_exec_block_addr _ _ _ _ _ Hexec). - intros res h2 Hcons. cbn. - rewrite <-(bi.sep_True (interpret_assertion post ι.["a"∷ty_exc_code ↦ a].["an"∷ty_exc_code ↦ res] : iProp Σ)). - eapply (consume_sound (fun _ => True%I : iProp Σ)). - revert Hcons. - refine (consume_monotonic _ _ _ _ _). - cbn. now iIntros. - } - iIntros "Hh". - clear -Hverifblock. - iIntros "(_ & Hpc & Hnpc & Hinstrs) Hk". - iApply (Hverifblock with "[Hh Hpc Hnpc Hinstrs] Hk"). - iFrame. - } - iApply (Hverif with "[Hpre] [Hpc Hnpc Hinstrs]"); - cbn; iFrame. - Qed. - - Lemma sound_VC__addr `{sailGS Σ} {Γ} {pre post instrs} : - safeE (simplify (BlockVerificationDerived2.VC__addr (Σ := Γ) pre instrs post)) -> - forall ι, - ⊢ semTripleBlock (fun a => interpret_assertion pre (ι.[("a"::ty_xlenbits) ↦ a])) - instrs - (fun a na => interpret_assertion post (ι.[("a"::ty_xlenbits) ↦ a].[("an"::ty_xlenbits) ↦ na])). - Proof. - intros Hverif ι. - eapply (sound_exec_triple_addr__c (W := {| wctx := Γ ; wco := [] |}) (pre := pre) (post := post) (instrs := instrs)). - eapply (refine_exec_triple_addr (Σ := {| wctx := Γ ; wco := [] |}) I (ta := λ w1 _ _ _ _, SymProp.block)). - all: cycle 3. - - rewrite SymProp.wsafe_safe SymProp.safe_debug_safe. - eapply (safeE_safe env.nil), simplify_sound in Hverif. - rewrite SymProp.safe_demonic_close in Hverif. - now eapply Hverif. - - unfold refine, RefineBox, RefineImpl, refine, RefineProp. - now intros. - - reflexivity. - - reflexivity. - Qed. - - Definition advAddrs := seqZ 88 (maxAddr - 88 + 1). - - (* Lemma liveAddr_split : liveAddrs = seqZ minAddr 88 ++ advAddrs. *) - (* Proof. *) - (* unfold liveAddrs. *) - (* change 88%Z with (minAddr + 88)%Z at 2. *) - (* replace (maxAddr - minAddr + 1)%Z with (88 + (maxAddr - 88 - minAddr + 1))%Z by lia. *) - (* eapply seqZ_app; unfold minAddr, maxAddr; lia. *) - (* Qed. *) - - Global Instance dec_has_some_access {ents p1} : forall x, Decision (exists p2, Pmp_access x ents p1 p2). - Proof. - intros x. - eapply finite.exists_dec. - intros p2. - unfold Pmp_access. - destruct (decide_pmp_access x ents p1 p2); [left|right]; intuition. - Defined. - - Lemma liveAddr_filter_advAddr : filter - (λ x : Val ty_exc_code, - (∃ p : Val ty_access_type, Pmp_access x BlockVerificationDerived2.femto_pmpentries User p)%type) - liveAddrs = advAddrs. - Proof. - now compute. - Qed. - - Lemma big_sepL_filter `{BiAffine PROP} {A : Type} {l : list A} - {φ : A → Prop} (dec : ∀ x, Decision (φ x)) (Φ : A -> PROP) : - ([∗ list] x ∈ filter φ l, Φ x) ⊣⊢ - ([∗ list] x ∈ l, ⌜φ x⌝ -∗ Φ x). - Proof. induction l. - - now cbn. - - cbn. - destruct (decide (φ a)) as [Hφ|Hnφ]. - + rewrite big_opL_cons. - rewrite <-IHl. - iSplit; iIntros "[Ha Hl]"; iFrame; try done. - now iApply ("Ha" $! Hφ). - + rewrite <-IHl. - iSplit. - * iIntros "Hl"; iFrame; iIntros "%Hφ"; intuition. - * iIntros "[Ha Hl]"; now iFrame. - Qed. - - Lemma memAdv_pmpPolicy `{sailGS Σ} : - (ptstoSthL advAddrs ⊢ - interp_pmp_addr_access liveAddrs BlockVerificationDerived2.femto_pmpentries User)%I. - Proof. - iIntros "Hadv". - unfold interp_pmp_addr_access. - rewrite <-(big_sepL_filter). - unfold ptstoSthL. - now rewrite <- liveAddr_filter_advAddr. - Qed. - - Definition femto_inv_ns : ns.namespace := (ns.ndot ns.nroot "femto_inv_ns"). - - Import iris.base_logic.lib.invariants. - (* This lemma transforms the postcondition of femtokernel_init into the precondition of the universal contract, so that we can use the UC to verify the invocation of untrusted code. - *) - - (* DOMI: for simplicity, we're currently treating the femtokernel invariant on the private state not as a shared invariant but as a piece of private state to be framed off during every invocation of the adversary. This is fine since for now we're assuming no concurrency... *) - Definition femto_inv_fortytwo `{sailGS Σ} : iProp Σ := - (interp_ptsto 84 42). - - Definition femto_handler_pre `{sailGS Σ} epc : iProp Σ := - (mstatus ↦ {| MPP := User |}) ∗ - (mtvec ↦ 72) ∗ - (∃ v, mcause ↦ v) ∗ - (mepc ↦ epc) ∗ - cur_privilege ↦ Machine ∗ - (∃ v, x1 ↦ v) ∗ - (∃ v, x2 ↦ v) ∗ - (∃ v, x3 ↦ v) ∗ - (∃ v, x4 ↦ v) ∗ - (∃ v, x5 ↦ v) ∗ - (∃ v, x6 ↦ v) ∗ - (∃ v, x7 ↦ v) ∗ - interp_pmp_entries BlockVerificationDerived2.femto_pmpentries ∗ - femto_inv_fortytwo ∗ - pc ↦ 72 ∗ - (∃ v, nextpc ↦ v) ∗ - ptsto_instrs 72 BlockVerificationDerived2.femtokernel_handler. - - Example femto_handler_post `{sailGS Σ} epc : iProp Σ := - (mstatus ↦ {| MPP := User |}) ∗ - (mtvec ↦ 72) ∗ - (∃ v, mcause ↦ v) ∗ - (mepc ↦ epc) ∗ - cur_privilege ↦ User ∗ - (∃ v, x1 ↦ v) ∗ - (∃ v, x2 ↦ v) ∗ - (∃ v, x3 ↦ v) ∗ - (∃ v, x4 ↦ v) ∗ - (∃ v, x5 ↦ v) ∗ - (∃ v, x6 ↦ v) ∗ - (∃ v, x7 ↦ v) ∗ - interp_pmp_entries BlockVerificationDerived2.femto_pmpentries ∗ - femto_inv_fortytwo ∗ - pc ↦ epc ∗ - (∃ v, nextpc ↦ v) ∗ - ptsto_instrs 72 BlockVerificationDerived2.femtokernel_handler. - - Definition femto_handler_contract `{sailGS Σ} : iProp Σ := - ∀ epc, - femto_handler_pre epc -∗ - (femto_handler_post epc -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop. - - (* Note: temporarily make femtokernel_init_pre opaque to prevent Gallina typechecker from taking extremely long *) - Opaque femtokernel_handler_pre. - - Import env.notations. - Lemma femto_handler_verified : forall `{sailGS Σ}, ⊢ femto_handler_contract. - Proof. - iIntros (Σ sG epc) "Hpre Hk". - iApply (sound_VC__addr $! 72 with "[Hpre] [Hk]"). - - exact BlockVerificationDerived2.sat__femtohandler. - Unshelve. - exact (env.snoc env.nil (_::ty_exc_code) epc). - - iDestruct "Hpre" as "(Hmstatus & Hmtvec & Hmcause & Hmepc & Hcurpriv & Hx1 & Hx2 & Hx3 & Hx4 & Hx5 & Hx6 & Hx7 & (Hpmp0cfg & Hpmpaddr0 & Hpmp1cfg & Hpmpaddr1) & Hfortytwo & Hpc & Hnpc & Hhandler)". - cbn. - unfold femto_inv_fortytwo. - now iFrame. - - iIntros (an) "(Hpc & Hnpc & Hhandler & (Hmstatus & Hmtvec & Hmcause & Hmepc & Hcurpriv & Hx1 & Hx2 & Hx3 & Hx4 & Hx5 & Hx6 & Hx7 & (Hpmp0cfg & Hpmp1cfg & Hpmpaddr0 & Hpmpaddr1 & Hfortytwo & %eq & _)))". - cbn. - iApply "Hk". - unfold femto_handler_post. - cbn in eq; destruct eq. - now iFrame. - Qed. - - Transparent femtokernel_handler_pre. - - Lemma femtokernel_hander_safe `{sailGS Σ} {mepcv}: - ⊢ mstatus ↦ {| MPP := User |} ∗ - (mtvec ↦ 72) ∗ - (∃ v, mcause ↦ v) ∗ - (mepc ↦ mepcv) ∗ - cur_privilege ↦ Machine ∗ - interp_gprs ∗ - interp_pmp_entries BlockVerificationDerived2.femto_pmpentries ∗ - femto_inv_fortytwo ∗ - (pc ↦ 72) ∗ - interp_pmp_addr_access liveAddrs BlockVerificationDerived2.femto_pmpentries User ∗ - (∃ v, nextpc ↦ v) ∗ - (* ptsto_instrs 0 femtokernel_init ∗ (domi: init code not actually needed anymore, can be dropped) *) - ptsto_instrs 72 BlockVerificationDerived2.femtokernel_handler - -∗ - LoopVerification.WP_loop. - Proof. - unfold interp_gprs; cbn -[interp_pmp_entries]. - rewrite ?big_opS_union ?big_opS_singleton ?big_opS_empty; try set_solver. - iIntros "". - iLöb as "Hind". - iIntros "(Hmstatus & Hmtvec & Hmcause & Hmepc & Hcurpriv & Hgprs & Hpmpentries & Hfortytwo & Hpc & Hmem & Hnextpc & Hinstrs)". - - iApply (femto_handler_verified $! mepcv with "[Hmstatus Hmtvec Hmcause Hmepc Hcurpriv Hgprs Hpmpentries Hfortytwo Hpc Hinstrs Hnextpc] [Hmem]"). - - unfold femto_handler_pre; iFrame. - iDestruct "Hgprs" as "(? & ? & ? & ? & ? & ? & ? & ? & _)". - now iFrame. - - iIntros "(Hmstatus & Hmtvec & Hmcause & Hmepc & Hcurpriv & Hx1 & Hx2 & Hx3 & Hx4 & Hx5 & Hx6 & Hx7 & Hpmpentries & Hfortytwo & Hpc & Hnextpc & Hinstrs)". - iApply LoopVerification.valid_semTriple_loop. - iSplitL "Hmem Hnextpc Hmstatus Hmtvec Hmcause Hmepc Hcurpriv Hx1 Hx2 Hx3 Hx4 Hx5 Hx6 Hx7 Hpmpentries Hpc". - + unfold LoopVerification.Execution. - iFrame. - iSplitR "Hpc". - * unfold interp_gprs; cbn -[interp_pmp_entries]. - rewrite ?big_opS_union ?big_opS_singleton ?big_opS_empty; try set_solver. - now iFrame. - * now iExists _. - + iSplitL "". - iModIntro. - unfold LoopVerification.CSRMod. - iIntros "(_ & _ & _ & %eq & _)". - inversion eq. - - iSplitR "". - iModIntro. - unfold LoopVerification.Trap. - iIntros "(Hmem & Hgprs & Hpmpentries & Hmcause & Hcurpriv & Hnextpc & Hpc & Hmtvec & Hmstatus & Hmepc)". - iApply "Hind". - unfold interp_gprs; cbn -[interp_pmp_entries]. - rewrite ?big_opS_union ?big_opS_singleton ?big_opS_empty; try set_solver. - iFrame. - now iExists _. - - iModIntro. - unfold LoopVerification.Recover. - iIntros "(_ & _ & _ & %eq & _)". - inversion eq. - Qed. - - Lemma femtokernel_manualStep2 `{sailGS Σ} : - ⊢ (∃ mpp, mstatus ↦ {| MPP := mpp |}) ∗ - (mtvec ↦ 72) ∗ - (∃ v, mcause ↦ v) ∗ - (∃ v, mepc ↦ v) ∗ - cur_privilege ↦ User ∗ - interp_gprs ∗ - interp_pmp_entries BlockVerificationDerived2.femto_pmpentries ∗ - (interp_ptsto 84 42) ∗ - (pc ↦ 88) ∗ - (∃ v, nextpc ↦ v) ∗ - (* ptsto_instrs 0 femtokernel_init ∗ (domi: init code not actually needed anymore, can be dropped) *) - ptsto_instrs 72 BlockVerificationDerived2.femtokernel_handler ∗ - ptstoSthL advAddrs - ={⊤}=∗ - ∃ mpp mepcv, LoopVerification.loop_pre User User 72 72 BlockVerificationDerived2.femto_pmpentries BlockVerificationDerived2.femto_pmpentries mpp mepcv. - Proof. - iIntros "([%mpp Hmst] & Hmtvec & [%mcause Hmcause] & [%mepc Hmepc] & Hcurpriv & Hgprs & Hpmpcfg & Hfortytwo & Hpc & Hnpc & Hhandler & Hmemadv)". - iExists mpp, mepc. - unfold LoopVerification.loop_pre, LoopVerification.Execution, interp_gprs. - rewrite ?big_opS_union ?big_opS_singleton ?big_opS_empty; try set_solver. - iFrame. - - (* iMod (inv_alloc femto_inv_ns ⊤ (interp_ptsto (mG := sailGS_memGS) 84 42) with "Hfortytwo") as "#Hinv". *) - (* change (inv femto_inv_ns (84 ↦ₘ 42)) with femto_inv_fortytwo. *) - iModIntro. - - iSplitL "Hmcause Hpc Hmemadv". - iSplitL "Hmemadv". - now iApply memAdv_pmpPolicy. - iSplitL "Hmcause". - now iExists mcause. - iExists 88; iFrame. - - iSplitL "". - iModIntro. - unfold LoopVerification.CSRMod. - iIntros "(_ & _ & _ & %eq & _)". - inversion eq. - - iSplitL. - unfold LoopVerification.Trap. - iModIntro. - iIntros "(Hmem & Hgprs & Hpmpents & Hmcause & Hcurpriv & Hnpc & Hpc & Hmtvec & Hmstatus & Hmepc)". - iApply femtokernel_hander_safe. - iFrame. - now iExists _. - - iModIntro. - unfold LoopVerification.Recover. - iIntros "(_ & _ & _ & %eq & _)". - inversion eq. - Qed. - - Definition femto_init_pre `{sailGS Σ} : iProp Σ := - ((∃ v, mstatus ↦ v) ∗ - (∃ v, mtvec ↦ v) ∗ - (∃ v, mcause ↦ v) ∗ - (∃ v, mepc ↦ v) ∗ - cur_privilege ↦ Machine ∗ - (∃ v, x1 ↦ v) ∗ - (∃ v, x2 ↦ v) ∗ - (∃ v, x3 ↦ v) ∗ - (∃ v, x4 ↦ v) ∗ - (∃ v, x5 ↦ v) ∗ - (∃ v, x6 ↦ v) ∗ - (∃ v, x7 ↦ v) ∗ - pmp0cfg ↦ BlockVerificationDerived2.femtokernel_default_pmpcfg ∗ - pmp1cfg ↦ BlockVerificationDerived2.femtokernel_default_pmpcfg ∗ - (∃ v, pmpaddr0 ↦ v) ∗ - (∃ v, pmpaddr1 ↦ v) ∗ - femto_inv_fortytwo) ∗ - pc ↦ 0 ∗ - (∃ v, nextpc ↦ v) ∗ - ptsto_instrs 0 BlockVerificationDerived2.femtokernel_init. - - Example femto_init_post `{sailGS Σ} : iProp Σ := - ((∃ v, mstatus ↦ v) ∗ - (mtvec ↦ 72) ∗ - (∃ v, mcause ↦ v) ∗ - (∃ v, mepc ↦ v) ∗ - cur_privilege ↦ User ∗ - (∃ v, x1 ↦ v) ∗ - (∃ v, x2 ↦ v) ∗ - (∃ v, x3 ↦ v) ∗ - (∃ v, x4 ↦ v) ∗ - (∃ v, x5 ↦ v) ∗ - (∃ v, x6 ↦ v) ∗ - (∃ v, x7 ↦ v) ∗ - pmp0cfg ↦ BlockVerificationDerived2.femto_pmpcfg_ent0 ∗ - pmp1cfg ↦ BlockVerificationDerived2.femto_pmpcfg_ent1 ∗ - (pmpaddr0 ↦ 88) ∗ - (pmpaddr1 ↦ BlockVerificationDerived2.femto_address_max) ∗ - femto_inv_fortytwo) ∗ - pc ↦ 88 ∗ - (∃ v, nextpc ↦ v) ∗ - ptsto_instrs 0 BlockVerificationDerived2.femtokernel_init. - - Definition femto_init_contract `{sailGS Σ} : iProp Σ := - femto_init_pre -∗ - (femto_init_post -∗ LoopVerification.WP_loop) -∗ - LoopVerification.WP_loop. - - (* Note: temporarily make femtokernel_init_pre opaque to prevent Gallina typechecker from taking extremely long *) - Opaque femtokernel_init_pre. - - Lemma femto_init_verified : forall `{sailGS Σ}, ⊢ femto_init_contract. - Proof. - iIntros (Σ sG) "Hpre Hk". - iApply (sound_VC__addr $! 0 with "[Hpre] [Hk]"). - - exact BlockVerificationDerived2.sat__femtoinit. - Unshelve. - exact env.nil. - - unfold femto_init_pre. - unfold interpret_assertion; cbn -[ptsto_instrs]. - iDestruct "Hpre" as "[Hpre1 Hpre2]". - now iFrame. - - iIntros (an) "Hpost". - iApply "Hk". - unfold femto_init_post. - cbn -[ptsto_instrs]. - iDestruct "Hpost" as "(Hpc & Hnpc & Hhandler & ([%eq _] & Hrest))". - subst. - iFrame. - Qed. - - (* see above *) - Transparent femtokernel_init_pre. - - Lemma femtokernel_init_safe `{sailGS Σ} : - ⊢ (∃ v, mstatus ↦ v) ∗ - (∃ v, mtvec ↦ v) ∗ - (∃ v, mcause ↦ v) ∗ - (∃ v, mepc ↦ v) ∗ - cur_privilege ↦ Machine ∗ - interp_gprs ∗ - reg_pointsTo pmp0cfg BlockVerificationDerived2.femtokernel_default_pmpcfg ∗ - (∃ v, reg_pointsTo pmpaddr0 v) ∗ - reg_pointsTo pmp1cfg BlockVerificationDerived2.femtokernel_default_pmpcfg ∗ - (∃ v, reg_pointsTo pmpaddr1 v) ∗ - (pc ↦ 0) ∗ - interp_ptsto 84 42 ∗ - ptstoSthL advAddrs ∗ - (∃ v, nextpc ↦ v) ∗ - ptsto_instrs 0 BlockVerificationDerived2.femtokernel_init ∗ - ptsto_instrs 72 BlockVerificationDerived2.femtokernel_handler - -∗ - LoopVerification.WP_loop. - Proof. - iIntros "(Hmstatus & Hmtvec & Hmcause & Hmepc & Hcurpriv & Hgprs & Hpmp0cfg & Hpmpaddr0 & Hpmp1cfg & Hpmpaddr1 & Hpc & Hfortytwo & Hadv & Hnextpc & Hinit & Hhandler)". - unfold interp_gprs. - rewrite ?big_opS_union ?big_opS_singleton ?big_opS_empty; try set_solver. - iDestruct "Hgprs" as "(_ & Hx1 & Hx2 & Hx3 & Hx4 & Hx5 & Hx6 & Hx7 & _)". - iApply (femto_init_verified with "[Hmstatus Hmtvec Hmcause Hmepc Hcurpriv Hx1 Hx2 Hx3 Hx4 Hx5 Hx6 Hx7 Hpmp0cfg Hpmpaddr0 Hpmp1cfg Hpmpaddr1 Hpc Hinit Hfortytwo Hnextpc]"). - - unfold femto_init_pre. - iFrame. - - iIntros "((Hmstatus & Hmtvec & Hmcause & Hmepc & Hcurpriv & Hx1 & Hx2 & Hx3 & Hx4 & Hx5 & Hx6 & Hx7 & Hpmp0cfg & Hpmpaddr0 & Hpmp1cfg & Hpmpaddr1 & Hfortytwo) & Hpc & Hnextpc & Hinit)". - iAssert (interp_pmp_entries BlockVerificationDerived2.femto_pmpentries) with "[Hpmp0cfg Hpmpaddr0 Hpmp1cfg Hpmpaddr1]" as "Hpmpents". - { unfold interp_pmp_entries; cbn; iFrame. } - iAssert interp_gprs with "[Hx1 Hx2 Hx3 Hx4 Hx5 Hx6 Hx7]" as "Hgprs". - { unfold interp_gprs. - rewrite ?big_opS_union ?big_opS_singleton ?big_opS_empty; try set_solver. - iFrame. - now iExists 0. - } - iApply fupd_wp. - iMod (femtokernel_manualStep2 with "[Hmstatus Hmtvec Hmcause Hgprs Hcurpriv Hpmpents Hfortytwo Hpc Hnextpc Hhandler Hadv Hmepc ]") as "[%mpp [%mepcv Hlooppre]]". - { iFrame. - iDestruct "Hmstatus" as "[%mst Hmstatus]". - destruct mst as [mpp]. - now iExists mpp. - } - iApply (LoopVerification.valid_semTriple_loop $! User User 72 72 BlockVerificationDerived2.femto_pmpentries BlockVerificationDerived2.femto_pmpentries mpp mepcv). - iModIntro. - iExact "Hlooppre". - Qed. - - Print Assumptions femtokernel_init_safe. - -End BlockVerificationDerived2Sem. diff --git a/case_study/RiscvPmp/Contracts.v b/case_study/RiscvPmp/Contracts.v deleted file mode 100644 index e9a60d21..00000000 --- a/case_study/RiscvPmp/Contracts.v +++ /dev/null @@ -1,2010 +0,0 @@ -(******************************************************************************) -(* Copyright (c) 2020 Steven Keuchel, Dominique Devriese, Sander Huyghebaert *) -(* All rights reserved. *) -(* *) -(* Redistribution and use in source and binary forms, with or without *) -(* modification, are permitted provided that the following conditions are *) -(* met: *) -(* *) -(* 1. Redistributions of source code must retain the above copyright notice, *) -(* this list of conditions and the following disclaimer. *) -(* *) -(* 2. Redistributions in binary form must reproduce the above copyright *) -(* notice, this list of conditions and the following disclaimer in the *) -(* documentation and/or other materials provided with the distribution. *) -(* *) -(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) -(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) -(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *) -(* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR *) -(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *) -(* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *) -(* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *) -(* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *) -(* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *) -(* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *) -(* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) -(******************************************************************************) - -From Coq Require Import - ZArith.ZArith - Lists.List - Strings.String. -From Katamaran Require Import - Notations - Shallow.Executor - Specification - Symbolic.Executor - Symbolic.Solver - Symbolic.Propositions - Symbolic.Worlds - RiscvPmp.Machine. -From Equations Require Import - Equations. - -Import RiscvPmpProgram. - -Set Implicit Arguments. -Import ctx.resolution. -Import ctx.notations. -Import env.notations. -Import ListNotations. -Open Scope string_scope. -Open Scope ctx_scope. -Open Scope Z_scope. - -Inductive PurePredicate : Set := -| pmp_access -| pmp_check_perms -| pmp_check_rwx -| sub_perm -| within_cfg -| not_within_cfg -| prev_addr -| in_entries -. - -Inductive Predicate : Set := -| pmp_entries -| pmp_addr_access -| pmp_addr_access_without -| gprs -| ptsto -| encodes_instr -| ptstomem -| ptstoinstr -. - -Section TransparentObligations. - Local Set Transparent Obligations. - - Derive NoConfusion for PurePredicate. - Derive NoConfusion for Predicate. - -End TransparentObligations. - -Derive EqDec for PurePredicate. -Derive EqDec for Predicate. - -Module Import RiscvPmpSignature <: Signature RiscvPmpBase. -Import RiscvPmpBase. -Section PredicateKit. - Definition 𝑷 := PurePredicate. - Definition 𝑷_Ty (p : 𝑷) : Ctx Ty := - match p with - | pmp_access => [ty_xlenbits; ty.list ty_pmpentry; ty_privilege; ty_access_type] - | pmp_check_perms => [ty_pmpcfg_ent; ty_access_type; ty_privilege] - | pmp_check_rwx => [ty_pmpcfg_ent; ty_access_type] - | sub_perm => [ty_access_type; ty_access_type] - | within_cfg => [ty_xlenbits; ty_pmpcfg_ent; ty_xlenbits; ty_xlenbits] - | not_within_cfg => [ty_xlenbits; ty.list ty_pmpentry] - | prev_addr => [ty_pmpcfgidx; ty.list ty_pmpentry; ty_xlenbits] - | in_entries => [ty_pmpcfgidx; ty_pmpentry; ty.list ty_pmpentry] - end. - - Definition PmpEntryCfg : Set := Pmpcfg_ent * Xlenbits. - Definition PmpAddrRange := option (Xlenbits * Xlenbits). - - Definition pmp_check_RWX (cfg : Val ty_pmpcfg_ent) (acc : Val ty_access_type) : bool := - match cfg with - | {| L := _; A := _; X := X; W := W; R := R |} => - match acc with - | Read => R - | Write => W - | ReadWrite => R && W - | Execute => X - end - end. - - Definition pmp_get_RWX (cfg : Val ty_pmpcfg_ent) : Val ty_access_type := - match cfg with - | {| L := _; A := _; X := X; W := W; R := R |} => - match X, W, R with - | false, false, true => Read - | false, true, false => Write - | true, false, false => Execute - | _, _, _ => ReadWrite - end - end. - - Definition decide_pmp_check_perms (cfg : Val ty_pmpcfg_ent) (acc : Val ty_access_type) (p : Val ty_privilege) : bool := - match p with - | Machine => - if L cfg - then pmp_check_RWX cfg acc - else true - | User => - pmp_check_RWX cfg acc - end. - - Definition pmp_get_perms (cfg : Val ty_pmpcfg_ent) (p : Val ty_privilege) : option (Val ty_access_type) := - match p with - | Machine => - if L cfg - then Some (pmp_get_RWX cfg) - else None - | User => - Some (pmp_get_RWX cfg) - end. - - Definition pmp_addr_range (cfg : Pmpcfg_ent) (hi lo : Xlenbits) : PmpAddrRange := - match A cfg with - | OFF => None - | TOR => Some (lo , hi) - end. - - Definition pmp_match_addr (a : Val ty_xlenbits) (rng : PmpAddrRange) : Val ty_pmpaddrmatch := - match rng with - | Some (lo, hi) => - if hi PMP_NoMatch - end. - - Definition pmp_match_entry (a : Val ty_xlenbits) (m : Val ty_privilege) (cfg : Val ty_pmpcfg_ent) (lo hi : Val ty_xlenbits) : Val ty_pmpmatch := - let rng := pmp_addr_range cfg hi lo in - match pmp_match_addr a rng with - | PMP_NoMatch => PMP_Continue - | PMP_PartialMatch => PMP_Fail - | PMP_Match => PMP_Success - end. - - Fixpoint pmp_check (a : Val ty_xlenbits) (entries : Val (ty.list ty_pmpentry)) (prev : Val ty_xlenbits) (m : Val ty_privilege) : (bool * option (Val ty_access_type)) := - match entries with - | [] => match m with - | Machine => (true, None) - | User => (false, None) - end - | (cfg , addr) :: entries => - match pmp_match_entry a m cfg prev addr with - | PMP_Success => (true, pmp_get_perms cfg m) - | PMP_Fail => (false, None) - | PMP_Continue => pmp_check a entries addr m - end - end%list. - - (* check_access is based on the pmpCheck algorithm, main difference - is that we can define it less cumbersome because entries will contain - the PMP entries in highest-priority order. *) - Definition check_pmp_access (a : Val ty_xlenbits) (entries : Val (ty.list ty_pmpentry)) (m : Val ty_privilege) : (bool * option (Val ty_access_type)) := - pmp_check a entries 0 m. - - Equations access_type_eqb (a1 a2 : Val ty_access_type) : bool := - | Read | Read := true; - | Write | Write := true; - | ReadWrite | ReadWrite := true; - | Execute | Execute := true; - | _ | _ := false. - - Equations decide_sub_perm (a1 a2 : Val ty_access_type) : bool := - | Read | Read := true; - | Write | Write := true; - | Execute | Execute := true; - | ReadWrite | ReadWrite := true; - | Read | Execute := true; - | Read | ReadWrite := true; - | Write | ReadWrite := true; - | _ | _ := false. - - Lemma decide_sub_perm_refl (a1 a2 : Val ty_access_type) : - a1 = a2 -> decide_sub_perm a1 a2 = true. - Proof. - intros ->; destruct a2; auto. - Qed. - - Definition Sub_perm (a1 a2 : Val ty_access_type) : Prop := - decide_sub_perm a1 a2 = true. - - Definition decide_pmp_access (a : Val ty_xlenbits) (entries : Val (ty.list ty_pmpentry)) (m : Val ty_privilege) (p : Val ty_access_type) : bool := - match check_pmp_access a entries m with - | (true, Some acc) => decide_sub_perm acc p - | (true, None) => true - | (false, _) => false - end. - - Definition Pmp_access (a : Val ty_xlenbits) (entries : Val (ty.list ty_pmpentry)) (m : Val ty_privilege) (p : Val ty_access_type) : Prop := - decide_pmp_access a entries m p = true. - - Definition Pmp_check_perms (cfg : Val ty_pmpcfg_ent) (acc : Val ty_access_type) (p : Val ty_privilege) : Prop := - decide_pmp_check_perms cfg acc p = true. - - Definition Pmp_check_rwx (cfg : Val ty_pmpcfg_ent) (acc : Val ty_access_type) : Prop := - pmp_check_RWX cfg acc = true. - - Equations PmpAddrMatchType_eqb (a1 a2 : PmpAddrMatchType) : bool := - | OFF | OFF := true; - | TOR | TOR := true; - | _ | _ := false. - - Definition pmpcfg_ent_eqb (c1 c2 : Pmpcfg_ent) : bool := - match c1, c2 with - | {| L := L1; A := A1; X := X1; W := W1; R := R1 |}, - {| L := L2; A := A2; X := X2; W := W2; R := R2 |} => - (Bool.eqb L1 L2) && (PmpAddrMatchType_eqb A1 A2) && (Bool.eqb X1 X2) - && (Bool.eqb W1 W2) && (Bool.eqb R1 R2) - end. - - Definition decide_in_entries (idx : Val ty_pmpcfgidx) (e : Val ty_pmpentry) (es : Val (ty.list ty_pmpentry)) : bool := - match es with - | cfg0 :: cfg1 :: [] => - let (c, a) := e in - let (c', a') := match idx with - | PMP0CFG => cfg0 - | PMP1CFG => cfg1 - end in - (pmpcfg_ent_eqb c c' && (a =? a')%Z)%bool - | _ => false - end%list. - - Definition In_entries (idx : Val ty_pmpcfgidx) (e : Val ty_pmpentry) (es : Val (ty.list ty_pmpentry)) : Prop := - decide_in_entries idx e es = true. - - Definition decide_prev_addr (cfg : Val ty_pmpcfgidx) (entries : Val (ty.list ty_pmpentry)) (prev : Val ty_xlenbits) : bool := - match entries with - | (c0 , a0) :: (c1 , a1) :: [] => - match cfg with - | PMP0CFG => prev =? 0 - | PMP1CFG => prev =? a0 - end - | _ => false - end%list. - - Definition Prev_addr (cfg : Val ty_pmpcfgidx) (entries : Val (ty.list ty_pmpentry)) (prev : Val ty_xlenbits) : Prop := - decide_prev_addr cfg entries prev = true. - - Definition decide_within_cfg (paddr : Val ty_xlenbits) (cfg : Val ty_pmpcfg_ent) (prev_addr addr : Val ty_xlenbits) : bool := - match A cfg with - | OFF => false - | TOR => (prev_addr <=? paddr)%Z && (paddr - (((PmpAddrMatchType_eqb (A c0) OFF) && (PmpAddrMatchType_eqb (A c1) OFF)) - || ((0 <=? paddr)%Z && (a0 <=? paddr)%Z && (a1 <=? paddr)%Z))%bool - | _ => false - end%list. - - Definition Not_within_cfg (paddr : Val ty_xlenbits) (entries : Val (ty.list ty_pmpentry)) : Prop := - decide_not_within_cfg paddr entries = true. - Definition 𝑷_inst (p : 𝑷) : env.abstract Val (𝑷_Ty p) Prop := - match p with - | pmp_access => Pmp_access - | pmp_check_perms => Pmp_check_perms - | pmp_check_rwx => Pmp_check_rwx - | sub_perm => Sub_perm - | within_cfg => Within_cfg - | not_within_cfg => Not_within_cfg - | prev_addr => Prev_addr - | in_entries => In_entries - end. - - Instance 𝑷_eq_dec : EqDec 𝑷 := PurePredicate_eqdec. - - Definition 𝑯 := Predicate. - Definition 𝑯_Ty (p : 𝑯) : Ctx Ty := - match p with - | pmp_entries => [ty.list ty_pmpentry] - | pmp_addr_access => [ty.list ty_pmpentry; ty_privilege] - | pmp_addr_access_without => [ty_xlenbits; ty.list ty_pmpentry; ty_privilege] - | gprs => ctx.nil - | ptsto => [ty_xlenbits; ty_xlenbits] - | encodes_instr => [ty.int; ty_ast] - | ptstomem => [ty_xlenbits; ty.int; ty.list ty_word] - | ptstoinstr => [ty_xlenbits; ty_ast] - end. - - Global Instance 𝑯_is_dup : IsDuplicable Predicate := { - is_duplicable p := - match p with - | pmp_entries => false - | pmp_addr_access => false - | pmp_addr_access_without => false - | gprs => false - | ptsto => false - | encodes_instr => true - | ptstomem => false - | ptstoinstr => false - end - }. - Instance 𝑯_eq_dec : EqDec 𝑯 := Predicate_eqdec. - - Local Arguments Some {_} &. - - (* TODO: look up precise predicates again, check if below makes sense *) - Definition 𝑯_precise (p : 𝑯) : option (Precise 𝑯_Ty p) := - match p with - | ptsto => Some (MkPrecise [ty_xlenbits] [ty_word] eq_refl) - | pmp_entries => Some (MkPrecise ε [ty.list ty_pmpentry] eq_refl) - | pmp_addr_access => Some (MkPrecise ε [ty.list ty_pmpentry; ty_privilege] eq_refl) - | pmp_addr_access_without => Some (MkPrecise [ty_xlenbits] [ty.list ty_pmpentry; ty_privilege] eq_refl) - | ptstomem => Some (MkPrecise [ty_xlenbits; ty.int] [ty.list ty_word] eq_refl) - | ptstoinstr => Some (MkPrecise [ty_xlenbits] [ty_ast] eq_refl) - | encodes_instr => Some (MkPrecise [ty.int] [ty_ast] eq_refl) - | _ => None - end. - -End PredicateKit. - -Include PredicateMixin RiscvPmpBase. - -Section ContractDefKit. - - Local Notation "r '↦' val" := (asn_chunk (chunk_ptsreg r val)) (at level 70). - Local Notation "a '↦ₘ' t" := (asn_chunk (chunk_user ptsto [a; t])) (at level 70). - Local Notation "p '∗' q" := (asn_sep p q). - Local Notation "a '=' b" := (asn_eq a b). - Local Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - Local Notation "a '∨' b" := (asn_or a b). - Local Notation "p '⊑' q" := (asn_formula (formula_user sub_perm [p;q])) (at level 70). - Local Notation "a <ₜ b" := (term_binop bop.lt a b) (at level 60). - Local Notation "a <=ₜ b" := (term_binop bop.le a b) (at level 60). - Local Notation "a &&ₜ b" := (term_binop bop.and a b) (at level 80). - Local Notation "a ||ₜ b" := (term_binop bop.or a b) (at level 85). - Local Notation asn_match_option T opt xl alt_inl alt_inr := (asn_match_sum T ty.unit opt xl alt_inl "_" alt_inr). - Local Notation asn_pmp_entries l := (asn_chunk (chunk_user pmp_entries [l])). - (* TODO: check if I can reproduce the issue with angelic stuff, I think it was checked_mem_read, with the correct postcondition *) - (* Local Notation asn_pmp_entries_angelic l := (asn_chunk_angelic (chunk_user pmp_entries [l])). *) - Local Notation asn_pmp_addr_access l m := (asn_chunk (chunk_user pmp_addr_access [l; m])). - Local Notation asn_pmp_addr_access_without a l m := (asn_chunk (chunk_user pmp_addr_access_without [a;l; m])). - Local Notation asn_gprs := (asn_chunk (chunk_user gprs env.nil)). - Local Notation asn_within_cfg a cfg prev_addr addr := (asn_formula (formula_user within_cfg [a; cfg; prev_addr; addr])). - Local Notation asn_not_within_cfg a es := (asn_formula (formula_user not_within_cfg [a; es])). - Local Notation asn_prev_addr cfg es prev := (asn_formula (formula_user prev_addr [cfg; es; prev])). - Local Notation asn_in_entries idx e es := (asn_formula (formula_user in_entries [idx; e; es])). - Local Notation asn_pmp_access addr es m p := (asn_formula (formula_user pmp_access [addr;es;m;p])). - Local Notation asn_pmp_check_perms cfg acc p := (asn_formula (formula_user pmp_check_perms [cfg;acc;p])). - Local Notation asn_pmp_check_rwx cfg acc := (asn_formula (formula_user pmp_check_rwx [cfg;acc])). - Local Notation asn_expand_pmpcfg_ent cfg := (asn_match_record rpmpcfg_ent cfg - (recordpat_snoc (recordpat_snoc (recordpat_snoc (recordpat_snoc (recordpat_snoc recordpat_nil "L" "L") "A" "A") "X" "X") "W" "W") "R" "R") - (asn_true)). - - Definition term_eqb {Σ} (e1 e2 : Term Σ ty.int) : Term Σ ty.bool := - term_binop bop.eq e1 e2. - - Local Notation "e1 '=?' e2" := (term_eqb e1 e2). - - Definition z_term {Σ} : Z -> Term Σ ty.int := term_val ty.int. - - Definition sep_contract_logvars (Δ : PCtx) (Σ : LCtx) : LCtx := - ctx.map (fun '(x::σ) => x::σ) Δ ▻▻ Σ. - - Definition create_localstore (Δ : PCtx) (Σ : LCtx) : SStore Δ (sep_contract_logvars Δ Σ) := - (env.tabulate (fun '(x::σ) xIn => - @term_var - (sep_contract_logvars Δ Σ) - x - σ - (ctx.in_cat_left Σ (ctx.in_map (fun '(y::τ) => y::τ) xIn)))). - - Definition SepContractFun {Δ τ} (f : Fun Δ τ) : Type := - SepContract Δ τ. - - Definition SepContractFunX {Δ τ} (f : FunX Δ τ) : Type := - SepContract Δ τ. - - Definition SepLemma {Δ} (f : Lem Δ) : Type := - Lemma Δ. - - Fixpoint asn_exists {Σ} (Γ : NCtx string Ty) : Assertion (Σ ▻▻ Γ) -> Assertion Σ := - match Γ return Assertion (Σ ▻▻ Γ) -> Assertion Σ with - | ctx.nil => fun asn => asn - | ctx.snoc Γ (x :: τ) => - fun asn => - @asn_exists Σ Γ (asn_exist x τ asn) - end. - - Definition asn_with_reg {Σ} (r : Term Σ ty.int) (asn : Reg ty_xlenbits -> Assertion Σ) (asn_default : Assertion Σ) : Assertion Σ := - asn_if (r =? z_term 1) - (asn x1) - (asn_if (r =? z_term 2) - (asn x2) - (asn_if (r =? z_term 3) - (asn x3) - asn_default)). - - Definition asn_and_regs {Σ} (f : Reg ty_xlenbits -> Assertion Σ) : Assertion Σ := - f x1 ∗ f x2 ∗ f x3 ∗ f x4 ∗ f x5 ∗ f x6 ∗ f x7. - - Definition asn_regs_ptsto {Σ} : Assertion Σ := - asn_and_regs - (fun r => ∃ "w", r ↦ term_var "w"). - - Local Notation "e1 ',ₜ' e2" := (term_binop bop.pair e1 e2) (at level 100). - - (* TODO: abstract away the concrete type, look into unions for that *) - (* TODO: length of list should be 16, no duplicates *) - Definition pmp_entries {Σ} : Term Σ (ty.list (ty.prod ty_pmpcfgidx ty_pmpaddridx)) := - term_list - (cons (term_val ty_pmpcfgidx PMP0CFG ,ₜ term_val ty_pmpaddridx PMPADDR0) - (cons (term_val ty_pmpcfgidx PMP1CFG ,ₜ term_val ty_pmpaddridx PMPADDR1) nil)). - -End ContractDefKit. -End RiscvPmpSignature. - -Module Import RiscvPmpSpecification <: Specification RiscvPmpBase RiscvPmpProgram RiscvPmpSignature. - Include SpecificationMixin RiscvPmpBase RiscvPmpProgram RiscvPmpSignature. - - Section Contracts. - Section ContractDefKit. - - Local Notation "r '↦' val" := (asn_chunk (chunk_ptsreg r val)) (at level 70). - Local Notation "a '↦ₘ' t" := (asn_chunk (chunk_user ptsto [a; t])) (at level 70). - Local Notation "p '∗' q" := (asn_sep p q). - Local Notation "a '=' b" := (asn_eq a b). - Local Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - Local Notation "a '∨' b" := (asn_or a b). - Local Notation "p '⊑' q" := (asn_formula (formula_user sub_perm [p;q])) (at level 70). - Local Notation "a <ₜ b" := (term_binop bop.lt a b) (at level 60). - Local Notation "a <=ₜ b" := (term_binop bop.le a b) (at level 60). - Local Notation "a &&ₜ b" := (term_binop bop.and a b) (at level 80). - Local Notation "a ||ₜ b" := (term_binop bop.or a b) (at level 85). - Local Notation asn_match_option T opt xl alt_inl alt_inr := (asn_match_sum T ty.unit opt xl alt_inl "_" alt_inr). - Local Notation asn_pmp_entries l := (asn_chunk (chunk_user Contracts.pmp_entries [l])). - (* TODO: check if I can reproduce the issue with angelic stuff, I think it was checked_mem_read, with the correct postcondition *) - (* Local Notation asn_pmp_entries_angelic l := (asn_chunk_angelic (chunk_user pmp_entries [l])). *) - Local Notation asn_pmp_addr_access l m := (asn_chunk (chunk_user pmp_addr_access [l; m])). - Local Notation asn_pmp_addr_access_without a l m := (asn_chunk (chunk_user pmp_addr_access_without [a;l; m])). - Local Notation asn_gprs := (asn_chunk (chunk_user gprs env.nil)). - Local Notation asn_within_cfg a cfg prev_addr addr := (asn_formula (formula_user within_cfg [a; cfg; prev_addr; addr])). - Local Notation asn_not_within_cfg a es := (asn_formula (formula_user not_within_cfg [a; es])). - Local Notation asn_prev_addr cfg es prev := (asn_formula (formula_user prev_addr [cfg; es; prev])). - Local Notation asn_in_entries idx e es := (asn_formula (formula_user in_entries [idx; e; es])). - Local Notation asn_pmp_access addr es m p := (asn_formula (formula_user pmp_access [addr;es;m;p])). - Local Notation asn_pmp_check_perms cfg acc p := (asn_formula (formula_user pmp_check_perms [cfg;acc;p])). - Local Notation asn_pmp_check_rwx cfg acc := (asn_formula (formula_user pmp_check_rwx [cfg;acc])). - Local Notation asn_expand_pmpcfg_ent cfg := (asn_match_record rpmpcfg_ent cfg - (recordpat_snoc (recordpat_snoc (recordpat_snoc (recordpat_snoc (recordpat_snoc recordpat_nil "L" "L") "A" "A") "X" "X") "W" "W") "R" "R") - (asn_true)). - - Local Notation "e1 ',ₜ' e2" := (term_binop bop.pair e1 e2) (at level 100). - - Import RiscvNotations. - (** Machine Invariant **) - (* - TODO: - this should work for the execute{,_/x/} functions, but step and loop will update - the pc, so this should be reflected in their contract (2nd pc(i) -> pc(i + 4)?) - - - - TODO: short notation out of sync with actual contract - @pre ∀ m h i . mode(m) ∗ mtvec(h) ∗ pmp_entries(ents) ∗ pc(i) ∗ mepc(_) ∗ mpp(_) - @post pmp_entries(ents) ∗ (mode(m) ∗ pc(i)) ∨ (mode(M) ∗ pc(h) ...) - τ f(Δ...)*) - Definition instr_exec_contract {τ Δ} : SepContract Δ τ := - let Σ := ["m" :: ty_privilege; "h" :: ty_xlenbits; "i" :: ty_xlenbits; "entries" :: ty.list ty_pmpentry; "mpp" :: ty_privilege; "mepc" :: ty_xlenbits; "npc" :: ty_xlenbits] in - {| sep_contract_logic_variables := sep_contract_logvars Δ Σ; - sep_contract_localstore := create_localstore Δ Σ; - sep_contract_precondition := - cur_privilege ↦ term_var "m" ∗ - mtvec ↦ term_var "h" ∗ - pc ↦ term_var "i" ∗ - nextpc ↦ term_var "npc" ∗ - ∃ "mcause", mcause ↦ term_var "mcause" ∗ - mepc ↦ term_var "mepc" ∗ - mstatus ↦ term_record rmstatus [ term_var "mpp" ] ∗ - asn_pmp_entries (term_var "entries") ∗ - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs; - sep_contract_result := "result_mach_inv"; - sep_contract_postcondition := - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs ∗ - pc ↦ term_var "i" ∗ - ∃ "mcause", mcause ↦ term_var "mcause" ∗ - ( (* Executing normally *) - asn_pmp_entries (term_var "entries") ∗ - cur_privilege ↦ term_var "m" ∗ - ∃ v, nextpc ↦ term_var v ∗ - mtvec ↦ term_var "h" ∗ - mstatus ↦ term_record rmstatus [ term_var "mpp" ] ∗ - mepc ↦ term_var "mepc" - ∨ - (* Modified CSRs, requires Machine mode *) - term_var "m" = term_val ty_privilege Machine ∗ - ∃ "entries", asn_pmp_entries (term_var "entries") ∗ - cur_privilege ↦ term_val ty_privilege Machine ∗ - nextpc ↦ term_var "npc" ∗ - ∃ "new_mtvec", mtvec ↦ term_var "new_mtvec" ∗ - ∃ "new_mpp", mstatus ↦ term_record rmstatus [ term_var "new_mpp" ] ∗ - ∃ "new_mepc", mepc ↦ term_var "new_mepc" - ∨ - (* Trap occured -> Go into M-mode *) - asn_pmp_entries (term_var "entries") ∗ - cur_privilege ↦ (term_val ty_privilege Machine) ∗ - nextpc ↦ term_var "h" ∗ - mtvec ↦ term_var "h" ∗ - mstatus ↦ term_record rmstatus [ term_var "m" ] ∗ - mepc ↦ term_var "i" - ∨ - (* MRET = Recover *) - asn_pmp_entries (term_var "entries") ∗ - term_var "m" = term_val ty_privilege Machine ∗ - cur_privilege ↦ term_var "mpp" ∗ - nextpc ↦ term_var "mepc" ∗ - mtvec ↦ term_var "h" ∗ - mstatus ↦ term_record rmstatus [ term_val ty_privilege User ] ∗ - mepc ↦ term_var "mepc") - |}. - - Definition sep_contract_execute_RTYPE : SepContractFun execute_RTYPE := - instr_exec_contract. - - Definition sep_contract_execute_ITYPE : SepContractFun execute_ITYPE := - instr_exec_contract. - - Definition sep_contract_execute_UTYPE : SepContractFun execute_UTYPE := - instr_exec_contract. - - Definition sep_contract_execute_BTYPE : SepContractFun execute_BTYPE := - instr_exec_contract. - - Definition sep_contract_execute_RISCV_JAL : SepContractFun execute_RISCV_JAL := - instr_exec_contract. - - Definition sep_contract_execute_RISCV_JALR : SepContractFun execute_RISCV_JALR := - instr_exec_contract. - - Definition sep_contract_execute_ECALL : SepContractFun execute_ECALL := - instr_exec_contract. - - Definition sep_contract_execute_MRET : SepContractFun execute_MRET := - instr_exec_contract. - - Definition sep_contract_execute_CSR : SepContractFun execute_CSR := - instr_exec_contract. - - Definition sep_contract_execute_STORE : SepContractFun execute_STORE := - instr_exec_contract. - - Definition sep_contract_execute_LOAD : SepContractFun execute_LOAD := - instr_exec_contract. - - Definition sep_contract_execute : SepContractFun execute := - instr_exec_contract. - - Definition sep_contract_process_load : SepContractFun process_load := - {| sep_contract_logic_variables := [rd :: ty_regno; vaddr :: ty_xlenbits; value :: ty_memory_op_result; "i" :: ty_xlenbits; tvec :: ty_xlenbits; p :: ty_privilege; "mpp" :: ty_privilege; "mepc" :: ty_xlenbits; "npc" :: ty_xlenbits; "mcause" :: ty_mcause]; - sep_contract_localstore := [term_var rd; term_var vaddr; term_var value]; - sep_contract_precondition := - asn_gprs - ∗ pc ↦ term_var "i" - ∗ nextpc ↦ term_var "npc" - ∗ cur_privilege ↦ term_var p - ∗ mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_var "mpp" ] - ∗ mtvec ↦ term_var tvec - ∗ mepc ↦ term_var "mepc"; - sep_contract_result := "result_process_load"; - sep_contract_postcondition := - asn_gprs ∗ - asn_match_union memory_op_result (term_var value) - (fun K => match K with - | KMemValue => [v :: ty_xlenbits] - | KMemException => [e :: ty_exception_type] - end) - (fun K => match K with - | KMemValue => pat_var v - | KMemException => pat_var e - end) - (fun K => match K with - | KMemValue => - term_var "result_process_load" = term_val ty_retired RETIRE_SUCCESS - ∗ pc ↦ term_var "i" - ∗ nextpc ↦ term_var "npc" - ∗ cur_privilege ↦ term_var p - ∗ mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_var "mpp" ] - ∗ mtvec ↦ term_var tvec - ∗ mepc ↦ term_var "mepc" - | KMemException => - term_var "result_process_load" = term_val ty_retired RETIRE_FAIL - ∗ pc ↦ term_var "i" - ∗ nextpc ↦ term_var tvec - ∗ cur_privilege ↦ term_val ty_privilege Machine - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_var p ] - ∗ mepc ↦ term_var "i" - ∗ mtvec ↦ term_var tvec - end); - |}. - - Definition sep_contract_readCSR : SepContractFun readCSR := - {| sep_contract_logic_variables := [csr :: ty_csridx; "mpp" :: ty_privilege; - "mtvec" :: ty_xlenbits; "mcause" :: ty_exc_code; - "mepc" :: ty_xlenbits; "cfg0" :: ty_pmpcfg_ent; "cfg1" :: ty_pmpcfg_ent; "addr0" :: ty_xlenbits; "addr1" :: ty_xlenbits]; - sep_contract_localstore := [term_var csr]; - sep_contract_precondition := - mstatus ↦ term_record rmstatus [term_var "mpp"] - ∗ mtvec ↦ term_var "mtvec" - ∗ mcause ↦ term_var "mcause" - ∗ mepc ↦ term_var "mepc" - ∗ pmp0cfg ↦ term_var "cfg0" - ∗ pmp1cfg ↦ term_var "cfg1" - ∗ pmpaddr0 ↦ term_var "addr0" - ∗ pmpaddr1 ↦ term_var "addr1"; - sep_contract_result := "result_readCSR"; - sep_contract_postcondition := - ∃ "result", term_var "result_readCSR" = term_var "result" - ∗ mstatus ↦ term_record rmstatus [term_var "mpp"] - ∗ mtvec ↦ term_var "mtvec" - ∗ mcause ↦ term_var "mcause" - ∗ mepc ↦ term_var "mepc" - ∗ pmp0cfg ↦ term_var "cfg0" - ∗ pmp1cfg ↦ term_var "cfg1" - ∗ pmpaddr0 ↦ term_var "addr0" - ∗ pmpaddr1 ↦ term_var "addr1"; - |}. - - Definition sep_contract_writeCSR : SepContractFun writeCSR := - {| sep_contract_logic_variables := [csr :: ty_csridx; value :: ty_xlenbits]; - sep_contract_localstore := [term_var csr; term_var value]; - sep_contract_precondition := - ∃ "mpp", mstatus ↦ term_record rmstatus [term_var "mpp"] - ∗ ∃ "mtvec", mtvec ↦ term_var "mtvec" - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ ∃ "mepc", mepc ↦ term_var "mepc" - ∗ ∃ "cfg0", (pmp0cfg ↦ term_var "cfg0" ∗ asn_expand_pmpcfg_ent (term_var "cfg0")) - ∗ ∃ "cfg1", (pmp1cfg ↦ term_var "cfg1" ∗ asn_expand_pmpcfg_ent (term_var "cfg1")) - ∗ ∃ "addr0", pmpaddr0 ↦ term_var "addr0" - ∗ ∃ "addr1", pmpaddr1 ↦ term_var "addr1"; - sep_contract_result := "result_writeCSR"; - sep_contract_postcondition := - term_var "result_writeCSR" = term_val ty.unit tt - ∗ ∃ "mpp", mstatus ↦ term_record rmstatus [term_var "mpp"] - ∗ ∃ "mtvec", mtvec ↦ term_var "mtvec" - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ ∃ "mepc", mepc ↦ term_var "mepc" - ∗ ∃ "cfg0", pmp0cfg ↦ term_var "cfg0" - ∗ ∃ "cfg1", pmp1cfg ↦ term_var "cfg1" - ∗ ∃ "addr0", pmpaddr0 ↦ term_var "addr0" - ∗ ∃ "addr1", pmpaddr1 ↦ term_var "addr1"; - |}. - - Definition sep_contract_check_CSR : SepContractFun check_CSR := - {| sep_contract_logic_variables := [csr :: ty_csridx; p :: ty_privilege]; - sep_contract_localstore := [term_var csr; term_var p]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_check_CSR"; - sep_contract_postcondition := - asn_match_enum privilege (term_var p) - (fun K => match K with - | Machine => term_var "result_check_CSR" = term_val ty.bool true - | User => term_var "result_check_CSR" = term_val ty.bool false - end) - |}. - - Definition sep_contract_is_CSR_defined : SepContractFun is_CSR_defined := - {| sep_contract_logic_variables := [csr :: ty_csridx; p :: ty_privilege]; - sep_contract_localstore := [term_var csr; term_var p]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_is_CSR_defined"; - sep_contract_postcondition := - asn_match_enum privilege (term_var p) - (fun K => match K with - | Machine => term_var "result_is_CSR_defined" = - term_val ty.bool true - | User =>term_var "result_is_CSR_defined" = - term_val ty.bool false - end); - |}. - - Definition sep_contract_check_CSR_access : SepContractFun check_CSR_access := - {| sep_contract_logic_variables := [csrrw :: ty_access_type; csrpr :: ty_privilege; p :: ty_privilege]; - sep_contract_localstore := [term_var csrrw; term_var csrpr; term_var p]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_check_CSR_access"; - sep_contract_postcondition := - asn_match_enum privilege (term_var csrpr) - (fun K => match K with - | Machine => - asn_match_enum privilege (term_var p) - (fun K => match K with - | Machine => term_var "result_check_CSR_access" = - term_val ty.bool true - | User => term_var "result_check_CSR_access" = - term_val ty.bool false - end) - | User => - asn_match_enum privilege (term_var p) - (fun K => match K with - | Machine => term_var "result_check_CSR_access" = - term_val ty.bool true - | User => term_var "result_check_CSR_access" = - term_val ty.bool true - end) - end); - |}. - - Definition sep_contract_privLevel_to_bits : SepContractFun privLevel_to_bits := - {| sep_contract_logic_variables := [p :: ty_privilege]; - sep_contract_localstore := [term_var p]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_privLevel_to_bits"; - sep_contract_postcondition := - asn_match_enum privilege (term_var p) - (fun K => match K with - | Machine => term_var "result_privLevel_to_bits" = - term_val ty_xlenbits 3%Z - | User => term_var "result_privLevel_to_bits" = - term_val ty_xlenbits 0%Z - end); - |}. - - Definition sep_contract_csrAccess : SepContractFun csrAccess := - {| sep_contract_logic_variables := [csr :: ty_csridx]; - sep_contract_localstore := [term_var csr]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_csrAccess"; - sep_contract_postcondition := - term_var "result_csrAccess" = term_val ty_access_type ReadWrite; - |}. - - Definition sep_contract_csrPriv : SepContractFun csrPriv := - {| sep_contract_logic_variables := [csr :: ty_csridx]; - sep_contract_localstore := [term_var csr]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_csrPriv"; - sep_contract_postcondition := - term_var "result_csrPriv" = term_val ty_privilege Machine; - |}. - - Definition sep_contract_handle_mem_exception : SepContractFun handle_mem_exception := - {| sep_contract_logic_variables := [addr :: ty_xlenbits; e :: ty_exception_type; "i" :: ty_xlenbits; tvec :: ty_xlenbits; p :: ty_privilege; "mpp" :: ty_privilege; "mepc" :: ty_xlenbits]; - sep_contract_localstore := [term_var addr; term_var e]; - sep_contract_precondition := - pc ↦ term_var "i" - ∗ ∃ "npc", nextpc ↦ term_var "npc" - ∗ cur_privilege ↦ term_var p - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_var "mpp" ] - ∗ mtvec ↦ term_var tvec - ∗ mepc ↦ term_var "mepc"; - sep_contract_result := "result_handle_mem_exception"; - sep_contract_postcondition := - term_var "result_handle_mem_exception" = term_val ty.unit tt - ∗ pc ↦ term_var "i" - ∗ nextpc ↦ term_var tvec - ∗ cur_privilege ↦ term_val ty_privilege Machine - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_var p ] - ∗ mepc ↦ term_var "i" - ∗ mtvec ↦ term_var tvec - |}. - - Definition sep_contract_exception_handler : SepContractFun exception_handler := - {| sep_contract_logic_variables := [cur_priv :: ty_privilege; ctl :: ty_ctl_result; "pc" :: ty_xlenbits; "mpp" :: ty_privilege; "mepc" :: ty_xlenbits; tvec :: ty_xlenbits; p :: ty_privilege]; - sep_contract_localstore := [term_var cur_priv; term_var ctl; term_var "pc"]; - sep_contract_precondition := - cur_privilege ↦ (term_var p) - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ mstatus ↦ (term_record rmstatus [ term_var "mpp" ]) - ∗ mtvec ↦ (term_var tvec) - ∗ mepc ↦ (term_var "mepc"); - sep_contract_result := "result_exception_handler"; - sep_contract_postcondition := asn_match_union ctl_result (term_var ctl) - (fun K => match K with - | KCTL_TRAP => ctx.snoc ε (e ∷ ty_exception_type) - | KCTL_MRET => ε - end) - (fun K => match K with - | KCTL_TRAP => pat_var e - | KCTL_MRET => pat_unit - end) - (fun K => match K with - | KCTL_TRAP => - term_var "result_exception_handler" = term_var tvec - ∗ cur_privilege ↦ term_val ty_privilege Machine - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_var p ] - ∗ mepc ↦ term_var "pc" - ∗ mtvec ↦ term_var tvec - | KCTL_MRET => - term_var "result_exception_handler" = term_var "mepc" - ∗ cur_privilege ↦ term_var "mpp" - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_val ty_privilege User ] - ∗ mtvec ↦ term_var tvec - ∗ mepc ↦ term_var "mepc" - end); - |}. - - Definition sep_contract_handle_illegal : SepContractFun handle_illegal := - {| sep_contract_logic_variables := [p :: ty_privilege; "pc" :: ty_xlenbits; tvec :: ty_xlenbits]; - sep_contract_localstore := env.nil; - sep_contract_precondition := - cur_privilege ↦ term_var p - ∗ pc ↦ term_var "pc" - ∗ ∃ "mcause_val", mcause ↦ term_var "mcause_val" - ∗ ∃ "mpp", mstatus ↦ term_record rmstatus [term_var "mpp"] - ∗ ∃ "mepc_val", mepc ↦ term_var "mepc_val" - ∗ mtvec ↦ term_var tvec - ∗ ∃ v, nextpc ↦ term_var v; - sep_contract_result := "result_handle_illegal"; - sep_contract_postcondition := - term_var "result_handle_illegal" = term_val ty.unit tt - ∗ cur_privilege ↦ term_val ty_privilege Machine - ∗ pc ↦ term_var "pc" - ∗ ∃ "mcause", mcause ↦ term_var "mcause" - ∗ mstatus ↦ term_record rmstatus [ term_var p ] - ∗ mepc ↦ term_var "pc" - ∗ mtvec ↦ term_var tvec - ∗ nextpc ↦ term_var tvec - |}. - - Definition sep_contract_trap_handler : SepContractFun trap_handler := - {| sep_contract_logic_variables := [del_priv :: ty_privilege; c :: ty_exc_code; "pc" :: ty_xlenbits; p :: ty_privilege; tvec :: ty_xlenbits]; - sep_contract_localstore := [term_var del_priv; term_var c; term_var "pc"]; - sep_contract_precondition := - cur_privilege ↦ term_var p - ∗ ∃ "mcause_val", mcause ↦ term_var "mcause_val" - ∗ ∃ "mstatus_val", mstatus ↦ term_var "mstatus_val" - ∗ ∃ "mepc_val", mepc ↦ term_var "mepc_val" - ∗ mtvec ↦ term_var tvec; - sep_contract_result := "result_trap_handler"; - sep_contract_postcondition := - term_var "result_trap_handler" = term_var tvec - ∗ term_var del_priv = term_val ty_privilege Machine - ∗ cur_privilege ↦ term_var del_priv - ∗ mcause ↦ term_var c - ∗ mstatus ↦ term_record rmstatus [ term_var p ] - ∗ mepc ↦ term_var "pc" - ∗ mtvec ↦ term_var tvec; - |}. - - Definition sep_contract_prepare_trap_vector : SepContractFun prepare_trap_vector := - {| sep_contract_logic_variables := [p :: ty_privilege; cause :: ty_mcause; tvec :: ty_xlenbits]; - sep_contract_localstore := [term_var p; term_var cause]; - sep_contract_precondition := mtvec ↦ term_var tvec; - sep_contract_result := "result_prepare_trap_vector"; - sep_contract_postcondition := - term_var "result_prepare_trap_vector" = term_var tvec - ∗ term_var p = term_val ty_privilege Machine - ∗ mtvec ↦ term_var tvec; - |}. - - Definition sep_contract_tvec_addr : SepContractFun tvec_addr := - {| sep_contract_logic_variables := [m :: ty_xlenbits; c :: ty_mcause]; - sep_contract_localstore := [term_var m; term_var c]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_tvec_addr"; - sep_contract_postcondition := - term_var "result_tvec_addr" = term_inl (term_var m); - |}. - - Definition sep_contract_exceptionType_to_bits : SepContractFun exceptionType_to_bits := - {| sep_contract_logic_variables := [e :: ty_exception_type]; - sep_contract_localstore := [term_var e]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_exceptionType_to_bits"; - sep_contract_postcondition := - ∃ result, term_var "result_exceptionType_to_bits" = term_var result - |}. - - Definition sep_contract_exception_delegatee : SepContractFun exception_delegatee := - {| sep_contract_logic_variables := [p :: ty_privilege]; - sep_contract_localstore := [term_var p]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_exception_delegatee"; - sep_contract_postcondition := - term_var "result_exception_delegatee" = term_val ty_privilege Machine - |}. - - Definition sep_contract_get_arch_pc : SepContractFun get_arch_pc := - {| sep_contract_logic_variables := [v :: ty_xlenbits]; - sep_contract_localstore := env.nil; - sep_contract_precondition := pc ↦ term_var v; - sep_contract_result := "result_get_arch_pc"; - sep_contract_postcondition := - term_var "result_get_arch_pc" = term_var v - ∗ pc ↦ term_var v; - |}. - - Definition sep_contract_set_next_pc : SepContractFun set_next_pc := - {| sep_contract_logic_variables := [addr :: ty_xlenbits]; - sep_contract_localstore := [term_var addr]; - sep_contract_precondition := ∃ v, nextpc ↦ term_var v; - sep_contract_result := "result_set_next_pc"; - sep_contract_postcondition := - term_var "result_set_next_pc" = term_val ty.unit tt - ∗ nextpc ↦ term_var addr; - |}. - - Definition sep_contract_get_next_pc : SepContractFun get_next_pc := - {| sep_contract_logic_variables := [v :: ty_xlenbits]; - sep_contract_localstore := env.nil; - sep_contract_precondition := nextpc ↦ term_var v; - sep_contract_result := "result_get_next_pc"; - sep_contract_postcondition := - term_var "result_get_next_pc" = term_var v - ∗ nextpc ↦ term_var v; - |}. - - Definition sep_contract_tick_pc : SepContractFun tick_pc := - {| sep_contract_logic_variables := ["npc" :: ty_xlenbits]; - sep_contract_localstore := env.nil; - sep_contract_precondition := nextpc ↦ term_var "npc" ∗ ∃ "i", pc ↦ term_var "i"; - sep_contract_result := "result_tick_pc"; - sep_contract_postcondition := - term_var "result_tick_pc" = term_val ty.unit tt - ∗ nextpc ↦ term_var "npc" - ∗ pc ↦ term_var "npc"; - |}. - - Definition sep_contract_rX : SepContractFun rX := - {| sep_contract_logic_variables := [rs :: ty_regno]; - sep_contract_localstore := [term_var rs]; - sep_contract_precondition := asn_gprs; - sep_contract_result := "result_rX"; - sep_contract_postcondition := asn_gprs; - |}. - - Definition sep_contract_wX : SepContractFun wX := - {| sep_contract_logic_variables := [rs :: ty_regno; v :: ty_xlenbits]; - sep_contract_localstore := [term_var rs; term_var v]; - sep_contract_precondition := asn_gprs; - sep_contract_result := "result_wX"; - sep_contract_postcondition := - term_var "result_wX" = term_val ty.unit tt - ∗ asn_gprs; - |}. - - Definition sep_contract_abs : SepContractFun abs := - {| sep_contract_logic_variables := [v :: ty.int]; - sep_contract_localstore := [term_var v]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_abs"; - sep_contract_postcondition := asn_true; - |}. - - Definition sep_contract_step {τ Δ} : SepContract Δ τ := - let Σ := ["m" :: ty_privilege; "h" :: ty_xlenbits; "entries" :: ty.list ty_pmpentry; "mpp" :: ty_privilege; "mepc" :: ty_xlenbits; "i" :: ty_xlenbits; "npc" :: ty_xlenbits] in - {| sep_contract_logic_variables := sep_contract_logvars Δ Σ; - sep_contract_localstore := create_localstore Δ Σ; - sep_contract_precondition := - cur_privilege ↦ term_var "m" ∗ - mtvec ↦ term_var "h" ∗ - pc ↦ term_var "i" ∗ - nextpc ↦ term_var "npc" ∗ - ∃ "mcause", mcause ↦ term_var "mcause" ∗ - mepc ↦ term_var "mepc" ∗ - mstatus ↦ term_record rmstatus [ term_var "mpp" ] ∗ - asn_pmp_entries (term_var "entries") ∗ - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs; - sep_contract_result := "result_mach_inv"; - sep_contract_postcondition := - ( (* Executing normally *) - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs ∗ - ∃ "mcause", mcause ↦ term_var "mcause" ∗ - asn_pmp_entries (term_var "entries") ∗ - cur_privilege ↦ term_var "m" ∗ - ∃ v, (nextpc ↦ term_var v ∗ - pc ↦ term_var v) ∗ - mtvec ↦ term_var "h" ∗ - mstatus ↦ term_record rmstatus [ term_var "mpp" ] ∗ - mepc ↦ term_var "mepc" - ∨ - (* Modified CSRs, requires Machine mode *) - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs ∗ - term_var "m" = term_val ty_privilege Machine ∗ - ∃ "entries", asn_pmp_entries (term_var "entries") ∗ - cur_privilege ↦ term_val ty_privilege Machine ∗ - ∃ v, (nextpc ↦ term_var v ∗ (* tick, nextpc + 4 *) - pc ↦ term_var v) ∗ - ∃ "new_mtvec", mtvec ↦ term_var "new_mtvec" ∗ - ∃ "new_mpp", mstatus ↦ term_record rmstatus [ term_var "new_mpp" ] ∗ - ∃ "new_mepc", mepc ↦ term_var "new_mepc" - ∨ - (* Trap occured -> Go into M-mode *) - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs ∗ - asn_pmp_entries (term_var "entries") ∗ - cur_privilege ↦ (term_val ty_privilege Machine) ∗ - nextpc ↦ term_var "h" ∗ - pc ↦ term_var "h" ∗ - mtvec ↦ term_var "h" ∗ - mstatus ↦ term_record rmstatus [ term_var "m" ] ∗ - mepc ↦ term_var "i" - ∨ - (* MRET = Recover *) - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs ∗ - asn_pmp_entries (term_var "entries") ∗ - term_var "m" = term_val ty_privilege Machine ∗ - cur_privilege ↦ term_var "mpp" ∗ - nextpc ↦ term_var "mepc" ∗ - pc ↦ term_var "mepc" ∗ - mtvec ↦ term_var "h" ∗ - mstatus ↦ term_record rmstatus [ term_val ty_privilege User ] ∗ - mepc ↦ term_var "mepc") - |}. - - Definition sep_contract_step' : SepContractFun step := - {| sep_contract_logic_variables := ["m" :: ty_privilege; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := env.nil; - sep_contract_precondition := - cur_privilege ↦ term_var "m" ∗ - ∃ "h", mtvec ↦ term_var "h" ∗ - ∃ "npc", nextpc ↦ term_var "npc" ∗ - ∃ "i", pc ↦ term_var "i" ∗ - ∃ "mcause", mcause ↦ term_var "mcause" ∗ - ∃ "mepc", mepc ↦ term_var "mepc" ∗ - ∃ "mpp", mstatus ↦ term_record rmstatus [ term_var "mpp" ] ∗ - asn_pmp_entries (term_var "entries") ∗ - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs ; - sep_contract_result := "result_step"; - sep_contract_postcondition := ∃ "p", ∃ "es", - ( cur_privilege ↦ term_var "p" ∗ - ∃ "h", mtvec ↦ term_var "h" ∗ - ∃ "npc", (nextpc ↦ term_var "npc" ∗ - pc ↦ term_var "npc") ∗ - ∃ "mcause", mcause ↦ term_var "mcause" ∗ - ∃ "mepc", mepc ↦ term_var "mepc" ∗ - ∃ "mpp", mstatus ↦ term_record rmstatus [ term_var "mpp" ] ∗ - asn_pmp_entries (term_var "es") ∗ - asn_pmp_addr_access (term_var "entries") (term_var "m") ∗ - asn_gprs); - |}. - - Definition sep_contract_fetch : SepContractFun fetch := - {| sep_contract_logic_variables := ["i" :: ty_xlenbits; p :: ty_privilege; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := env.nil; - sep_contract_precondition := - pc ↦ term_var "i" - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - sep_contract_result := "result_fetch"; - sep_contract_postcondition := - pc ↦ term_var "i" - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - |}. - - Definition sep_contract_init_model : SepContractFun init_model := - {| sep_contract_logic_variables := ctx.nil; - sep_contract_localstore := env.nil; - sep_contract_precondition := - ∃ p, cur_privilege ↦ term_var p - ∗ ∃ "es", asn_pmp_entries (term_var "es"); - sep_contract_result := "result_init_model"; - sep_contract_postcondition := - term_var "result_init_model" = term_val ty.unit tt - ∗ cur_privilege ↦ term_val ty_privilege Machine - ∗ ∃ "es", asn_pmp_entries (term_var "es"); - |}. - - Definition sep_contract_init_sys : SepContractFun init_sys := - {| sep_contract_logic_variables := ctx.nil; - sep_contract_localstore := env.nil; - sep_contract_precondition := - ∃ p, cur_privilege ↦ term_var p - ∗ ∃ "es", asn_pmp_entries (term_var "es"); - sep_contract_result := "result_init_sys"; - sep_contract_postcondition := - term_var "result_init_sys" = term_val ty.unit tt - ∗ cur_privilege ↦ term_val ty_privilege Machine - ∗ ∃ "es", asn_pmp_entries (term_var "es"); - |}. - - Definition sep_contract_init_pmp : SepContractFun init_pmp := - {| sep_contract_logic_variables := ctx.nil; - sep_contract_localstore := env.nil; - sep_contract_precondition := - ∃ "cfg0", pmp0cfg ↦ term_var "cfg0" ∗ ∃ "cfg1", pmp1cfg ↦ term_var "cfg1"; - sep_contract_result := "result_init_pmp"; - sep_contract_postcondition := - ∃ "cfg0", pmp0cfg ↦ term_var "cfg0" ∗ ∃ "cfg1", pmp1cfg ↦ term_var "cfg1" - ∗ term_var "result_init_pmp" = term_val ty.unit tt; - |}. - - Definition sep_contract_within_phys_mem : SepContractFun within_phys_mem := - {| sep_contract_logic_variables := [paddr :: ty_xlenbits]; - sep_contract_localstore := [term_var paddr]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_within_phys_mem"; - sep_contract_postcondition := - asn_if (term_var "result_within_phys_mem") - (asn_bool (term_val ty_xlenbits minAddr <=ₜ term_var paddr) - ∗ asn_bool (term_var paddr <=ₜ term_val ty_xlenbits maxAddr)) - asn_true; - |}. - - Definition sep_contract_checked_mem_read : SepContractFun checked_mem_read := - {| sep_contract_logic_variables := [t :: ty_access_type; paddr :: ty_xlenbits; p :: ty_privilege; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := [term_var t; term_var paddr]; - sep_contract_precondition := - term_union access_type KRead (term_val ty.unit tt) ⊑ term_var t - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p) - ∗ asn_pmp_access (term_var paddr) (term_var "entries") (term_var p) (term_var t); - sep_contract_result := "result_checked_mem_read"; - sep_contract_postcondition := - cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p) - |}. - - Definition sep_contract_checked_mem_write : SepContractFun checked_mem_write := - {| sep_contract_logic_variables := [paddr :: ty_xlenbits; data :: ty_xlenbits; p :: ty_privilege; "entries" :: ty.list ty_pmpentry; acc :: ty_access_type]; - sep_contract_localstore := [term_var paddr; term_var data]; - sep_contract_precondition := - term_union access_type KWrite (term_val ty.unit tt) ⊑ term_var acc - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p) - ∗ asn_pmp_access (term_var paddr) (term_var "entries") (term_var p) (term_var acc); - sep_contract_result := "result_checked_mem_write"; - sep_contract_postcondition := - cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - |}. - - Definition sep_contract_pmp_mem_read : SepContractFun pmp_mem_read := - {| sep_contract_logic_variables := [t :: ty_access_type; p :: ty_privilege; paddr :: ty_xlenbits; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := [term_var t; term_var p; term_var paddr]; - sep_contract_precondition := - term_union access_type KRead (term_val ty.unit tt) ⊑ term_var t - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - sep_contract_result := "result_pmp_mem_read"; - sep_contract_postcondition := - cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - |}. - - Definition sep_contract_pmp_mem_write : SepContractFun pmp_mem_write := - {| sep_contract_logic_variables := [paddr :: ty_xlenbits; data :: ty_xlenbits; typ :: ty_access_type; priv :: ty_privilege; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := [term_var paddr; term_var data; term_var typ; term_var priv]; - sep_contract_precondition := (* NOTE: only ever called with typ = Write *) - (term_var typ = term_union access_type KWrite (term_val ty.unit tt) - ∨ term_var typ = term_union access_type KReadWrite (term_val ty.unit tt)) - ∗ cur_privilege ↦ term_var priv - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var priv); - sep_contract_result := "result_pmp_mem_write"; - sep_contract_postcondition := - cur_privilege ↦ term_var priv - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var priv); - |}. - - Definition sep_contract_mem_write_value : SepContractFun mem_write_value := - {| sep_contract_logic_variables := [paddr :: ty_xlenbits; value :: ty_xlenbits; p :: ty_privilege; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := [term_var paddr; term_var value]; - sep_contract_precondition := - cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - sep_contract_result := "result_pmp_mem_write"; - sep_contract_postcondition := - cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - |}. - - Definition sep_contract_mem_read : SepContractFun mem_read := - {| sep_contract_logic_variables := [typ :: ty_access_type; paddr :: ty_xlenbits; p :: ty_privilege; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := [term_var typ; term_var paddr]; - sep_contract_precondition := - (term_var typ = term_union access_type KRead (term_val ty.unit tt) - ∨ term_var typ = term_union access_type KExecute (term_val ty.unit tt)) - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - sep_contract_result := "result_mem_read"; - sep_contract_postcondition := - cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p); - |}. - - Definition sep_contract_pmpCheck : SepContractFun pmpCheck := - {| sep_contract_logic_variables := [addr :: ty_xlenbits; acc :: ty_access_type; priv :: ty_privilege; "entries" :: ty.list ty_pmpentry]; - sep_contract_localstore := [term_var addr; term_var acc; term_var priv]; - sep_contract_precondition := - asn_pmp_entries (term_var "entries"); - sep_contract_result := "result_pmpCheck"; - sep_contract_postcondition := - asn_match_option - _ (term_var "result_pmpCheck") e - (asn_pmp_entries (term_var "entries")) - (asn_pmp_entries (term_var "entries") ∗ asn_pmp_access (term_var addr) (term_var "entries") (term_var priv) (term_var acc)); - |}. - - Definition sep_contract_pmpCheckPerms : SepContractFun pmpCheckPerms := - let Σ : LCtx := [acc :: ty_access_type; priv :: ty_privilege; L :: ty.bool; A :: ty_pmpaddrmatchtype; X :: ty.bool; W :: ty.bool; R :: ty.bool] in - let entry : Term Σ _ := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - {| sep_contract_logic_variables := Σ; - sep_contract_localstore := [nenv entry; term_var acc; term_var priv]; - sep_contract_precondition := - asn_true; - sep_contract_result := "result_pmpCheckPerms"; - sep_contract_postcondition := - let entry := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - asn_if (term_var "result_pmpCheckPerms") - (asn_pmp_check_perms entry (term_var acc) (term_var priv)) - asn_true; - |}. - - Definition sep_contract_pmpCheckRWX : SepContractFun pmpCheckRWX := - let Σ : LCtx := [acc :: ty_access_type; L :: ty.bool; A :: ty_pmpaddrmatchtype; X :: ty.bool; W :: ty.bool; R :: ty.bool] in - let entry : Term Σ _ := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - {| sep_contract_logic_variables := Σ; - sep_contract_localstore := [nenv entry; term_var acc]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_pmpCheckRWX"; - sep_contract_postcondition := - let entry := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - asn_if (term_var "result_pmpCheckRWX") - (asn_pmp_check_rwx entry (term_var acc)) - asn_true; - |}. - - Definition sep_contract_pmpAddrRange : SepContractFun pmpAddrRange := - let Σ : LCtx := [pmpaddr :: ty_xlenbits; prev_pmpaddr :: ty_xlenbits; L :: ty.bool; A :: ty_pmpaddrmatchtype; X :: ty.bool; W :: ty.bool; R :: ty.bool] in - let entry : Term Σ _ := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - {| sep_contract_logic_variables := Σ; - sep_contract_localstore := [nenv entry; term_var pmpaddr; term_var prev_pmpaddr]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_pmpAddrRange"; - sep_contract_postcondition := - asn_match_enum pmpaddrmatchtype (term_var A) - (fun K => match K with - | OFF => term_var "result_pmpAddrRange" = term_inr (term_val ty.unit tt) - | TOR => term_var "result_pmpAddrRange" = term_inl (term_var prev_pmpaddr ,ₜ term_var pmpaddr) - end); - |}. - - Definition sep_contract_pmpMatchAddr : SepContractFun pmpMatchAddr := - {| sep_contract_logic_variables := [addr :: ty_xlenbits; rng :: ty_pmp_addr_range]; - sep_contract_localstore := [term_var addr; term_var rng]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_pmpMatchAddr"; - sep_contract_postcondition := - asn_match_option - _ (term_var rng) v - (asn_match_prod - (term_var v) lo hi - (asn_match_enum pmpaddrmatch (term_var "result_pmpMatchAddr") - (fun K => match K with - | PMP_NoMatch => - asn_bool (term_var hi <ₜ term_var lo) ∨ asn_bool (term_var addr <ₜ term_var lo ||ₜ term_var hi <=ₜ term_var addr) ∨ term_var rng = term_inr (term_val ty.unit tt) - | PMP_PartialMatch => asn_bool - (term_not - (term_var lo <=ₜ term_var addr &&ₜ term_var addr <ₜ term_var hi)) - | PMP_Match => asn_formula (formula_bool (term_var lo <=ₜ term_var addr)) ∗ asn_formula (formula_bool (term_var addr <ₜ term_var hi)) - end))) - (term_var "result_pmpMatchAddr" = term_val ty_pmpaddrmatch PMP_NoMatch); - |}. - - Definition sep_contract_pmpMatchEntry : SepContractFun pmpMatchEntry := - let Σ : LCtx := [addr :: ty_xlenbits; acc :: ty_access_type; priv :: ty_privilege; pmpaddr :: ty_xlenbits; prev_pmpaddr :: ty_xlenbits; L :: ty.bool; A :: ty_pmpaddrmatchtype; X :: ty.bool; W :: ty.bool; R :: ty.bool] in - let entry : Term Σ _ := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - {| sep_contract_logic_variables := Σ; - sep_contract_localstore := [nenv term_var addr; term_var acc; term_var priv; entry; term_var pmpaddr; term_var prev_pmpaddr]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_pmpMatchEntry"; - sep_contract_postcondition := - let entry := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - asn_match_enum pmpmatch (term_var "result_pmpMatchEntry") - (fun K => match K with - | PMP_Continue => - asn_bool (term_var pmpaddr <ₜ term_var prev_pmpaddr) ∨ asn_bool (term_var addr <ₜ term_var prev_pmpaddr ||ₜ term_var pmpaddr <=ₜ term_var addr) ∨ term_var A = term_val ty_pmpaddrmatchtype OFF - | PMP_Fail => - asn_bool (term_not - (term_var prev_pmpaddr <=ₜ term_var addr &&ₜ term_var addr <ₜ term_var pmpaddr)) ∨ - asn_true (* TODO: either we have a partial match, or we don't have the required permissions! *) - | PMP_Success => - asn_bool (term_var prev_pmpaddr <=ₜ term_var addr &&ₜ term_var addr <ₜ term_var pmpaddr) ∗ - asn_pmp_check_perms entry (term_var acc) (term_var priv) - end); - |}. - - Definition sep_contract_pmpLocked : SepContractFun pmpLocked := - let Σ : LCtx := [L :: ty.bool; A :: ty_pmpaddrmatchtype; X :: ty.bool; W :: ty.bool; R :: ty.bool] in - let entry : Term Σ _ := term_record rpmpcfg_ent [term_var L; term_var A; term_var X; term_var W; term_var R] in - {| sep_contract_logic_variables := Σ; - sep_contract_localstore := env.snoc env.nil (_::_) entry; - sep_contract_precondition := asn_true; - sep_contract_result := "result_pmpLocked"; - sep_contract_postcondition := term_var "result_pmpLocked" = term_var L; - |}. - - Definition sep_contract_pmpWriteCfg : SepContractFun pmpWriteCfg := - {| sep_contract_logic_variables := [cfg :: ty_pmpcfg_ent; value :: ty_xlenbits]; - sep_contract_localstore := [term_var cfg; term_var value]; - sep_contract_precondition := asn_expand_pmpcfg_ent (term_var cfg); - sep_contract_result := "result_pmpWriteCfg"; - sep_contract_postcondition := - ∃ "cfg", term_var "result_pmpWriteCfg" = term_var "cfg"; - |}. - - Definition sep_contract_pmpWriteCfgReg : SepContractFun pmpWriteCfgReg := - {| sep_contract_logic_variables := [idx :: ty_pmpcfgidx; value :: ty_xlenbits]; - sep_contract_localstore := [term_var idx; term_var value]; - sep_contract_precondition := - ∃ "cfg0", (pmp0cfg ↦ term_var "cfg0" ∗ asn_expand_pmpcfg_ent (term_var "cfg0")) - ∗ ∃ "cfg1", (pmp1cfg ↦ term_var "cfg1" ∗ asn_expand_pmpcfg_ent (term_var "cfg1")); - sep_contract_result := "result_pmpWriteCfgReg"; - sep_contract_postcondition := - term_var "result_pmpWriteCfgReg" = term_val ty.unit tt - ∗ ∃ "cfg0", pmp0cfg ↦ term_var "cfg0" - ∗ ∃ "cfg1", pmp1cfg ↦ term_var "cfg1"; - |}. - - Definition sep_contract_pmpWriteAddr : SepContractFun pmpWriteAddr := - {| sep_contract_logic_variables := [locked :: ty.bool; addr :: ty_xlenbits; value :: ty_xlenbits]; - sep_contract_localstore := [term_var locked; term_var addr; term_var value]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_pmpWriteAddr"; - sep_contract_postcondition := - asn_if (term_var locked) - (term_var "result_pmpWriteAddr" = term_var addr) - (term_var "result_pmpWriteAddr" = term_var value); - |}. - - Definition sep_contract_read_ram : SepContractFunX read_ram := - {| sep_contract_logic_variables := [paddr :: ty_xlenbits; w :: ty_xlenbits; "entries" :: ty.list ty_pmpentry; p :: ty_privilege; t :: ty_access_type]; - sep_contract_localstore := [term_var paddr]; - sep_contract_precondition := - term_union access_type KRead (term_val ty.unit tt) ⊑ term_var t - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_access (term_var paddr) (term_var "entries") (term_var p) (term_var t) (* TODO: move predicates that do unification earlier in the precond *) - ∗ term_var paddr ↦ₘ term_var w; - sep_contract_result := "result_read_ram"; - sep_contract_postcondition := term_var "result_read_ram" = term_var w - ∗ cur_privilege ↦ term_var p - ∗ term_var paddr ↦ₘ term_var w - ∗ asn_pmp_entries (term_var "entries"); - |}. - - Definition sep_contract_write_ram : SepContractFunX write_ram := - {| sep_contract_logic_variables := [paddr :: ty.int; data :: ty_word; "entries" :: ty.list ty_pmpentry; p :: ty_privilege; t :: ty_access_type]; - sep_contract_localstore := [term_var paddr; term_var data]; - sep_contract_precondition := - term_union access_type KWrite (term_val ty.unit tt) ⊑ term_var t - ∗ cur_privilege ↦ term_var p - ∗ asn_pmp_entries (term_var "entries") - ∗ asn_pmp_access (term_var paddr) (term_var "entries") (term_var p) (term_var t) - ∗ ∃ w, term_var paddr ↦ₘ term_var w; - sep_contract_result := "result_write_ram"; - sep_contract_postcondition := - cur_privilege ↦ term_var p - ∗ term_var paddr ↦ₘ term_var data - ∗ asn_pmp_entries (term_var "entries"); - |}. - - Definition sep_contract_decode : SepContractFunX decode := - {| sep_contract_logic_variables := [bv :: ty.int]; - sep_contract_localstore := [term_var bv]; - sep_contract_precondition := asn_true; - sep_contract_result := "result_decode"; - sep_contract_postcondition := asn_true; - |}. - - Definition lemma_open_gprs : SepLemma open_gprs := - {| lemma_logic_variables := ctx.nil; - lemma_patterns := env.nil; - lemma_precondition := asn_gprs; - lemma_postcondition := asn_regs_ptsto; - |}. - - Definition lemma_close_gprs : SepLemma close_gprs := - {| lemma_logic_variables := ctx.nil; - lemma_patterns := env.nil; - lemma_precondition := asn_regs_ptsto; - lemma_postcondition := asn_gprs; - |}. - - Definition lemma_open_pmp_entries : SepLemma open_pmp_entries := - {| lemma_logic_variables := ["entries" :: ty.list ty_pmpentry]; - lemma_patterns := env.nil; - lemma_precondition := asn_pmp_entries (term_var "entries"); - lemma_postcondition := ∃ "cfg0", ∃ "addr0", ∃ "cfg1", ∃ "addr1", - (pmp0cfg ↦ term_var "cfg0" ∗ pmpaddr0 ↦ term_var "addr0" ∗ - pmp1cfg ↦ term_var "cfg1" ∗ pmpaddr1 ↦ term_var "addr1" ∗ - asn_expand_pmpcfg_ent (term_var "cfg0") ∗ - asn_expand_pmpcfg_ent (term_var "cfg1") ∗ - term_var "entries" = term_list [(term_var "cfg0" ,ₜ term_var "addr0"); - (term_var "cfg1" ,ₜ term_var "addr1")]); - |}. - - Definition lemma_close_pmp_entries : SepLemma close_pmp_entries := - {| lemma_logic_variables := ["cfg0" :: ty_pmpcfg_ent; "addr0" :: _; - "cfg1" :: ty_pmpcfg_ent; "addr1" :: _]; - lemma_patterns := env.nil; - lemma_precondition := - pmp0cfg ↦ term_var "cfg0" ∗ pmpaddr0 ↦ term_var "addr0" ∗ - pmp1cfg ↦ term_var "cfg1" ∗ pmpaddr1 ↦ term_var "addr1" ∗ - asn_expand_pmpcfg_ent (term_var "cfg0") ∗ - asn_expand_pmpcfg_ent (term_var "cfg1"); - lemma_postcondition := - asn_pmp_entries (term_list [(term_var "cfg0" ,ₜ term_var "addr0"); - (term_var "cfg1" ,ₜ term_var "addr1")]); - |}. - - Definition lemma_update_pmp_entries : SepLemma update_pmp_entries := - {| lemma_logic_variables := ["cfg0" :: ty_pmpcfg_ent; "addr0" :: ty_xlenbits; "cfg1" :: ty_pmpcfg_ent; "addr1" :: ty_xlenbits]; - lemma_patterns := env.nil; - lemma_precondition := - pmp0cfg ↦ term_var "cfg0" ∗ pmpaddr0 ↦ term_var "addr0" ∗ - pmp1cfg ↦ term_var "cfg1" ∗ pmpaddr1 ↦ term_var "addr1" ∗ - cur_privilege ↦ term_val ty_privilege Machine; - lemma_postcondition := - cur_privilege ↦ term_val ty_privilege Machine ∗ - asn_pmp_entries (term_list [(term_var "cfg0" ,ₜ term_var "addr0"); - (term_var "cfg1" ,ₜ term_var "addr1")]); - |}. - - Definition lemma_extract_pmp_ptsto : SepLemma extract_pmp_ptsto := - {| lemma_logic_variables := [paddr :: ty_xlenbits; acc :: ty_access_type; "entries" :: ty.list ty_pmpentry; p :: ty_privilege]; - lemma_patterns := [term_var paddr]; - lemma_precondition := - asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p) - ∗ asn_bool (term_val ty_xlenbits minAddr <=ₜ term_var paddr) - ∗ asn_bool (term_var paddr <=ₜ term_val ty_xlenbits maxAddr) - ∗ asn_pmp_access (term_var paddr) (term_var "entries") (term_var p) (term_var acc); - lemma_postcondition := - asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access_without (term_var paddr) (term_var "entries") (term_var p) - ∗ ∃ "w", term_var paddr ↦ₘ term_var w; - |}. - - Definition lemma_return_pmp_ptsto : SepLemma return_pmp_ptsto := - {| lemma_logic_variables := [paddr :: ty_xlenbits; "entries" :: ty.list ty_pmpentry; p :: ty_privilege]; - lemma_patterns := [term_var paddr]; - lemma_precondition := - asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access_without (term_var paddr) (term_var "entries") (term_var p) - ∗ ∃ "w", term_var paddr ↦ₘ term_var w; - lemma_postcondition := - asn_pmp_entries (term_var "entries") - ∗ asn_pmp_addr_access (term_var "entries") (term_var p) - |}. - - End ContractDefKit. - - Definition CEnv : SepContractEnv := - fun Δ τ f => - match f with - | execute_RTYPE => Some sep_contract_execute_RTYPE - | execute_ITYPE => Some sep_contract_execute_ITYPE - | execute_UTYPE => Some sep_contract_execute_UTYPE - | execute_BTYPE => Some sep_contract_execute_BTYPE - | execute_RISCV_JAL => Some sep_contract_execute_RISCV_JAL - | execute_RISCV_JALR => Some sep_contract_execute_RISCV_JALR - | execute_ECALL => Some sep_contract_execute_ECALL - | execute_MRET => Some sep_contract_execute_MRET - | execute_CSR => Some sep_contract_execute_CSR - | execute_STORE => Some sep_contract_execute_STORE - | execute_LOAD => Some sep_contract_execute_LOAD - | process_load => Some sep_contract_process_load - | get_arch_pc => Some sep_contract_get_arch_pc - | get_next_pc => Some sep_contract_get_next_pc - | set_next_pc => Some sep_contract_set_next_pc - | tick_pc => Some sep_contract_tick_pc - | exception_handler => Some sep_contract_exception_handler - | handle_mem_exception => Some sep_contract_handle_mem_exception - | handle_illegal => Some sep_contract_handle_illegal - | trap_handler => Some sep_contract_trap_handler - | prepare_trap_vector => Some sep_contract_prepare_trap_vector - | tvec_addr => Some sep_contract_tvec_addr - | exceptionType_to_bits => Some sep_contract_exceptionType_to_bits - | exception_delegatee => Some sep_contract_exception_delegatee - | rX => Some sep_contract_rX - | wX => Some sep_contract_wX - | abs => Some sep_contract_abs - | within_phys_mem => Some sep_contract_within_phys_mem - | readCSR => Some sep_contract_readCSR - | writeCSR => Some sep_contract_writeCSR - | check_CSR => Some sep_contract_check_CSR - | is_CSR_defined => Some sep_contract_is_CSR_defined - | check_CSR_access => Some sep_contract_check_CSR_access - | privLevel_to_bits => Some sep_contract_privLevel_to_bits - | csrAccess => Some sep_contract_csrAccess - | csrPriv => Some sep_contract_csrPriv - | checked_mem_read => Some sep_contract_checked_mem_read - | checked_mem_write => Some sep_contract_checked_mem_write - | pmp_mem_read => Some sep_contract_pmp_mem_read - | pmp_mem_write => Some sep_contract_pmp_mem_write - | pmpCheck => Some sep_contract_pmpCheck - | pmpCheckPerms => Some sep_contract_pmpCheckPerms - | pmpCheckRWX => Some sep_contract_pmpCheckRWX - | pmpAddrRange => Some sep_contract_pmpAddrRange - | pmpMatchAddr => Some sep_contract_pmpMatchAddr - | pmpMatchEntry => Some sep_contract_pmpMatchEntry - | pmpLocked => Some sep_contract_pmpLocked - | pmpWriteCfgReg => Some sep_contract_pmpWriteCfgReg - | pmpWriteCfg => Some sep_contract_pmpWriteCfg - | pmpWriteAddr => Some sep_contract_pmpWriteAddr - | mem_write_value => Some sep_contract_mem_write_value - | mem_read => Some sep_contract_mem_read - | init_model => Some sep_contract_init_model - | init_sys => Some sep_contract_init_sys - | init_pmp => Some sep_contract_init_pmp - | fetch => Some sep_contract_fetch - | execute => Some sep_contract_execute - | step => Some sep_contract_step - | _ => None - end. - - Lemma linted_cenv : - forall Δ τ (f : Fun Δ τ), - match CEnv f with - | Some c => Linted c - | None => True - end. - Proof. intros ? ? []; try constructor. Qed. - - Definition CEnvEx : SepContractEnvEx := - fun Δ τ f => - match f with - | read_ram => sep_contract_read_ram - | write_ram => sep_contract_write_ram - | decode => sep_contract_decode - end. - - Definition LEnv : LemmaEnv := - fun Δ l => - match l with - | open_gprs => lemma_open_gprs - | close_gprs => lemma_close_gprs - | open_pmp_entries => lemma_open_pmp_entries - | close_pmp_entries => lemma_close_pmp_entries - | update_pmp_entries => lemma_update_pmp_entries - | extract_pmp_ptsto => lemma_extract_pmp_ptsto - | return_pmp_ptsto => lemma_return_pmp_ptsto - end. - - Lemma linted_cenvex : - forall Δ τ (f : FunX Δ τ), - Linted (CEnvEx f). - Proof. - intros ? ? []; try constructor. - Qed. - - End Contracts. - -End RiscvPmpSpecification. - -Module RiscvPmpSolverKit <: SolverKit RiscvPmpBase RiscvPmpSignature. - (* TODO: User predicates can be simplified smarter *) - Equations(noeqns) decide_pmp_check_rwx {Σ} (X W R : Term Σ ty.bool) (acc : Term Σ ty_access_type) : bool := - | term_val true | _ | _ | term_union KExecute (term_val tt) := true; - | _ | term_val true | _ | term_union KWrite (term_val tt) := true; - | _ | _ | term_val true | term_union KRead (term_val tt) := true; - | _ | term_val true | term_val true | term_union KReadWrite (term_val tt) := true; - | _ | _ | _ | _ := false. - - Equations(noeqns) simplify_sub_perm {Σ} (a1 a2 : Term Σ ty_access_type) : option (List Formula Σ) := - | term_val a1 | term_val a2 := if decide_sub_perm a1 a2 then Some nil else None; - | a1 | a2 := Some (cons (formula_user sub_perm [a1;a2]) nil). - - Equations(noeqns) simplify_pmp_check_rwx {Σ} (cfg : Term Σ ty_pmpcfg_ent) (acc : Term Σ ty_access_type) : option (List Formula Σ) := - | term_record pmpcfg_ent [_;_;X;W;R] | acc := - if decide_pmp_check_rwx X W R acc then Some nil else None; - | term_val cfg | term_val acc := - if pmp_check_RWX cfg acc then Some nil else None; - | cfg | acc := - Some (cons (formula_user pmp_check_rwx [cfg;acc]) nil). - - Equations(noeqns) simplify_pmp_check_perms {Σ} (cfg : Term Σ ty_pmpcfg_ent) (acc : Term Σ ty_access_type) (p : Term Σ ty_privilege) : option (List Formula Σ) := - | term_record pmpcfg_ent [term_val false;_;_;_;_] | acc | term_val Machine := - Some nil; - | cfg | acc | p := - simplify_pmp_check_rwx cfg acc. - - Equations(noeqns) simplify_within_cfg {Σ} (paddr : Term Σ ty_xlenbits) (cfg : Term Σ ty_pmpcfg_ent) (prev_addr addr : Term Σ ty_xlenbits) : option (List Formula Σ) := - | term_val paddr | term_val cfg | term_val a | term_val a' := - if decide_within_cfg paddr cfg a a' then Some nil else None; - | paddr | cfg | a | a' := - Some (cons (formula_user within_cfg [paddr; cfg; a; a']) nil). - - Equations(noeqns) simplify_prev_addr {Σ} (cfg : Term Σ ty_pmpcfgidx) (entries : Term Σ (ty.list ty_pmpentry)) (prev : Term Σ ty_xlenbits) : option (List Formula Σ) := - | term_val cfg | term_val entries | term_val prev := if decide_prev_addr cfg entries prev then Some nil else None; - | cfg | entries | prev := - Some (cons (formula_user prev_addr [cfg; entries; prev]) nil). - - Equations(noeqns) simplify_pmp_access {Σ} (paddr : Term Σ ty_xlenbits) (es : Term Σ (ty.list ty_pmpentry)) (p : Term Σ ty_privilege) (acc : Term Σ ty_access_type) : option (List Formula Σ) := - | term_val paddr | term_val entries | term_val p | acc := - match check_pmp_access paddr entries p with - | (true, Some typ) => simplify_sub_perm (term_val ty_access_type typ) acc - | (true, None) => Some nil - | (false, _) => None - end - | paddr | entries | p | acc := - Some (cons (formula_user pmp_access [paddr; entries; p; acc]) nil). - - Definition simplify_user {Σ} (p : 𝑷) : Env (Term Σ) (𝑷_Ty p) -> option (List Formula Σ) := - match p with - | pmp_access => fun ts => - let (ts,perm) := env.snocView ts in - let (ts,priv) := env.snocView ts in - let (ts,entries) := env.snocView ts in - let (ts,paddr) := env.snocView ts in - simplify_pmp_access paddr entries priv perm - | pmp_check_perms => fun ts => - let (ts,priv) := env.snocView ts in - let (ts,acc) := env.snocView ts in - let (ts,cfg) := env.snocView ts in - simplify_pmp_check_perms cfg acc priv - | pmp_check_rwx => fun ts => - let (ts,acc) := env.snocView ts in - let (ts,cfg) := env.snocView ts in - simplify_pmp_check_rwx cfg acc - | sub_perm => fun ts => - let (ts,a2) := env.snocView ts in - let (ts,a1) := env.snocView ts in - simplify_sub_perm a1 a2 - | within_cfg => fun ts => - let (ts,addr) := env.snocView ts in - let (ts,prev_addr) := env.snocView ts in - let (ts,cfg) := env.snocView ts in - let (ts,paddr) := env.snocView ts in - simplify_within_cfg paddr cfg prev_addr addr - | not_within_cfg => fun ts => - let (ts,entries) := env.snocView ts in - let (ts,paddr) := env.snocView ts in - Some (cons (formula_user not_within_cfg [paddr; entries]) nil) - | prev_addr => fun ts => - let (ts,prev) := env.snocView ts in - let (ts,entries) := env.snocView ts in - let (ts,cfg) := env.snocView ts in - simplify_prev_addr cfg entries prev - | in_entries => fun ts => - let (ts,prev) := env.snocView ts in - let (ts,entries) := env.snocView ts in - let (ts,cfg) := env.snocView ts in - Some (cons (formula_user in_entries [cfg; entries; prev]) nil) - end. - - Definition simplify_formula {Σ} (fml : Formula Σ) : option (List Formula Σ) := - match fml with - | formula_user p ts => simplify_user p ts - | _ => Some (cons fml nil) - end. - - Import base. - Definition simplify_all {Σ} (g : Formula Σ -> option (List Formula Σ)) := - fix simplify_all (fmls k : List Formula Σ) {struct fmls} : option (List Formula Σ) := - match fmls with - | nil => Some k - | cons fml0 fmls => - ks ← simplify_all fmls k ; - k0 ← g fml0 ; - Some (app k0 ks) - end. - - Definition solver : Solver := - fun w fmls => option_map (fun l => existT w (tri_id , l)) (simplify_all simplify_formula fmls nil). - Definition solver_spec : SolverSpec solver. - Admitted. -End RiscvPmpSolverKit. -Module RiscvPmpSolver := MakeSolver RiscvPmpBase RiscvPmpSignature RiscvPmpSolverKit. - -Module Import RiscvPmpExecutor := - MakeExecutor RiscvPmpBase RiscvPmpProgram RiscvPmpSignature RiscvPmpSpecification RiscvPmpSolver. - -Notation "r '↦' val" := (chunk_ptsreg r val) (at level 79). - -Definition ValidContract {Δ τ} (f : Fun Δ τ) : Prop := - match CEnv f with - | Some c => Symbolic.ValidContractReflect c (FunDef f) - | None => False - end. - -Definition ValidContractDebug {Δ τ} (f : Fun Δ τ) : Prop := - match CEnv f with - | Some c => Symbolic.ValidContract c (FunDef f) - | None => False - end. - -Section Debug. - Coercion stm_exp : Exp >-> Stm. - Local Notation "'use' 'lemma' lem args" := (stm_lemma lem args%env) (at level 10, lem at next level) : exp_scope. - Local Notation "'use' 'lemma' lem" := (stm_lemma lem env.nil) (at level 10, lem at next level) : exp_scope. - Local Notation "a '↦ₘ' t" := (asn_chunk (chunk_user ptsto [a; t])) (at level 70). - Local Notation "p '∗' q" := (asn_sep p q). - Local Notation "a '=' b" := (asn_eq a b). - Local Notation "'∃' w ',' a" := (asn_exist w _ a) (at level 79, right associativity). - - (* Import RiscvNotations. - Import RiscvμSailNotations. *) - Import SymProp.notations. - -End Debug. - -Lemma valid_contract_step : ValidContract step. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpWriteCfgReg : ValidContract pmpWriteCfgReg. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpWriteCfg : ValidContract pmpWriteCfg. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpWriteAddr : ValidContract pmpWriteAddr. -Proof. reflexivity. Qed. - -Lemma valid_contract_init_model : ValidContract init_model. -Proof. reflexivity. Qed. - -Lemma valid_contract_fetch : ValidContract fetch. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute : ValidContract execute. -Proof. reflexivity. Qed. - -Lemma valid_contract_init_sys : ValidContract init_sys. -Proof. reflexivity. Qed. - -Lemma valid_contract_init_pmp : ValidContract init_pmp. -Proof. reflexivity. Qed. - -Lemma valid_contract_handle_mem_exception : ValidContract handle_mem_exception. -Proof. reflexivity. Qed. - -Lemma valid_contract_mem_write_value : ValidContract mem_write_value. -Proof. reflexivity. Qed. - -Lemma valid_contract_mem_read : ValidContractDebug mem_read. -Proof. - apply Symbolic.validcontract_with_erasure_sound. - compute; constructor; cbn. - intros typ paddr p entries; repeat split; auto. -Qed. - -Lemma valid_contract_process_load : ValidContract process_load. -Proof. reflexivity. Qed. - -Lemma valid_contract_checked_mem_read : ValidContractDebug checked_mem_read. -Proof. - apply Symbolic.validcontract_with_erasure_sound. - compute. - constructor. - cbn. - intros acc paddr p entries Hsub Hacc **. - firstorder. -Qed. - -Lemma valid_contract_checked_mem_write : ValidContractDebug checked_mem_write. -Proof. - apply Symbolic.validcontract_with_erasure_sound. - compute. - constructor. - cbn. - intros addr _ p entries acc. - repeat split; firstorder. -Qed. - -Lemma valid_contract_pmp_mem_read : ValidContract pmp_mem_read. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmp_mem_write : ValidContractDebug pmp_mem_write. -Proof. - apply Symbolic.validcontract_with_erasure_sound. - compute. - constructor. - cbn. - firstorder. -Qed. - -Lemma valid_contract_pmpCheckRWX : ValidContract pmpCheckRWX. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpCheckPerms : ValidContract pmpCheckPerms. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpAddrRange : ValidContract pmpAddrRange. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpMatchAddr : ValidContract pmpMatchAddr. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpMatchEntry : ValidContract pmpMatchEntry. -Proof. reflexivity. Qed. - -Lemma valid_contract_pmpLocked : ValidContract pmpLocked. -Proof. reflexivity. Qed. - -Lemma valid_contract_readCSR : ValidContract readCSR. -Proof. reflexivity. Qed. - -Lemma valid_contract_writeCSR : ValidContract writeCSR. -Proof. reflexivity. Qed. - -Lemma valid_contract_check_CSR : ValidContract check_CSR. -Proof. reflexivity. Qed. - -Lemma valid_contract_is_CSR_defined : ValidContract is_CSR_defined. -Proof. reflexivity. Qed. - -Lemma valid_contract_check_CSR_access : ValidContract check_CSR_access. -Proof. reflexivity. Qed. - -Lemma valid_contract_csrAccess : ValidContract csrAccess. -Proof. reflexivity. Qed. - -Lemma valid_contract_csrPriv : ValidContract csrPriv. -Proof. reflexivity. Qed. - -Lemma valid_contract_privLevel_to_bits : ValidContract privLevel_to_bits. -Proof. reflexivity. Qed. - -Lemma valid_contract_exception_handler : ValidContract exception_handler. -Proof. reflexivity. Qed. - -Lemma valid_contract_handle_illegal : ValidContract handle_illegal. -Proof. reflexivity. Qed. - -Lemma valid_contract_trap_handler : ValidContract trap_handler. -Proof. reflexivity. Qed. - -Lemma valid_contract_prepare_trap_vector : ValidContract prepare_trap_vector. -Proof. reflexivity. Qed. - -Lemma valid_contract_tvec_addr : ValidContract tvec_addr. -Proof. reflexivity. Qed. - -Lemma valid_contract_exceptionType_to_bits : ValidContract exceptionType_to_bits. -Proof. reflexivity. Qed. - -Lemma valid_contract_exception_delegatee : ValidContract exception_delegatee. -Proof. reflexivity. Qed. - -Lemma valid_contract_get_arch_pc : ValidContract get_arch_pc. -Proof. reflexivity. Qed. - -Lemma valid_contract_get_next_pc : ValidContract get_next_pc. -Proof. reflexivity. Qed. - -Lemma valid_contract_set_next_pc : ValidContract set_next_pc. -Proof. reflexivity. Qed. - -Lemma valid_contract_tick_pc : ValidContract tick_pc. -Proof. reflexivity. Qed. - -Lemma valid_contract_rX : ValidContract rX. -Proof. reflexivity. Qed. - -Lemma valid_contract_wX : ValidContract wX. -Proof. reflexivity. Qed. - -Lemma valid_contract_abs : ValidContract abs. -Proof. reflexivity. Qed. - -Lemma valid_contract_within_phys_mem : ValidContract within_phys_mem. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_RTYPE : ValidContract execute_RTYPE. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_ITYPE : ValidContract execute_ITYPE. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_UTYPE : ValidContract execute_UTYPE. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_BTYPE : ValidContract execute_BTYPE. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_RISCV_JAL : ValidContract execute_RISCV_JAL. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_RISCV_JALR : ValidContract execute_RISCV_JALR. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_ECALL : ValidContract execute_ECALL. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_MRET : ValidContract execute_MRET. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_STORE : ValidContract execute_STORE. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_LOAD : ValidContract execute_LOAD. -Proof. reflexivity. Qed. - -Lemma valid_contract_execute_CSR : ValidContract execute_CSR. -Proof. reflexivity. Qed. - -(* TODO: the pmpCheck contract requires some manual proof effort in the case - that no pmp entry matches (i.e. we end up in the final check of - the unrolled loop, more specifically the match on the privilege level, - and the Machine case (= the check is true) - Ideas: - - A lemma capturing the different conditions that can arise that lead to those - cases (have the conditions as precond, and asn_pmp_access ... as postcond, - we can then proof it sound in the model (which should be equivalent to what - is currently happening in the proof below, but we should be able to define - the contract is one that can be proven by reflexivity)) - *) -Lemma valid_contract_pmpCheck : ValidContractDebug pmpCheck. -Proof. - apply Symbolic.validcontract_with_erasure_sound. - vm_compute. constructor. - cbv - [Z.gt Z.gtb Z.lt Z.ltb Z.le Z.leb andb orb - Pmp_access - Pmp_check_perms - Pmp_check_rwx - Sub_perm - Within_cfg - Not_within_cfg - Prev_addr - In_entries - ]. - intros addr acc priv addr0 addr1 R0 W0 X0 A0 L0 R1 W1 X1 A1 L1. - repeat - match goal with - | |- _ /\ _ => split; intros; subst - end; - try progress cbn; auto; - cbv [Pmp_access decide_pmp_access check_pmp_access pmp_check pmp_match_entry pmp_match_addr pmp_addr_range A]; - repeat - match goal with - | |- context[if ?b then ?x else ?x] => rewrite (Tauto.if_same b x) - | |- context[(?b || true)%bool]=> rewrite (Bool.orb_true_r b) - | |- context[match ?amt in PmpAddrMatchType with | _ => _ end] => - destruct amt; try progress cbn - | H: ?x < ?y |- context[?x - rewrite (proj2 (Z.ltb_lt _ _) H); - try progress cbn - | H: (?x || ?y)%bool = true |- _ => - apply Bool.orb_prop in H as [[= ->]|[= ->]]; - try progress cbn - end; cbn; auto. -Qed. - -(* TODO: this is just to make sure that all contracts defined so far are valid - (i.e. ensure no contract was defined and then forgotten to validate it) *) -Lemma defined_contracts_valid : forall {Δ τ} (f : Fun Δ τ), - match CEnv f with - | Some c => ValidContract f - | None => True - end. -Proof. - destruct f; simpl; trivial; - try reflexivity. -Admitted. diff --git a/case_study/RiscvPmp/LoopVerification.v b/case_study/RiscvPmp/LoopVerification.v deleted file mode 100644 index b92e00b1..00000000 --- a/case_study/RiscvPmp/LoopVerification.v +++ /dev/null @@ -1,357 +0,0 @@ -(******************************************************************************) -(* Copyright (c) 2020 Steven Keuchel, Dominique Devriese, Sander Huyghebaert *) -(* All rights reserved. *) -(* *) -(* Redistribution and use in source and binary forms, with or without *) -(* modification, are permitted provided that the following conditions are *) -(* met: *) -(* *) -(* 1. Redistributions of source code must retain the above copyright notice, *) -(* this list of conditions and the following disclaimer. *) -(* *) -(* 2. Redistributions in binary form must reproduce the above copyright *) -(* notice, this list of conditions and the following disclaimer in the *) -(* documentation and/or other materials provided with the distribution. *) -(* *) -(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) -(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) -(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *) -(* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR *) -(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *) -(* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *) -(* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *) -(* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *) -(* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *) -(* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *) -(* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) -(******************************************************************************) - -From Coq Require Import - Lists.List. -From Katamaran Require Import - Bitvector - Environment - Iris.Logic - Iris.Model - Program - Semantics - Sep.Hoare - Sep.Logic - Specification - RiscvPmp.Machine - RiscvPmp.Model - RiscvPmp.Contracts. - -From iris.base_logic Require lib.gen_heap lib.iprop. -From iris.base_logic Require Export invariants. -From iris.bi Require interface big_op. -From iris.algebra Require dfrac. -From iris.program_logic Require Import weakestpre adequacy. -From iris.proofmode Require Import string_ident tactics. - -Set Implicit Arguments. -Import ListNotations. -Import RiscvPmpSpecification. -Import RiscvPmpProgram. -Import RiscvPmpIrisBase. -Import RiscvPmpIrisInstance. -Import RiscvPmpModel2. - -Section Loop. - Context `{sg : sailGS Σ}. - Definition step_sem_contract := - Eval cbn in ValidContractSemCurried fun_step sep_contract_step. - - Local Notation "r '↦' val" := (reg_pointsTo r val). - - Definition PmpEntry : Set := Pmpcfg_ent * Z. - Definition PtstosPred : Type := Privilege -> Privilege -> Z -> Z -> list PmpEntry -> list PmpEntry -> Privilege -> Z -> Z -> iProp Σ. - - (* TODO: added some parameters because the interp_pmp_addr_access predicate can get - "out of sync" with the current state of the machine. - - Might sound odd, but for a given configuration and privilege mode we will - still have that pmp_addr_access holds, however, it won't match up with - the current live config (represented by interp_pmp_entries) and so - contracts regarding PMP checks will have an unsatisfiable precondition - (i.e., we will not be granted access with an "out of sync" pmp_addr_access - predicate). - - Maybe sketch a situation that showcases this? *) - - (* Executing normally *) - (* TODO: this should be the same as Start of iteration (P), drop one of them *) - Definition Execution (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z) := - ( interp_pmp_addr_access (mG := sailGS_memGS) liveAddrs entries m ∗ - interp_gprs ∗ - interp_pmp_entries es ∗ - (∃ mc : Z, mcause ↦ mc) ∗ - cur_privilege ↦ cp ∗ - (∃ npc : Z, nextpc ↦ npc) ∗ - (∃ cpc : Z, pc ↦ cpc) ∗ - mtvec ↦ h ∗ - mstatus ↦ {| MPP := mpp |} ∗ - mepc ↦ mepc_v)%I. - - (* Modified CSRs, requires Machine mode *) - Definition CSRMod (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z) := - ( interp_pmp_addr_access (mG := sailGS_memGS) liveAddrs entries m ∗ - interp_gprs ∗ - (∃ es : list (Pmpcfg_ent * Z), interp_pmp_entries es) ∗ - ⌜m = Machine⌝ ∗ - (∃ mc : Z, mcause ↦ mc) ∗ - cur_privilege ↦ Machine ∗ - (∃ npc : Z, nextpc ↦ npc ∗ - pc ↦ npc) ∗ - (∃ h : Z, mtvec ↦ h) ∗ - (∃ mpp : Privilege, mstatus ↦ {| MPP := mpp |}) ∗ - (∃ epc : Z, mepc ↦ epc))%I. - - (* Trap occured -> Go into M-mode *) - Definition Trap (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z) := - (interp_pmp_addr_access (mG := sailGS_memGS) liveAddrs entries m ∗ - interp_gprs ∗ - interp_pmp_entries es ∗ - (∃ mc : Z, mcause ↦ mc) ∗ - cur_privilege ↦ Machine ∗ - nextpc ↦ h ∗ - pc ↦ h ∗ - mtvec ↦ h ∗ - mstatus ↦ {| MPP := m |} ∗ - mepc ↦ i)%I. - - (* MRET = Recover *) - Definition Recover (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z) := - (interp_pmp_addr_access (mG := sailGS_memGS) liveAddrs entries m ∗ - interp_gprs ∗ - interp_pmp_entries es ∗ - ⌜m = Machine⌝ ∗ - (∃ mc : Z, mcause ↦ mc) ∗ - cur_privilege ↦ mpp ∗ - nextpc ↦ mepc_v ∗ - pc ↦ mepc_v ∗ - mtvec ↦ h ∗ - mstatus ↦ {| MPP := User |} ∗ - mepc ↦ mepc_v)%I. - - Definition step_post (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z) : iProp Σ := - (Execution m cp h i entries es mpp mepc_v ∨ - CSRMod m cp h i entries es mpp mepc_v ∨ - Trap m cp h i entries es mpp mepc_v ∨ - Recover m cp h i entries es mpp mepc_v)%I. - - Definition semTriple_step : iProp Σ := - (∀ (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z), - semTriple env.nil (Execution m cp h i entries es mpp mepc_v) (FunDef step) (fun _ _ => step_post m cp h i entries es mpp mepc_v))%I. - - Definition semTriple_init_model : iProp Σ := - semTriple env.nil - ((∃ p, reg_pointsTo cur_privilege p) ∗ (∃ es, interp_pmp_entries es))%I - (FunDef init_model) - (fun _ _ => reg_pointsTo cur_privilege Machine ∗ (∃ es, interp_pmp_entries es))%I. - - Axiom step_iprop : ⊢ semTriple_step. - Axiom init_model_iprop : ⊢ semTriple_init_model. - - Definition WP_loop : iProp Σ := - (WP (MkConf (FunDef loop) env.nil) ?{{_, True}})%I. - - Definition loop_pre (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z) : iProp Σ := - ( - Execution m cp h i entries es mpp mepc_v ∗ - ▷ (CSRMod m cp h i entries es mpp mepc_v -∗ WP_loop) ∗ - ▷ (Trap m cp h i entries es mpp mepc_v -∗ WP_loop) ∗ - ▷ (Recover m cp h i entries es mpp mepc_v -∗ WP_loop))%I. - - Definition semTriple_loop : iProp Σ := - (∀ (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z), - semTriple env.nil (loop_pre m cp h i entries es mpp mepc_v) (FunDef loop) (fun _ _ => True))%I. - - Definition semTriple_main : iProp Σ := - (∀ (m cp : Privilege) (h i : Z) (entries es : list (Pmpcfg_ent * Z)) (mpp : Privilege) (mepc_v : Z), - semTriple env.nil (loop_pre m cp h i entries es mpp mepc_v) (FunDef main) (fun _ _ => True))%I. - - Lemma valid_semTriple_loop : - ⊢ semTriple_loop. - Proof. - iIntros. - iLöb as "H". - iIntros (m cp h i entries es mpp mepc_v) "[HP HPwp]". - cbn. - unfold fun_loop. - iApply ((iris_rule_stm_seq env.nil (stm_call step _) (stm_call loop _) _ (fun δ => step_post m cp h i entries es mpp mepc_v ∧ ⌜env.nil = δ⌝)%I (fun _ _ => True%I)) with "[] [HPwp] HP"). - iApply (iris_rule_stm_call_inline env.nil step env.nil (Execution m cp h i entries es mpp mepc_v) (fun _ => step_post m cp h i entries es mpp mepc_v)). - iApply step_iprop. - iIntros. - iApply iris_rule_consequence. - iIntros "[Hstep _]". - iExact "Hstep". - 2: { - destruct (env.nilView δ'). - iApply (iris_rule_stm_call_inline_later env.nil loop env.nil _ (fun _ => True%I)). - iModIntro. - cbn. - unfold semTriple_loop. - unfold loop_pre, step_post. - unfold semTriple. - cbn. - iDestruct "HPwp" as "(H2 & H3 & H4)". - iIntros "[HP|[HP|[HP|HP]]]". - iApply "H". - iSplitL "HP"; try iAssumption. - iSplitL "H2"; try (iModIntro; iAssumption). - iSplitL "H3"; iModIntro; iAssumption. - iApply ("H2" with "HP"). - iApply ("H3" with "HP"). - iApply ("H4" with "HP"). - } - now iIntros (_ δ) "_". - Qed. - - (* DOMI: some comments: - - I think a universal contract for main doesn't make sense. - I don't see when this would ever be used. - I believe the only UC we need in practice is the one for loop. - I would propose dropping this? - - semTriple_main quantifies over two arbitrary pmp configs: one which is currently set in the pmp configuration registers and one for which authority is available. - However, main will start by setting a third one in the registers. - I think the contract needs to be adapted to take this into account, by updating at least the pmp configuration that will be set in the contracts for the continuations (i.e. CSRMod, Trap, Recover). - I suspect this is the problem you're hitting in the (STUCK) case. - *) - (* NOTE/TODO: this is quite an ugly and overly explicit proof... - I had trouble rewriting sep logic rules (commutativity of ∗) - and just "abused" the consequence rules to apply it instead of rewriting *) - (* TODO: Alternative: contract for loop specified with Katamaran, verify main in Katamaran *) - Lemma valid_semTriple_main : - ⊢ semTriple_main. (* main := init_model() ;; loop() *) - Proof. - iIntros (m cp h i entries es mpp mepc_v) "Hloop_pre". - cbn. - unfold fun_main. - iApply ((iris_rule_stm_seq env.nil (stm_call init_model _) (stm_call loop _) (loop_pre m cp h i entries es mpp mepc_v) (fun _ => ∃ es, loop_pre m Machine h i entries es mpp mepc_v)%I (fun _ _ => True%I)) with "[] [] Hloop_pre"). - - - 2: { - iIntros. - destruct (env.nilView δ'). - unfold semTriple. - iIntros "[%es' H]". - iRevert "H". - fold (semTriple env.nil (loop_pre m Machine h i entries es' mpp mepc_v) (call loop) (fun _ _ => True)%I). - iApply (@iris_rule_consequence _ _ _ _ _ _ (loop_pre m Machine h i entries es' mpp mepc_v) _ _ _). - 3: { - iApply (iris_rule_stm_call_inline env.nil loop env.nil _ (fun _ => True%I)). - iApply valid_semTriple_loop. - } - now iIntros. - now iIntros. - } - - - unfold loop_pre. - About iris_rule_consequence. - iApply (@iris_rule_consequence _ _ _ _ _ _ - ( - ∃ es0 : list (Pmpcfg_ent * Z), Execution m cp h i entries es0 mpp mepc_v ∗ - ▷ (CSRMod m cp h i entries es0 mpp mepc_v -∗ WP_loop) ∗ - ▷ (Trap m cp h i entries es0 mpp mepc_v -∗ WP_loop) ∗ - ▷ (Recover m cp h i entries es0 mpp mepc_v -∗ WP_loop))%I - _ - (fun _ _ => - ∃ es0 : list (Pmpcfg_ent * Z), Execution m Machine h i entries es0 mpp mepc_v ∗ - ▷ (CSRMod m Machine h i entries es0 mpp mepc_v -∗ WP_loop) ∗ - ▷ (Trap m Machine h i entries es0 mpp mepc_v -∗ WP_loop) ∗ - ▷ (Recover m Machine h i entries es0 mpp mepc_v -∗ WP_loop))%I _). - iIntros "H". - iExists es; iFrame. - now iIntros. - unfold semTriple. - iIntros "[%es' H]". - iRevert "H". - fold (semTriple env.nil - (Execution m cp h i entries es' mpp mepc_v ∗ - ▷ (CSRMod m cp h i entries es' mpp mepc_v -∗ WP_loop) ∗ - ▷ (Trap m cp h i entries es' mpp mepc_v -∗ WP_loop) ∗ - ▷ (Recover m cp h i entries es' mpp mepc_v -∗ WP_loop))%I (call init_model) - (fun _ _ => ∃ es0 : list (Pmpcfg_ent * Z), Execution m Machine h i entries es0 mpp mepc_v ∗ - ▷ (CSRMod m Machine h i entries es0 mpp mepc_v -∗ WP_loop) ∗ - ▷ (Trap m Machine h i entries es0 mpp mepc_v -∗ WP_loop) ∗ - ▷ (Recover m Machine h i entries es0 mpp mepc_v -∗ WP_loop))%I). - iApply (@iris_rule_consequence _ _ _ _ _ _ _ _ (fun _ _ => - Execution m Machine h i entries es' mpp mepc_v ∗ - ▷ (CSRMod m Machine h i entries es' mpp mepc_v -∗ WP_loop) ∗ - ▷ (Trap m Machine h i entries es' mpp mepc_v -∗ WP_loop) ∗ - ▷ (Recover m Machine h i entries es' mpp mepc_v -∗ WP_loop))%I _). - iIntros "H"; iExact "H". - iIntros (_ _) "H". - iExists es'; iFrame. - - iApply iris_rule_consequence. - iIntros "H". - iApply (bi.sep_comm with "H"). - 2: { - iApply (iris_rule_frame _ _ (fun _ _ => Execution m Machine h i entries es' mpp mepc_v)%I _). - iApply (@iris_rule_consequence _ _ _ _ _ _ _ _ (fun _ _ => ∃ es, Execution m Machine h i entries es mpp mepc_v)%I _). - iIntros "H"; iExact "H". - (* STUCK *) - (* unfold Execution. *) - (* iApply (@iris_rule_consequence _ _ _ _ _ _ ((reg_pointsTo mtvec h ∗ (∃, reg_pointsTo pc ∗ *) - (* reg_pointsTo nextpc) ∗ *) - (* (∃ mc : Val ty_exc_code, reg_pointsTo mcause mc ∗ reg_pointsTo mepc mepc_v ∗ *) - (* reg_pointsTo mstatus {| MPP := mpp |} ∗ *) - (* interp_pmp_addr_access liveAddrs entries m ∗ interp_gprs)) ∗ *) - (* (reg_pointsTo cur_privilege cp ∗ ∃ es, interp_pmp_entries es)) _ _ _). *) - (* iIntros "(Hacc & Hgprs & Hes & (% & Hmc) & Hmepc & (% & Hnpc & Hpc) & Hmt & Hms & Hme)". *) - (* iFrame. *) - (* iSplitR "Hes". *) - (* iSplitL "Hnpc Hpc". *) - (* iExists0; iFrame. *) - (* now iExists mc. *) - (* now iExists es'. *) - (* 2: { *) - (* iApply (iris_rule_frame _ _ (fun _ _ => reg_pointsTo cur_privilege Machine ∗ ∃ es, interp_pmp_entries es)%I _). *) - (* iApply iris_rule_consequence. *) - (* 3: { *) - (* iApply (iris_rule_stm_call_inline env.nil init_model env.nil _ (fun _ => _)). *) - (* iApply init_model_iprop. *) - (* } *) - (* iIntros "(HP & Hes)". *) - (* iSplitL "HP". *) - (* iExists cp; iFrame. *) - (* iExact "Hes". *) - (* iIntros (_ δ) "((Hcp & Hes) & %)". *) - (* iFrame. *) - (* } *) - (* iIntros (v δ) "((Hmt & (% & Hpc & Hnpc) & % & Hmc & Hmepc & Hms &Hacc & Hgprs) & (Hcp & [% Hes]))". *) - (* iFrame. *) - (* iExists es0; iFrame. *) - (* iSplitL "Hmc". *) - (* iExists mc; iFrame. *) - (* iExists0; iFrame. *) - admit. - admit. - } - (* iIntros (v δ) "[Hloop [% HP]]". *) - (* iExists es; iFrame. *) - (* - iIntros. *) - (* destruct (env.nilView δ). *) - (* unfold semTriple. *) - (* iDestruct "Hloop" as "(HCSRMod & HTrap & HRecover)". *) - (* iSplitL "HCSRMod". *) - (* unfold CSRMod. *) - (* iFrame. *) - (* (* pmp_entries es ≠ pmp_entries es0 *) *) - - (* iIntros "[%es' H]". *) - (* iRevert "H". *) - (* fold (semTriple env.nil (loop_pre m Machine h i entries es' mpp mepc_v) (call loop) (fun _ _ => True)%I). *) - (* iApply (@iris_rule_consequence _ _ _ _ _ _ (loop_pre m Machine h i entries es' mpp mepc_v) _ _ _). *) - (* 3: { *) - (* iApply (iris_rule_stm_call_inline env.nil loop env.nil _ (fun _ => True%I)). *) - (* iApply valid_semTriple_loop. *) - (* } *) - (* now iIntros. *) - (* now iIntros. *) - (* Qed. *) - Admitted. -End Loop. diff --git a/case_study/RiscvPmp/Machine.v b/case_study/RiscvPmp/Machine.v deleted file mode 100644 index 0327f3f2..00000000 --- a/case_study/RiscvPmp/Machine.v +++ /dev/null @@ -1,1107 +0,0 @@ -(******************************************************************************) -(* Copyright (c) 2020 Steven Keuchel, Dominique Devriese, Sander Huyghebaert *) -(* All rights reserved. *) -(* *) -(* Redistribution and use in source and binary forms, with or without *) -(* modification, are permitted provided that the following conditions are *) -(* met: *) -(* *) -(* 1. Redistributions of source code must retain the above copyright notice, *) -(* this list of conditions and the following disclaimer. *) -(* *) -(* 2. Redistributions in binary form must reproduce the above copyright *) -(* notice, this list of conditions and the following disclaimer in the *) -(* documentation and/or other materials provided with the distribution. *) -(* *) -(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) -(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) -(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *) -(* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR *) -(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *) -(* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *) -(* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *) -(* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *) -(* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *) -(* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *) -(* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) -(******************************************************************************) - -From Coq Require Import - Strings.String - ZArith.ZArith. -From Equations Require Import - Equations. -Require Import Equations.Prop.EqDec. -From Katamaran Require Import - Semantics.Registers - Program - Syntax.BinOps. -From Katamaran Require Export - RiscvPmp.Base. - -From stdpp Require Import decidable finite. - -Set Implicit Arguments. -Import ctx.notations. -Import ctx.resolution. -Import env.notations. -Open Scope string_scope. - -Module RiscvNotations. - Notation "'rs'" := "rs" : string_scope. - Notation "'rs1'" := "rs1" : string_scope. - Notation "'rs2'" := "rs2" : string_scope. - Notation "'rd'" := "rd" : string_scope. - Notation "'op'" := "op" : string_scope. - Notation "'v'" := "v" : string_scope. - Notation "'imm'" := "imm" : string_scope. - Notation "'t'" := "t" : string_scope. - Notation "'addr'" := "addr" : string_scope. - Notation "'paddr'" := "paddr" : string_scope. - Notation "'vaddr'" := "vaddr" : string_scope. - Notation "'typ'" := "typ" : string_scope. - Notation "'acc'" := "acc" : string_scope. - Notation "'value'" := "value" : string_scope. - Notation "'data'" := "data" : string_scope. - Notation "'ent'" := "ent" : string_scope. - Notation "'pmpaddr'" := "pmpaddr" : string_scope. - Notation "'prev_pmpaddr'" := "prev_pmpaddr" : string_scope. - Notation "'cfg'" := "cfg" : string_scope. - Notation "'rng'" := "rng" : string_scope. - Notation "'bv'" := "bv" : string_scope. - Notation "'e'" := "e" : string_scope. - Notation "'ctl'" := "ctl" : string_scope. - Notation "'c'" := "c" : string_scope. - Notation "'cause'" := "cause" : string_scope. - Notation "'m'" := "m" : string_scope. - Notation "'priv'" := "priv" : string_scope. - Notation "'cur_priv'" := "cur_priv" : string_scope. - Notation "'del_priv'" := "del_priv" : string_scope. - Notation "'p'" := "p" : string_scope. - Notation "'rs1_val'" := "rs1_val" : string_scope. - Notation "'rs2_val'" := "rs2_val" : string_scope. - Notation "'csr_val'" := "csr_val" : string_scope. - Notation "'op'" := "op" : string_scope. - Notation "'result'" := "result" : string_scope. - Notation "'res'" := "res" : string_scope. - Notation "'immext'" := "immext" : string_scope. - Notation "'off'" := "off" : string_scope. - Notation "'offset'" := "offset" : string_scope. - Notation "'ret'" := "ret" : string_scope. - Notation "'tmp'" := "tmp" : string_scope. - Notation "'tmp1'" := "tmp1" : string_scope. - Notation "'tmp2'" := "tmp2" : string_scope. - Notation "'tmp3'" := "tmp3" : string_scope. - Notation "'taken'" := "taken" : string_scope. - Notation "'check'" := "check" : string_scope. - Notation "'L'" := "L" : string_scope. - Notation "'A'" := "A" : string_scope. - Notation "'X'" := "X" : string_scope. - Notation "'W'" := "W" : string_scope. - Notation "'R'" := "R" : string_scope. - Notation "'lo'" := "lo" : string_scope. - Notation "'hi'" := "hi" : string_scope. - Notation "'f'" := "f" : string_scope. - Notation "'w'" := "w" : string_scope. - Notation "'tvec'" := "tvec" : string_scope. - Notation "'epc'" := "epc" : string_scope. - Notation "'prev_priv'" := "prev_priv" : string_scope. - Notation "'MPP'" := "MPP" : string_scope. - Notation "'csr'" := "csr" : string_scope. - Notation "'csrrw'" := "csrrw" : string_scope. - Notation "'csrpr'" := "csrpr" : string_scope. - Notation "'idx'" := "idx" : string_scope. - Notation "'locked'" := "locked" : string_scope. -End RiscvNotations. - -(* We postulate a pure decode function and assume that that's what the decode primitive implements. *) -(* Similarly for *_{from,to}_bits functions, ideally we would move to actual bitvectors for values... *) -Axiom pure_decode : Z -> string + AST. - -Module Import RiscvPmpProgram <: Program RiscvPmpBase. - - Section FunDeclKit. - Import RiscvNotations. - - (** Functions **) - Inductive Fun : PCtx -> Ty -> Set := - | rX : Fun [rs ∷ ty_regno] ty_xlenbits - | wX : Fun [rd ∷ ty_regno; v ∷ ty_xlenbits] ty.unit - | get_arch_pc : Fun ctx.nil ty_xlenbits - | get_next_pc : Fun ctx.nil ty_xlenbits - | set_next_pc : Fun [addr ∷ ty_xlenbits] ty.unit - | tick_pc : Fun ctx.nil ty.unit - | abs : Fun [v ∷ ty.int] ty.int - | within_phys_mem : Fun [paddr ∷ ty_xlenbits] ty.bool - | mem_read : Fun [typ ∷ ty_access_type; paddr ∷ ty_xlenbits] ty_memory_op_result - | checked_mem_read : Fun [t ∷ ty_access_type; paddr ∷ ty_xlenbits] ty_memory_op_result - | checked_mem_write : Fun [paddr ∷ ty_xlenbits; data ∷ ty.int] ty_memory_op_result - | pmp_mem_read : Fun [t∷ ty_access_type; p ∷ ty_privilege; paddr ∷ ty_xlenbits] ty_memory_op_result - | pmp_mem_write : Fun [paddr ∷ ty_xlenbits; data ∷ ty.int; typ ∷ ty_access_type; priv ∷ ty_privilege] ty_memory_op_result - | pmpLocked : Fun [cfg ∷ ty_pmpcfg_ent] ty.bool - | pmpWriteCfgReg : Fun [idx :: ty_pmpcfgidx; value :: ty_xlenbits] ty.unit - | pmpWriteCfg : Fun [cfg :: ty_pmpcfg_ent; value :: ty_xlenbits] ty_pmpcfg_ent - | pmpWriteAddr : Fun [locked :: ty.bool; addr :: ty_xlenbits; value :: ty_xlenbits] ty_xlenbits - | pmpCheck : Fun [addr ∷ ty_xlenbits; acc ∷ ty_access_type; priv ∷ ty_privilege] (ty.option ty_exception_type) - | pmpCheckPerms : Fun [ent ∷ ty_pmpcfg_ent; acc ∷ ty_access_type; priv ∷ ty_privilege] ty.bool - | pmpCheckRWX : Fun [ent ∷ ty_pmpcfg_ent; acc ∷ ty_access_type] ty.bool - | pmpMatchEntry : Fun [addr ∷ ty_xlenbits; acc ∷ ty_access_type; priv ∷ ty_privilege; ent ∷ ty_pmpcfg_ent; pmpaddr ∷ ty_xlenbits; prev_pmpaddr ∷ ty_xlenbits] ty_pmpmatch - | pmpAddrRange : Fun [cfg ∷ ty_pmpcfg_ent; pmpaddr ∷ ty_xlenbits; prev_pmpaddr ∷ ty_xlenbits] ty_pmp_addr_range - | pmpMatchAddr : Fun [addr ∷ ty_xlenbits; rng ∷ ty_pmp_addr_range] ty_pmpaddrmatch - | process_load : Fun [rd ∷ ty_regno; vaddr ∷ ty_xlenbits; value ∷ ty_memory_op_result] ty_retired - | mem_write_value : Fun [paddr ∷ ty_xlenbits; value ∷ ty.int] ty_memory_op_result - | main : Fun ctx.nil ty.unit - | init_model : Fun ctx.nil ty.unit - | loop : Fun ctx.nil ty.unit - | step : Fun ctx.nil ty.unit - | fetch : Fun ctx.nil ty_fetch_result - | init_sys : Fun ctx.nil ty.unit - | init_pmp : Fun ctx.nil ty.unit - | exceptionType_to_bits : Fun [e ∷ ty_exception_type] ty_exc_code - | privLevel_to_bits : Fun [p ∷ ty_privilege] ty_xlenbits - | handle_mem_exception : Fun [addr ∷ ty_xlenbits; e ∷ ty_exception_type] ty.unit - | exception_handler : Fun [cur_priv ∷ ty_privilege; ctl ∷ ty_ctl_result; "pc" ∷ ty_xlenbits] ty.int - | exception_delegatee : Fun [p ∷ ty_privilege] ty_privilege - | trap_handler : Fun [del_priv ∷ ty_privilege; c ∷ ty_exc_code; "pc" ∷ ty_xlenbits] ty_xlenbits - | prepare_trap_vector : Fun [p ∷ ty_privilege; cause ∷ ty_mcause] ty_xlenbits - | tvec_addr : Fun [m ∷ ty.int; c ∷ ty_mcause] (ty.option ty_xlenbits) - | handle_illegal : Fun ctx.nil ty.unit - | check_CSR : Fun [csr ∷ ty_csridx; p ∷ ty_privilege] ty.bool - | is_CSR_defined : Fun [csr ∷ ty_csridx; p ∷ ty_privilege] ty.bool - | csrAccess : Fun [csr ∷ ty_csridx] ty_access_type - | csrPriv : Fun [csr ∷ ty_csridx] ty_privilege - | check_CSR_access : Fun [csrrw ∷ ty_access_type; csrpr ∷ ty_privilege; p ∷ ty_privilege] ty.bool - | readCSR : Fun [csr ∷ ty_csridx] ty_xlenbits - | writeCSR : Fun [csr ∷ ty_csridx; value ∷ ty_xlenbits] ty.unit - | execute : Fun ["ast" ∷ ty_ast] ty_retired - | execute_RTYPE : Fun [rs2 ∷ ty_regno; rs1 ∷ ty_regno; rd ∷ ty_regno; op ∷ ty_rop] ty_retired - | execute_ITYPE : Fun [imm ∷ ty.int; rs1 ∷ ty_regno; rd ∷ ty_regno; op ∷ ty_iop] ty_retired - | execute_UTYPE : Fun [imm ∷ ty.int; rd ∷ ty_regno; op ∷ ty_uop] ty_retired - | execute_BTYPE : Fun [imm ∷ ty.int; rs2 ∷ ty_regno; rs1 ∷ ty_regno; op ∷ ty_bop] ty_retired - | execute_RISCV_JAL : Fun [imm ∷ ty.int; rd ∷ ty_regno] ty_retired - | execute_RISCV_JALR : Fun [imm ∷ ty.int; rs1 ∷ ty_regno; rd ∷ ty_regno] ty_retired - | execute_LOAD : Fun [imm ∷ ty.int; rs1 ∷ ty_regno; rd ∷ ty_regno] ty_retired - | execute_STORE : Fun [imm ∷ ty.int; rs2 ∷ ty_regno; rs1 ∷ ty_regno] ty_retired - | execute_ECALL : Fun ctx.nil ty_retired - | execute_MRET : Fun ctx.nil ty_retired - | execute_CSR : Fun [csr ∷ ty_csridx; rs1 ∷ ty_regno; rd ∷ ty_regno; op ∷ ty_csrop] ty_retired - . - - Inductive FunX : PCtx -> Ty -> Set := - | read_ram : FunX [paddr ∷ ty.int] ty_word - | write_ram : FunX [paddr ∷ ty.int; data ∷ ty_word] ty_word - | decode : FunX [bv ∷ ty.int] ty_ast - . - - Inductive Lem : PCtx -> Set := - | open_gprs : Lem ctx.nil - | close_gprs : Lem ctx.nil - | open_pmp_entries : Lem ctx.nil - | close_pmp_entries : Lem ctx.nil - | update_pmp_entries : Lem ctx.nil - | extract_pmp_ptsto : Lem [paddr :: ty_xlenbits] - | return_pmp_ptsto : Lem [paddr :: ty_xlenbits] - . - - Definition 𝑭 : PCtx -> Ty -> Set := Fun. - Definition 𝑭𝑿 : PCtx -> Ty -> Set := FunX. - Definition 𝑳 : PCtx -> Set := Lem. - End FunDeclKit. - - Include FunDeclMixin RiscvPmpBase. - - Module RiscvμSailNotations. - Notation "'rs'" := (@exp_var _ "rs" _ _) : exp_scope. - Notation "'rs1'" := (@exp_var _ "rs1" _ _) : exp_scope. - Notation "'rs1_val'" := (@exp_var _ "rs1_val" _ _) : exp_scope. - Notation "'rs2'" := (@exp_var _ "rs2" _ _) : exp_scope. - Notation "'rs2_val'" := (@exp_var _ "rs2_val" _ _) : exp_scope. - Notation "'csr_val'" := (@exp_var _ "csr_val" _ _) : exp_scope. - Notation "'rd'" := (@exp_var _ "rd" _ _) : exp_scope. - Notation "'op'" := (@exp_var _ "op" _ _) : exp_scope. - Notation "'result'" := (@exp_var _ "result" _ _) : exp_scope. - Notation "'res'" := (@exp_var _ "res" _ _) : exp_scope. - Notation "'v'" := (@exp_var _ "v" _ _) : exp_scope. - Notation "'imm'" := (@exp_var _ "imm" _ _) : exp_scope. - Notation "'immext'" := (@exp_var _ "immext" _ _) : exp_scope. - Notation "'off'" := (@exp_var _ "off" _ _) : exp_scope. - Notation "'offset'" := (@exp_var _ "offset" _ _) : exp_scope. - Notation "'ret'" := (@exp_var _ "ret" _ _) : exp_scope. - Notation "'tmp'" := (@exp_var _ "tmp" _ _) : exp_scope. - Notation "'tmp1'" := (@exp_var _ "tmp1" _ _) : exp_scope. - Notation "'tmp2'" := (@exp_var _ "tmp2" _ _) : exp_scope. - Notation "'tmp3'" := (@exp_var _ "tmp3" _ _) : exp_scope. - Notation "'t'" := (@exp_var _ "t" _ _) : exp_scope. - Notation "'e'" := (@exp_var _ "e" _ _) : exp_scope. - Notation "'addr'" := (@exp_var _ "addr" _ _) : exp_scope. - Notation "'paddr'" := (@exp_var _ "paddr" _ _) : exp_scope. - Notation "'vaddr'" := (@exp_var _ "vaddr" _ _) : exp_scope. - Notation "'taken'" := (@exp_var _ "taken" _ _) : exp_scope. - Notation "'typ'" := (@exp_var _ "typ" _ _) : exp_scope. - Notation "'acc'" := (@exp_var _ "acc" _ _) : exp_scope. - Notation "'value'" := (@exp_var _ "value" _ _) : exp_scope. - Notation "'data'" := (@exp_var _ "data" _ _) : exp_scope. - Notation "'check'" := (@exp_var _ "check" _ _) : exp_scope. - Notation "'ent'" := (@exp_var _ "ent" _ _) : exp_scope. - Notation "'pmpaddr'" := (@exp_var _ "pmpaddr" _ _) : exp_scope. - Notation "'prev_pmpaddr'" := (@exp_var _ "prev_pmpaddr" _ _) : exp_scope. - Notation "'rng'" := (@exp_var _ "rng" _ _) : exp_scope. - Notation "'cfg'" := (@exp_var _ "cfg" _ _) : exp_scope. - Notation "'L'" := (@exp_var _ "L" _ _) : exp_scope. - Notation "'A'" := (@exp_var _ "A" _ _) : exp_scope. - Notation "'X'" := (@exp_var _ "X" _ _) : exp_scope. - Notation "'W'" := (@exp_var _ "W" _ _) : exp_scope. - Notation "'R'" := (@exp_var _ "R" _ _) : exp_scope. - Notation "'lo'" := (@exp_var _ "lo" _ _) : exp_scope. - Notation "'hi'" := (@exp_var _ "hi" _ _) : exp_scope. - Notation "'f'" := (@exp_var _ "f" _ _) : exp_scope. - Notation "'w'" := (@exp_var _ "w" _ _) : exp_scope. - Notation "'ctl'" := (@exp_var _ "ctl" _ _) : exp_scope. - Notation "'c'" := (@exp_var _ "c" _ _) : exp_scope. - Notation "'cause'" := (@exp_var _ "cause" _ _) : exp_scope. - Notation "'tvec'" := (@exp_var _ "tvec" _ _) : exp_scope. - Notation "'m'" := (@exp_var _ "m" _ _) : exp_scope. - Notation "'epc'" := (@exp_var _ "epc" _ _) : exp_scope. - Notation "'priv'" := (@exp_var _ "priv" _ _) : exp_scope. - Notation "'cur_priv'" := (@exp_var _ "cur_priv" _ _) : exp_scope. - Notation "'del_priv'" := (@exp_var _ "del_priv" _ _) : exp_scope. - Notation "'prev_priv'" := (@exp_var _ "prev_priv" _ _) : exp_scope. - Notation "'p'" := (@exp_var _ "p" _ _) : exp_scope. - Notation "'MPP'" := (@exp_var _ "MPP" _ _) : exp_scope. - Notation "'csr'" := (@exp_var _ "csr" _ _) : exp_scope. - Notation "'csrrw'" := (@exp_var _ "csrrw" _ _) : exp_scope. - Notation "'csrpr'" := (@exp_var _ "csrpr" _ _) : exp_scope. - Notation "'idx'" := (@exp_var _ "idx" _ _) : exp_scope. - Notation "'locked'" := (@exp_var _ "locked" _ _) : exp_scope. - - Notation "'Read'" := (exp_union access_type KRead (exp_val ty.unit tt)) : exp_scope. - Notation "'Write'" := (exp_union access_type KWrite (exp_val ty.unit tt)) : exp_scope. - Notation "'ReadWrite'" := (exp_union access_type KReadWrite (exp_val ty.unit tt)) : exp_scope. - Notation "'Execute'" := (exp_union access_type KExecute (exp_val ty.unit tt)) : exp_scope. - - Notation "'E_Fetch_Access_Fault'" := (exp_union exception_type KE_Fetch_Access_Fault (exp_val ty.unit tt)) : exp_scope. - Notation "'E_Load_Access_Fault'" := (exp_union exception_type KE_Load_Access_Fault (exp_val ty.unit tt)) : exp_scope. - Notation "'E_SAMO_Access_Fault'" := (exp_union exception_type KE_SAMO_Access_Fault (exp_val ty.unit tt)) : exp_scope. - Notation "'E_U_EnvCall'" := (exp_union exception_type KE_U_EnvCall (exp_val ty.unit tt)) : exp_scope. - Notation "'E_M_EnvCall'" := (exp_union exception_type KE_M_EnvCall (exp_val ty.unit tt)) : exp_scope. - Notation "'E_Illegal_Instr'" := (exp_union exception_type KE_Illegal_Instr (exp_val ty.unit tt)) : exp_scope. - - Notation "'None'" := (exp_inr (exp_val ty.unit tt)) : exp_scope. - Notation "'Some' va" := (exp_inl va) (at level 10, va at next level) : exp_scope. - - Notation "'MemValue' memv" := (exp_union memory_op_result KMemValue memv) (at level 10, memv at next level) : exp_scope. - Notation "'MemException' meme" := (exp_union memory_op_result KMemException meme) (at level 10, meme at next level) : exp_scope. - - Notation "'F_Base' memv" := (exp_union fetch_result KF_Base memv) (at level 10, memv at next level) : exp_scope. - Notation "'F_Error' meme memv" := (exp_union fetch_result KF_Error (exp_binop bop.pair meme memv)) (at level 10, meme at next level, memv at next level) : exp_scope. - - Notation "'CTL_TRAP' exc" := (exp_union ctl_result KCTL_TRAP exc) (at level 10, exc at next level) : exp_scope. - Notation "'CTL_MRET'" := (exp_union ctl_result KCTL_MRET (exp_val ty.unit tt)) : exp_scope. - End RiscvμSailNotations. - - Section FunDefKit. - Import RiscvNotations. - Import RiscvμSailNotations. - Local Coercion stm_exp : Exp >-> Stm. - - Notation "'use' 'lemma' lem args" := (stm_lemma lem args%env) (at level 10, lem at next level) : exp_scope. - Notation "'use' 'lemma' lem" := (stm_lemma lem env.nil) (at level 10, lem at next level) : exp_scope. - - Definition z_exp {Γ} : Z -> Exp Γ ty.int := exp_val ty.int. - - Definition zero_reg {Γ} : Stm Γ ty_xlenbits := exp_val ty.int 0%Z. - - (** Pure inlined functions **) - Definition stm_mstatus_from_bits {Γ} (b : Stm Γ ty_xlenbits) : Stm Γ ty_mstatus := - let: "b" := b in - let: "mpp" := let: "mstatus_mpp" := exp_binop bop.land (exp_var "b") (exp_int (Z.shiftl 3 11)) in - if: exp_var "mstatus_mpp" = exp_int (Z.shiftl 0 11) then stm_val ty_privilege User else - (* if: exp_var "mstatus_mpp" = exp_int (Z.shiftl 1 11) then stm_val ty_privilege Supervisor else *) - if: exp_var "mstatus_mpp" = exp_int (Z.shiftl 3 11) then stm_val ty_privilege Machine else - stm_fail ty_privilege "mstatus_from_bits" - in stm_exp (exp_record rmstatus [ exp_var "mpp" ]). - - Definition stm_mstatus_to_bits {Γ} (mst : Stm Γ ty_mstatus) : Stm Γ ty_xlenbits := - let: "mst" := mst in - match: exp_var "mst" in rmstatus with - ["mpp"] => let: "mppb" := match: exp_var "mpp" in privilege with - | User => stm_val ty_exc_code (Z.shiftl 0 11) - | Machine => stm_val ty_exc_code (Z.shiftl 0 11) - end - in exp_var "mppb" - end. - - Definition exp_testbit {Γ} (eb : Exp Γ ty_xlenbits) (i : Z) : Exp Γ ty.bool := - let em := exp_int (Z.shiftl 1 i) in - exp_binop bop.eq (exp_binop bop.land eb em) em. - - Definition stm_pmpcfg_ent_from_bits {Γ} (b : Stm Γ ty_xlenbits) : Stm Γ ty_pmpcfg_ent := - let: "b" := b in - let: "L" := exp_testbit (exp_var "b") 7 in - let: "A" := if: exp_testbit (exp_var "b") 4 - then if: exp_testbit (exp_var "b") 3 - then stm_fail ty_pmpaddrmatchtype "stm_pmpcfg_ent_from_bits NAPOT" - else stm_fail ty_pmpaddrmatchtype "stm_pmpcfg_ent_from_bits NA4" - else if: exp_testbit (exp_var "b") 3 - then exp_val ty_pmpaddrmatchtype TOR - else exp_val ty_pmpaddrmatchtype OFF in - let: "X" := exp_testbit (exp_var "b") 2 in - let: "W" := exp_testbit (exp_var "b") 1 in - let: "R" := exp_testbit (exp_var "b") 0 in - exp_record rpmpcfg_ent [L; A; X; W; R]. - - Definition stm_pmpcfg_ent_to_bits {Γ} (cfgent : Stm Γ ty_pmpcfg_ent) : Stm Γ ty_xlenbits := - let: "cfgent" := cfgent in - match: exp_var "cfgent" in rpmpcfg_ent with - ["L";"A";"X";"W";"R"] => - let: "L'" := if: exp_var "L" then exp_int (Z.shiftl 1 7) else exp_int 0 in - let: "A'" := match: A in pmpaddrmatchtype with - | OFF => exp_int (Z.shiftl 0 3) - | TOR => exp_int (Z.shiftl 1 3) - end in - let: "X'" := if: exp_var "X" then exp_int (Z.shiftl 1 2) else exp_int 0 in - let: "W'" := if: exp_var "W" then exp_int (Z.shiftl 1 1) else exp_int 0 in - let: "R'" := if: exp_var "R" then exp_int (Z.shiftl 1 0) else exp_int 0 in - exp_var "L'" + exp_var "A'" + exp_var "X'" + exp_var "W'" + exp_var "R'" - end. - - (** Functions **) - Import Bitvector.bv.notations. - Definition fun_rX : Stm [rs ∷ ty_regno] ty_xlenbits := - use lemma open_gprs ;; - let: v := match: rs in bvec 3 with - | 000 => z_exp 0 - | 001 => stm_read_register x1 - | 010 => stm_read_register x2 - | 011 => stm_read_register x3 - | 100 => stm_read_register x4 - | 101 => stm_read_register x5 - | 110 => stm_read_register x6 - | 111 => stm_read_register x7 - end in - use lemma close_gprs ;; - v. - - Definition fun_wX : Stm [rd ∷ ty_regno; v ∷ ty_xlenbits] ty.unit := - use lemma open_gprs ;; - match: rd in bvec 3 with - | 000 => z_exp 0 - | 001 => stm_write_register x1 v - | 010 => stm_write_register x2 v - | 011 => stm_write_register x3 v - | 100 => stm_write_register x4 v - | 101 => stm_write_register x5 v - | 110 => stm_write_register x6 v - | 111 => stm_write_register x7 v - end ;; - use lemma close_gprs. - - Definition fun_get_arch_pc : Stm ctx.nil ty_xlenbits := - stm_read_register pc. - - Definition fun_get_next_pc : Stm ctx.nil ty_xlenbits := - stm_read_register nextpc. - - Definition fun_set_next_pc : Stm [addr ∷ ty_xlenbits] ty.unit := - stm_write_register nextpc addr ;; - stm_val ty.unit tt. - - Definition fun_tick_pc : Stm ctx.nil ty.unit := - let: tmp := stm_read_register nextpc in - stm_write_register pc tmp ;; - stm_val ty.unit tt. - - Definition fun_abs : Stm [v ∷ ty.int] ty.int := - if: v < z_exp 0 - then v * z_exp (-1) - else v. - - Definition fun_within_phys_mem : Stm [paddr :: ty_xlenbits] ty.bool := - if: (z_exp minAddr <= paddr) && (paddr <= z_exp maxAddr) - then stm_val ty.bool true - else stm_val ty.bool false. - - Definition fun_mem_read : Stm [typ ∷ ty_access_type; paddr ∷ ty_xlenbits] ty_memory_op_result := - let: tmp := stm_read_register cur_privilege in - call pmp_mem_read typ tmp paddr. - - Definition fun_checked_mem_read : Stm [t ∷ ty_access_type; paddr ∷ ty_xlenbits] ty_memory_op_result := - let: tmp := call within_phys_mem paddr in - if: tmp - then (use lemma extract_pmp_ptsto [paddr] ;; - let: tmp := foreign read_ram paddr in - use lemma return_pmp_ptsto [paddr] ;; - MemValue tmp) - else match: t in union access_type with - |> KRead pat_unit => MemException E_Load_Access_Fault - |> KWrite pat_unit => MemException E_SAMO_Access_Fault - |> KReadWrite pat_unit => MemException E_SAMO_Access_Fault - |> KExecute pat_unit => MemException E_Fetch_Access_Fault - end. - - Definition fun_checked_mem_write : Stm [paddr ∷ ty_xlenbits; data ∷ ty.int] ty_memory_op_result := - let: tmp := call within_phys_mem paddr in - if: tmp - then (use lemma extract_pmp_ptsto [paddr] ;; - let: tmp := foreign write_ram paddr data in - use lemma return_pmp_ptsto [paddr] ;; - MemValue tmp) - else MemException E_SAMO_Access_Fault. - - Definition fun_pmp_mem_read : Stm [t∷ ty_access_type; p ∷ ty_privilege; paddr ∷ ty_xlenbits] ty_memory_op_result := - let: tmp := call pmpCheck paddr t p in - match: tmp with - | inl e => MemException e - | inr v => call checked_mem_read t paddr - end. - - Definition fun_pmp_mem_write : Stm [paddr ∷ ty_xlenbits; data ∷ ty.int; typ ∷ ty_access_type; priv ∷ ty_privilege] ty_memory_op_result := - let: tmp := call pmpCheck paddr typ priv in - match: tmp with - | inl e => MemException e - | inr v => call checked_mem_write paddr data - end. - - Definition fun_pmpLocked : Stm [cfg ∷ ty_pmpcfg_ent] ty.bool := - match: cfg in rpmpcfg_ent with [L; A; X; W; R] => L end. - - Definition fun_pmpWriteCfgReg : Stm [idx :: ty_pmpcfgidx; value :: ty_xlenbits] ty.unit := - match: idx in pmpcfgidx with - | PMP0CFG => let: tmp1 := stm_read_register pmp0cfg in - let: tmp2 := call pmpWriteCfg tmp1 value in - stm_write_register pmp0cfg tmp2 ;; - stm_val ty.unit tt - | PMP1CFG => let: tmp1 := stm_read_register pmp1cfg in - let: tmp2 := call pmpWriteCfg tmp1 value in - stm_write_register pmp1cfg tmp2 ;; - stm_val ty.unit tt - end. - - Definition fun_pmpWriteCfg : Stm [cfg :: ty_pmpcfg_ent; value :: ty_xlenbits] ty_pmpcfg_ent := - let: locked := call pmpLocked cfg in - if: locked then cfg else stm_pmpcfg_ent_from_bits value. - - Definition fun_pmpWriteAddr : Stm [locked :: ty.bool; addr :: ty_xlenbits; value :: ty_xlenbits] ty_xlenbits := - if: locked then addr else value. - - Definition fun_pmpCheck : Stm [addr ∷ ty_xlenbits; acc ∷ ty_access_type; priv ∷ ty_privilege] (ty.option ty_exception_type) := - use lemma open_pmp_entries ;; - let: check%string := - let: tmp1 := stm_read_register pmp0cfg in - let: tmp2 := stm_read_register pmpaddr0 in - let: tmp3 := z_exp 0 in - let: tmp := call pmpMatchEntry addr acc priv tmp1 tmp2 tmp3 in - match: tmp in pmpmatch with - | PMP_Success => stm_val ty.bool true - | PMP_Fail => stm_val ty.bool false - | PMP_Continue => - let: tmp1 := stm_read_register pmp1cfg in - let: tmp2 := stm_read_register pmpaddr1 in - let: tmp3 := stm_read_register pmpaddr0 in - let: tmp := call pmpMatchEntry addr acc priv tmp1 tmp2 tmp3 in - match: tmp in pmpmatch with - | PMP_Success => stm_val ty.bool true - | PMP_Fail => stm_val ty.bool false - | PMP_Continue => - match: priv in privilege with - | Machine => stm_val ty.bool true - | User => stm_val ty.bool false - end - end - end in - use lemma close_pmp_entries ;; - if: check - then None - else - match: acc in union access_type with - |> KRead pat_unit => Some E_Load_Access_Fault - |> KWrite pat_unit => Some E_SAMO_Access_Fault - |> KReadWrite pat_unit => Some E_SAMO_Access_Fault - |> KExecute pat_unit => Some E_Fetch_Access_Fault - end. - - Definition fun_pmpCheckPerms : Stm [ent ∷ ty_pmpcfg_ent; acc ∷ ty_access_type; priv ∷ ty_privilege] ty.bool := - match: priv in privilege with - | Machine => - let: tmp := call pmpLocked ent in - if: tmp - then call pmpCheckRWX ent acc - else stm_val ty.bool true - | User => - call pmpCheckRWX ent acc - end. - - Definition fun_pmpCheckRWX : Stm [ent ∷ ty_pmpcfg_ent; acc ∷ ty_access_type] ty.bool := - match: ent in rpmpcfg_ent with - [L; A; X; W; R] => - match: acc in union access_type with - |> KRead pat_unit => if: R then stm_val ty.bool true else stm_val ty.bool false - |> KWrite pat_unit => if: W then stm_val ty.bool true else stm_val ty.bool false - |> KReadWrite pat_unit => if: R && W then stm_val ty.bool true else stm_val ty.bool false - |> KExecute pat_unit => if: X then stm_val ty.bool true else stm_val ty.bool false - end - end. - - Definition fun_pmpMatchEntry : Stm [addr ∷ ty_xlenbits; acc ∷ ty_access_type; priv ∷ ty_privilege; ent ∷ ty_pmpcfg_ent; pmpaddr ∷ ty_xlenbits; prev_pmpaddr ∷ ty_xlenbits] ty_pmpmatch := - let: rng := call pmpAddrRange ent pmpaddr prev_pmpaddr in - let: tmp := call pmpMatchAddr addr rng in - match: tmp in pmpaddrmatch with - | PMP_NoMatch => exp_val ty_pmpmatch PMP_Continue - | PMP_PartialMatch => exp_val ty_pmpmatch PMP_Fail - | PMP_Match => - let: tmp := call pmpCheckPerms ent acc priv in - if: tmp - then exp_val ty_pmpmatch PMP_Success - else exp_val ty_pmpmatch PMP_Fail - end. - - Definition fun_pmpAddrRange : Stm [cfg ∷ ty_pmpcfg_ent; pmpaddr ∷ ty_xlenbits; prev_pmpaddr ∷ ty_xlenbits] ty_pmp_addr_range := - match: cfg in rpmpcfg_ent with - [L; A; X; W; R] => - match: A in pmpaddrmatchtype with - | OFF => None - | TOR => Some (exp_binop bop.pair prev_pmpaddr pmpaddr) - end - end. - - Definition fun_pmpMatchAddr : Stm [addr ∷ ty.int; rng ∷ ty_pmp_addr_range] ty_pmpaddrmatch := - match: rng with - | inl v => - match: v in (ty.int , ty.int) with - | (lo , hi) => - if: hi < lo - then exp_val ty_pmpaddrmatch PMP_NoMatch - else - if: (addr < lo) || (hi <= addr) (* NOTE: this only makes sense when using a "width" (see Sail impl), having this without the width means the PartialMatch case will never occur *) - then exp_val ty_pmpaddrmatch PMP_NoMatch - else if: (lo <= addr) && (addr < hi) (* NOTE: small difference with actual model due to lack of width, but more correct with respect to the manual (y matches TOR if pmpaddrᵢ₋₁ <= y < pmpaddrᵢ) *) - then exp_val ty_pmpaddrmatch PMP_Match - else exp_val ty_pmpaddrmatch PMP_PartialMatch - end - | inr v => exp_val ty_pmpaddrmatch PMP_NoMatch - end. - - Definition fun_process_load : Stm [rd ∷ ty_regno; vaddr ∷ ty_xlenbits; value ∷ ty_memory_op_result] ty_retired := - match: value in union memory_op_result with - |> KMemValue (pat_var "result") => call wX rd result;; - stm_val ty_retired RETIRE_SUCCESS - |> KMemException (pat_var "e") => call handle_mem_exception vaddr e;; - stm_val ty_retired RETIRE_FAIL - end. - - Definition fun_mem_write_value : Stm [paddr ∷ ty_xlenbits; value ∷ ty.int] ty_memory_op_result := - let: tmp := stm_read_register cur_privilege in - call pmp_mem_write paddr value Write tmp. - - Definition fun_main : Stm ctx.nil ty.unit := - call init_model ;; - call loop. - - (* NOTE: simplified init_model function, just calls init_sys which just calls - init_pmp *) - Definition fun_init_model : Stm ctx.nil ty.unit := - call init_sys. - - (* TODO: specify contract for loop in the Iris Model *) - (* TODO: (Katamaran-based solution, but stuck on ▹)introduce missing Iris stuff as abstract predicates (▹, wp loop ⊤) *) - Definition fun_loop : Stm ctx.nil ty.unit := - call step ;; call loop. - - Definition fun_fetch : Stm ctx.nil ty_fetch_result := - let: tmp1 := stm_read_register pc in - let: tmp2 := call mem_read Execute tmp1 in - match: tmp2 in union memory_op_result with - |> KMemValue (pat_var "result") => F_Base result - |> KMemException (pat_var "e") => F_Error e tmp1 - end. - - (* TODO: Define contract for step, with addition of pc ↦ ... *) - Definition fun_step : Stm ctx.nil ty.unit := - let: f := call fetch in - match: f in union fetch_result with - |> KF_Base (pat_var "w") => let: "ast" := foreign decode w in - let: tmp := stm_read_register pc in - stm_write_register nextpc (tmp + (z_exp 4)) ;; - call execute (exp_var "ast") - |> KF_Error (pat_pair "e" "addr") => call handle_mem_exception addr e ;; - stm_val ty_retired RETIRE_FAIL - end ;; - call tick_pc. - - Definition fun_init_sys : Stm ctx.nil ty.unit := - stm_write_register cur_privilege (exp_val ty_privilege Machine) ;; - use lemma open_pmp_entries ;; - call init_pmp ;; - use lemma update_pmp_entries. - - Definition fun_init_pmp : Stm ctx.nil ty.unit := - let: tmp := stm_read_register pmp0cfg in - match: tmp in rpmpcfg_ent with - ["L"; "A"; "X"; "W"; "R"] => - stm_write_register - pmp0cfg (exp_record rpmpcfg_ent - [nenv L; - exp_val ty_pmpaddrmatchtype OFF; - X; - W; - R ]) ;; - stm_val ty.unit tt - end ;; - let: tmp := stm_read_register pmp1cfg in - match: tmp in rpmpcfg_ent with - ["L"; "A"; "X"; "W"; "R"] => - stm_write_register - pmp1cfg (exp_record rpmpcfg_ent - [nenv L; - exp_val ty_pmpaddrmatchtype OFF; - X; - W; - R ]) ;; - stm_val ty.unit tt - end. - - Definition fun_exceptionType_to_bits : Stm [e ∷ ty_exception_type] ty_exc_code := - match: e in union exception_type with - |> KE_Fetch_Access_Fault pat_unit => stm_val ty_exc_code 1%Z - |> KE_Illegal_Instr pat_unit => stm_val ty_exc_code 2%Z - |> KE_Load_Access_Fault pat_unit => stm_val ty_exc_code 5%Z - |> KE_SAMO_Access_Fault pat_unit => stm_val ty_exc_code 7%Z - |> KE_U_EnvCall pat_unit => stm_val ty_exc_code 8%Z - |> KE_M_EnvCall pat_unit => stm_val ty_exc_code 11%Z - end. - - Definition fun_handle_mem_exception : Stm [addr ∷ ty_xlenbits; e ∷ ty_exception_type] ty.unit := - let: tmp1 := stm_read_register pc in - let: tmp2 := stm_read_register cur_privilege in - let: tmp3 := call exception_handler tmp2 (CTL_TRAP e) tmp1 in - call set_next_pc tmp3. - - Definition fun_exception_handler : Stm [cur_priv ∷ ty_privilege; ctl ∷ ty_ctl_result; "pc" ∷ ty_xlenbits] ty_xlenbits := - match: ctl in union ctl_result with - |> KCTL_TRAP (pat_var "e") => let: del_priv := call exception_delegatee cur_priv in - let: tmp := call exceptionType_to_bits e in - call trap_handler del_priv tmp (exp_var "pc") - |> KCTL_MRET pat_unit => - (* NOTE: normally the return address is computed with: - prepare_xret_target(Machine) & pc_alignment_mask() - we drop the alignment mask and inline prepare_xret_target, - which just calls get_xret_target, which returns (for M-mode) - the value of mepc *) - let: tmp1 := stm_read_register mstatus in - (stm_match_record rmstatus tmp1 - (recordpat_snoc recordpat_nil "MPP" MPP%string) - (stm_write_register cur_privilege MPP ;; - stm_write_register mstatus (exp_record rmstatus [ exp_val ty_privilege User ]) ;; - stm_read_register mepc)) - end. - - Definition fun_exception_delegatee : Stm [p ∷ ty_privilege] ty_privilege := - stm_val ty_privilege Machine. - - Definition fun_trap_handler : Stm [del_priv ∷ ty_privilege; c ∷ ty_exc_code; "pc" ∷ ty_xlenbits] ty_xlenbits := - stm_write_register mcause c ;; - let: tmp := stm_read_register cur_privilege in - stm_write_register mstatus (exp_record rmstatus [ tmp ]) ;; - stm_write_register mepc (exp_var "pc") ;; - stm_write_register cur_privilege del_priv ;; - (* NOTE: the following let can be dropped by just reusing c (the value we are - writing into mcause, but this (manual) translation is more faithful to - what I expect an automatic translation would produce, i.e. do an - stm_read_register when a register is used as param to a function call, - to get the value in the register - - Also keep into account that the risc-v model trap handler function handles - more cases than represented here, i.e. we only have support for M-mode and - do not explicitly check for this here. So we could simplify - prepare_trap_vector to not take a cause parameter (which it won't use - anyway because we only support direct mode for the trap vector, meaning - that the trap handler function installed at the memory address denoted - by mtvec will need to read the mcause register to dispatch to the - corresponding trap handler for the cause). *) - let: tmp := stm_read_register mcause in - call prepare_trap_vector del_priv tmp. - - Definition fun_prepare_trap_vector : Stm [p ∷ ty_privilege; cause ∷ ty_mcause] ty_xlenbits := - let: tvec := match: p in privilege with - | Machine => stm_read_register mtvec - | User => fail "N extension (user-level interrupts) not supported" - end in - let: tmp := call tvec_addr tvec cause in - (* NOTE: tvec_addr will only ever return Some(epc), because we don't support - the 2 mode bits and only have direct mode. The None case only arises - for the Reserved mode of trap vectors. - - The given privilege level (p) is ignored, this only makes sense when - supervisor mode is supported. *) - match: tmp with - | inl epc => epc - | inr e => fail "Invalid tvec mode" - end. - - Definition fun_tvec_addr : Stm [m ∷ ty_xlenbits; c ∷ ty_mcause] (ty.option ty_xlenbits) := - Some m. - - Definition fun_handle_illegal : Stm ctx.nil ty.unit := - let: t := E_Illegal_Instr in - let: tmp1 := stm_read_register cur_privilege in - let: tmp2 := stm_read_register pc in - let: tmp3 := call exception_handler tmp1 (CTL_TRAP t) tmp2 in - call set_next_pc tmp3. - - Definition fun_check_CSR : Stm [csr ∷ ty_csridx; p ∷ ty_privilege] ty.bool := - let: tmp1 := call is_CSR_defined csr p in - let: tmp2 := call csrAccess csr in - let: tmp3 := call csrPriv csr in - let: tmp := call check_CSR_access tmp2 tmp3 p in - tmp1 && tmp. - - Definition fun_is_CSR_defined : Stm [csr ∷ ty_csridx; p ∷ ty_privilege] ty.bool := - match: csr in csridx with - | MStatus => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - | MTvec => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - | MCause => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - | MEpc => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - | MPMP0CFG => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - | MPMP1CFG => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - | MPMPADDR0 => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - | MPMPADDR1 => match: p in privilege with - | Machine => stm_val ty.bool true - | _ => stm_val ty.bool false - end - end. - - (* NOTE: - normally this information is part of the CSR bitpattern, - we are reusing our existing access_type - - all CSRs we currently support are MRW (= Machine, ReadWrite) *) - Definition fun_csrAccess : Stm [csr ∷ ty_csridx] ty_access_type := - ReadWrite. - Definition fun_csrPriv : Stm [csr ∷ ty_csridx] ty_privilege := - stm_val ty_privilege Machine. - - Definition fun_check_CSR_access : Stm [csrrw ∷ ty_access_type; csrpr ∷ ty_privilege; p ∷ ty_privilege] ty.bool := - let: tmp1 := call privLevel_to_bits csrpr in - let: tmp2 := call privLevel_to_bits p in - tmp1 <= tmp2. - - Definition fun_privLevel_to_bits : Stm [p ∷ ty_privilege] ty_xlenbits := - match: p in privilege with - | Machine => stm_val ty.int 3%Z - | User => stm_val ty.int 0%Z - end. - - Definition fun_readCSR : Stm [csr ∷ ty_csridx] ty_xlenbits := - match: csr in csridx with - | MStatus => stm_mstatus_to_bits (stm_read_register mstatus) - | MTvec => stm_read_register mtvec - | MCause => stm_read_register mcause - | MEpc => stm_read_register mepc - | MPMP0CFG => stm_pmpcfg_ent_to_bits (stm_read_register pmp0cfg) - | MPMP1CFG => stm_pmpcfg_ent_to_bits (stm_read_register pmp1cfg) - | MPMPADDR0 => stm_read_register pmpaddr0 - | MPMPADDR1 => stm_read_register pmpaddr1 - end. - - Definition fun_writeCSR : Stm [csr ∷ ty_csridx; value ∷ ty_xlenbits] ty.unit := - match: csr in csridx with - | MStatus => let: tmp := stm_mstatus_from_bits value in - stm_write_register mstatus tmp ;; - stm_val ty.unit tt - | MTvec => stm_write_register mtvec value ;; - stm_val ty.unit tt - | MCause => stm_write_register mcause value ;; - stm_val ty.unit tt - | MEpc => stm_write_register mepc value ;; - stm_val ty.unit tt - | MPMP0CFG => call pmpWriteCfgReg (exp_val ty_pmpcfgidx PMP0CFG) value - | MPMP1CFG => call pmpWriteCfgReg (exp_val ty_pmpcfgidx PMP1CFG) value - | MPMPADDR0 => let: tmp1 := stm_read_register pmp0cfg in - let: tmp1 := call pmpLocked tmp1 in - let: tmp2 := stm_read_register pmpaddr0 in - let: tmp := call pmpWriteAddr tmp1 tmp2 value in - stm_write_register pmpaddr0 tmp ;; - stm_val ty.unit tt - | MPMPADDR1 => let: tmp1 := stm_read_register pmp1cfg in - let: tmp1 := call pmpLocked tmp1 in - let: tmp2 := stm_read_register pmpaddr1 in - let: tmp := call pmpWriteAddr tmp1 tmp2 value in - stm_write_register pmpaddr1 value ;; - stm_val ty.unit tt - end. - - (* NOTE: normally the definitions of execute_X are inlined and defined as - function clauses of execute (a scattered definition) *) - Definition fun_execute : Stm ["ast" ∷ ty_ast] ty_retired := - match: exp_var "ast" in union ast with - |> KRTYPE (pat_tuple (rs2 , rs1 , rd , op)) => call execute_RTYPE rs2 rs1 rd op - |> KITYPE (pat_tuple (imm , rs1 , rd , op)) => call execute_ITYPE imm rs1 rd op - |> KUTYPE (pat_tuple (imm , rd , op)) => call execute_UTYPE imm rd op - |> KBTYPE (pat_tuple (imm , rs2, rs1 , op)) => call execute_BTYPE imm rs2 rs1 op - |> KRISCV_JAL (pat_tuple (imm , rd)) => call execute_RISCV_JAL imm rd - |> KRISCV_JALR (pat_tuple (imm , rs1 , rd)) => call execute_RISCV_JALR imm rs1 rd - |> KLOAD (pat_tuple (imm , rs1, rd)) => call execute_LOAD imm rs1 rd - |> KSTORE (pat_tuple (imm , rs2 , rs1)) => call execute_STORE imm rs2 rs1 - |> KECALL pat_unit => call execute_ECALL - |> KMRET pat_unit => call execute_MRET - |> KCSR (pat_tuple (csr , rs1 , rd , op)) => call execute_CSR csr rs1 rd op - end. - - Definition fun_execute_RTYPE : Stm [rs2 ∷ ty_regno; rs1 ∷ ty_regno; rd ∷ ty_regno; op ∷ ty_rop] ty_retired := - let: rs1_val := call rX rs1 in - let: rs2_val := call rX rs2 in - let: result := - match: op in rop with - | RISCV_ADD => rs1_val + rs2_val - | RISCV_SUB => rs1_val - rs2_val - end in - call wX rd result ;; - stm_val ty_retired RETIRE_SUCCESS. - - Definition fun_execute_ITYPE : Stm [imm ∷ ty.int; rs1 ∷ ty_regno; rd ∷ ty_regno; op ∷ ty_iop] ty_retired := - let: rs1_val := call rX rs1 in - let: immext := imm in - let: result := - match: op in iop with - | RISCV_ADDI => rs1_val + immext - end in - call wX rd result ;; - stm_val ty_retired RETIRE_SUCCESS. - - Definition fun_execute_UTYPE : Stm [imm ∷ ty.int; rd ∷ ty_regno; op ∷ ty_uop] ty_retired := - let: off := imm in - let: ret := - match: op in uop with - | RISCV_LUI => off - | RISCV_AUIPC => - let: tmp := call get_arch_pc in - tmp + off - end in - call wX rd ret ;; - stm_val ty_retired RETIRE_SUCCESS. - - Definition fun_execute_RISCV_JAL : Stm [imm ∷ ty.int; rd ∷ ty_regno] ty_retired := - let: tmp := stm_read_register pc in - let: t := tmp + imm in - let: tmp := call get_next_pc in - call wX rd tmp ;; - call set_next_pc t ;; - stm_val ty_retired RETIRE_SUCCESS. - - Definition fun_execute_RISCV_JALR : Stm [imm ∷ ty.int ; rs1 ∷ ty_regno; rd ∷ ty_regno] ty_retired := - let: tmp := call rX rs1 in - let: t := tmp + imm in - let: tmp := call get_next_pc in - call wX rd tmp ;; - call set_next_pc t ;; - stm_val ty_retired RETIRE_SUCCESS. - - Definition fun_execute_BTYPE : Stm [imm ∷ ty.int; rs2 ∷ ty_regno; rs1 ∷ ty_regno; op ∷ ty_bop] ty_retired := - let: rs1_val := call rX rs1 in - let: rs2_val := call rX rs2 in - let: taken := - match: op in bop with - | RISCV_BEQ => rs1_val = rs2_val - | RISCV_BNE => exp_not (rs1_val = rs2_val) - | RISCV_BLT => rs1_val < rs2_val - | RISCV_BGE => rs2_val <= rs1_val - | RISCV_BLTU => - let: tmp1 := call abs rs1_val in - let: tmp2 := call abs rs2_val in - tmp1 < tmp2 - | RISCV_BGEU => - let: tmp1 := call abs rs1_val in - let: tmp2 := call abs rs2_val in - tmp2 <= tmp1 - end in - let: tmp := stm_read_register pc in - let: t := tmp + imm in - if: taken - then - call set_next_pc t ;; - stm_val ty_retired RETIRE_SUCCESS - else - stm_val ty_retired RETIRE_SUCCESS. - - Definition fun_execute_LOAD : Stm [imm ∷ ty.int; rs1 ∷ ty_regno; rd ∷ ty_regno] ty_retired := - let: offset := imm in - let: tmp := call rX rs1 in - let: paddr := tmp + offset in - let: tmp := call mem_read Read paddr in - call process_load rd paddr tmp ;; - stm_val ty_retired RETIRE_SUCCESS. - - Definition fun_execute_STORE : Stm [imm ∷ ty.int; rs2 ∷ ty_regno; rs1 ∷ ty_regno] ty_retired := - let: offset := imm in - let: tmp := call rX rs1 in - let: paddr := tmp + offset in - let: rs2_val := call rX rs2 in - let: res := call mem_write_value paddr rs2_val in - match: res in union memory_op_result with - |> KMemValue (pat_var "v") => if: v = z_exp 1 - then stm_val ty_retired RETIRE_SUCCESS - else fail "store got false from write_mem_value" - |> KMemException (pat_var "e") => call handle_mem_exception paddr e ;; - stm_val ty_retired RETIRE_FAIL - end. - - Definition fun_execute_ECALL : Stm ctx.nil ty_retired := - let: tmp1 := stm_read_register cur_privilege in - let: t := match: tmp1 in privilege with - | Machine => E_M_EnvCall - | User => E_U_EnvCall - end in - let: tmp2 := stm_read_register pc in - let: tmp3 := call exception_handler tmp1 (CTL_TRAP t) tmp2 in - call set_next_pc tmp3 ;; - stm_val ty_retired RETIRE_FAIL. - - Definition fun_execute_MRET : Stm ctx.nil ty_retired := - let: tmp1 := stm_read_register cur_privilege in - match: tmp1 in privilege with - | Machine => - let: tmp2 := stm_read_register pc in - let: tmp3 := call exception_handler tmp1 CTL_MRET tmp2 in - call set_next_pc tmp3 ;; - stm_val ty_retired RETIRE_SUCCESS - | User => - call handle_illegal ;; - stm_val ty_retired RETIRE_FAIL - end. - - Definition fun_execute_CSR : Stm [csr ∷ ty_csridx; rs1 ∷ ty_regno; rd ∷ ty_regno; op ∷ ty_csrop] ty_retired := - let: rs1_val := call rX rs1 in - let: tmp1 := stm_read_register cur_privilege in - let: tmp2 := call check_CSR csr tmp1 in - if: tmp2 (* then and else branch switched, Sail model uses a not here *) - then - (use lemma open_pmp_entries ;; - let: csr_val := call readCSR csr in - call writeCSR csr rs1_val ;; - use lemma update_pmp_entries ;; - call wX rd csr_val ;; - stm_val ty_retired RETIRE_SUCCESS) - else (call handle_illegal ;; - stm_val ty_retired RETIRE_FAIL). - - End FunDefKit. - - Include DefaultRegStoreKit RiscvPmpBase. - - Section ForeignKit. - (* Memory *) - Definition Memory := Addr -> Word. - - Definition fun_read_ram (μ : Memory) (addr : Val ty.int) : Val ty_word := - μ addr. - - Definition fun_write_ram (μ : Memory) (addr : Val ty.int) (data : Val ty_word) : Memory := - fun addr' => if Z.eqb addr addr' then data else μ addr'. - - #[derive(equations=no)] - Equations ForeignCall {σs σ} (f : 𝑭𝑿 σs σ) (args : NamedEnv Val σs) (res : string + Val σ) (γ γ' : RegStore) (μ μ' : Memory) : Prop := - ForeignCall read_ram (env.snoc env.nil _ addr) res γ γ' μ μ' := - (γ' , μ' , res) = (γ , μ , inr (fun_read_ram μ addr)); - ForeignCall write_ram (env.snoc (env.snoc env.nil _ addr) _ data) res γ γ' μ μ' := - (γ' , μ' , res) = (γ , fun_write_ram μ addr data , inr 1%Z); - ForeignCall decode (env.snoc env.nil _ code) res γ γ' μ μ' := - (γ' , μ' , res) = (γ , μ , pure_decode code). - - Import bv.notations. - Lemma ForeignProgress {σs σ} (f : 𝑭𝑿 σs σ) (args : NamedEnv Val σs) γ μ : - exists γ' μ' res, ForeignCall f args res γ γ' μ μ'. - Proof. - destruct f; cbn. - - repeat depelim args; repeat eexists; constructor. - - repeat depelim args; repeat eexists; constructor. - - repeat depelim args. - exists γ, μ. eexists. reflexivity. - Qed. - End ForeignKit. - - Definition FunDef {Δ τ} (f : Fun Δ τ) : Stm Δ τ := - match f with - | rX => fun_rX - | wX => fun_wX - | get_arch_pc => fun_get_arch_pc - | get_next_pc => fun_get_next_pc - | set_next_pc => fun_set_next_pc - | tick_pc => fun_tick_pc - | abs => fun_abs - | within_phys_mem => fun_within_phys_mem - | mem_read => fun_mem_read - | mem_write_value => fun_mem_write_value - | checked_mem_read => fun_checked_mem_read - | checked_mem_write => fun_checked_mem_write - | pmp_mem_read => fun_pmp_mem_read - | pmp_mem_write => fun_pmp_mem_write - | pmpLocked => fun_pmpLocked - | pmpWriteCfgReg => fun_pmpWriteCfgReg - | pmpWriteCfg => fun_pmpWriteCfg - | pmpWriteAddr => fun_pmpWriteAddr - | pmpCheck => fun_pmpCheck - | pmpCheckPerms => fun_pmpCheckPerms - | pmpCheckRWX => fun_pmpCheckRWX - | pmpMatchEntry => fun_pmpMatchEntry - | pmpAddrRange => fun_pmpAddrRange - | pmpMatchAddr => fun_pmpMatchAddr - | process_load => fun_process_load - | exceptionType_to_bits => fun_exceptionType_to_bits - | privLevel_to_bits => fun_privLevel_to_bits - | main => fun_main - | init_model => fun_init_model - | init_sys => fun_init_sys - | init_pmp => fun_init_pmp - | loop => fun_loop - | step => fun_step - | fetch => fun_fetch - | handle_mem_exception => fun_handle_mem_exception - | exception_handler => fun_exception_handler - | exception_delegatee => fun_exception_delegatee - | trap_handler => fun_trap_handler - | prepare_trap_vector => fun_prepare_trap_vector - | tvec_addr => fun_tvec_addr - | handle_illegal => fun_handle_illegal - | check_CSR => fun_check_CSR - | is_CSR_defined => fun_is_CSR_defined - | csrAccess => fun_csrAccess - | csrPriv => fun_csrPriv - | check_CSR_access => fun_check_CSR_access - | readCSR => fun_readCSR - | writeCSR => fun_writeCSR - | execute => fun_execute - | execute_RTYPE => fun_execute_RTYPE - | execute_ITYPE => fun_execute_ITYPE - | execute_UTYPE => fun_execute_UTYPE - | execute_BTYPE => fun_execute_BTYPE - | execute_RISCV_JAL => fun_execute_RISCV_JAL - | execute_RISCV_JALR => fun_execute_RISCV_JALR - | execute_LOAD => fun_execute_LOAD - | execute_STORE => fun_execute_STORE - | execute_ECALL => fun_execute_ECALL - | execute_MRET => fun_execute_MRET - | execute_CSR => fun_execute_CSR - end. - - Include ProgramMixin RiscvPmpBase. - -End RiscvPmpProgram. diff --git a/case_study/RiscvPmp/Model.v b/case_study/RiscvPmp/Model.v deleted file mode 100644 index 0119d9a1..00000000 --- a/case_study/RiscvPmp/Model.v +++ /dev/null @@ -1,533 +0,0 @@ -(******************************************************************************) -(* Copyright (c) 2020 Steven Keuchel, Dominique Devriese, Sander Huyghebaert *) -(* All rights reserved. *) -(* *) -(* Redistribution and use in source and binary forms, with or without *) -(* modification, are permitted provided that the following conditions are *) -(* met: *) -(* *) -(* 1. Redistributions of source code must retain the above copyright notice, *) -(* this list of conditions and the following disclaimer. *) -(* *) -(* 2. Redistributions in binary form must reproduce the above copyright *) -(* notice, this list of conditions and the following disclaimer in the *) -(* documentation and/or other materials provided with the distribution. *) -(* *) -(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) -(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) -(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *) -(* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR *) -(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *) -(* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *) -(* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *) -(* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *) -(* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *) -(* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *) -(* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) -(******************************************************************************) - -From Coq Require Import - Program.Tactics - Lists.List. -From Katamaran Require Import - Bitvector - Environment - Iris.Logic - Iris.Model - Program - Semantics - Sep.Hoare - Sep.Logic - Specification - RiscvPmp.Machine - RiscvPmp.Contracts. -From Equations Require Import - Equations. - -From iris.base_logic Require lib.gen_heap lib.iprop. -From iris.base_logic Require Export invariants. -From iris.bi Require interface big_op. -From iris.algebra Require dfrac. -From iris.program_logic Require Import weakestpre adequacy. -From iris.proofmode Require Import string_ident tactics. - -Set Implicit Arguments. -Import ListNotations. - -Module gh := iris.base_logic.lib.gen_heap. - -Module RiscvPmpSemantics <: Semantics RiscvPmpBase RiscvPmpProgram := - MakeSemantics RiscvPmpBase RiscvPmpProgram. - -Import RiscvPmpProgram. -Import RiscvPmpSignature. - -Ltac destruct_syminstance ι := - repeat - match type of ι with - | Env _ (ctx.snoc _ (MkB ?s _)) => - let id := string_to_ident s in - let fr := fresh id in - destruct (env.snocView ι) as [ι fr]; - destruct_syminstance ι - | Env _ ctx.nil => destruct (env.nilView ι) - | _ => idtac - end. - -Module Import RiscvPmpIrisBase <: IrisBase RiscvPmpBase RiscvPmpProgram RiscvPmpSemantics. - Include IrisPrelims RiscvPmpBase RiscvPmpProgram RiscvPmpSemantics. - - Section RiscvPmpIrisParams. - Import iris.bi.interface. - Import iris.bi.big_op. - Import iris.base_logic.lib.iprop. - Import iris.base_logic.lib.gen_heap. - - Definition MemVal : Set := Word. - - Class mcMemGS Σ := - McMemGS { - (* ghost variable for tracking state of registers *) - mc_ghGS : gh.gen_heapGS Addr MemVal Σ - }. - #[export] Existing Instance mc_ghGS. - - Definition memGpreS : gFunctors -> Set := fun Σ => gh.gen_heapGpreS Z MemVal Σ. - Definition memGS : gFunctors -> Set := mcMemGS. - Definition memΣ : gFunctors := gh.gen_heapΣ Addr MemVal. - - Definition liveAddrs := seqZ minAddr (maxAddr - minAddr + 1). - Definition initMemMap μ := (list_to_map (map (fun a => (a , μ a)) liveAddrs) : gmap Addr MemVal). - - Definition memΣ_GpreS : forall {Σ}, subG memΣ Σ -> memGpreS Σ := - fun {Σ} => gh.subG_gen_heapGpreS (Σ := Σ) (L := Addr) (V := MemVal). - - Definition mem_inv : forall {Σ}, mcMemGS Σ -> Memory -> iProp Σ := - fun {Σ} hG μ => - (∃ memmap, gen_heap_interp memmap ∗ - ⌜ map_Forall (fun a v => μ a = v) memmap ⌝ - )%I. - - Definition mem_res : forall {Σ}, mcMemGS Σ -> Memory -> iProp Σ := - fun {Σ} hG μ => - ([∗ map] l↦v ∈ initMemMap μ, mapsto l (DfracOwn 1) v) %I. - - Lemma initMemMap_works μ : map_Forall (λ (a : Addr) (v : MemVal), μ a = v) (initMemMap μ). - Proof. - unfold initMemMap. - rewrite map_Forall_to_list. - rewrite Forall_forall. - intros (a , v). - rewrite elem_of_map_to_list. - intros el. - apply elem_of_list_to_map_2 in el. - apply elem_of_list_In in el. - apply in_map_iff in el. - by destruct el as (a' & <- & _). - Qed. - - Lemma mem_inv_init : forall Σ (μ : Memory), memGpreS Σ -> - ⊢ |==> ∃ mG : mcMemGS Σ, (mem_inv mG μ ∗ mem_res mG μ)%I. - Proof. - iIntros (Σ μ gHP). - - iMod (gen_heap_init (gen_heapGpreS0 := gHP) (L := Addr) (V := MemVal) empty) as (gH) "[inv _]". - - pose (memmap := initMemMap μ). - iMod (gen_heap_alloc_big empty memmap (map_disjoint_empty_r memmap) with "inv") as "(inv & res & _)". - iModIntro. - - rewrite (right_id empty union memmap). - - iExists (McMemGS gH). - iFrame. - iExists memmap. - iFrame. - iPureIntro. - apply initMemMap_works. - Qed. - End RiscvPmpIrisParams. - - Include IrisResources RiscvPmpBase RiscvPmpProgram RiscvPmpSemantics. - -End RiscvPmpIrisBase. - -Module Import RiscvPmpIrisInstance <: - IrisInstance RiscvPmpBase RiscvPmpProgram RiscvPmpSemantics - RiscvPmpSignature RiscvPmpIrisBase. - - Section WithSailGS. - Import iris.bi.interface. - Import iris.bi.big_op. - Import iris.base_logic.lib.iprop. - Import iris.base_logic.lib.gen_heap. - Import Contracts. - - Context `{sailRegGS Σ} `{invGS Σ} `{mG : mcMemGS Σ}. - - Definition reg_file : gset (bv 3) := list_to_set (finite.enum (bv 3)). - - Definition interp_ptsreg `{sailRegGS Σ} (r : RegIdx) (v : Z) : iProp Σ := - match reg_convert r with - | Some x => reg_pointsTo x v - | None => True - end. - - Definition interp_gprs : iProp Σ := - [∗ set] r ∈ reg_file, (∃ v, interp_ptsreg r v)%I. - - Definition PmpEntryCfg : Set := Pmpcfg_ent * Xlenbits. - - Definition interp_pmp_entries (entries : list PmpEntryCfg) : iProp Σ := - match entries with - | (cfg0, addr0) :: (cfg1, addr1) :: [] => - reg_pointsTo pmp0cfg cfg0 ∗ - reg_pointsTo pmpaddr0 addr0 ∗ - reg_pointsTo pmp1cfg cfg1 ∗ - reg_pointsTo pmpaddr1 addr1 - | _ => False - end. - - Definition interp_ptsto (addr : Addr) (w : Word) : iProp Σ := - mapsto addr (DfracOwn 1) w. - Definition ptstoSth : Addr -> iProp Σ := fun a => (∃ w, interp_ptsto a w)%I. - Definition ptstoSthL : list Addr -> iProp Σ := - fun addrs => ([∗ list] k↦a ∈ addrs, ptstoSth a)%I. - Lemma ptstoSthL_app {l1 l2} : (ptstoSthL (l1 ++ l2) ⊣⊢ ptstoSthL l1 ∗ ptstoSthL l2)%I. - Proof. eapply big_sepL_app. Qed. - - Definition interp_pmp_addr_access (addrs : list Addr) (entries : list PmpEntryCfg) (m : Privilege) : iProp Σ := - [∗ list] a ∈ addrs, - (⌜∃ p, Pmp_access a entries m p⌝ -∗ ptstoSth a)%I. - - Definition interp_pmp_addr_access_without (addr : Addr) (addrs : list Addr) (entries : list PmpEntryCfg) (m : Privilege) : iProp Σ := - (ptstoSth addr -∗ interp_pmp_addr_access addrs entries m)%I. - - Definition interp_ptsto_instr (addr : Z) (instr : AST) : iProp Σ := - (∃ v, interp_ptsto addr v ∗ ⌜ pure_decode v = inr instr ⌝)%I. - - End WithSailGS. - - Section RiscvPmpIrisPredicates. - - Definition luser_inst `{sailRegGS Σ, invGS Σ, mcMemGS Σ} (p : Predicate) : Env Val (𝑯_Ty p) -> iProp Σ := - match p return Env Val (𝑯_Ty p) -> iProp Σ with - | Contracts.pmp_entries => fun ts => interp_pmp_entries (env.head ts) - | pmp_addr_access => fun ts => interp_pmp_addr_access liveAddrs (env.head (env.tail ts)) (env.head ts) - | pmp_addr_access_without => fun ts => interp_pmp_addr_access_without (env.head (env.tail (env.tail ts))) liveAddrs (env.head (env.tail ts)) (env.head ts) - | gprs => fun _ => interp_gprs - | ptsto => fun ts => interp_ptsto (env.head (env.tail ts)) (env.head ts) - | encodes_instr => fun _ => True%I - | ptstomem => fun _ => True%I - | ptstoinstr => fun ts => interp_ptsto_instr (env.head (env.tail ts)) (env.head ts)%I - end. - - Definition lduplicate_inst `{sailRegGS Σ, invGS Σ, mcMemGS Σ} : - forall (p : Predicate) (ts : Env Val (𝑯_Ty p)), - is_duplicable p = true -> - (luser_inst p ts) ⊢ (luser_inst p ts ∗ luser_inst p ts). - Proof. - iIntros (p ts hdup) "H". - destruct p; inversion hdup; - iDestruct "H" as "#H"; - auto. - Qed. - - End RiscvPmpIrisPredicates. - - Include IrisSignatureRules RiscvPmpBase RiscvPmpProgram RiscvPmpSemantics - RiscvPmpSignature RiscvPmpIrisBase. - -End RiscvPmpIrisInstance. - -Module RiscvPmpModel2. - Import RiscvPmpSignature. - Import RiscvPmpSpecification. - Import RiscvPmpProgram. - - Include ProgramLogicOn RiscvPmpBase RiscvPmpProgram RiscvPmpSignature RiscvPmpSpecification. - Include IrisInstanceWithContracts RiscvPmpBase RiscvPmpProgram RiscvPmpSemantics - RiscvPmpSignature RiscvPmpSpecification RiscvPmpIrisBase RiscvPmpIrisInstance. - - Lemma read_ram_sound `{sg : sailGS Σ} `{invGS} {Γ es δ} : - forall paddr w t entries p, - evals es δ = env.snoc env.nil ("paddr"∷ty_exc_code) paddr - → ⊢ semTriple δ - ((⌜Sub_perm Read t⌝ ∧ emp) ∗ reg_pointsTo cur_privilege p ∗ - interp_pmp_entries entries ∗ - (⌜Pmp_access paddr entries p t⌝ ∧ emp) ∗ interp_ptsto paddr w) - (stm_foreign read_ram es) - (λ (v : Z) (δ' : CStore Γ), - ((⌜v = w⌝ ∧ emp) ∗ reg_pointsTo cur_privilege p ∗ - interp_ptsto paddr w ∗ - interp_pmp_entries entries) ∗ ⌜δ' = δ⌝). - Proof. - iIntros (paddr w t entries p Heq) "((%Hperm & _) & Hcp & Hes & (%Hpmp & _) & H)". - rewrite wp_unfold. - cbn. - iIntros (? ? ? ? ?) "[Hregs [% (Hmem & %Hmap)]]". - iMod (fupd_mask_subseteq empty) as "Hclose"; first set_solver. - iModIntro. - iSplitR; first auto. - iIntros. - iModIntro. - iModIntro. - iModIntro. - dependent elimination H0. - dependent elimination s. - rewrite Heq in f1. - cbn in f1. - dependent elimination f1. - cbn. - iMod "Hclose" as "_". - iModIntro. - cbn. - iAssert (⌜ memmap !! paddr = Some w ⌝)%I with "[H Hmem]" as "%". - { iApply (gen_heap.gen_heap_valid with "Hmem H"). } - iSplitL "Hregs Hmem". - iSplitL "Hregs"; first iFrame. - iExists memmap; iFrame. - iPureIntro; assumption. - iSplitL; [|auto]. - iApply wp_value; cbn. - iSplitL; [|auto]. - iSplitR. - apply map_Forall_lookup_1 with (i := paddr) (x := w) in Hmap; auto. - iFrame. - Qed. - - - Lemma write_ram_sound `{sg : sailGS Σ} `{HGS: invGS} {Γ es δ} : - forall paddr data t entries p, - evals es δ = - env.snoc (env.snoc env.nil ("paddr"∷ty_exc_code) paddr) ("data"∷ty_exc_code) data - → ⊢ semTriple δ - ((⌜Sub_perm Write t⌝ ∧ emp) ∗ reg_pointsTo cur_privilege p ∗ - interp_pmp_entries entries ∗ - (⌜Pmp_access paddr entries p t⌝ ∧ emp) ∗ - (∃ v : Z, interp_ptsto paddr v)) (stm_foreign write_ram es) - (λ (_ : Z) (δ' : CStore Γ), - (reg_pointsTo cur_privilege p ∗ interp_ptsto paddr data ∗ - interp_pmp_entries entries) ∗ ⌜δ' = δ⌝). - Proof. - iIntros (paddr data t entries p Heq) "((%Hperm & _) & Hcp & Hes & (%Hpmp & _) & H)". - rewrite wp_unfold. - cbn. - iIntros (? ? ? ? ?) "[Hregs [% (Hmem & %Hmap)]]". - iMod (fupd_mask_subseteq empty) as "Hclose"; first set_solver. - iModIntro. - iSplitR; first auto. - iIntros. - iModIntro. - iModIntro. - iModIntro. - dependent elimination H. - dependent elimination s. - rewrite Heq in f1. - cbn in f1. - dependent elimination f1. - cbn. - iDestruct "H" as "(%w & H)". - iMod (gen_heap.gen_heap_update _ _ _ data with "Hmem H") as "[Hmem H]". - iMod "Hclose" as "_". - iModIntro. - cbn. - iSplitL "Hregs Hmem". - - iSplitL "Hregs"; first iFrame. - iExists (<[paddr:=data]> memmap); iFrame. - unfold fun_write_ram; iPureIntro. - apply map_Forall_lookup. - intros i x H. - destruct (Z.eqb paddr i) eqn:Heqb. - + rewrite -> Z.eqb_eq in Heqb. - subst. - apply (lookup_insert_rev memmap i); assumption. - + rewrite -> map_Forall_lookup in Hmap. - rewrite -> Z.eqb_neq in Heqb. - rewrite -> (lookup_insert_ne _ _ _ _ Heqb) in H. - apply Hmap; assumption. - - iSplitL; trivial; iApply wp_value; cbn. - iSplitL; now iFrame. - Qed. - - Lemma decode_sound `{sg : sailGS Σ} `{HGS: invGS} {Γ es δ} : - forall bv, - evals es δ = env.snoc env.nil ("bv"∷ty_exc_code) bv - → ⊢ semTriple δ (⌜true = true⌝ ∧ emp) (stm_foreign decode es) - (λ (_ : AST) (δ' : CStore Γ), (⌜true = true⌝ ∧ emp) ∗ ⌜δ' = δ⌝). - Proof. - iIntros (bv Heq) "%_". - iApply wp_unfold. - cbn. - iIntros (? ? ? ? ?) "[Hregs [% (Hmem & %Hmap)]]". - iMod (fupd_mask_subseteq empty) as "Hclose"; first set_solver. - iModIntro. - iSplitR; first auto. - iIntros. - iModIntro. - iModIntro. - iModIntro. - dependent elimination H. - dependent elimination s. - rewrite Heq in f1. - cbn in f1. - dependent elimination f1. - cbn. - iMod "Hclose" as "_". - iModIntro. - cbn. - iSplitL "Hregs Hmem". - iSplitL "Hregs"; first iFrame. - iExists memmap; iFrame. - iPureIntro; assumption. - iSplitL; trivial. - destruct (pure_decode bv) eqn:Ed. - iApply wp_compat_fail. - iApply wp_value. - iSplitL; first iPureIntro; auto. - Qed. - - Lemma foreignSem `{sailGS Σ} : ForeignSem. - Proof. - intros Γ τ Δ f es δ. - destruct f; cbn; - intros ι; destruct_syminstance ι; cbn in *; - eauto using read_ram_sound, write_ram_sound, decode_sound. - Qed. - - Section Lemmas. - Context `{sg : sailGS Σ}. - - Lemma open_gprs_sound : - ValidLemma RiscvPmpSpecification.lemma_open_gprs. - Proof. - intros ι; destruct_syminstance ι; cbn. - unfold interp_gprs, reg_file. - rewrite big_sepS_list_to_set; [|apply finite.NoDup_enum]; cbn. - iIntros "[_ [Hx1 [Hx2 [Hx3 [Hx4 [Hx5 [Hx6 [Hx7 _]]]]]]]]". iFrame. - Qed. - - Lemma close_gprs_sound : - ValidLemma RiscvPmpSpecification.lemma_close_gprs. - Proof. - intros ι; destruct_syminstance ι; cbn. - unfold interp_gprs, reg_file. - iIntros "[Hx1 [Hx2 [Hx3 [Hx4 [Hx5 [Hx6 Hx7]]]]]]". - iApply big_sepS_list_to_set; [apply finite.NoDup_enum|]. - cbn; iFrame. eauto using 0%Z. - Qed. - - Lemma open_pmp_entries_sound : - ValidLemma RiscvPmpSpecification.lemma_open_pmp_entries. - Proof. - intros ι; destruct_syminstance ι; cbn. - unfold interp_pmp_entries. - iIntros "H". - destruct entries; try done. - destruct v as [cfg0 addr0]. - destruct entries; try done. - destruct v as [cfg1 addr1]. - destruct entries; try done. - iExists cfg0. - iExists addr0. - iExists cfg1. - iExists addr1. - iDestruct "H" as "[Hcfg0 [Haddr0 [Hcfg1 Haddr1]]]". - iSplitL "Hcfg0"; eauto. - iSplitL "Haddr0"; eauto. - iSplitL "Hcfg1"; eauto. - Qed. - - Lemma close_pmp_entries_sound : - ValidLemma RiscvPmpSpecification.lemma_close_pmp_entries. - Proof. - intros ι; destruct_syminstance ι; cbn. - unfold interp_pmp_entries. - iIntros "[Hcfg0 [Haddr0 [Hcfg1 [Haddr1 _]]]]". - iAccu. - Qed. - - Lemma update_pmp_entries_sound : - ValidLemma RiscvPmpSpecification.lemma_update_pmp_entries. - Proof. - intros ι; destruct_syminstance ι; cbn. - iIntros "[Hcfg0 [Haddr0 [Hcfg1 [Haddr1 Hpriv]]]]". - iFrame. - Qed. - - Lemma in_liveAddrs : forall (addr : Addr), - (minAddr <= addr)%Z -> - (addr <= maxAddr)%Z -> - addr ∈ liveAddrs. - Proof. - intros addr Hmin Hmax. - unfold liveAddrs. - apply elem_of_seqZ. - split; auto. - rewrite Z.add_assoc. - rewrite Zplus_minus. - apply Zle_lt_succ; auto. - Qed. - - Lemma in_liveAddrs_split : forall (addr : Addr), - (minAddr <= addr)%Z -> - (addr <= maxAddr)%Z -> - exists l1 l2, liveAddrs = l1 ++ ([addr] ++ l2). - Proof. - intros addr Hmin Hmax. - unfold liveAddrs. - exists (seqZ minAddr (addr - minAddr)). - exists (seqZ (addr + 1) (maxAddr - addr)). - transitivity (seqZ minAddr (addr - minAddr) ++ seqZ (addr) (maxAddr - addr + 1)). - refine (eq_trans _ (eq_trans (seqZ_app minAddr (addr - minAddr) (maxAddr - addr + 1) _ _) _)); - do 2 (f_equal; try lia). - f_equal; cbn. - refine (eq_trans (seqZ_cons _ _ _) _); try lia. - do 2 f_equal; lia. - Qed. - - Lemma extract_pmp_ptsto_sound : - ValidLemma RiscvPmpSpecification.lemma_extract_pmp_ptsto. - Proof. - intros ι; destruct_syminstance ι; cbn. - rewrite ?Z.leb_le. - iIntros "[Hentries [Hmem [[%Hlemin _] [[%Hlemax _] [%Hpmp _]]]]]". - iSplitL "Hentries"; try done. - unfold interp_pmp_addr_access_without, - interp_pmp_addr_access, - interp_ptsto, - MemVal, Word. - - destruct (in_liveAddrs_split Hlemin Hlemax) as (l1 & l2 & eq). - rewrite eq. - rewrite big_opL_app big_opL_cons. - iDestruct "Hmem" as "[Hmem1 [Hpaddr Hmem2]]". - iSplitR "Hpaddr". - - iIntros "Hpaddr". - iFrame. - now iIntros "_". - - iApply "Hpaddr". - iPureIntro. - now exists acc. - Qed. - - Lemma return_pmp_ptsto_sound : - ValidLemma RiscvPmpSpecification.lemma_return_pmp_ptsto. - Proof. - intros ι; destruct_syminstance ι; cbn. - iIntros "[Hentries [Hwithout Hptsto]]". - iSplitL "Hentries"; first iFrame. - unfold interp_pmp_addr_access_without. - iApply ("Hwithout" with "Hptsto"). - Qed. - - End Lemmas. - - Lemma lemSem `{sailGS Σ} : LemmaSem. - Proof. - intros Δ []; - eauto using open_gprs_sound, close_gprs_sound, open_pmp_entries_sound, - close_pmp_entries_sound, update_pmp_entries_sound, extract_pmp_ptsto_sound, return_pmp_ptsto_sound. - Qed. - -End RiscvPmpModel2. diff --git a/case_study/RiscvPmp/README.md b/case_study/RiscvPmp/README.md deleted file mode 100644 index d62ceb5e..00000000 --- a/case_study/RiscvPmp/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Case Study: RISC-V with PMP -Case study for (base) RISC-V with Physical Memory Protection (PMP). - -Focus is on RV32I, with the PMP extension. -Remarks/Comments/Info: -- instructions with "W" suffix are not implemented (these are for RV64 and are variants that operate only on the lower 32 bits of a doubleword) -- fence instructions not implemented, our model is simple and sequential, updates to registers and memory happen instantly -- WFI (wait for interrupt) instruction not implemented, focus in this model is on exceptions, not interrupts -- store & load instructions are simplified (i.e. no size, always word, no sign/zero extension, no aq or rl -- keep AccessType simple (i.e. no type parameter for extensions, this is ignored in the PMP related code anyway), but still represent it as a *union* (note that we could opt to represent this as an enum, but this way is more faithful to the (simplified) Sail model) -- MemoryOpResult is simplified and MemValue can only be a Word (no type param in definition of MemoryOpResult, this complicates EqDec...) -- Store instructions involve a function mem_write that returns a MemoryOpResult with a boolean value to indicate failure, to keep things simple (point above), I model this as a ty_word where 0 = false and 1 = true -- the model does not support S-mode, so any checks/pattern matches that depend on M-mode and S-mode privileges are simplified to only consider the M-mode case -- some auxiliary functions that convert bits to enums are dropped, the model uses the enum immediately (example: pmpAddrRange calls a function pmpAddrMatchType_of_bits that converts a bitvector into the corresponding enum value of PmpAddrMatchType) -- note that the main loop (function "loop") just calls the step function, this is a lot simpler than the one in the actual sail model, which is complicated with tracing, interrupts, ... -- step function shortened, dropped extension related code, also not doing anything with the "retire" result of an execution (has to do with "minstret", doesn't seem relevant for our case study at this point) - + have kept the "stm_lit ty_retire RETIRE_SUCCESS/FAIL" stmts tho, can however drop this? (TODO: consider) -- the fetch function is simplified, in the sail model it reads 16 bits at a time (to support the compressed extension), in our case we read the entire instruction at once (no support for the compressed extension) (this also means our fetchresult type is simplified) -- trap vector register (mtvec) is limited to only direct mode, i.e. we don't include "mode" bit and take the address in mtvec as is -- the mcause register is limited to just contain an exception code, this suffices for our purposes -- No alignment checks -- exception_delegatee is simplified, note that we can never transition to a less-privileged mode, resulting in this function always returning M-mode (we only have M-mode and U-mode support) -- mem related function are simplified and some auxiliary functions are inlined (see riscv_mem.sail, example: mem_write_value calls mem_write_value_meta, which is inlined in our model) -- mstatus is limited to those fields we require. The fields themselves are also *NOT* bits but rather the corresponding non-bit representation (for example: MPP is normally a 2-bit field of mstatus but in our model is a field that will contain Privilege enum value), this means that we don't need the conversion functions from/to bits - -## Translation Notes -Inline function call expressions get translated into -``` -# ... -# | RISCV_AUIPC => get_arch_pc() + off -# ==> -| RISCV_AUIPC => - let: tmp := call get_arch_pc in - tmp + off -``` - -Currently ommitting alignment related checks and exceptions (bitvector support needed for this). --> OR simply check if address is divisible by 4? - -Ignoring instructions that rely on bitvector operations (like shift operations), this mostly affects the support for RTYPE- and ITYPE-instructions. - -## Source - -This machine is based on a minimal model of the official RISC-V Sail model. -The corresponding model can be found at [https://gitlab.soft.vub.ac.be/shuygheb/sail-minimal-riscv](sail-minimal-riscv). - -The machine that this case study represents is based on the official RISC-V code, more specifically, (parts of) the following files: -- [https://github.com/rems-project/sail-riscv/blob/master/model/riscv_insts_base.sail](Base Instructions) -- [https://github.com/rems-project/sail-riscv/blob/master/model/riscv_pmp_regs.sail](PMP Configuration) -- [https://github.com/rems-project/sail-riscv/blob/master/model/riscv_pmp_control.sail](PMP) - -## Machine Invariant -TODO diff --git a/case_study/RiscvPmp/dune b/case_study/RiscvPmp/dune deleted file mode 100644 index d13bb9df..00000000 --- a/case_study/RiscvPmp/dune +++ /dev/null @@ -1,6 +0,0 @@ -(coq.theory - (name Katamaran.RiscvPmp) - (package coq-katamaran) - (theories Katamaran)) - -(include_subdirs qualified) diff --git a/theories/.gitattributes b/theories/.gitattributes deleted file mode 100644 index 5b088c43..00000000 --- a/theories/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -Staging export-ignore diff --git a/theories/Staging/CommandStep.v b/theories/Staging/CommandStep.v deleted file mode 100644 index 7a4e2094..00000000 --- a/theories/Staging/CommandStep.v +++ /dev/null @@ -1,269 +0,0 @@ -(******************************************************************************) -(* Copyright (c) 2021 Steven Keuchel *) -(* All rights reserved. *) -(* *) -(* Redistribution and use in source and binary forms, with or without *) -(* modification, are permitted provided that the following conditions are *) -(* met: *) -(* *) -(* 1. Redistributions of source code must retain the above copyright notice, *) -(* this list of conditions and the following disclaimer. *) -(* *) -(* 2. Redistributions in binary form must reproduce the above copyright *) -(* notice, this list of conditions and the following disclaimer in the *) -(* documentation and/or other materials provided with the distribution. *) -(* *) -(* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *) -(* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) -(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *) -(* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR *) -(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *) -(* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *) -(* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *) -(* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *) -(* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *) -(* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *) -(* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) -(******************************************************************************) - -From Coq Require Import - Program.Tactics - Strings.String. -From Equations Require Import - Equations. -From Katamaran Require Import - Semantics.Registers - Program - Tactics. - -Import ctx.notations. -Import env.notations. - -Set Implicit Arguments. - -Module Type CommandsOn (Import B : Base) (Import F : FunDeclKit B). - - Inductive Command (A : Type) : Type := - | cmd_return (a : A) - | cmd_fail - | cmd_read_register {τ} (reg : 𝑹𝑬𝑮 τ) (c : Val τ -> Command A) - | cmd_write_register {τ} (reg : 𝑹𝑬𝑮 τ) (v : Val τ) (c : Command A) - | cmd_call {Δ τ} (f : 𝑭 Δ τ) (vs : CStore Δ) (c : Val τ -> Command A) - | cmd_foreign {Δ τ} (f : 𝑭𝑿 Δ τ) (vs : CStore Δ) (c : Val τ -> Command A). - Global Arguments cmd_fail {A}. - - Fixpoint cmd_bind {A B} (m : Command A) (g : A -> Command B) {struct m} : Command B := - match m with - | cmd_return a => g a - | cmd_fail => cmd_fail - | cmd_read_register reg k => cmd_read_register reg (fun v => cmd_bind (k v) g) - | cmd_write_register reg v c => cmd_write_register reg v (cmd_bind c g) - | cmd_call f vs k => cmd_call f vs (fun v => cmd_bind (k v) g) - | cmd_foreign f vs k => cmd_foreign f vs (fun v => cmd_bind (k v) g) - end. - - Definition cmd_map {A B} (f : A -> B) (ma : Command A) : Command B := - cmd_bind ma (fun v => cmd_return (f v)). - -End CommandsOn. - -Module Type CFunDefKit (Import B : Base) (Import F : FunDeclKit B) (Import C : CommandsOn B F). - - Include RegStoreKit B. - - (* Memory model *) - Parameter Memory : Type. - (* Step relation for calling an external function. The complete function call - is done in one step. The result of an external call is either a failure - with an error message msg (res = inl msg) or a successful computation with - a result value v (res = inr v). - *) - Parameter ForeignCall : - forall - {Δ σ} (f : 𝑭𝑿 Δ σ) - (args : CStore Δ) - (res : string + Val σ) - (γ γ' : RegStore) - (μ μ' : Memory), Prop. - Parameter ForeignProgress : - forall {Δ σ} (f : 𝑭𝑿 Δ σ) (args : CStore Δ) γ μ, - exists γ' μ' res, ForeignCall f args res γ γ' μ μ'. - - Parameter Inline FunDef : forall {Δ τ} (f : 𝑭 Δ τ), CStore Δ -> Command (Val τ). - -End CFunDefKit. - -Module Type CProgram (B : Base) := FunDeclKit B <+ CommandsOn B <+ CFunDefKit B. - -Module SmallStepOn (Import B : Base) (Import P : CProgram B). - - Reserved Notation "⟨ γ1 , μ1 , c1 ⟩ ---> ⟨ γ2 , μ2 , s2 ⟩" (at level 75, no associativity). - - Inductive Step {A} (γ : RegStore) (μ : Memory) : - forall (γ2 : RegStore) (μ2 : Memory) (c1 c2 : Command A), Prop := - - | step_call - {Δ τ} {f : 𝑭 Δ τ} (vs : CStore Δ) (c : Val τ -> Command A) : - ⟨ γ , μ , cmd_call f vs c ⟩ ---> - ⟨ γ , μ , cmd_bind (FunDef f vs) c ⟩ - | step_foreign - {Δ τ} {f : 𝑭𝑿 Δ τ} (vs : CStore Δ) (c : Val τ -> Command A) - (γ' : RegStore) (μ' : Memory) (res : string + Val τ) : - ForeignCall f vs res γ γ' μ μ' -> - ⟨ γ , μ , cmd_foreign f vs c ⟩ ---> - ⟨ γ' , μ' , match res with - | inl msg => cmd_fail - | inr v => c v - end ⟩ - | step_read_register - {τ} (r : 𝑹𝑬𝑮 τ) (c : Val τ -> Command A) : - ⟨ γ, μ , cmd_read_register r c ⟩ ---> ⟨ γ, μ , c (read_register γ r) ⟩ - | step_write_register - {τ} (r : 𝑹𝑬𝑮 τ) (v : Val τ) (c : Command A) : - ⟨ γ , μ , cmd_write_register r v c ⟩ ---> ⟨ write_register γ r v , μ , c ⟩ - - where "⟨ γ1 , μ1 , c1 ⟩ ---> ⟨ γ2 , μ2 , c2 ⟩" := (@Step _ γ1%env μ1%env γ2%env μ2%env c1 c2). - -End SmallStepOn. - -Module CInterpreter (Import B : Base) - (Import F : FunDeclKit B) (Import C : CommandsOn B F) - (Import S : StatementsOn B F). - - Definition M (Γ1 Γ2 : PCtx) (A : Type) : Type := - CStore Γ1 -> Command (CStore Γ2 * A). - Definition run {Γ1 Γ2 A} (m : M Γ1 Γ2 A) (δ : CStore Γ1) : Command A := - cmd_map snd (m δ). - - Definition pure {Γ A} (a : A) : M Γ Γ A := - fun δ => cmd_return (δ , a). - Definition bind {Γ1 Γ2 Γ3 A B} (m : M Γ1 Γ2 A) (f : A -> M Γ2 Γ3 B) : M Γ1 Γ3 B := - fun δ1 => cmd_bind (m δ1) (fun '(δ2,a) => f a δ2). - Definition bind_right {Γ1 Γ2 Γ3 A B} (ma : M Γ1 Γ2 A) (mb : M Γ2 Γ3 B) : M Γ1 Γ3 B := - bind ma (fun _ => mb). - Definition map {Γ1 Γ2 A B} (f : A -> B) (ma : M Γ1 Γ2 A) : M Γ1 Γ2 B := - bind ma (fun a => pure (f a )). - Definition error {Γ1 Γ2 A} : M Γ1 Γ2 A := - fun _ => @cmd_fail _. - Definition mcall {Γ Δ τ} (f : 𝑭 Δ τ) (args : CStore Δ) : M Γ Γ (Val τ) := - fun δ => cmd_call f args (fun v => cmd_return (δ,v)). - Definition mforeign {Γ Δ τ} (f : 𝑭𝑿 Δ τ) (args : CStore Δ) : M Γ Γ (Val τ) := - fun δ => cmd_foreign f args (fun v => cmd_return (δ,v)). - Definition mreadreg {Γ τ} (reg : 𝑹𝑬𝑮 τ) : M Γ Γ (Val τ) := - fun δ => cmd_read_register reg (fun v => cmd_return (δ,v)). - Definition mwritereg {Γ τ} (reg : 𝑹𝑬𝑮 τ) (v : Val τ) : M Γ Γ unit := - fun δ => cmd_write_register reg v (cmd_return (δ,tt)). - - Definition pushpop {A Γ1 Γ2 x σ} (v : Val σ) - (d : M (Γ1 ▻ x∷σ) (Γ2 ▻ x∷σ) A) : M Γ1 Γ2 A := - fun δ1 => cmd_map (fun '(δ2,a) => (env.tail δ2 , a)) (d (δ1 ► (x∷σ ↦ v))). - Definition pushspops {A} {Γ1 Γ2 Δ} (δΔ : CStore Δ) - (d : M (Γ1 ▻▻ Δ) (Γ2 ▻▻ Δ) A) : M Γ1 Γ2 A := - fun δ1 => cmd_map (fun '(δ2,a) => (env.drop Δ δ2 , a)) (d (δ1 ►► δΔ)). - Definition get_local {Γ} : M Γ Γ (CStore Γ) := - fun δ => cmd_return (δ,δ). - Definition put_local {Γ1 Γ2} (δ : CStore Γ2) : M Γ1 Γ2 unit := - fun _ => cmd_return (δ,tt). - - Definition eval_exp {Γ σ} (e : Exp Γ σ) : M Γ Γ (Val σ) := - fun δ => cmd_return (δ,eval e δ). - Definition eval_exps {Γ} {σs : PCtx} (es : NamedEnv (Exp Γ) σs) : M Γ Γ (CStore σs) := - fun δ => cmd_return (δ,evals es δ). - Definition assign {Γ} x {σ} {xIn : x∷σ ∈ Γ} (v : Val σ) : M Γ Γ unit := - fun δ => cmd_return (δ ⟪ x ↦ v ⟫ , tt). - Arguments assign {Γ} x {σ xIn} v. - - Notation "x <- ma ;; mb" := - (bind ma (fun x => mb)) - (at level 80, ma at level 90, mb at level 200, right associativity). - Notation "m1 ;; m2" := (bind_right m1 m2). - - Fixpoint exec {Γ τ} (s : Stm Γ τ) : M Γ Γ (Val τ) := - match s with - | stm_val _ l => pure l - | stm_exp e => eval_exp e - | stm_let x σ s k => - v <- exec s ;; - pushpop v (exec k) - | stm_block δ k => - pushspops δ (exec k) - | stm_assign x e => - v <- exec e ;; - assign x v ;; - pure v - | stm_call f es => - bind (eval_exps es) (mcall f) - | stm_foreign f es => - bind (eval_exps es) (mforeign f) - | stm_lemmak l es k => - exec k - | stm_call_frame δ' s => - δ <- get_local ;; - put_local δ' ;; - v <- exec s ;; - put_local δ ;; - pure v - | stm_if e s1 s2 => - v <- eval_exp e ;; - if v then exec s1 else exec s2 - | stm_seq s k => exec s ;; exec k - | stm_assertk e1 _ k => - v <- eval_exp e1 ;; - if v then exec k else error - | stm_fail _ s => - error - | stm_match_enum E e alts => - v <- eval_exp e ;; - exec (alts v) - | stm_read_register reg => - mreadreg reg - | stm_write_register reg e => - v <- eval_exp e ;; - mwritereg reg v ;; - pure v - | @stm_match_list _ _ σ e s1 xh xt s2 => - v <- eval_exp e ;; - match v with - | nil => exec s1 - | cons h t => - pushspops - (env.snoc (env.snoc env.nil (xh∷σ) h) (xt∷ty.list σ) t) - (exec s2) - end - | stm_match_sum e xinl s1 xinr s2 => - v <- eval_exp e ;; - match v with - | inl v => pushpop v (exec s1) - | inr v => pushpop v (exec s2) - end - | stm_match_prod e xl xr s => - v <- eval_exp e ;; - match v with - | (vl,vr) => - pushspops - (env.snoc (env.snoc env.nil (xl∷_) vl) (xr∷_) vr) - (exec s) - end - | stm_match_tuple e p rhs => - v <- eval_exp e ;; - pushspops (tuple_pattern_match_val p v) (exec rhs) - | stm_match_union U e alt__pat alt__rhs => - v <- eval_exp e ;; - match unionv_unfold U v with - | existT K v => - pushspops (pattern_match_val (alt__pat K) v) (exec (alt__rhs K)) - end - | stm_match_record R e p rhs => - v <- eval_exp e ;; - pushspops (record_pattern_match_val p v) (exec rhs) - | stm_match_bvec n e rhs => - v <- eval_exp e ;; - exec (rhs v) - | stm_bind s k => - v <- exec s ;; - exec (k v) - | stm_debugk k => - exec k - end. - -End CInterpreter.