1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-22 08:06:17 +04:00

Use uart16550 as serial in riscv as well

This commit is contained in:
Jiajie Chen 2020-06-20 22:06:45 +08:00
parent 548495a149
commit b3f86cc3d1
7 changed files with 66 additions and 64 deletions

View File

@ -1,5 +1,5 @@
pub mod consts;
#[path = "../../../../drivers/serial/16550_reg.rs"]
#[path = "../../../../drivers/serial/uart16550.rs"]
pub mod serial;
/// Device tree bytes

View File

@ -2,6 +2,7 @@ pub use self::context::*;
use crate::drivers::IRQ_MANAGER;
use log::*;
use riscv::register::*;
use riscv::register::{scause::Scause, sscratch, stvec};
use trapframe::UserContext;
pub mod consts;
@ -33,7 +34,7 @@ pub unsafe fn restore(flags: usize) {
///
/// This function is called from `trap.asm`.
#[no_mangle]
pub extern "C" fn rust_trap(tf: &mut TrapFrame) {
pub extern "C" fn trap_handler(scause: Scause, stval: usize, tf: &mut TrapFrame) {
use self::scause::{Exception as E, Interrupt as I, Trap};
trace!(
"Interrupt @ CPU{}: {:?} ",
@ -59,27 +60,7 @@ fn external() {
super::board::handle_external_interrupt();
}
// true means handled, false otherwise
let handlers = [try_process_serial, try_process_drivers];
for handler in handlers.iter() {
if handler() == true {
break;
}
}
}
fn try_process_serial() -> bool {
match super::io::getchar_option() {
Some(ch) => {
crate::trap::serial(ch);
true
}
None => false,
}
}
fn try_process_drivers() -> bool {
IRQ_MANAGER.read().try_handle_interrupt(None)
IRQ_MANAGER.read().try_handle_interrupt(None);
}
fn ipi() {

View File

@ -5,7 +5,9 @@ use device_tree::{DeviceTree, Node};
use super::bus::virtio_mmio::virtio_probe;
use super::net::router::router_init;
use super::serial::uart16550;
use super::CMDLINE;
use crate::memory::phys_to_virt;
const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed;
@ -18,7 +20,11 @@ fn walk_dt_node(dt: &Node) {
if compatible == "rcore,router" {
router_init();
}
// TODO: initial other devices (16650, etc.)
if compatible == "ns16550a" {
let addr = dt.prop_u64("reg").unwrap() as usize;
uart16550::init(None, phys_to_virt(addr));
}
// TODO: init other devices
}
if let Ok(bootargs) = dt.prop_str("bootargs") {
if bootargs.len() > 0 {

View File

@ -38,7 +38,7 @@ impl Driver for COM {
}
fn get_id(&self) -> String {
format!("com_{}", self.base)
format!("uart16550_{}", self.base)
}
}

View File

@ -7,6 +7,7 @@ use core::fmt::{Result, Write};
pub mod com;
#[cfg(target_arch = "x86_64")]
pub mod keyboard;
pub mod uart16550;
pub trait SerialDriver: Driver {
// read one byte from tty

View File

@ -1,18 +1,42 @@
//! 16550 serial adapter driver for malta board
#![allow(dead_code)]
use super::SerialDriver;
use crate::drivers::IRQ_MANAGER;
use crate::drivers::SERIAL_DRIVERS;
use crate::drivers::{DeviceType, Driver, DRIVERS};
use crate::sync::SpinLock as Mutex;
use crate::util::{read, write};
use alloc::{string::String, sync::Arc};
use core::fmt::{Arguments, Result, Write};
pub struct SerialPort {
base: usize,
}
impl Driver for SerialPort {
fn try_handle_interrupt(&self, irq: Option<usize>) -> bool {
if let Some(c) = self.getchar_option() {
crate::trap::serial(c);
true
} else {
false
}
}
fn device_type(&self) -> DeviceType {
DeviceType::Serial
}
fn get_id(&self) -> String {
format!("com_{}", self.base)
}
}
impl SerialPort {
fn new() -> SerialPort {
SerialPort { base: 0 }
fn new(base: usize) -> SerialPort {
let mut res = SerialPort { base: 0 };
res.init(base);
res
}
pub fn init(&mut self, base: usize) {
@ -34,12 +58,12 @@ impl SerialPort {
}
/// non-blocking version of putchar()
pub fn putchar(&mut self, c: u8) {
pub fn putchar(&self, c: u8) {
write(self.base + COM_TX, c);
}
/// blocking version of getchar()
pub fn getchar(&mut self) -> char {
pub fn getchar(&mut self) -> u8 {
loop {
if (read::<u8>(self.base + COM_LSR) & COM_LSR_DATA) == 0 {
break;
@ -47,43 +71,29 @@ impl SerialPort {
}
let c = read::<u8>(self.base + COM_RX);
match c {
255 => '\0', // null
c => c as char,
255 => b'\0', // null
c => c,
}
}
/// non-blocking version of getchar()
pub fn getchar_option(&mut self) -> Option<char> {
pub fn getchar_option(&self) -> Option<u8> {
match read::<u8>(self.base + COM_LSR) & COM_LSR_DATA {
0 => None,
_ => Some(read::<u8>(self.base + COM_RX) as u8 as char),
_ => Some(read::<u8>(self.base + COM_RX) as u8),
}
}
pub fn putfmt(&mut self, fmt: Arguments) {
self.write_fmt(fmt).unwrap();
}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
match c {
127 => {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
}
b'\n' => {
self.putchar(b'\r');
self.putchar(b'\n');
}
c => {
self.putchar(c);
}
}
impl SerialDriver for SerialPort {
fn read(&self) -> u8 {
self.getchar_option().unwrap_or(0)
}
fn write(&self, data: &[u8]) {
for byte in data {
self.putchar(*byte);
}
Ok(())
}
}
@ -107,10 +117,10 @@ const COM_LSR_DATA: u8 = 0x01; // Data available
const COM_LSR_TXRDY: u8 = 0x20; // Transmit buffer avail
const COM_LSR_TSRE: u8 = 0x40; // Transmitter off
lazy_static! {
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
}
pub fn init(base: usize) {
SERIAL_PORT.lock().init(base);
pub fn init(irq: Option<usize>, base: usize) {
info!("Init uart16550 at {:#x}", base);
let com = Arc::new(SerialPort::new(base));
DRIVERS.write().push(com.clone());
SERIAL_DRIVERS.write().push(com.clone());
IRQ_MANAGER.write().register_opt(irq, com);
}

View File

@ -9,6 +9,7 @@ use crate::arch::{
memory::{get_page_fault_addr, set_page_table},
paging::*,
};
use crate::drivers::IRQ_MANAGER;
use crate::fs::{FileHandle, FileLike, OpenOptions, FOLLOW_MAX_DEPTH};
use crate::ipc::SemProc;
use crate::memory::{
@ -443,9 +444,12 @@ pub fn spawn(thread: Arc<Thread>) {
Syscall => exit = handle_syscall(&thread, &mut cx).await,
IrqMin..=IrqMax => {
crate::arch::interrupt::ack(trap_num);
trace!("handle irq {}", trap_num);
info!("handle irq {:#x}", trap_num);
if trap_num == Timer {
crate::arch::interrupt::timer();
} else {
// we don't know the actual irq
IRQ_MANAGER.read().try_handle_interrupt(None);
}
}
_ if is_page_fault(trap_num) => {