diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index c8cff9f..bdd0b21 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -2,8 +2,12 @@ extern crate bcm2837; +pub mod serial; + pub fn init() { - // TODO - bcm2837::gpio::Gpio::new(14).set_gpio_pd(0); - bcm2837::gpio::Gpio::new(15).set_gpio_pd(0); + assert_has_not_been_called!("board::init must be called only once"); + + serial::SERIAL_PORT.lock().init(); + + println!("Hello Raspberry Pi!"); } diff --git a/kernel/src/arch/aarch64/board/raspi3/serial.rs b/kernel/src/arch/aarch64/board/raspi3/serial.rs new file mode 100644 index 0000000..b6c29f7 --- /dev/null +++ b/kernel/src/arch/aarch64/board/raspi3/serial.rs @@ -0,0 +1,73 @@ +use super::bcm2837::mini_uart::MiniUart; + +use core::fmt; +use spin::Mutex; + +/// Struct to get a global SerialPort interface +pub struct SerialPort { + mu: Option, +} + +pub trait SerialRead { + fn receive(&mut self) -> u8; +} + +impl SerialPort { + /// Creates a new instance of `SerialPort`. + const fn new() -> SerialPort { + SerialPort { mu: None } + } + + /// Init a newly created SerialPort, can only be called once. + pub fn init(&mut self) { + assert_has_not_been_called!("SerialPort::init must be called only once"); + self.mu = Some(MiniUart::new()); + } + + /// Writes the byte `byte` to the UART device. + pub fn write_byte(&mut self, byte: u8) { + match &mut self.mu { + Some(mu) => mu.write_byte(byte), + None => panic!("SerialPort is not initialized"), + } + } + + /// Reads a byte from the UART device, blocking until a byte is available. + pub fn read_byte(&mut self) -> u8 { + match &mut self.mu { + Some(mu) => return mu.read_byte(), + None => panic!("SerialPort is not initialized"), + } + } +} + +impl SerialRead for SerialPort { + fn receive(&mut self) -> u8 { + self.read_byte() + } +} + +impl fmt::Write for SerialPort { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + match byte { + // Backspace + b'\x7f' => { + self.write_byte(b'\x08'); + self.write_byte(b' '); + self.write_byte(b'\x08'); + } + // Return + b'\n' => { + self.write_byte(b'\r'); + self.write_byte(b'\n'); + } + // Others + _ => self.write_byte(byte), + } + } + Ok(()) + } +} + +pub static SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); diff --git a/kernel/src/arch/aarch64/boot/boot.S b/kernel/src/arch/aarch64/boot/boot.S index ab0601c..974d6ed 100644 --- a/kernel/src/arch/aarch64/boot/boot.S +++ b/kernel/src/arch/aarch64/boot/boot.S @@ -55,6 +55,15 @@ switch_to_el1: movk x0, #0x8000, lsl #16 msr hcr_el2, x0 + + # don't trap accessing SVE registers (ref: D10.2.30) + msr cptr_el2, xzr + + # enable floating point and SVE (SIMD) (bits 20, 21) (ref: D10.2.29) + mrs x0, cpacr_el1 + orr x0, x0, #(0x3 << 20) + msr cpacr_el1, x0 + # Set SCTLR to known state (RES1: 11, 20, 22, 23, 28, 29) (ref: D10.2.100) mov x0, #0x0800 movk x0, #0x30d0, lsl #16 diff --git a/kernel/src/arch/aarch64/io.rs b/kernel/src/arch/aarch64/io.rs index 70f4035..5e5a645 100644 --- a/kernel/src/arch/aarch64/io.rs +++ b/kernel/src/arch/aarch64/io.rs @@ -1,13 +1,12 @@ //! Serial driver for aarch64. -use core::fmt::{Arguments}; +use core::fmt::{Arguments, Write}; +use super::board::serial::{SerialRead, SERIAL_PORT}; -/// TODO pub fn getchar() -> char { - unimplemented!() + SERIAL_PORT.lock().receive() as char } -/// TODO -pub fn putfmt(fmt: Arguments<'_>) { - unimplemented!() +pub fn putfmt(fmt: Arguments) { + SERIAL_PORT.lock().write_fmt(fmt).unwrap() } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 0f66365..0dfddc3 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -13,21 +13,33 @@ pub mod board; /// The entry point of kernel #[no_mangle] // don't mangle the name of this function pub extern "C" fn rust_main() -> ! { - // Init board. + // Init board to enable serial port. board::init(); - println!("Hello ARM64!"); - // First init log mod, so that we can print log info. - // ::logging::init(); - // Init trap handling. - // interrupt::init(); - // Init physical memory management and heap. - // memory::init(); - // Now heap is available - // timer::init(); + ::logging::init(); + + loop { + print!(">> "); + loop { + let c = io::getchar(); + match c { + '\u{7f}' => { + print!("\u{7f}"); + } + ' '...'\u{7e}' => { + print!("{}", c); + } + '\n' | '\r' => { + print!("\n"); + break; + } + _ => {} + } + } + } - ::kmain(); + // ::kmain(); } global_asm!(include_str!("boot/boot.S"));