Next Generation WASM Microkernel Operating System
at trap_handler 452 lines 16 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 core::alloc::{Layout, LayoutError}; 10use core::fmt; 11use core::range::Range; 12 13macro_rules! address_impl { 14 ($addr:ident) => { 15 impl $addr { 16 pub const MAX: Self = Self(usize::MAX); 17 pub const MIN: Self = Self(0); 18 pub const BITS: u32 = usize::BITS; 19 20 #[must_use] 21 #[inline] 22 pub const fn checked_add(self, rhs: usize) -> Option<Self> { 23 if let Some(out) = self.0.checked_add(rhs) { 24 Some(Self(out)) 25 } else { 26 None 27 } 28 } 29 30 #[must_use] 31 #[inline] 32 pub const fn checked_add_signed(self, rhs: isize) -> Option<Self> { 33 if let Some(out) = self.0.checked_add_signed(rhs) { 34 Some(Self(out)) 35 } else { 36 None 37 } 38 } 39 40 #[must_use] 41 #[inline] 42 pub const fn checked_sub(self, rhs: usize) -> Option<Self> { 43 if let Some(out) = self.0.checked_sub(rhs) { 44 Some(Self(out)) 45 } else { 46 None 47 } 48 } 49 #[must_use] 50 #[inline] 51 pub const fn checked_div(self, rhs: usize) -> Option<Self> { 52 if let Some(out) = self.0.checked_div(rhs) { 53 Some(Self(out)) 54 } else { 55 None 56 } 57 } 58 #[must_use] 59 #[inline] 60 pub const fn checked_mul(self, rhs: usize) -> Option<Self> { 61 if let Some(out) = self.0.checked_mul(rhs) { 62 Some(Self(out)) 63 } else { 64 None 65 } 66 } 67 #[must_use] 68 #[inline] 69 pub const fn checked_shl(self, rhs: u32) -> Option<Self> { 70 if let Some(out) = self.0.checked_shl(rhs) { 71 Some(Self(out)) 72 } else { 73 None 74 } 75 } 76 #[must_use] 77 #[inline] 78 pub const fn checked_shr(self, rhs: u32) -> Option<Self> { 79 if let Some(out) = self.0.checked_shr(rhs) { 80 Some(Self(out)) 81 } else { 82 None 83 } 84 } 85 // #[must_use] 86 // #[inline] 87 // pub const fn saturating_add(self, rhs: usize) -> Self { 88 // Self(self.0.saturating_add(rhs)) 89 // } 90 // #[must_use] 91 // #[inline] 92 // pub const fn saturating_add_signed(self, rhs: isize) -> Self { 93 // Self(self.0.saturating_add_signed(rhs)) 94 // } 95 // #[must_use] 96 // #[inline] 97 // pub const fn saturating_div(self, rhs: usize) -> Self { 98 // Self(self.0.saturating_div(rhs)) 99 // } 100 // #[must_use] 101 // #[inline] 102 // pub const fn saturating_sub(self, rhs: usize) -> Self { 103 // Self(self.0.saturating_sub(rhs)) 104 // } 105 // #[must_use] 106 // #[inline] 107 // pub const fn saturating_mul(self, rhs: usize) -> Self { 108 // Self(self.0.saturating_mul(rhs)) 109 // } 110 #[must_use] 111 #[inline] 112 pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { 113 let (a, b) = self.0.overflowing_shl(rhs); 114 (Self(a), b) 115 } 116 #[must_use] 117 #[inline] 118 pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { 119 let (a, b) = self.0.overflowing_shr(rhs); 120 (Self(a), b) 121 } 122 123 #[must_use] 124 #[inline] 125 pub const fn checked_sub_addr(self, rhs: Self) -> Option<usize> { 126 self.0.checked_sub(rhs.0) 127 } 128 129 // #[must_use] 130 // #[inline] 131 // pub const fn saturating_sub_addr(self, rhs: Self) -> usize { 132 // self.0.saturating_sub(rhs.0) 133 // } 134 135 #[must_use] 136 #[inline] 137 pub const fn is_aligned_to(&self, align: usize) -> bool { 138 assert!( 139 align.is_power_of_two(), 140 "is_aligned_to: align is not a power-of-two" 141 ); 142 143 self.0 & (align - 1) == 0 144 } 145 146 #[must_use] 147 #[inline] 148 pub const fn checked_align_up(self, align: usize) -> Option<Self> { 149 if !align.is_power_of_two() { 150 panic!("checked_align_up: align is not a power-of-two"); 151 } 152 153 // SAFETY: `align` has been checked to be a power of 2 above 154 let align_minus_one = unsafe { align.unchecked_sub(1) }; 155 156 // addr.wrapping_add(align_minus_one) & 0usize.wrapping_sub(align) 157 if let Some(addr_plus_align) = self.0.checked_add(align_minus_one) { 158 let aligned = Self(addr_plus_align & 0usize.wrapping_sub(align)); 159 debug_assert!(aligned.is_aligned_to(align)); 160 debug_assert!(aligned.0 >= self.0); 161 Some(aligned) 162 } else { 163 None 164 } 165 } 166 167 // #[must_use] 168 // #[inline] 169 // pub const fn wrapping_align_up(self, align: usize) -> Self { 170 // if !align.is_power_of_two() { 171 // panic!("checked_align_up: align is not a power-of-two"); 172 // } 173 // 174 // // SAFETY: `align` has been checked to be a power of 2 above 175 // let align_minus_one = unsafe { align.unchecked_sub(1) }; 176 // 177 // // addr.wrapping_add(align_minus_one) & 0usize.wrapping_sub(align) 178 // let out = addr.wrapping_add(align_minus_one) & 0usize.wrapping_sub(align); 179 // debug_assert!(out.is_aligned_to(align)); 180 // out 181 // } 182 183 #[inline] 184 pub const fn alignment(&self) -> usize { 185 self.0 & (!self.0 + 1) 186 } 187 188 #[must_use] 189 #[inline] 190 pub const fn align_down(self, align: usize) -> Self { 191 if !align.is_power_of_two() { 192 panic!("checked_align_up: align is not a power-of-two"); 193 } 194 195 let aligned = Self(self.0 & 0usize.wrapping_sub(align)); 196 debug_assert!(aligned.is_aligned_to(align)); 197 debug_assert!(aligned.0 <= self.0); 198 aligned 199 } 200 201 #[inline] 202 pub const fn as_ptr(self) -> *const u8 { 203 self.0 as *const u8 204 } 205 #[inline] 206 pub const fn as_mut_ptr(self) -> *mut u8 { 207 self.0 as *mut u8 208 } 209 #[inline] 210 pub const fn get(self) -> usize { 211 self.0 212 } 213 } 214 215 impl fmt::Display for $addr { 216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 217 f.write_fmt(format_args!("{:#018x}", self.0)) // 18 digits to account for the leading 0x 218 } 219 } 220 221 impl fmt::Debug for $addr { 222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 223 f.debug_tuple(stringify!($addr)) 224 .field(&format_args!("{:#018x}", self.0)) // 18 digits to account for the leading 0x 225 .finish() 226 } 227 } 228 229 impl core::iter::Step for $addr { 230 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) { 231 core::iter::Step::steps_between(&start.0, &end.0) 232 } 233 234 fn forward_checked(start: Self, count: usize) -> Option<Self> { 235 core::iter::Step::forward_checked(start.0, count).map(Self) 236 } 237 238 fn forward(start: Self, count: usize) -> Self { 239 Self(core::iter::Step::forward(start.0, count)) 240 } 241 242 unsafe fn forward_unchecked(start: Self, count: usize) -> Self { 243 // Safety: checked by the caller 244 Self(unsafe { core::iter::Step::forward_unchecked(start.0, count) }) 245 } 246 247 fn backward_checked(start: Self, count: usize) -> Option<Self> { 248 core::iter::Step::backward_checked(start.0, count).map(Self) 249 } 250 251 fn backward(start: Self, count: usize) -> Self { 252 Self(core::iter::Step::backward(start.0, count)) 253 } 254 255 unsafe fn backward_unchecked(start: Self, count: usize) -> Self { 256 // Safety: checked by the caller 257 Self(unsafe { core::iter::Step::backward_unchecked(start.0, count) }) 258 } 259 } 260 }; 261} 262 263macro_rules! address_range_impl { 264 () => { 265 fn size(&self) -> usize { 266 debug_assert!(self.start <= self.end); 267 let is = self.end.checked_sub_addr(self.start).unwrap_or_default(); 268 let should = if self.is_empty() { 269 0 270 } else { 271 self.end.get() - self.start.get() 272 }; 273 debug_assert_eq!(is, should); 274 is 275 } 276 fn checked_add(self, offset: usize) -> Option<Self> { 277 Some(Range::from( 278 self.start.checked_add(offset)?..self.end.checked_add(offset)?, 279 )) 280 } 281 fn as_ptr_range(&self) -> Range<*const u8> { 282 Range::from(self.start.as_ptr()..self.end.as_ptr()) 283 } 284 fn as_mut_ptr_range(&self) -> Range<*mut u8> { 285 Range::from(self.start.as_mut_ptr()..self.end.as_mut_ptr()) 286 } 287 fn checked_align_in(self, align: usize) -> Option<Self> 288 where 289 Self: Sized, 290 { 291 let res = Range::from(self.start.checked_align_up(align)?..self.end.align_down(align)); 292 Some(res) 293 } 294 fn checked_align_out(self, align: usize) -> Option<Self> 295 where 296 Self: Sized, 297 { 298 let res = Range::from(self.start.align_down(align)..self.end.checked_align_up(align)?); 299 // aligning outwards can only increase the size 300 debug_assert!(res.start.0 <= res.end.0); 301 Some(res) 302 } 303 // fn saturating_align_in(self, align: usize) -> Self { 304 // self.start.saturating_align_up(align)..self.end.saturating_align_down(align) 305 // } 306 // fn saturating_align_out(self, align: usize) -> Self { 307 // self.start.saturating_align_down(align)..self.end.saturating_align_up(align) 308 // } 309 310 // TODO test 311 fn alignment(&self) -> usize { 312 self.start.alignment() 313 } 314 fn into_layout(self) -> core::result::Result<Layout, LayoutError> { 315 Layout::from_size_align(self.size(), self.alignment()) 316 } 317 fn is_overlapping(&self, other: &Self) -> bool { 318 (self.start < other.end) & (other.start < self.end) 319 } 320 fn difference(&self, other: Self) -> (Option<Self>, Option<Self>) { 321 debug_assert!(self.is_overlapping(&other)); 322 let a = Range::from(self.start..other.start); 323 let b = Range::from(other.end..self.end); 324 ((!a.is_empty()).then_some(a), (!b.is_empty()).then_some(b)) 325 } 326 fn clamp(&self, range: Self) -> Self { 327 Range::from(self.start.max(range.start)..self.end.min(range.end)) 328 } 329 }; 330} 331 332#[repr(transparent)] 333#[derive(Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] 334pub struct VirtualAddress(usize); 335address_impl!(VirtualAddress); 336 337impl VirtualAddress { 338 pub const ZERO: Self = Self(0); 339 340 #[must_use] 341 pub const fn new(n: usize) -> Option<Self> { 342 let this = Self(n); 343 if this.is_canonical() { 344 Some(this) 345 } else { 346 None 347 } 348 } 349 350 pub const fn is_canonical(self) -> bool { 351 (self.0 & arch::CANONICAL_ADDRESS_MASK).wrapping_sub(1) >= arch::CANONICAL_ADDRESS_MASK - 1 352 } 353 354 #[must_use] 355 pub fn from_phys(phys: PhysicalAddress) -> Option<VirtualAddress> { 356 arch::KERNEL_ASPACE_RANGE.start.checked_add(phys.0) 357 } 358 359 #[inline] 360 pub const fn is_user_accessible(self) -> bool { 361 // This address refers to userspace if it is in the lower half of the 362 // canonical addresses. IOW - if all of the bits in the canonical address 363 // mask are zero. 364 (self.0 & arch::CANONICAL_ADDRESS_MASK) == 0 365 } 366} 367 368#[repr(transparent)] 369#[derive(Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] 370pub struct PhysicalAddress(usize); 371address_impl!(PhysicalAddress); 372 373impl PhysicalAddress { 374 #[must_use] 375 pub const fn new(n: usize) -> Self { 376 Self(n) 377 } 378} 379 380pub trait AddressRangeExt { 381 fn size(&self) -> usize; 382 #[must_use] 383 fn checked_add(self, offset: usize) -> Option<Self> 384 where 385 Self: Sized; 386 #[must_use] 387 fn as_ptr_range(&self) -> Range<*const u8>; 388 #[must_use] 389 fn as_mut_ptr_range(&self) -> Range<*mut u8>; 390 #[must_use] 391 fn checked_align_in(self, align: usize) -> Option<Self> 392 where 393 Self: Sized; 394 #[must_use] 395 fn checked_align_out(self, align: usize) -> Option<Self> 396 where 397 Self: Sized; 398 // #[must_use] 399 // fn saturating_align_in(self, align: usize) -> Self; 400 // #[must_use] 401 // fn saturating_align_out(self, align: usize) -> Self; 402 fn alignment(&self) -> usize; 403 fn into_layout(self) -> core::result::Result<Layout, LayoutError>; 404 fn is_user_accessible(&self) -> bool; 405 fn is_overlapping(&self, other: &Self) -> bool; 406 fn difference(&self, other: Self) -> (Option<Self>, Option<Self>) 407 where 408 Self: Sized; 409 fn clamp(&self, range: Self) -> Self; 410} 411 412impl AddressRangeExt for Range<PhysicalAddress> { 413 address_range_impl!(); 414 fn is_user_accessible(&self) -> bool { 415 unimplemented!("PhysicalAddress is never user accessible") 416 } 417} 418 419impl AddressRangeExt for Range<VirtualAddress> { 420 address_range_impl!(); 421 422 fn is_user_accessible(&self) -> bool { 423 if self.is_empty() { 424 return false; 425 } 426 let Some(end_minus_one) = self.end.checked_sub(1) else { 427 return false; 428 }; 429 430 self.start.is_user_accessible() && end_minus_one.is_user_accessible() 431 } 432} 433 434static_assertions::const_assert!(VirtualAddress(0xffffffc000000000).is_aligned_to(4096)); 435static_assertions::const_assert_eq!( 436 VirtualAddress(0xffffffc0000156e8).align_down(4096).0, 437 0xffffffc000015000 438); 439static_assertions::const_assert_eq!( 440 VirtualAddress(0xffffffc000000000) 441 .checked_align_up(4096) 442 .unwrap() 443 .0, 444 0xffffffc000000000 445); 446static_assertions::const_assert_eq!( 447 VirtualAddress(0xffffffc0000156e8) 448 .checked_align_up(4096) 449 .unwrap() 450 .0, 451 0xffffffc000016000 452);