From 20b1bc534d3885e929797075bffcfdeb88ce0aaf Mon Sep 17 00:00:00 2001 From: gjz010 Date: Tue, 11 May 2021 02:09:23 +0800 Subject: [PATCH] New virtio serial as well as bugfix for uart16650 --- kernel/src/drivers/bus/virtio_mmio.rs | 2 + kernel/src/drivers/irq/plic.rs | 7 +- kernel/src/drivers/serial/mod.rs | 11 +++ kernel/src/drivers/serial/uart16550.rs | 8 ++- kernel/src/drivers/serial/virtio_console.rs | 80 +++++++++++++++++++++ 5 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 kernel/src/drivers/serial/virtio_console.rs diff --git a/kernel/src/drivers/bus/virtio_mmio.rs b/kernel/src/drivers/bus/virtio_mmio.rs index 80bf4b77..5305894c 100644 --- a/kernel/src/drivers/bus/virtio_mmio.rs +++ b/kernel/src/drivers/bus/virtio_mmio.rs @@ -2,6 +2,7 @@ use super::super::block::virtio_blk; use super::super::gpu::virtio_gpu; use super::super::input::virtio_input; use super::super::net::virtio_net; +use super::super::serial::virtio_console; use crate::drivers::device_tree::DEVICE_TREE_REGISTRY; use crate::memory::phys_to_virt; use device_tree::util::SliceRead; @@ -35,6 +36,7 @@ pub fn virtio_probe(node: &Node) { DeviceType::Block => virtio_blk::init(header), DeviceType::GPU => virtio_gpu::init(header), DeviceType::Input => virtio_input::init(header), + DeviceType::Console => virtio_console::init(node, header), t => warn!("Unrecognized virtio device: {:?}", t), } } diff --git a/kernel/src/drivers/irq/plic.rs b/kernel/src/drivers/irq/plic.rs index 59c4e728..f8374523 100644 --- a/kernel/src/drivers/irq/plic.rs +++ b/kernel/src/drivers/irq/plic.rs @@ -45,7 +45,10 @@ impl IntcDriver for Plic { /// Register interrupt controller local irq fn register_local_irq(&self, irq: usize, driver: Arc) { // enable irq for context 1 - write(self.base + 0x2080, 1 << irq); + write( + self.base + 0x2080, + read::(self.base + 0x2080) | (1 << irq), + ); // set priority to 7 write(self.base + irq * 4, 7); let mut manager = self.manager.lock(); @@ -58,7 +61,7 @@ pub const SupervisorExternal: usize = usize::MAX / 2 + 1 + 8; fn init_dt(dt: &Node) { let addr = dt.prop_u64("reg").unwrap() as usize; let phandle = dt.prop_u32("phandle").unwrap(); - info!("Found riscv plic at {:#x}", addr); + info!("Found riscv plic at {:#x}, {:?}", addr, dt); let base = phys_to_virt(addr); let plic = Arc::new(Plic { base, diff --git a/kernel/src/drivers/serial/mod.rs b/kernel/src/drivers/serial/mod.rs index bcefa307..f4ca2a34 100644 --- a/kernel/src/drivers/serial/mod.rs +++ b/kernel/src/drivers/serial/mod.rs @@ -11,10 +11,21 @@ pub mod com; pub mod keyboard; pub mod uart16550; +pub mod virtio_console; + pub trait SerialDriver: Driver { // read one byte from tty fn read(&self) -> u8; // write bytes to tty fn write(&self, data: &[u8]); + + // get if it is ready. as a hint. + fn try_read(&self) -> Option { + Some(self.read()) + } +} +use crate::sync::Condvar; +lazy_static! { + pub static ref SERIAL_ACTIVITY: Condvar = Condvar::new(); } diff --git a/kernel/src/drivers/serial/uart16550.rs b/kernel/src/drivers/serial/uart16550.rs index fb66fb76..58f9c992 100644 --- a/kernel/src/drivers/serial/uart16550.rs +++ b/kernel/src/drivers/serial/uart16550.rs @@ -23,6 +23,7 @@ impl Driver for SerialPort { fn try_handle_interrupt(&self, irq: Option) -> bool { if let Some(c) = self.getchar_option() { crate::trap::serial(c); + super::SERIAL_ACTIVITY.notify_all(); true } else { false @@ -72,7 +73,8 @@ impl SerialPort { /// non-blocking version of putchar() pub fn putchar(&self, c: u8) { for _ in 0..100 { - if (read::(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == 0 { + if (read::(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == COM_LSR_TXRDY + { break; } } @@ -112,6 +114,9 @@ impl SerialDriver for SerialPort { self.putchar(*byte); } } + fn try_read(&self) -> Option { + self.getchar_option() + } } const COM_RX: usize = 0; // In: Receive buffer (DLAB=0) @@ -149,6 +154,7 @@ pub fn init_dt(dt: &Node) { if let Some(manager) = DEVICE_TREE_INTC.write().get_mut(&intc) { manager.register_local_irq(irq, com.clone()); info!("registered uart16550 to intc"); + info!("Init uart16550 at {:#x}, {:?}", base, dt); found = true; } } diff --git a/kernel/src/drivers/serial/virtio_console.rs b/kernel/src/drivers/serial/virtio_console.rs new file mode 100644 index 00000000..22284950 --- /dev/null +++ b/kernel/src/drivers/serial/virtio_console.rs @@ -0,0 +1,80 @@ +use alloc::boxed::Box; +use alloc::string::String; +use alloc::sync::Arc; + +use super::super::{DeviceType, Driver, DRIVERS, IRQ_MANAGER, SERIAL_DRIVERS}; +use crate::drivers::device_tree::{DEVICE_TREE_INTC, DEVICE_TREE_REGISTRY}; +use crate::{ + drivers::{BlockDriver, NetDriver}, + sync::SpinNoIrqLock as Mutex, +}; +use device_tree::Node; +use log::*; +use virtio_drivers::VirtIOConsole; +use virtio_drivers::{VirtIOHeader, VirtIOInput}; + +struct VirtIOConsoleDriver(Mutex>); +pub fn init(dt: &Node, header: &'static mut VirtIOHeader) { + let mut console = VirtIOConsole::new(header).expect("failed to create virtio console"); + let driver = Arc::new(VirtIOConsoleDriver(Mutex::new(console))); + let irq_opt = dt.prop_u32("interrupts").ok().map(|irq| irq as usize); + let mut found = false; + if let Ok(intc) = dt.prop_u32("interrupt-parent") { + if let Some(irq) = irq_opt { + if let Some(manager) = DEVICE_TREE_INTC.write().get_mut(&intc) { + manager.register_local_irq(irq, driver.clone()); + info!("registered virtio_console to intc"); + found = true; + } + } + } + if !found { + info!("registered virtio_console to root"); + IRQ_MANAGER.write().register_opt(irq_opt, driver.clone()); + } + SERIAL_DRIVERS.write().push(driver); +} +impl Driver for VirtIOConsoleDriver { + fn try_handle_interrupt(&self, _irq: Option) -> bool { + let mut console = self.0.lock(); + let ack = console.ack_interrupt().expect("failed to ack interrupt"); + if ack { + super::SERIAL_ACTIVITY.notify_all(); + } + ack + } + + fn device_type(&self) -> DeviceType { + DeviceType::Serial + } + + fn get_id(&self) -> String { + String::from("virtio_console") + } + + fn as_net(&self) -> Option<&dyn NetDriver> { + None + } + + fn as_block(&self) -> Option<&dyn BlockDriver> { + None + } +} + +impl crate::drivers::serial::SerialDriver for VirtIOConsoleDriver { + fn read(&self) -> u8 { + let mut console = self.0.lock(); + console.recv(true).unwrap().unwrap_or(0) + } + + fn write(&self, data: &[u8]) { + let mut console = self.0.lock(); + for byte in data { + console.send(*byte).unwrap(); + } + } + fn try_read(&self) -> Option { + let mut console = self.0.lock(); + console.recv(true).unwrap() + } +}