Next Generation WASM Microkernel Operating System
at trap_handler 212 lines 5.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::tracing::color::{AnsiEscapes, Color, SetColor}; 9use core::cell::UnsafeCell; 10use core::fmt::{Arguments, Write}; 11use core::{cmp, fmt}; 12use spin::{ReentrantMutex, ReentrantMutexGuard}; 13use tracing_core::Metadata; 14 15pub trait MakeWriter<'a> { 16 type Writer: fmt::Write; 17 fn make_writer(&'a self) -> Self::Writer; 18 19 fn enabled(&self, meta: &Metadata<'_>) -> bool { 20 let _ = meta; 21 true 22 } 23 24 #[inline] 25 fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> { 26 if self.enabled(meta) { 27 return Some(self.make_writer()); 28 } 29 30 None 31 } 32 33 fn line_len(&self) -> usize { 34 120 35 } 36} 37 38#[derive(Debug, Copy, Clone, Eq, PartialEq)] 39pub enum IndentKind { 40 Event, 41 NewSpan, 42 Indent, 43} 44 45pub struct Writer<W: Write> { 46 pub(super) writer: W, 47 pub(super) indent: usize, 48 pub(super) max_line_len: usize, 49 pub(super) current_line: usize, 50} 51 52impl<W: Write> Writer<W> { 53 pub fn indent(&mut self, kind: IndentKind) -> fmt::Result { 54 self.write_indent(" ")?; 55 56 for i in 1..=self.indent { 57 let indent_str = match (i, kind) { 58 (i, IndentKind::Event) if i == self.indent => "", 59 _ => "", 60 }; 61 self.write_indent(indent_str)?; 62 } 63 64 if kind == IndentKind::NewSpan { 65 self.write_indent("")?; 66 } 67 68 Ok(()) 69 } 70 71 fn write_indent(&mut self, chars: &'static str) -> fmt::Result { 72 self.writer.write_str(chars)?; 73 self.current_line += chars.len(); 74 Ok(()) 75 } 76 77 fn write_newline(&mut self) -> fmt::Result { 78 // including width of the 16-character timestamp bit 79 self.writer.write_str(" ")?; 80 self.current_line = 3; 81 self.indent(IndentKind::Indent) 82 } 83 84 pub fn finish(&mut self) -> fmt::Result { 85 self.current_line = 0; 86 self.writer.write_char('\n') 87 } 88} 89 90impl<W> Write for Writer<W> 91where 92 W: Write, 93{ 94 fn write_str(&mut self, s: &str) -> fmt::Result { 95 let lines = s.split_inclusive('\n'); 96 for line in lines { 97 let mut line = line; 98 while self.current_line + line.len() >= self.max_line_len { 99 let offset = if let Some(last_ws) = line[..self.max_line_len - self.current_line] 100 .chars() 101 .rev() 102 .position(|c| c.is_whitespace()) 103 { 104 // found a nice whitespace to break on! 105 self.writer.write_str(&line[..last_ws])?; 106 last_ws 107 } else { 108 let offset = cmp::min(line.len(), self.max_line_len); 109 self.writer.write_str(&line[..offset])?; 110 offset 111 }; 112 113 self.writer.write_char('\n')?; 114 self.write_newline()?; 115 self.writer.write_char(' ')?; 116 self.current_line += 1; 117 line = &line[offset..]; 118 } 119 120 self.writer.write_str(line)?; 121 if line.ends_with('\n') { 122 self.write_newline()?; 123 self.writer.write_char(' ')?; 124 } 125 self.current_line += line.len(); 126 } 127 128 Ok(()) 129 } 130 131 fn write_char(&mut self, ch: char) -> fmt::Result { 132 self.writer.write_char(ch)?; 133 if ch == '\n' { 134 self.write_newline() 135 } else { 136 Ok(()) 137 } 138 } 139} 140 141impl<W> SetColor for Writer<W> 142where 143 W: Write + SetColor, 144{ 145 fn set_fg_color(&mut self, color: Color) { 146 self.writer.set_fg_color(color); 147 } 148 149 fn fg_color(&self) -> Color { 150 self.writer.fg_color() 151 } 152 153 fn set_bold(&mut self, bold: bool) { 154 self.writer.set_bold(bold); 155 } 156} 157 158impl<W: Write> Drop for Writer<W> { 159 fn drop(&mut self) { 160 let _ = self.finish(); 161 } 162} 163 164// Architecture-specific debug output implementation 165cfg_if::cfg_if! { 166 if #[cfg(target_arch = "riscv64")] { 167 type DebugStream = riscv::hio::HostStream; 168 169 fn new_debug_stream() -> DebugStream { 170 riscv::hio::HostStream::new_stdout() 171 } 172 } else { 173 compile_error!("Unsupported architecture for debug output"); 174 } 175} 176 177pub struct Semihosting(ReentrantMutex<UnsafeCell<DebugStream>>); 178pub struct SemihostingWriter<'a>(ReentrantMutexGuard<'a, UnsafeCell<DebugStream>>); 179 180impl Semihosting { 181 pub fn new() -> Self { 182 Self(ReentrantMutex::new(UnsafeCell::new(new_debug_stream()))) 183 } 184} 185 186impl<'a> MakeWriter<'a> for Semihosting { 187 type Writer = AnsiEscapes<SemihostingWriter<'a>>; 188 189 fn make_writer(&'a self) -> Self::Writer { 190 AnsiEscapes::new(SemihostingWriter(self.0.lock())) 191 } 192} 193 194impl Write for SemihostingWriter<'_> { 195 fn write_str(&mut self, s: &str) -> fmt::Result { 196 // Safety: Racy access to the HostStream is safe, at worst this produces interleaved debug output 197 let this = unsafe { &mut *self.0.get() }; 198 this.write_str(s) 199 } 200 201 fn write_char(&mut self, c: char) -> fmt::Result { 202 // Safety: Racy access to the HostStream is safe, at worst this produces interleaved debug output 203 let this = unsafe { &mut *self.0.get() }; 204 this.write_char(c) 205 } 206 207 fn write_fmt(&mut self, args: Arguments<'_>) -> fmt::Result { 208 // Safety: Racy access to the HostStream is safe, at worst this produces interleaved debug output 209 let this = unsafe { &mut *self.0.get() }; 210 this.write_fmt(args) 211 } 212}