1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-25 17:33:28 +04:00

New virtio serial as well as bugfix for uart16650

This commit is contained in:
gjz010 2021-05-11 02:09:23 +08:00
parent ceb679726d
commit 20b1bc534d
5 changed files with 105 additions and 3 deletions

View File

@ -2,6 +2,7 @@ use super::super::block::virtio_blk;
use super::super::gpu::virtio_gpu; use super::super::gpu::virtio_gpu;
use super::super::input::virtio_input; use super::super::input::virtio_input;
use super::super::net::virtio_net; use super::super::net::virtio_net;
use super::super::serial::virtio_console;
use crate::drivers::device_tree::DEVICE_TREE_REGISTRY; use crate::drivers::device_tree::DEVICE_TREE_REGISTRY;
use crate::memory::phys_to_virt; use crate::memory::phys_to_virt;
use device_tree::util::SliceRead; use device_tree::util::SliceRead;
@ -35,6 +36,7 @@ pub fn virtio_probe(node: &Node) {
DeviceType::Block => virtio_blk::init(header), DeviceType::Block => virtio_blk::init(header),
DeviceType::GPU => virtio_gpu::init(header), DeviceType::GPU => virtio_gpu::init(header),
DeviceType::Input => virtio_input::init(header), DeviceType::Input => virtio_input::init(header),
DeviceType::Console => virtio_console::init(node, header),
t => warn!("Unrecognized virtio device: {:?}", t), t => warn!("Unrecognized virtio device: {:?}", t),
} }
} }

View File

@ -45,7 +45,10 @@ impl IntcDriver for Plic {
/// Register interrupt controller local irq /// Register interrupt controller local irq
fn register_local_irq(&self, irq: usize, driver: Arc<dyn Driver>) { fn register_local_irq(&self, irq: usize, driver: Arc<dyn Driver>) {
// enable irq for context 1 // enable irq for context 1
write(self.base + 0x2080, 1 << irq); write(
self.base + 0x2080,
read::<u32>(self.base + 0x2080) | (1 << irq),
);
// set priority to 7 // set priority to 7
write(self.base + irq * 4, 7); write(self.base + irq * 4, 7);
let mut manager = self.manager.lock(); let mut manager = self.manager.lock();
@ -58,7 +61,7 @@ pub const SupervisorExternal: usize = usize::MAX / 2 + 1 + 8;
fn init_dt(dt: &Node) { fn init_dt(dt: &Node) {
let addr = dt.prop_u64("reg").unwrap() as usize; let addr = dt.prop_u64("reg").unwrap() as usize;
let phandle = dt.prop_u32("phandle").unwrap(); 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 base = phys_to_virt(addr);
let plic = Arc::new(Plic { let plic = Arc::new(Plic {
base, base,

View File

@ -11,10 +11,21 @@ pub mod com;
pub mod keyboard; pub mod keyboard;
pub mod uart16550; pub mod uart16550;
pub mod virtio_console;
pub trait SerialDriver: Driver { pub trait SerialDriver: Driver {
// read one byte from tty // read one byte from tty
fn read(&self) -> u8; fn read(&self) -> u8;
// write bytes to tty // write bytes to tty
fn write(&self, data: &[u8]); fn write(&self, data: &[u8]);
// get if it is ready. as a hint.
fn try_read(&self) -> Option<u8> {
Some(self.read())
}
}
use crate::sync::Condvar;
lazy_static! {
pub static ref SERIAL_ACTIVITY: Condvar = Condvar::new();
} }

View File

@ -23,6 +23,7 @@ impl Driver for SerialPort {
fn try_handle_interrupt(&self, irq: Option<usize>) -> bool { fn try_handle_interrupt(&self, irq: Option<usize>) -> bool {
if let Some(c) = self.getchar_option() { if let Some(c) = self.getchar_option() {
crate::trap::serial(c); crate::trap::serial(c);
super::SERIAL_ACTIVITY.notify_all();
true true
} else { } else {
false false
@ -72,7 +73,8 @@ impl SerialPort {
/// non-blocking version of putchar() /// non-blocking version of putchar()
pub fn putchar(&self, c: u8) { pub fn putchar(&self, c: u8) {
for _ in 0..100 { for _ in 0..100 {
if (read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == 0 { if (read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == COM_LSR_TXRDY
{
break; break;
} }
} }
@ -112,6 +114,9 @@ impl SerialDriver for SerialPort {
self.putchar(*byte); self.putchar(*byte);
} }
} }
fn try_read(&self) -> Option<u8> {
self.getchar_option()
}
} }
const COM_RX: usize = 0; // In: Receive buffer (DLAB=0) 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) { if let Some(manager) = DEVICE_TREE_INTC.write().get_mut(&intc) {
manager.register_local_irq(irq, com.clone()); manager.register_local_irq(irq, com.clone());
info!("registered uart16550 to intc"); info!("registered uart16550 to intc");
info!("Init uart16550 at {:#x}, {:?}", base, dt);
found = true; found = true;
} }
} }

View File

@ -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<VirtIOConsole<'static>>);
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<usize>) -> 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<u8> {
let mut console = self.0.lock();
console.recv(true).unwrap()
}
}