From 53b967c826d1cb6463a1a7aa5f869ea2646d3835 Mon Sep 17 00:00:00 2001 From: Berkus Decker Date: Sat, 23 Feb 2019 22:59:41 +0200 Subject: [PATCH] [sq] add generic console --- src/devices/console.rs | 144 +++++++++++++++++++++++++++++++++++++++++ src/devices/mod.rs | 3 + src/macros.rs | 49 ++++++++++++++ src/main.rs | 41 ++++++++++-- 4 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 src/devices/console.rs create mode 100644 src/devices/mod.rs create mode 100644 src/macros.rs diff --git a/src/devices/console.rs b/src/devices/console.rs new file mode 100644 index 0000000..2f1063f --- /dev/null +++ b/src/devices/console.rs @@ -0,0 +1,144 @@ +/* + * MIT License + * + * Copyright (c) 2019 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use crate::platform; +use core::fmt; + +/// A trait that must be implemented by devices that are candidates for the +/// global console. +#[allow(unused_variables)] +pub trait ConsoleOps: Drop { + fn putc(&self, c: char) {} + fn puts(&self, string: &str) {} + fn getc(&self) -> char { + ' ' + } + fn flush(&self) {} +} + +/// A dummy console that just ignores its inputs. +pub struct NullConsole; +impl Drop for NullConsole { + fn drop(&mut self) {} +} +impl ConsoleOps for NullConsole {} + +/// Possible outputs which the console can store. +pub enum Output { + None(NullConsole), + MiniUart(platform::MiniUart), + PL011Uart(platform::PL011Uart), +} + +impl From for Output { + fn from(instance: platform::MiniUart) -> Self { + Output::MiniUart(instance) + } +} + +impl From for Output { + fn from(instance: platform::PL011Uart) -> Self { + Output::PL011Uart(instance) + } +} + +pub struct Console { + output: Output, +} + +impl Console { + pub const fn new() -> Console { + Console { + output: Output::None(NullConsole {}), + } + } + + #[inline(always)] + fn current_ptr(&self) -> &dyn ConsoleOps { + match &self.output { + Output::None(i) => i, + Output::MiniUart(i) => i, + Output::PL011Uart(i) => i, + } + } + + /// Overwrite the current output. The old output will go out of scope and + /// it's Drop function will be called. + pub fn replace_with(&mut self, x: Output) { + self.current_ptr().flush(); + + self.output = x; + } + + /// A command prompt. Currently does nothing. + pub fn command_prompt(&self) -> ! { + self.puts("\n$> "); + + let mut input; + loop { + input = self.getc(); + + if input == '\n' { + self.puts("\n$> ") + } else { + self.putc(input); + } + } + } +} + +impl Drop for Console { + fn drop(&mut self) {} +} + +/// Dispatch the respective function to the currently stored output device. +impl ConsoleOps for Console { + fn putc(&self, c: char) { + self.current_ptr().putc(c); + } + + fn puts(&self, string: &str) { + self.current_ptr().puts(string); + } + + fn getc(&self) -> char { + self.current_ptr().getc() + } + + fn flush(&self) { + self.current_ptr().flush() + } +} + +/// Implementing this trait enables usage of the format_args! macros, which in +/// turn are used to implement the kernel's print! and println! macros. +/// +/// See src/macros.rs. +impl fmt::Write for Console { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.current_ptr().puts(s); + + Ok(()) + } +} diff --git a/src/devices/mod.rs b/src/devices/mod.rs new file mode 100644 index 0000000..8cbb3f9 --- /dev/null +++ b/src/devices/mod.rs @@ -0,0 +1,3 @@ +pub mod console; + +pub use console::{Console, ConsoleOps}; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..28280be --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,49 @@ +/* + * MIT License + * + * Copyright (c) 2019 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use core::fmt; + +// https://doc.rust-lang.org/src/std/macros.rs.html +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); +} + +// https://doc.rust-lang.org/src/std/macros.rs.html +#[macro_export] +macro_rules! println { + () => (print!("\n")); + ($($arg:tt)*) => ({ + $crate::macros::_print(format_args_nl!($($arg)*)); + }) +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + + crate::CONSOLE.lock(|c| { + c.write_fmt(args).unwrap(); + }) +} diff --git a/src/main.rs b/src/main.rs index a3d6308..7c2f891 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ #![no_main] #![feature(asm)] #![feature(const_fn)] +#![feature(format_args_nl)] #![feature(lang_items)] #![feature(ptr_internals)] // until we mark with PhantomData instead? #![feature(core_intrinsics)] @@ -25,6 +26,8 @@ extern crate rlibc; #[macro_use] pub mod arch; pub use arch::*; +pub mod macros; +pub use macros::*; pub mod platform; mod write_to; @@ -41,15 +44,41 @@ use platform::{ // Actual interfaces to call these syscalls are in vesper-user (similar to libsel4) // pub mod vesper; -- exported from vesper-user +/// The global console. Output of the print! and println! macros. +static CONSOLE: sync::NullLock = sync::NullLock::new(devices::Console::new()); + // Kernel entry point // arch crate is responsible for calling this fn kmain() -> ! { - // let mut uart = MiniUart::new(); - // uart.init(); - // Crashes if uncommenting next line: vvv - // writeln!(uart, "Hey there, mini uart talking!"); - // uart.puts("Hey there, mini uart talking!\n"); // shall this work though? - // uart.write_str(); // shall this? + let gpio = GPIO::new_default(); + + let uart = platform::MiniUart::new_default(); + uart.init(&gpio); + CONSOLE.lock(|c| { + // Moves uart into the global CONSOLE. It is not accessible + // anymore for the remaining parts of kernel_entry(). + c.replace_with(uart.into()); + }); + + let uart = platform::PL011Uart::new_default(); + + let mut mbox = platform::mailbox::Mailbox::new(); + + match uart.init(&mut mbox, &gpio) { + Ok(_) => { + CONSOLE.lock(|c| { + // Moves uart into the global CONSOLE. It is not accessible + // anymore for the remaining parts of kernel_entry(). + c.replace_with(uart.into()); + }); + } + Err(_) => endless_sleep(), + } + + println!("\n[0] UART is live!"); + + println!("Hello, world!"); + unsafe { mmu::init();