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:
parent
ceb679726d
commit
20b1bc534d
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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