Next Generation WASM Microkernel Operating System
at trap_handler 149 lines 4.5 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::mem::{AddressSpace, Mmap, VirtualAddress}; 9use crate::wasm::TrapKind; 10use crate::wasm::compile::{CompiledFunctionInfo, FunctionLoc}; 11use crate::wasm::indices::{DefinedFuncIndex, ModuleInternedTypeIndex}; 12use crate::wasm::vm::{MmapVec, VMWasmCallFunction}; 13use alloc::vec; 14use alloc::vec::Vec; 15use anyhow::Context; 16use core::ptr::NonNull; 17use core::range::Range; 18use core::slice; 19use cranelift_entity::PrimaryMap; 20 21#[derive(Debug)] 22pub struct CodeObject { 23 mmap: Mmap, 24 len: usize, 25 published: bool, 26 27 trap_offsets: Vec<u32>, 28 traps: Vec<TrapKind>, 29 wasm_to_host_trampolines: Vec<(ModuleInternedTypeIndex, FunctionLoc)>, 30 function_info: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo>, 31} 32 33impl CodeObject { 34 pub fn empty() -> Self { 35 Self { 36 mmap: Mmap::new_empty(), 37 len: 0, 38 published: false, 39 trap_offsets: vec![], 40 traps: vec![], 41 wasm_to_host_trampolines: vec![], 42 function_info: PrimaryMap::new(), 43 } 44 } 45 46 pub fn new( 47 mmap_vec: MmapVec<u8>, 48 trap_offsets: Vec<u32>, 49 traps: Vec<TrapKind>, 50 wasm_to_host_trampolines: Vec<(ModuleInternedTypeIndex, FunctionLoc)>, 51 function_info: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo>, 52 ) -> Self { 53 let (mmap, size) = mmap_vec.into_parts(); 54 Self { 55 mmap, 56 len: size, 57 published: false, 58 trap_offsets, 59 traps, 60 wasm_to_host_trampolines, 61 function_info, 62 } 63 } 64 65 pub fn publish(&mut self, aspace: &mut AddressSpace) -> crate::Result<()> { 66 debug_assert!(!self.published); 67 self.published = true; 68 69 if self.mmap.is_empty() { 70 tracing::warn!("Compiled module has no code to publish"); 71 return Ok(()); 72 } 73 74 // Switch the executable portion from readonly to read/execute. 75 self.mmap 76 .make_executable(aspace, true) 77 .context("Failed to mark mmap'ed region as executable")?; 78 79 Ok(()) 80 } 81 82 pub fn text(&self) -> &[u8] { 83 let base = self.mmap.as_ptr(); 84 if base.is_null() { 85 &[] 86 } else { 87 // Safety: we have checked the slice is valid (both above and through construction) 88 unsafe { slice::from_raw_parts(self.mmap.as_ptr(), self.len) } 89 } 90 } 91 92 #[inline] 93 pub fn text_range(&self) -> Range<VirtualAddress> { 94 let start = self.mmap.range().start; 95 96 Range::from(start..start.checked_add(self.len).unwrap()) 97 } 98 99 pub fn resolve_function_loc(&self, func_loc: FunctionLoc) -> usize { 100 let text_range = self.text_range(); 101 let addr = text_range.start.get() + func_loc.start as usize; 102 103 tracing::trace!( 104 "resolve_function_loc {func_loc:?}, text {:?} => {:?}", 105 self.mmap.as_ptr(), 106 addr, 107 ); 108 109 // Assert the function location actually lies in our text section 110 debug_assert!( 111 text_range.start.get() <= addr 112 && text_range.end.get() 113 >= addr.saturating_add(usize::try_from(func_loc.length).unwrap()) 114 ); 115 116 addr 117 } 118 119 pub fn lookup_trap_code(&self, text_offset: usize) -> Option<TrapKind> { 120 let text_offset = u32::try_from(text_offset).unwrap(); 121 122 let index = self 123 .trap_offsets 124 .binary_search_by_key(&text_offset, |val| *val) 125 .ok()?; 126 127 Some(self.traps[index]) 128 } 129 130 pub(crate) fn function_info(&self) -> &PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo> { 131 &self.function_info 132 } 133 134 pub fn wasm_to_host_trampoline( 135 &self, 136 sig: ModuleInternedTypeIndex, 137 ) -> NonNull<VMWasmCallFunction> { 138 let Ok(idx) = self 139 .wasm_to_host_trampolines 140 .binary_search_by_key(&sig, |entry| entry.0) 141 else { 142 panic!("missing trampoline for {sig:?}") 143 }; 144 145 let (_, loc) = self.wasm_to_host_trampolines[idx]; 146 147 NonNull::new(self.resolve_function_loc(loc) as *mut VMWasmCallFunction).unwrap() 148 } 149}