mod uart;
mod heap;
mod trap;
+mod uart_console;
+mod monitor;
use core::arch::asm;
use core::arch::global_asm;
extern crate alloc;
use alloc::boxed::Box;
+use alloc::sync::Arc;
use trap::TrapFrame;
use uart::Uart;
use uart::SERIAL_BASE;
extern "C" fn entry() -> ! {
// Init serial console
use crate::uart;
+ use crate::uart_console::UartConsole;
+ use crate::monitor::Monitor;
use core::arch::asm;
uart::init_uart();
println!("UART init complete");
// Safety: initialize once (and that's done now)
unsafe { heap::init() };
+
+ // Declared outside the unsafe block for scoping reasons
+ // we'll start the console ouside the unsafe block
+ let console_main_handle: Arc<UartConsole>;
unsafe {
// Load the trap frame for interrupt handling
// This must be done here rather than in the _start function because the _start function is naked and
// we can't use keywords other than const and sym
- let trap_frame = Box::new(TrapFrame::new(Uart::new(SERIAL_BASE)));
+ let console = UartConsole::new::<Monitor>(Uart::new(SERIAL_BASE));
+ console_main_handle = console.clone();
+ let trap_frame = Box::new(TrapFrame::new(console));
asm!(
// Turn on floating point support
"li t0, 1 << 13",
trap::init_interrupts();
}
+ println!("Going idle!");
println!("Kernel init complete");
+ console_main_handle.start();
- println!("Going idle!");
unsafe { asm!("1:", "wfi", "j 1b") } // Hopefully wfi will make this less busy (1b is
// 'backwards to 1:'
loop {} // Definitely not gonna happen
--- /dev/null
+use crate::uart_console::UartConsole;
+use crate::uart_console::ConsoleListener;
+use alloc::string::String;
+use alloc::sync::Arc;
+use alloc::sync::Weak;
+
+pub struct Monitor {
+ console: Weak<UartConsole>,
+}
+
+impl ConsoleListener for Monitor {
+ fn new(uart_console: Weak<UartConsole>) -> Arc<Self> {
+ Arc::new_cyclic(|_self_ref| Self {
+ console: uart_console,
+ })
+ }
+
+ fn new_input_line(&self, s: &String) {
+ let _ = self.console.upgrade().unwrap().write_str("You said: ");
+ let _ = self.console.upgrade().unwrap().writeln(s);
+ self.print_prompt();
+ }
+
+ fn init(&self) { self.print_prompt(); }
+}
+
+impl Monitor {
+
+
+ pub fn print_prompt(&self) {
+ let _ = self.console.upgrade().unwrap().write_str("(*)");
+ }
+}
-use crate::uart::uart_read;
-use crate::uart::Uart;
+use crate::uart_console::UartConsole;
use core::arch::asm;
use plic::Plic;
+use alloc::sync::Arc;
#[repr(C)]
//#[derive(Clone, Copy)]
// We're also skipping this; it's not needed when we've got only one hart and besides
// that we're in machine mode.
//pub hartid: usize, // 528
- pub uart: Uart,
+ pub uart_handler: Arc<UartConsole>,
}
impl TrapFrame {
- pub fn new(u: Uart) -> Self {
+ pub fn new(u: Arc<UartConsole>) -> Self {
TrapFrame {
regs: [0; 32],
fregs: [0; 32],
- uart: u
+ uart_handler: u
}
}
}
let plic = get_plic();
match plic.claim(0) {
Some(int) => {
- let data = frame.uart.read();
- frame.uart.write(data);
+ frame.uart_handler.data_pending();
plic.complete(0, int);
}
_ => {
use spinning_top::Spinlock;
use uart_16550::MmioSerialPort;
-
+use core::fmt::Write;
/*
* The goal here is to produce a console logging singleton
* that can then be accessed through print! and println!
*/
pub struct Uart {
- serial_port: MmioSerialPort,
+ serial_port: Spinlock<MmioSerialPort>,
}
impl Uart {
pub unsafe fn new(base: usize) -> Self {
- let mut serial_port = MmioSerialPort::new(base);
- serial_port.init();
- Uart { serial_port }
+ let mut serial = MmioSerialPort::new(base);
+ serial.init();
+ return Uart { serial_port: Spinlock::new(MmioSerialPort::new(base)) }
}
- pub fn write(&mut self, data: u8) {
- self.serial_port.send(data);
+ pub fn write(&self, data: u8) {
+ self.serial_port.lock().send(data);
}
- pub fn read(&mut self) -> u8 {
- return self.serial_port.receive();
+ pub fn read(&self) -> u8 {
+ return self.serial_port.lock().receive();
+ }
+ pub fn write_str_immutable(&self, s: &str) -> core::fmt::Result {
+ return self.serial_port.lock().write_str(s);
}
}
impl core::fmt::Write for Uart {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
- return self.serial_port.write_str(s);
+ return self.write_str_immutable(s);
}
}
--- /dev/null
+use crate::uart::Uart;
+use alloc::string::String;
+use alloc::sync::{Arc, Weak};
+use alloc::vec::Vec;
+use core::fmt::Result;
+use spinning_top::Spinlock;
+
+pub trait ConsoleListener: 'static {
+ fn new(console: Weak<UartConsole>) -> Arc<Self>
+ where
+ Self: Sized;
+ fn new_input_line(&self, s: &String);
+ fn init(&self);
+}
+
+pub struct UartConsole {
+ uart: Uart,
+ buf: Spinlock<Vec<u8>>,
+ listener: Arc<dyn ConsoleListener>,
+}
+
+impl UartConsole {
+ pub fn new<T: ConsoleListener>(u: Uart) -> Arc<Self> {
+ let retval = Arc::new_cyclic(|self_ref| {
+ let monitor = T::new(self_ref.clone());
+ let retval = Self {
+ uart: u,
+ buf: Spinlock::new(Vec::new()),
+ listener: monitor,
+ };
+ return retval;
+ });
+ return retval;
+ }
+
+ pub fn data_pending(&self) {
+ let data = self.uart.read();
+ let mut buf = self.buf.lock();
+ match data {
+ // Backspace; drop last character
+ b'\x08' => {
+ buf.pop();
+ }
+ b'\r' => {
+ buf.push(data);
+ buf.push(b'\n');
+ self.uart.write(data);
+ self.uart.write(b'\n');
+ let line = String::from_utf8_lossy(buf.as_slice()).into_owned();
+ self.listener.new_input_line(&line);
+ buf.clear();
+ }
+ _ => {
+ buf.push(data);
+ self.uart.write(data);
+ }
+ }
+ }
+
+ pub fn write_str(&self, s: &str) -> Result {
+ return self.uart.write_str_immutable(s);
+ }
+
+ pub fn writeln(&self, s: &str) -> Result {
+ self.uart.write_str_immutable(s)?;
+ return self.uart.write_str_immutable("\r\n");
+ }
+
+ pub fn start(&self) {
+ self.listener.init();
+ }
+}