summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boards/qemu-virt/qemu-virt.ld25
-rw-r--r--kernel/src/console.rs59
-rw-r--r--kernel/src/panic.rs2
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") }