Next Generation WASM Microkernel Operating System
at trap_handler 84 lines 2.9 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::ptr; 10use gimli::{Pointer, Register, RegisterRule, UnwindTableRow}; 11 12pub struct StoreOnStack; 13 14// gimli's MSRV doesn't allow const generics, so we need to pick a supported array size. 15const fn next_value(x: usize) -> usize { 16 let supported = [0, 1, 2, 3, 4, 8, 16, 32, 64, 128]; 17 let mut i = 0; 18 while i < supported.len() { 19 if supported[i] >= x { 20 return supported[i]; 21 } 22 i += 1; 23 } 24 192 25} 26 27impl<R: gimli::ReaderOffset> gimli::UnwindContextStorage<R> for StoreOnStack { 28 type Rules = [(Register, RegisterRule<R>); next_value(arch::MAX_REG_RULES)]; 29 type Stack = [UnwindTableRow<R, Self>; 2]; 30} 31 32pub unsafe fn get_unlimited_slice<'a>(start: *const u8) -> &'a [u8] { 33 // Create the largest possible slice for this address. 34 let start = start as usize; 35 let end = start.saturating_add(isize::MAX as usize); 36 let len = end - start; 37 // Safety: caller has to ensure start is valid 38 unsafe { core::slice::from_raw_parts(start as *const u8, len) } 39} 40 41pub unsafe fn deref_pointer(ptr: Pointer) -> u64 { 42 match ptr { 43 Pointer::Direct(x) => x, 44 // Safety: caller has to ensure `ptr` is valid 45 Pointer::Indirect(x) => unsafe { *(x as *const u64) }, 46 } 47} 48 49// Helper function to turn `save_context` which takes function pointer to a closure-taking function. 50pub fn with_context<T, F: FnOnce(&mut arch::Registers, usize) -> T>(f: F) -> T { 51 use core::mem::ManuallyDrop; 52 53 union Data<T, F> { 54 f: ManuallyDrop<F>, 55 t: ManuallyDrop<T>, 56 } 57 58 extern "C" fn delegate<T, F: FnOnce(&mut arch::Registers, usize) -> T>( 59 regs: &mut arch::Registers, 60 ptr: *mut (), 61 ) { 62 // SAFETY: This function is called exactly once; it extracts the function, call it and 63 // store the return value. This function is `extern "C"` so we don't need to worry about 64 // unwinding past it. 65 unsafe { 66 let data = &mut *ptr.cast::<Data<T, F>>(); 67 68 // Due to the way we capture the register context the effective program counter for unwinding 69 // is the return address. TODO explain why 70 let ip = regs[arch::RA]; 71 72 let t = ManuallyDrop::take(&mut data.f)(regs, ip); 73 data.t = ManuallyDrop::new(t); 74 } 75 } 76 77 let mut data = Data { 78 f: ManuallyDrop::new(f), 79 }; 80 arch::save_context(delegate::<T, F>, ptr::addr_of_mut!(data).cast()); 81 82 // Safety: `delegate` places the closure return value into `data.t` 83 unsafe { ManuallyDrop::into_inner(data.t) } 84}