support multiple UART interfaces
This commit is contained in:
parent
49584f0f26
commit
765598c80c
@ -1,7 +1,3 @@
|
|||||||
// QEMU puts UART registers here in physical memory.
|
|
||||||
pub const UART0: usize = 0x10000000;
|
|
||||||
pub const UART0_IRQ: usize = 10;
|
|
||||||
|
|
||||||
// Virtio MMIO interface
|
// Virtio MMIO interface
|
||||||
pub const VIRTIO0: usize = 0x10001000;
|
pub const VIRTIO0: usize = 0x10001000;
|
||||||
pub const VIRTIO0_IRQ: usize = 1;
|
pub const VIRTIO0_IRQ: usize = 1;
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
//! The RISC-V Platform Level Interrupt Controller (PLIC)
|
//! The RISC-V Platform Level Interrupt Controller (PLIC)
|
||||||
|
|
||||||
use super::hardware::{UART0_IRQ, VIRTIO0_IRQ};
|
use super::hardware::VIRTIO0_IRQ;
|
||||||
use crate::proc::cpu::Cpu;
|
use crate::proc::cpu::Cpu;
|
||||||
|
|
||||||
// QEMU puts platform-level interrupt controller (PLIC) here.
|
// QEMU puts platform-level interrupt controller (PLIC) here.
|
||||||
pub const PLIC: usize = 0x0c000000;
|
pub const PLIC: usize = 0x0c000000;
|
||||||
const PLIC_PRIORITY: usize = PLIC;
|
const PLIC_PRIORITY: usize = PLIC;
|
||||||
const PLIC_PENDING: usize = PLIC + 0x1000;
|
const PLIC_PENDING: usize = PLIC + 0x1000;
|
||||||
const UART0_IRQ_ADDR: usize = PLIC + UART0_IRQ * 4;
|
|
||||||
const VIRTIO0_IRQ_ADDR: usize = PLIC + VIRTIO0_IRQ * 4;
|
const VIRTIO0_IRQ_ADDR: usize = PLIC + VIRTIO0_IRQ * 4;
|
||||||
|
|
||||||
/// Get a pointer to the CPU-specific machine-mode enable register.
|
/// Get a pointer to the CPU-specific machine-mode enable register.
|
||||||
@ -37,7 +36,9 @@ fn plic_sclaim(hartid: usize) -> *mut u32 {
|
|||||||
|
|
||||||
pub unsafe fn plicinit() {
|
pub unsafe fn plicinit() {
|
||||||
// Set desired IRQ priorities non-zero (otherwise disabled).
|
// Set desired IRQ priorities non-zero (otherwise disabled).
|
||||||
*(UART0_IRQ_ADDR as *mut u32) = 1;
|
for (uart_irq, _) in &crate::hardware::UARTS {
|
||||||
|
*((PLIC + uart_irq * 4) as *mut u32) = 1;
|
||||||
|
}
|
||||||
*(VIRTIO0_IRQ_ADDR as *mut u32) = 1;
|
*(VIRTIO0_IRQ_ADDR as *mut u32) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +47,12 @@ pub unsafe fn plicinithart() {
|
|||||||
|
|
||||||
// Set enable bits for this hart's S-mode
|
// Set enable bits for this hart's S-mode
|
||||||
// for the UART and VIRTIO disk.
|
// for the UART and VIRTIO disk.
|
||||||
*plic_senable(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
|
let mut enable_bits = 0;
|
||||||
|
for (uart_irq, _) in &crate::hardware::UARTS {
|
||||||
|
enable_bits |= 1 << uart_irq;
|
||||||
|
}
|
||||||
|
enable_bits |= 1 << VIRTIO0_IRQ;
|
||||||
|
*plic_senable(hart) = enable_bits;
|
||||||
|
|
||||||
// Set this hart's S-mode priority threshold to 0.
|
// Set this hart's S-mode priority threshold to 0.
|
||||||
*plic_spriority(hart) = 0;
|
*plic_spriority(hart) = 0;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::{asm, mem::make_satp, SSTATUS_SPIE, SSTATUS_SPP};
|
use super::{asm, mem::make_satp, SSTATUS_SPIE, SSTATUS_SPP};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{
|
arch::{
|
||||||
hardware::{UART0_IRQ, VIRTIO0_IRQ},
|
hardware::VIRTIO0_IRQ,
|
||||||
interrupt,
|
interrupt,
|
||||||
mem::{PAGE_SIZE, TRAMPOLINE},
|
mem::{PAGE_SIZE, TRAMPOLINE},
|
||||||
},
|
},
|
||||||
@ -56,12 +56,20 @@ pub unsafe fn devintr() -> i32 {
|
|||||||
// IRQ indicates which device interrupted.
|
// IRQ indicates which device interrupted.
|
||||||
let irq = interrupt::handle_interrupt();
|
let irq = interrupt::handle_interrupt();
|
||||||
|
|
||||||
if irq == UART0_IRQ {
|
let mut uart_interrupt = false;
|
||||||
crate::hardware::uart::UART0.interrupt();
|
for (uart_irq, uart) in &crate::hardware::UARTS {
|
||||||
} else if irq == VIRTIO0_IRQ {
|
if irq == *uart_irq {
|
||||||
virtio_disk_intr();
|
uart_interrupt = true;
|
||||||
} else if irq > 0 {
|
uart.interrupt();
|
||||||
println!("unexpected interrupt irq={}", irq);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !uart_interrupt {
|
||||||
|
if irq == VIRTIO0_IRQ {
|
||||||
|
virtio_disk_intr();
|
||||||
|
} else if irq > 0 {
|
||||||
|
println!("unexpected interrupt irq={}", irq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The PLIC allows each device to raise at most one
|
// The PLIC allows each device to raise at most one
|
||||||
|
@ -7,7 +7,7 @@ use super::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::{
|
arch::{
|
||||||
self,
|
self,
|
||||||
hardware::{UART0, VIRTIO0},
|
hardware::VIRTIO0,
|
||||||
mem::{
|
mem::{
|
||||||
round_down_page, round_up_page, Pagetable, PagetableEntry, KERNEL_BASE, PAGE_SIZE,
|
round_down_page, round_up_page, Pagetable, PagetableEntry, KERNEL_BASE, PAGE_SIZE,
|
||||||
PHYSICAL_END, PTE_R, PTE_U, PTE_V, PTE_W, PTE_X, TRAMPOLINE, VIRTUAL_MAX,
|
PHYSICAL_END, PTE_R, PTE_U, PTE_V, PTE_W, PTE_X, TRAMPOLINE, VIRTUAL_MAX,
|
||||||
@ -46,13 +46,15 @@ pub unsafe fn kvmmake() -> Pagetable {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// UART registers
|
// UART registers
|
||||||
kvmmap(
|
for (_, uart) in &crate::hardware::UARTS {
|
||||||
pagetable,
|
kvmmap(
|
||||||
UART0 as u64,
|
pagetable,
|
||||||
UART0 as u64,
|
uart.base_address as u64,
|
||||||
PAGE_SIZE as u64,
|
uart.base_address as u64,
|
||||||
PTE_R | PTE_W,
|
PAGE_SIZE as u64,
|
||||||
);
|
PTE_R | PTE_W,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// VirtIO MMIO disk interface
|
// VirtIO MMIO disk interface
|
||||||
kvmmap(
|
kvmmap(
|
||||||
|
@ -12,12 +12,12 @@ pub mod printf;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fs::file::{devsw, CONSOLE},
|
fs::file::{devsw, CONSOLE},
|
||||||
hardware::uart::UART0,
|
|
||||||
proc::{
|
proc::{
|
||||||
process::{procdump, Process},
|
process::{procdump, Process},
|
||||||
scheduler::wakeup,
|
scheduler::wakeup,
|
||||||
},
|
},
|
||||||
sync::mutex::Mutex,
|
sync::mutex::Mutex,
|
||||||
|
hardware::uart::Uart,
|
||||||
};
|
};
|
||||||
use core::{ffi::c_void, ptr::addr_of_mut};
|
use core::{ffi::c_void, ptr::addr_of_mut};
|
||||||
|
|
||||||
@ -26,6 +26,8 @@ extern "C" {
|
|||||||
fn either_copyout(user_dst: i32, dst: u64, src: *mut c_void, len: u64) -> i32;
|
fn either_copyout(user_dst: i32, dst: u64, src: *mut c_void, len: u64) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static UART0: &'static Uart = &crate::hardware::UARTS[0].1;
|
||||||
|
|
||||||
pub const BACKSPACE: u8 = 0x00;
|
pub const BACKSPACE: u8 = 0x00;
|
||||||
pub const INPUT_BUF_SIZE: usize = 128;
|
pub const INPUT_BUF_SIZE: usize = 128;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ macro_rules! uprint {
|
|||||||
// Do some casts to get a mutable reference.
|
// Do some casts to get a mutable reference.
|
||||||
// Safe because Uart's core::fmt::Write implementation
|
// Safe because Uart's core::fmt::Write implementation
|
||||||
// only uses the &mut reference immutably.
|
// only uses the &mut reference immutably.
|
||||||
let uart: *const Uart = &$crate::hardware::uart::UART0 as *const Uart;
|
let uart: *const Uart = &$crate::hardware::UARTS[0].1 as *const Uart;
|
||||||
let uart: &mut Uart = unsafe { &mut *uart.cast_mut() };
|
let uart: &mut Uart = unsafe { &mut *uart.cast_mut() };
|
||||||
|
|
||||||
let _ = core::write!(uart, $($arg)*);
|
let _ = core::write!(uart, $($arg)*);
|
||||||
|
@ -3,3 +3,9 @@
|
|||||||
pub mod ramdisk;
|
pub mod ramdisk;
|
||||||
pub mod uart;
|
pub mod uart;
|
||||||
pub mod virtio_disk;
|
pub mod virtio_disk;
|
||||||
|
|
||||||
|
use uart::Uart;
|
||||||
|
|
||||||
|
pub static UARTS: [(usize, Uart); 1] = [
|
||||||
|
(10, Uart::new(0x1000_0000)),
|
||||||
|
];
|
||||||
|
@ -25,8 +25,6 @@ const LSR_RX_READY: u8 = 1 << 0;
|
|||||||
/// THR can accept another character to send
|
/// THR can accept another character to send
|
||||||
const LSR_TX_IDLE: u8 = 1 << 5;
|
const LSR_TX_IDLE: u8 = 1 << 5;
|
||||||
|
|
||||||
pub static UART0: Uart = Uart::new(crate::arch::hardware::UART0);
|
|
||||||
|
|
||||||
enum Register {
|
enum Register {
|
||||||
ReceiveHolding,
|
ReceiveHolding,
|
||||||
TransmitHolding,
|
TransmitHolding,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user