diff options
author | Rishiyur S. Nikhil <nikhil@acm.org> | 2024-04-01 11:07:57 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-01 10:07:57 -0500 |
commit | f601c866153c79a7ae8404f939dc2d66aa2e41f9 (patch) | |
tree | 276b3e032c8455d415ccf2265d5288f1f316bc82 /model/riscv_vmem_pte.sail | |
parent | d564b93310dd43f519325a418da056f78b1daef2 (diff) | |
download | sail-riscv-f601c866153c79a7ae8404f939dc2d66aa2e41f9.zip sail-riscv-f601c866153c79a7ae8404f939dc2d66aa2e41f9.tar.gz sail-riscv-f601c866153c79a7ae8404f939dc2d66aa2e41f9.tar.bz2 |
Unify VM code
Old vmem code had much 'cut-and-paste' replication for RV32 (Sv32) and (#408)
RV64 (Sv39, Sv48), and was scattered over several files.
New code unifies them into single set of parameterized functions
that works for RV32/RV64 and Sv32/Sv39/Sv48 (and is ready for Sv57).
Deleted old files:
riscv_vmem_rv32.sail riscv_vmem_rv64.sail
riscv_vmem_sv32.sail riscv_vmem_sv39.sail riscv_vmem_sv48.sail
riscv_pte.sail
riscv_ptw.sail
Current files: all named riscv_vmem_*
riscv_vmem.sail (root file for vmem)
riscv_vmem_common.sail
riscv_vmem_pte.sail
riscv_vmem_ptw.sail
riscv_vmem_tlb.sail
riscv_vmem_types.sail
Modified top-level Makefile accordingly.
Added documentation on new vmem code: doc/notes_Virtual_Memory.adoc
Diffstat (limited to 'model/riscv_vmem_pte.sail')
-rw-r--r-- | model/riscv_vmem_pte.sail | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/model/riscv_vmem_pte.sail b/model/riscv_vmem_pte.sail new file mode 100644 index 0000000..dfe032c --- /dev/null +++ b/model/riscv_vmem_pte.sail @@ -0,0 +1,135 @@ +/*=======================================================================================*/ +/* This Sail RISC-V architecture model, comprising all files and */ +/* directories except where otherwise noted is subject the BSD */ +/* two-clause license in the LICENSE file. */ +/* */ +/* SPDX-License-Identifier: BSD-2-Clause */ +/*=======================================================================================*/ + +// **************************************************************** +// PTE (Page Table Entry) in PTN (Page Table Node) + +// PTE MSBs PPNs RSW BITs +// Sv32 - 31..10 9..8 7..0 +// Sv39 63..54 53..10 9..8 7..0 +// Sv48 63..54 53..10 9..8 7..0 + +// MSBs of PTE are reserved for RV64 extensions. +// There are not available bits on RV32, so these bits will be zeros on RV32. + +type pte_flags_bits = bits(8) + +// For PTW extensions (non-standard) +type extPte = bits(64) + +// PRIVATE: extract msbs of PTE above the PPN +function msbs_of_PTE(sv_params : SV_Params, pte : bits(64)) -> bits(64) = { + let mask : bits(64) = zero_extend(ones(sv_params.pte_msbs_size_bits)); + (pte >> sv_params.pte_msbs_lsb_index) & mask +} + +// PRIVATE: extract PPNs of PTE +function PPNs_of_PTE(sv_params : SV_Params, pte : bits(64)) -> bits(64) = { + let mask : bits(64) = zero_extend(ones(sv_params.pte_PPNs_size_bits)); + (pte >> sv_params.pte_PPNs_lsb_index) & mask +} + +// PRIVATE: 8 LSBs of PTEs in Sv32, Sv39, Sv48 and Sv57 +bitfield PTE_Flags : pte_flags_bits = { + D : 7, // dirty + A : 6, // accessed + G : 5, // global + U : 4, // User + X : 3, // Execute permission + W : 2, // Write permission + R : 1, // Read permission + V : 0 // Valid +} + +// PRIVATE: check if a PTE is a pointer to next level (non-leaf) +function pte_is_ptr(pte_flags : PTE_Flags) -> bool = (pte_flags[X] == 0b0) + & (pte_flags[W] == 0b0) + & (pte_flags[R] == 0b0) + +// PRIVATE: check if a PTE is valid +function pte_is_invalid(pte_flags : PTE_Flags) -> bool = (pte_flags[V] == 0b0) + | ((pte_flags[W] == 0b1) + & (pte_flags[R] == 0b0)) + +// ---------------- +// Check access permissions in PTE + +// For (non-standard) extensions: this function gets the extension-available bits +// of the PTE in extPte, and the accumulated information of the page-table-walk +// in ext_ptw. It should return the updated ext_ptw in both success and failure cases. + +union PTE_Check = { + PTE_Check_Success : ext_ptw, + PTE_Check_Failure : (ext_ptw, ext_ptw_fail) +} + +// PRIVATE +function check_PTE_permission(ac : AccessType(ext_access_type), + priv : Privilege, + mxr : bool, + do_sum : bool, + pte_flags : PTE_Flags, + ext : extPte, + ext_ptw : ext_ptw) -> PTE_Check = { + let pte_U = pte_flags[U]; + let pte_R = pte_flags[R]; + let pte_W = pte_flags[W]; + let pte_X = pte_flags[X]; + let success : bool = + match (ac, priv) { + (Read(_), User) => (pte_U == 0b1) + & ((pte_R == 0b1) + | ((pte_X == 0b1 & mxr))), + (Write(_), User) => (pte_U == 0b1) & (pte_W == 0b1), + (ReadWrite(_, _), User) => (pte_U == 0b1) + & (pte_W == 0b1) + & ((pte_R == 0b1) | ((pte_X == 0b1) & mxr)), + (Execute(), User) => (pte_U == 0b1) & (pte_X == 0b1), + (Read(_), Supervisor) => ((pte_U == 0b0) | do_sum) + & ((pte_R == 0b1) | ((pte_X == 0b1) & mxr)), + (Write(_), Supervisor) => ((pte_U == 0b0) | do_sum) + & (pte_W == 0b1), + (ReadWrite(_, _), Supervisor) => ((pte_U == 0b0) | do_sum) + & (pte_W == 0b1) + & ((pte_R == 0b1) + | ((pte_X == 0b1) & mxr)), + (Execute(), Supervisor) => (pte_U == 0b0) & (pte_X == 0b1), + (_, Machine) => internal_error(__FILE__, __LINE__, + "m-mode mem perm check")}; + if success then PTE_Check_Success(()) + else PTE_Check_Failure((), ()) +} + +// Update PTE bits if needed; return new PTE if updated +// PRIVATE +function update_PTE_Bits(sv_params : SV_Params, + pte : bits(64), + a : AccessType(ext_access_type)) + -> option(bits(64)) = { + let pte_flags = Mk_PTE_Flags(pte [7 .. 0]); + + // Update 'dirty' bit? + let update_d : bool = (pte_flags[D] == 0b0) + & (match a { + Execute() => false, + Read() => false, + Write(_) => true, + ReadWrite(_, _) => true + }); + // Update 'accessed'-bit? + let update_a = (pte_flags[A] == 0b0); + + if update_d | update_a then { + let pte_flags = [pte_flags with + A = 0b1, + D = (if update_d then 0b1 else pte_flags[D])]; + Some(pte[63 .. 8] @ pte_flags.bits()) + } + else + None() +} |