(
pte: u64,
vaddr: u64,
level: usize,
priv_mode: PrivilegeMode,
sum: u64,
mxr: u64,
is_write: bool,
is_execute: bool,
pmpcfg0: u64,
pmpaddr0: u64,
)
| 99 | Self { |
| 100 | satp: 0, |
| 101 | entries: [TlbEntry { |
| 102 | valid: false, |
| 103 | vpn: 0, |
| 104 | pte: 0, |
| 105 | level: 0, |
| 106 | }; TLB_ENTRIES], |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | /// Invalidate every entry. Called on sfence.vma. |
| 111 | pub fn flush(&mut self) { |
| 112 | for e in &mut self.entries { |
| 113 | e.valid = false; |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | // Drop all entries if the active address space (satp) changed. |
| 118 | fn sync_satp(&mut self, satp: u64) { |
| 119 | if self.satp != satp { |
| 120 | self.satp = satp; |
| 121 | self.flush(); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | pub(crate) fn lookup(&self, vpn: u64) -> Option<(u64, usize)> { |
| 126 | let e = &self.entries[(vpn as usize) & (TLB_ENTRIES - 1)]; |
| 127 | if e.valid && e.vpn == vpn { |
| 128 | Some((e.pte, e.level)) |
| 129 | } else { |
| 130 | None |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | fn insert(&mut self, vpn: u64, pte: u64, level: usize) { |
| 135 | self.entries[(vpn as usize) & (TLB_ENTRIES - 1)] = TlbEntry { |
| 136 | valid: true, |
| 137 | vpn, |
| 138 | pte, |
| 139 | level, |
| 140 | }; |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | // Check a leaf PTE and build the physical address (permission/privilege/superpage/ |
| 145 | // PMP). Shared by the walk and a TLB hit; touches no memory and no A/D bits. |
| 146 | pub(crate) fn finalize_leaf( |
| 147 | pte: u64, |
| 148 | vaddr: u64, |
| 149 | level: usize, |
| 150 | ctx: TranslationContext, |
| 151 | access: AccessKind, |
| 152 | ) -> Result<u64, VmError> { |
| 153 | let sum = (ctx.mstatus >> 18) & 1; |
| 154 | let mxr = (ctx.mstatus >> 19) & 1; |
| 155 | let r = (pte >> 1) & 1; |
| 156 | let w = (pte >> 2) & 1; |
| 157 | let x = (pte >> 3) & 1; |
| 158 | let u_bit = (pte >> 4) & 1; |
no outgoing calls
no test coverage detected