diff options
-rw-r--r-- | boards/qemu-virt/qemu-virt.ld | 25 | ||||
-rw-r--r-- | kernel/src/console.rs | 59 | ||||
-rw-r--r-- | kernel/src/panic.rs | 2 |
3 files changed, 63 insertions, 23 deletions
diff --git a/boards/qemu-virt/qemu-virt.ld b/boards/qemu-virt/qemu-virt.ld index 9673637..1b9ff79 100644 --- a/boards/qemu-virt/qemu-virt.ld +++ b/boards/qemu-virt/qemu-virt.ld @@ -3,27 +3,34 @@ ENTRY(_start) SECTIONS { . = 0x80000000; + + PROVIDE(kernel_start = .); .text : { *(.text.start) *(.text .text.*) - . = ALIGN(0x1000); } - + . = ALIGN(0x1000); .rodata : { - *(.rodata) - . = ALIGN(0x1000); + *(.srodata .srodata.*) + . = ALIGN(16); + *(.rodata .rodata.*) } - + . = ALIGN(0x1000); .data : { - *(.data) + *(.sdata .sdata.*) + . = ALIGN(16); + *(.data .data.*) + . = ALIGN(16); } .bss : { - *(.bss) - . = ALIGN(0x1000); + *(.sbss .sbss.*) + . = ALIGN(16); + *(.bss .bss.*) } - + . = ALIGN(0x1000); .hart0_initial_stack : { . += 0x1000; PROVIDE(hart0_initial_stack_top = .); } + PROVIDE(kernel_end = .); } diff --git a/kernel/src/console.rs b/kernel/src/console.rs index 7364807..626edef 100644 --- a/kernel/src/console.rs +++ b/kernel/src/console.rs @@ -10,11 +10,21 @@ use spin::Mutex; /// The console singleton. static CONSOLE: Console = Console(Mutex::new(ConsoleInner::new())); +/// A function pointer that may be set by the platform-specific initialization +/// code **before** hart0_boot is called. It must never be modified after that +/// point. +/// +/// If present, this function is called after every write to the console with +/// the buffer contents, after which the console buffer is cleared. +#[no_mangle] +static mut CONSOLE_STRICT_FLUSH: Option<unsafe extern "C" fn(*const u8, usize)> = None; + /// Initializes the console subsystem. This must be done before any logging is /// performed, and must /// only be called once. pub fn init() { log::set_logger(&CONSOLE).expect("failed to set logger"); + log::set_max_level(log::LevelFilter::Trace); } /// The point of interaction with the console. This is a singleton; see @@ -31,7 +41,8 @@ impl Log for Console { return; } - let body = |line| { + let mut inner = self.0.lock(); + let mut body = |line| { let level = match record.level() { log::Level::Error => "ERR", log::Level::Warn => "WRN", @@ -45,15 +56,15 @@ impl Log for Console { let result = if args.as_str() == Some("") { // A silly convenience, but don't write the extra space if we're // not going to write anything anyways. - writeln!(self.0.lock(), "[{level}][{file}:{line}]") + writeln!(inner, "[{level}][{file}:{line}]") } else { - writeln!(self.0.lock(), "[{level}][{file}:{line}] {args}") + writeln!(inner, "[{level}][{file}:{line}] {args}") }; - // Since the fmt::Write impl for ConsoleInner has a contract - // promising that it won't ever return an error, this should be - // unreachable. - result.expect("ConsoleInner failed to write"); + // UNWRAP: Since the fmt::Write impl for ConsoleInner has a + // contract promising that it won't ever return an error, this + // should be unreachable. + result.unwrap(); }; // Some contortions to avoid running afoul of the lifetime requirements @@ -62,11 +73,22 @@ impl Log for Console { Some(line) => body(format_args!("{line}")), None => body(format_args!("???")), } - } - fn flush(&self) { - todo!() + // Check for a strict flush handler. + // + // SAFETY: We document the function that should be called, as well as + // the requirement that the function pointer cannot be concurrently + // modified. + unsafe { + if let Some(console_strict_flush) = CONSOLE_STRICT_FLUSH { + let buffer = inner.buffer(); + console_strict_flush(buffer.as_ptr(), buffer.len()); + inner.clear_buffer(); + } + } } + + fn flush(&self) {} } /// The internals of the console. This is put behind a lock. @@ -92,6 +114,20 @@ impl<const BUFFER_SIZE: usize> ConsoleInner<BUFFER_SIZE> { } } + /// Returns a reference to the filled portion of the buffer. + fn buffer<'a>(&'a self) -> &'a [u8] { + &self.buffer[..self.len] + } + + /// Marks the buffer as cleared. + fn clear_buffer(&mut self) { + self.len = 0; + if self.has_overflowed { + self.has_overflowed = false; + log::warn!("console buffer overflowed"); + } + } + /// Writes bytes to the buffer, wrapping and setting the flag on overflow. fn write(&mut self, bytes: &[u8]) { // Check if there's enough room for the contents of the buffer. @@ -174,6 +210,3 @@ fn console_handles_overflow_larger_than_buffer() { assert_eq!(console.len, 8); assert_eq!(console.has_overflowed, true); } - -/// The trait that a console backend must implement. -pub trait ConsoleBackend {} diff --git a/kernel/src/panic.rs b/kernel/src/panic.rs index 9aabb01..aa7df78 100644 --- a/kernel/src/panic.rs +++ b/kernel/src/panic.rs @@ -4,7 +4,7 @@ use core::{arch::asm, panic::PanicInfo}; #[panic_handler] fn panic(info: &PanicInfo) -> ! { - log::error!("{info:?}"); + log::error!("{info}"); loop { unsafe { asm!("wfi") } |