mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-25 09:26:17 +04:00
New virtio serial as well as bugfix for uart16650
This commit is contained in:
parent
ceb679726d
commit
20b1bc534d
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,10 @@ impl IntcDriver for Plic {
|
||||
/// Register interrupt controller local irq
|
||||
fn register_local_irq(&self, irq: usize, driver: Arc<dyn Driver>) {
|
||||
// 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
|
||||
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,
|
||||
|
@ -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<u8> {
|
||||
Some(self.read())
|
||||
}
|
||||
}
|
||||
use crate::sync::Condvar;
|
||||
lazy_static! {
|
||||
pub static ref SERIAL_ACTIVITY: Condvar = Condvar::new();
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ impl Driver for SerialPort {
|
||||
fn try_handle_interrupt(&self, irq: Option<usize>) -> 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::<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;
|
||||
}
|
||||
}
|
||||
@ -112,6 +114,9 @@ impl SerialDriver for SerialPort {
|
||||
self.putchar(*byte);
|
||||
}
|
||||
}
|
||||
fn try_read(&self) -> Option<u8> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
80
kernel/src/drivers/serial/virtio_console.rs
Normal file
80
kernel/src/drivers/serial/virtio_console.rs
Normal 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()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user