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