Next Generation WASM Microkernel Operating System
at main 96 lines 2.8 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use core::ops::Range; 9use core::{cmp, mem}; 10 11use anyhow::bail; 12use kmem::VirtualAddress; 13 14use crate::arch; 15 16#[must_use] 17pub struct Flush { 18 asid: u16, 19 range: Option<Range<VirtualAddress>>, 20} 21 22impl Drop for Flush { 23 fn drop(&mut self) { 24 if self.range.is_some() { 25 tracing::error!("dropped Flush without calling ignore/flush"); 26 } 27 } 28} 29 30impl Flush { 31 pub fn empty(asid: u16) -> Self { 32 Self { asid, range: None } 33 } 34 35 pub fn new(asid: u16, range: Range<VirtualAddress>) -> Self { 36 Self { 37 asid, 38 range: Some(range), 39 } 40 } 41 42 pub fn range(&self) -> Option<&Range<VirtualAddress>> { 43 self.range.as_ref() 44 } 45 46 /// Flush the range of virtual addresses from the TLB. 47 /// 48 /// # Errors 49 /// 50 /// Returns an error if the range could not be flushed due to an underlying hardware error. 51 pub fn flush(mut self) -> crate::Result<()> { 52 if let Some(range) = self.range.take() { 53 tracing::trace!(?range, asid = self.asid, "flushing range"); 54 arch::invalidate_range(self.asid, range)?; 55 } else { 56 tracing::warn!("attempted to flush empty range, ignoring"); 57 } 58 59 Ok(()) 60 } 61 62 /// # Safety 63 /// 64 /// Not flushing after mutating the page translation tables will likely lead to unintended 65 /// consequences such as inconsistent views of the address space between different cpus. 66 /// 67 /// You should only call this if you know what you're doing. 68 pub unsafe fn ignore(self) { 69 mem::forget(self); 70 } 71 72 /// Extend the range to include the given range. 73 /// 74 /// # Errors 75 /// 76 /// Returns an error if the given ASID does not match the ASID of this `Flush`. 77 pub fn extend_range(&mut self, asid: u16, other: Range<VirtualAddress>) -> crate::Result<()> { 78 if self.asid == asid { 79 if let Some(this) = self.range.take() { 80 self.range = Some(Range { 81 start: cmp::min(this.start, other.start), 82 end: cmp::max(this.end, other.end), 83 }); 84 } else { 85 self.range = Some(other); 86 } 87 88 Ok(()) 89 } else { 90 bail!( 91 "Attempted to operate on mismatched address space. Expected {} but found {asid}.", 92 self.asid 93 ); 94 } 95 } 96}