Next Generation WASM Microkernel Operating System
at trap_handler 235 lines 7.2 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::error::Error; 9use crate::{Header, Node}; 10 11#[derive(Clone)] 12pub struct Parser<'dt> { 13 stream: Stream<'dt>, 14 pub strings: StringsBlock<'dt>, 15 pub structs: StructsBlock<'dt>, 16} 17 18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 19#[repr(transparent)] 20pub struct BigEndianU32(pub(crate) u32); 21 22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 23#[repr(transparent)] 24pub struct BigEndianToken(pub(crate) BigEndianU32); 25 26pub(crate) struct Stream<'dt>(&'dt [u32]); 27 28#[derive(Debug, Clone, Copy)] 29#[repr(transparent)] 30pub struct StringsBlock<'dt>(pub(crate) &'dt [u8]); 31 32#[derive(Debug, Clone, Copy)] 33#[repr(transparent)] 34pub struct StructsBlock<'dt>(pub(crate) &'dt [u32]); 35 36impl<'dt> Parser<'dt> { 37 pub fn new(data: &'dt [u32], strings: StringsBlock<'dt>, structs: StructsBlock<'dt>) -> Self { 38 Self { 39 stream: Stream::new(data), 40 strings, 41 structs, 42 } 43 } 44 45 pub fn data(&self) -> &'dt [u32] { 46 self.stream.0 47 } 48 49 pub fn byte_data(&self) -> &'dt [u8] { 50 // SAFETY: it is always valid to cast a `u32` to 4 `u8`s 51 unsafe { 52 core::slice::from_raw_parts( 53 self.stream.0.as_ptr().cast::<u8>(), 54 self.stream.0.len() * 4, 55 ) 56 } 57 } 58 59 pub fn advance_token(&mut self) -> Result<BigEndianToken, Error> { 60 loop { 61 match BigEndianToken( 62 self.stream 63 .advance() 64 .map(BigEndianU32) 65 .ok_or(Error::UnexpectedEof)?, 66 ) { 67 BigEndianToken::NOP => continue, 68 token @ (BigEndianToken::BEGIN_NODE 69 | BigEndianToken::END_NODE 70 | BigEndianToken::PROP 71 | BigEndianToken::END) => break Ok(token), 72 t => break Err(Error::InvalidToken(t)), 73 } 74 } 75 } 76 77 pub(crate) fn peek_token(&self) -> Result<BigEndianToken, Error> { 78 self.clone().advance_token() 79 } 80 81 pub fn advance_u32(&mut self) -> Result<BigEndianU32, Error> { 82 self.stream 83 .advance() 84 .map(BigEndianU32) 85 .ok_or(Error::UnexpectedEof) 86 } 87 88 pub fn advance_cstr(&mut self) -> Result<&'dt core::ffi::CStr, Error> { 89 // SAFETY: It is safe to reinterpret the stream data to a smaller integer size 90 let bytes = unsafe { 91 core::slice::from_raw_parts( 92 self.stream.0.as_ptr().cast::<u8>(), 93 self.stream.0.len() * 4, 94 ) 95 }; 96 let cstr = core::ffi::CStr::from_bytes_until_nul(bytes)?; 97 98 // Round up to the next multiple of 4, if necessary 99 let skip = ((cstr.to_bytes_with_nul().len() + 3) & !3) / 4; 100 self.stream.skip_many(skip); 101 102 Ok(cstr) 103 } 104 105 pub fn advance_aligned(&mut self, n: usize) { 106 // Round up to the next multiple of 4, if necessary 107 let skip = ((n + 3) & !3) / 4; 108 self.stream.skip_many(skip); 109 } 110 111 pub fn parse_header(&mut self) -> Result<Header, Error> { 112 let magic = self.advance_u32()?.to_ne(); 113 let total_size = self.advance_u32()?.to_ne(); 114 let struct_offset = self.advance_u32()?.to_ne(); 115 let strings_offset = self.advance_u32()?.to_ne(); 116 let memory_reserve_map_offset = self.advance_u32()?.to_ne(); 117 let version = self.advance_u32()?.to_ne(); 118 let last_compatible_version = self.advance_u32()?.to_ne(); 119 let boot_cpuid = self.advance_u32()?.to_ne(); 120 let strings_size = self.advance_u32()?.to_ne(); 121 let structs_size = self.advance_u32()?.to_ne(); 122 123 Ok(Header { 124 magic, 125 total_size, 126 structs_offset: struct_offset, 127 strings_offset, 128 memory_reserve_map_offset, 129 version, 130 last_compatible_version, 131 boot_cpuid, 132 strings_size, 133 structs_size, 134 }) 135 } 136 137 pub fn parse_root(&mut self) -> Result<Node<'dt>, Error> { 138 match self.advance_token()? { 139 BigEndianToken::BEGIN_NODE => {} 140 t => return Err(Error::UnexpectedToken(t)), 141 } 142 143 let byte_data = self.byte_data(); 144 match byte_data 145 .get(byte_data.len() - 4..) 146 .map(<[u8; 4]>::try_from) 147 { 148 Some(Ok(data @ [_, _, _, _])) => { 149 match BigEndianToken(BigEndianU32(u32::from_ne_bytes(data))) { 150 BigEndianToken::END => {} 151 t => return Err(Error::UnexpectedToken(t)), 152 } 153 } 154 _ => return Err(Error::UnexpectedEof), 155 } 156 157 // advance past this nodes name 158 let name = self.advance_cstr()?; 159 160 let starting_data = self.data(); 161 162 Ok(Node { 163 name, 164 raw: &starting_data[..starting_data.len() - 1], 165 strings: self.strings, 166 structs: self.structs, 167 }) 168 } 169 170 pub fn parse_raw_property(&mut self) -> Result<(usize, &'dt [u8]), Error> { 171 match self.advance_token()? { 172 BigEndianToken::PROP => { 173 // Properties are in the format: <data len> <name offset> <data...> 174 let len = usize::try_from(self.advance_u32()?.to_ne())?; 175 let name_offset = usize::try_from(self.advance_u32()?.to_ne())?; 176 let data = self.byte_data().get(..len).ok_or(Error::UnexpectedEof)?; 177 178 self.advance_aligned(data.len()); 179 180 Ok((name_offset, data)) 181 } 182 t => Err(Error::UnexpectedToken(t)), 183 } 184 } 185} 186 187impl BigEndianU32 { 188 pub const fn from_ne(n: u32) -> Self { 189 Self(n.to_be()) 190 } 191 192 pub const fn to_ne(self) -> u32 { 193 u32::from_be(self.0) 194 } 195} 196 197impl BigEndianToken { 198 pub const BEGIN_NODE: Self = Self(BigEndianU32::from_ne(1)); 199 pub const END_NODE: Self = Self(BigEndianU32::from_ne(2)); 200 pub const PROP: Self = Self(BigEndianU32::from_ne(3)); 201 pub const NOP: Self = Self(BigEndianU32::from_ne(4)); 202 pub const END: Self = Self(BigEndianU32::from_ne(9)); 203} 204 205impl<'a> Stream<'a> { 206 #[inline(always)] 207 pub(crate) fn new(data: &'a [u32]) -> Self { 208 Self(data) 209 } 210 211 #[inline(always)] 212 pub(crate) fn advance(&mut self) -> Option<u32> { 213 let ret = *self.0.first()?; 214 self.0 = self.0.get(1..)?; 215 Some(ret) 216 } 217 218 pub(crate) fn skip_many(&mut self, n: usize) { 219 self.0 = self.0.get(n..).unwrap_or_default(); 220 } 221} 222 223impl Clone for Stream<'_> { 224 fn clone(&self) -> Self { 225 Self(self.0) 226 } 227} 228 229impl<'a> StringsBlock<'a> { 230 pub fn offset_at(self, offset: usize) -> Result<&'a str, Error> { 231 core::ffi::CStr::from_bytes_until_nul(self.0.get(offset..).ok_or(Error::UnexpectedEof)?)? 232 .to_str() 233 .map_err(Into::into) 234 } 235}