diff --git a/Cargo.lock b/Cargo.lock index 905076383..4f5a92de6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -669,6 +669,13 @@ dependencies = [ name = "driver_common" version = "0.1.0" +[[package]] +name = "driver_console" +version = "0.1.0" +dependencies = [ + "driver_common", +] + [[package]] name = "driver_display" version = "0.1.0" @@ -700,6 +707,7 @@ dependencies = [ "driver_9p", "driver_block", "driver_common", + "driver_console", "driver_display", "driver_net", "log", @@ -1682,12 +1690,16 @@ dependencies = [ "bitflags 2.4.0", "cfg-if", "crate_interface", + "driver_common", + "driver_console", + "driver_virtio", "dtb", "dw_apb_uart", "embedded-hal", "handler_table", "kernel_guard", "lazy_init", + "lazy_static", "log", "memory_addr", "page_table", @@ -1702,6 +1714,7 @@ dependencies = [ "static_assertions", "tock-registers", "tty", + "virtio-drivers", "x2apic", "x86", "x86_64", diff --git a/Cargo.toml b/Cargo.toml index 2f381d05b..2fd169f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "crates/driver_block", "crates/driver_common", "crates/driver_display", + "crates/driver_console", "crates/driver_net", "crates/driver_pci", "crates/driver_virtio", diff --git a/Makefile b/Makefile index 97b46532b..0307c99a1 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ FEATURES ?= APP_FEATURES ?= # QEMU options +CONSOLE ?= n BLK ?= n NET ?= n GRAPHIC ?= n diff --git a/api/ruxfeat/Cargo.toml b/api/ruxfeat/Cargo.toml index 7926cee2f..a7c423aff 100644 --- a/api/ruxfeat/Cargo.toml +++ b/api/ruxfeat/Cargo.toml @@ -73,6 +73,9 @@ virtio-9p = [ ] net-9p = ["9pfs", "net", "rux9p/net-9p", "ruxruntime/net-9p"] +# virtio console +virtio_console = ["ruxhal/virtio_console", "ruxruntime/virtio_console", "alloc", "ruxdriver/virtio_console", "ruxdriver/virtio"] + # Device drivers bus-mmio = ["ruxdriver?/bus-mmio"] bus-pci = ["ruxdriver?/bus-pci"] diff --git a/crates/driver_console/Cargo.toml b/crates/driver_console/Cargo.toml new file mode 100644 index 000000000..30fc2b253 --- /dev/null +++ b/crates/driver_console/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "driver_console" +version = "0.1.0" +edition = "2021" +authors = [ + "Hangqi Ren <2572131118@qq.com>" +] +description = "Common traits and types for console drivers" +license = "GPL-3.0-or-later OR Apache-2.0" +homepage = "https://github.com/syswonder/ruxos" +repository = "https://github.com/syswonder/ruxos/tree/main/crates/driver_console" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = [] + +[dependencies] +driver_common = { path = "../driver_common" } \ No newline at end of file diff --git a/crates/driver_console/src/lib.rs b/crates/driver_console/src/lib.rs new file mode 100644 index 000000000..68342c693 --- /dev/null +++ b/crates/driver_console/src/lib.rs @@ -0,0 +1,27 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Ruxos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +//! Common traits and types for block storage device drivers (i.e. disk). + +#![no_std] +#![feature(doc_auto_cfg)] +#![feature(const_trait_impl)] + +#[doc(no_inline)] +pub use driver_common::{BaseDriverOps, DevError, DevResult, DeviceType}; + +/// Operations that require a console device driver to implement. +pub trait ConsoleDriverOps: BaseDriverOps { + /// Writes a single byte to the console. + fn putchar(&mut self, c: u8); + /// Reads a single byte from the console. + fn getchar(&mut self) -> Option; + /// Acknowledge an interrupt from the console. + fn ack_interrupt(&mut self) -> DevResult; +} diff --git a/crates/driver_virtio/Cargo.toml b/crates/driver_virtio/Cargo.toml index 2415441ec..6dfd49fb3 100644 --- a/crates/driver_virtio/Cargo.toml +++ b/crates/driver_virtio/Cargo.toml @@ -14,6 +14,7 @@ block = ["driver_block"] net = ["driver_net"] gpu = ["driver_display"] v9p = ["driver_9p"] +console = ["driver_console"] [dependencies] log = "0.4" @@ -23,4 +24,5 @@ driver_block = { path = "../driver_block", optional = true } driver_net = { path = "../driver_net", optional = true } driver_display = { path = "../driver_display", optional = true} driver_9p = { path = "../driver_9p", optional = true} +driver_console = { path = "../driver_console", optional = true} virtio-drivers = { git = "https://github.com/syswonder/virtio-drivers.git", rev = "62dbe5a" } diff --git a/crates/driver_virtio/src/console.rs b/crates/driver_virtio/src/console.rs new file mode 100644 index 000000000..091176e69 --- /dev/null +++ b/crates/driver_virtio/src/console.rs @@ -0,0 +1,59 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Ruxos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +use crate::as_dev_err; +use driver_common::{BaseDriverOps, DevResult, DeviceType}; +use driver_console::ConsoleDriverOps; +use virtio_drivers::{device::console::VirtIOConsole as InnerDev, transport::Transport, Hal}; + +/// VirtIO console device +pub struct VirtIoConsoleDev { + inner: InnerDev<'static, H, T>, +} + +unsafe impl Send for VirtIoConsoleDev {} +unsafe impl Sync for VirtIoConsoleDev {} + +impl VirtIoConsoleDev { + /// Creates a new driver instance and initializes the device, or returns + /// an error if any step fails. + pub fn try_new(transport: T) -> DevResult { + Ok(Self { + inner: InnerDev::new(transport).map_err(as_dev_err)?, + }) + } +} + +impl BaseDriverOps for VirtIoConsoleDev { + fn device_name(&self) -> &str { + "virtio-console" + } + + fn device_type(&self) -> DeviceType { + DeviceType::Char + } +} + +impl ConsoleDriverOps for VirtIoConsoleDev { + fn putchar(&mut self, c: u8) { + self.inner + .send(c) + .expect("VirtConsole: failed to send char"); + } + + fn getchar(&mut self) -> Option { + self.inner + .recv(true) + .expect("VirtConsole: failed to recv char") + } + + fn ack_interrupt(&mut self) -> DevResult { + self.inner.ack_interrupt().map_err(as_dev_err) + } +} diff --git a/crates/driver_virtio/src/lib.rs b/crates/driver_virtio/src/lib.rs index 269a5c1d5..ea6a46946 100644 --- a/crates/driver_virtio/src/lib.rs +++ b/crates/driver_virtio/src/lib.rs @@ -25,6 +25,8 @@ #[cfg(feature = "block")] mod blk; +#[cfg(feature = "console")] +mod console; #[cfg(feature = "gpu")] mod gpu; #[cfg(feature = "net")] @@ -34,6 +36,8 @@ mod v9p; #[cfg(feature = "block")] pub use self::blk::VirtIoBlkDev; +#[cfg(feature = "console")] +pub use self::console::VirtIoConsoleDev; #[cfg(feature = "gpu")] pub use self::gpu::VirtIoGpuDev; #[cfg(feature = "net")] @@ -89,6 +93,7 @@ const fn as_dev_type(t: VirtIoDevType) -> Option { Network => Some(DeviceType::Net), GPU => Some(DeviceType::Display), _9P => Some(DeviceType::_9P), + Console => Some(DeviceType::Char), _ => None, } } diff --git a/modules/ruxdriver/Cargo.toml b/modules/ruxdriver/Cargo.toml index b90a247c6..aaf0b6331 100644 --- a/modules/ruxdriver/Cargo.toml +++ b/modules/ruxdriver/Cargo.toml @@ -15,20 +15,23 @@ repository = "https://github.com/syswonder/ruxos/tree/main/modules/ruxdriver" [features] dyn = [] bus-mmio = [] -bus-pci = ["dep:driver_pci", "dep:ruxhal", "dep:ruxconfig"] +bus-pci = ["dep:driver_pci", "dep:ruxhal", "dep:ruxconfig", "virtio_hal"] net = ["driver_net"] block = ["driver_block"] display = ["driver_display"] _9p = ["driver_9p"] + + # Enabled by features `virtio-*` virtio = ["driver_virtio", "dep:axalloc", "dep:ruxhal", "dep:ruxconfig"] - +virtio_hal = ["ruxhal/virtio_hal"] # various types of drivers -virtio-blk = ["block", "virtio", "driver_virtio/block"] -virtio-net = ["net", "virtio", "driver_virtio/net"] -virtio-gpu = ["display", "virtio", "driver_virtio/gpu"] -virtio-9p = ["_9p","virtio", "driver_virtio/v9p"] +virtio-blk = ["block", "virtio", "driver_virtio/block","virtio_hal"] +virtio-net = ["net", "virtio", "driver_virtio/net", "virtio_hal"] +virtio-gpu = ["display", "virtio", "driver_virtio/gpu", "virtio_hal"] +virtio-9p = ["_9p","virtio", "driver_virtio/v9p", "virtio_hal"] +virtio_console = ["virtio"] ramdisk = ["block", "driver_block/ramdisk"] bcm2835-sdhci = ["block", "driver_block/bcm2835-sdhci"] ixgbe = ["net", "driver_net/ixgbe", "dep:axalloc", "dep:ruxhal"] diff --git a/modules/ruxdriver/src/bus/mmio.rs b/modules/ruxdriver/src/bus/mmio.rs index 498a4d487..58c306a04 100644 --- a/modules/ruxdriver/src/bus/mmio.rs +++ b/modules/ruxdriver/src/bus/mmio.rs @@ -9,12 +9,19 @@ #[allow(unused_imports)] use crate::{prelude::*, AllDevices}; +#[cfg(all(feature = "virtio_console", feature = "virtio"))] +use ruxhal::virtio::virtio_console; impl AllDevices { pub(crate) fn probe_bus_devices(&mut self) { // TODO: parse device tree #[cfg(feature = "virtio")] for reg in ruxconfig::VIRTIO_MMIO_REGIONS { + #[cfg(feature = "virtio_console")] + if virtio_console::is_probe(reg.0) { + warn!("Avoiding virtio-console probe again"); + continue; + } for_each_drivers!(type Driver, { if let Some(dev) = Driver::probe_mmio(reg.0, reg.1) { info!( diff --git a/modules/ruxdriver/src/virtio.rs b/modules/ruxdriver/src/virtio.rs index ec97412b5..245dca568 100644 --- a/modules/ruxdriver/src/virtio.rs +++ b/modules/ruxdriver/src/virtio.rs @@ -7,16 +7,15 @@ * See the Mulan PSL v2 for more details. */ -use core::marker::PhantomData; -use core::ptr::NonNull; - -use axalloc::global_allocator; +use crate::{drivers::DriverProbe, AxDeviceEnum}; use cfg_if::cfg_if; +use core::marker::PhantomData; use driver_common::{BaseDriverOps, DevResult, DeviceType}; -use driver_virtio::{BufferDirection, PhysAddr, VirtIoHal}; -use ruxhal::mem::{direct_virt_to_phys, phys_to_virt, virt_to_phys}; +#[cfg(bus = "mmio")] +use ruxhal::mem::phys_to_virt; -use crate::{drivers::DriverProbe, AxDeviceEnum}; +#[cfg(feature = "virtio_hal")] +use ruxhal::virtio::virtio_hal::VirtIoHalImpl; cfg_if! { if #[cfg(bus = "pci")] { @@ -161,37 +160,3 @@ impl DriverProbe for VirtIoDriver { None } } - -pub struct VirtIoHalImpl; - -unsafe impl VirtIoHal for VirtIoHalImpl { - fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull) { - let vaddr = if let Ok(vaddr) = global_allocator().alloc_pages(pages, 0x1000) { - vaddr - } else { - return (0, NonNull::dangling()); - }; - let paddr = direct_virt_to_phys(vaddr.into()); - let ptr = NonNull::new(vaddr as _).unwrap(); - (paddr.as_usize(), ptr) - } - - unsafe fn dma_dealloc(_paddr: PhysAddr, vaddr: NonNull, pages: usize) -> i32 { - global_allocator().dealloc_pages(vaddr.as_ptr() as usize, pages); - 0 - } - - #[inline] - unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull { - NonNull::new(phys_to_virt(paddr.into()).as_mut_ptr()).unwrap() - } - - #[inline] - unsafe fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr { - let vaddr = buffer.as_ptr() as *mut u8 as usize; - virt_to_phys(vaddr.into()).into() - } - - #[inline] - unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {} -} diff --git a/modules/ruxhal/Cargo.toml b/modules/ruxhal/Cargo.toml index 1454a5373..521b91a09 100644 --- a/modules/ruxhal/Cargo.toml +++ b/modules/ruxhal/Cargo.toml @@ -12,6 +12,7 @@ homepage = "https://github.com/syswonder/ruxos" repository = "https://github.com/syswonder/ruxos/tree/main/modules/ruxhal" [features] +virtio_hal = ["driver_virtio","virtio-drivers","axalloc"] smp = [] alloc = [] fp_simd = [] @@ -22,6 +23,8 @@ tls = ["alloc"] default = [] musl = [] signal = [] +virtio_console = ["driver_console", "driver_virtio", "driver_virtio/console", "driver_common", "virtio-drivers", "axalloc", "lazy_static", "alloc", "virtio_hal"] + [dependencies] log = "0.4" @@ -39,6 +42,11 @@ lazy_init = { path = "../../crates/lazy_init" } page_table = { path = "../../crates/page_table", optional = true } page_table_entry = { path = "../../crates/page_table_entry" } percpu = { path = "../../crates/percpu" } +driver_console = { path = "../../crates/driver_console", optional = true } +driver_virtio = { path = "../../crates/driver_virtio", optional = true } +driver_common = { path = "../../crates/driver_common", optional = true } +virtio-drivers = { git = "https://github.com/syswonder/virtio-drivers.git", rev = "62dbe5a", optional = true } +lazy_static = { version = "1.4", features = ["spin_no_std"], optional = true } memory_addr = "0.1.0" handler_table = "0.1.0" crate_interface = "0.1.1" diff --git a/modules/ruxhal/src/lib.rs b/modules/ruxhal/src/lib.rs index 7ecc3b81b..d0c0fd94c 100644 --- a/modules/ruxhal/src/lib.rs +++ b/modules/ruxhal/src/lib.rs @@ -43,13 +43,13 @@ #[macro_use] extern crate log; -mod platform; - pub mod arch; pub mod cpu; pub mod mem; +mod platform; pub mod time; pub mod trap; +pub mod virtio; #[cfg(feature = "tls")] pub mod tls; diff --git a/modules/ruxhal/src/platform/aarch64_common/gic.rs b/modules/ruxhal/src/platform/aarch64_common/gic.rs index 1df2ef11e..30d172e66 100644 --- a/modules/ruxhal/src/platform/aarch64_common/gic.rs +++ b/modules/ruxhal/src/platform/aarch64_common/gic.rs @@ -19,9 +19,15 @@ pub const MAX_IRQ_COUNT: usize = 1024; /// The timer IRQ number. pub const TIMER_IRQ_NUM: usize = translate_irq(14, InterruptType::PPI).unwrap(); +#[cfg(not(feature = "virtio_console"))] /// The UART IRQ number. pub const UART_IRQ_NUM: usize = translate_irq(ruxconfig::UART_IRQ, InterruptType::SPI).unwrap(); +#[cfg(all(feature = "irq", feature = "virtio_console"))] +/// The Virtio-console IRQ number +pub const VIRTIO_CONSOLE_IRQ_NUM: usize = + translate_irq(ruxconfig::VIRTIO_CONSOLE_IRQ, InterruptType::SPI).unwrap(); + const GICD_BASE: PhysAddr = PhysAddr::from(ruxconfig::GICD_PADDR); const GICC_BASE: PhysAddr = PhysAddr::from(ruxconfig::GICC_PADDR); diff --git a/modules/ruxhal/src/platform/aarch64_common/mod.rs b/modules/ruxhal/src/platform/aarch64_common/mod.rs index 572642be6..933847f3d 100644 --- a/modules/ruxhal/src/platform/aarch64_common/mod.rs +++ b/modules/ruxhal/src/platform/aarch64_common/mod.rs @@ -16,7 +16,7 @@ pub mod psci; #[cfg(feature = "irq")] pub mod gic; -#[cfg(not(platform_family = "aarch64-bsta1000b"))] +#[cfg(not(any(platform_family = "aarch64-bsta1000b", feature = "virtio_console")))] pub mod pl011; #[cfg(feature = "rtc")] diff --git a/modules/ruxhal/src/platform/aarch64_qemu_virt/mod.rs b/modules/ruxhal/src/platform/aarch64_qemu_virt/mod.rs index 34236fb04..b15270403 100644 --- a/modules/ruxhal/src/platform/aarch64_qemu_virt/mod.rs +++ b/modules/ruxhal/src/platform/aarch64_qemu_virt/mod.rs @@ -18,7 +18,10 @@ pub mod irq { } pub mod console { + #[cfg(not(feature = "virtio_console"))] pub use crate::platform::aarch64_common::pl011::*; + #[cfg(feature = "virtio_console")] + pub use crate::virtio::virtio_console::*; } pub mod time { @@ -46,6 +49,7 @@ pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { dtb::init(crate::mem::phys_to_virt(dtb.into()).as_ptr()); } crate::cpu::init_primary(cpu_id); + #[cfg(not(feature = "virtio_console"))] super::aarch64_common::pl011::init_early(); super::aarch64_common::generic_timer::init_early(); rust_main(cpu_id, dtb); @@ -68,7 +72,10 @@ pub fn platform_init() { super::aarch64_common::generic_timer::init_percpu(); #[cfg(feature = "rtc")] super::aarch64_common::pl031::init(); + #[cfg(not(feature = "virtio_console"))] super::aarch64_common::pl011::init(); + #[cfg(feature = "virtio_console")] + crate::virtio::virtio_console::enable_interrupt(); } /// Initializes the platform devices for secondary CPUs. diff --git a/modules/ruxhal/src/virtio/mod.rs b/modules/ruxhal/src/virtio/mod.rs new file mode 100644 index 000000000..c368c3e57 --- /dev/null +++ b/modules/ruxhal/src/virtio/mod.rs @@ -0,0 +1,14 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Ruxos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +//! ruxos and virtio code related mod definition +#[cfg(feature = "virtio_console")] +pub mod virtio_console; +#[cfg(feature = "virtio_hal")] +pub mod virtio_hal; diff --git a/modules/ruxhal/src/virtio/virtio_console.rs b/modules/ruxhal/src/virtio/virtio_console.rs new file mode 100644 index 000000000..e98e9e396 --- /dev/null +++ b/modules/ruxhal/src/virtio/virtio_console.rs @@ -0,0 +1,218 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Ruxos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +//! virtio_console +use crate::mem::phys_to_virt; +use crate::virtio::virtio_hal::VirtIoHalImpl; +use driver_console::ConsoleDriverOps; +use driver_virtio::VirtIoConsoleDev; +use spinlock::SpinNoIrq; +const VIRTIO_CONSOLE_BASE: usize = ruxconfig::VIRTIO_CONSOLE_PADDR; +const VIRTIO_CONSOLE_REG: usize = 0x200; + +#[cfg(all(feature = "irq", target_arch = "aarch64"))] +use crate::platform::irq::VIRTIO_CONSOLE_IRQ_NUM; + +/// Store buffer size +const MEM_SIZE: usize = 4096; + +#[cfg(feature = "irq")] +const BUFFER_SIZE: usize = 128; + +#[cfg(feature = "irq")] +struct RxRingBuffer { + buffer: [u8; BUFFER_SIZE], + head: usize, + tail: usize, + empty: bool, +} + +/// The UART RxRingBuffer +#[cfg(feature = "irq")] +impl RxRingBuffer { + /// Create a new ring buffer + const fn new() -> Self { + RxRingBuffer { + buffer: [0_u8; BUFFER_SIZE], + head: 0_usize, + tail: 0_usize, + empty: true, + } + } + + /// Push a byte into the buffer + fn push(&mut self, n: u8) { + if self.tail != self.head || self.empty { + self.buffer[self.tail] = n; + self.tail = (self.tail + 1) % BUFFER_SIZE; + self.empty = false; + } + } + + /// Pop a byte from the buffer + fn pop(&mut self) -> Option { + if self.empty { + None + } else { + let ret = self.buffer[self.head]; + self.head = (self.head + 1) % BUFFER_SIZE; + if self.head == self.tail { + self.empty = true; + } + Some(ret) + } + } +} + +/// The UART driver +struct UartDrv { + inner: Option>, + buffer: [u8; MEM_SIZE], + #[cfg(feature = "irq")] + irq_buffer: RxRingBuffer, + pointer: usize, + addr: usize, +} + +/// The UART driver instance +static UART: SpinNoIrq = SpinNoIrq::new(UartDrv { + inner: None, + buffer: [0; MEM_SIZE], + #[cfg(feature = "irq")] + irq_buffer: RxRingBuffer::new(), + pointer: 0, + addr: 0, +}); + +/// Writes a byte to the console. +pub fn putchar(c: u8) { + let mut uart_drv = UART.lock(); + if uart_drv.inner.is_some() { + if uart_drv.pointer > 0 { + for i in 0..uart_drv.pointer { + let c = uart_drv.buffer[i]; + let uart = uart_drv.inner.as_mut().unwrap(); + match c { + b'\n' => { + uart.putchar(b'\r'); + uart.putchar(b'\n'); + } + c => uart.putchar(c), + } + } + uart_drv.pointer = 0; + warn!("######################### The above content is printed from buffer! #########################"); + } + let uart = uart_drv.inner.as_mut().unwrap(); + uart.putchar(c); + } else { + let ptr = uart_drv.pointer; + uart_drv.buffer[ptr] = c; + uart_drv.pointer += 1; + } +} + +/// Reads a byte from the console. +pub fn getchar() -> Option { + let mut uart_drv = UART.lock(); + #[cfg(feature = "irq")] + return uart_drv.irq_buffer.pop(); + #[cfg(not(feature = "irq"))] + if let Some(ref mut uart_inner) = uart_drv.inner { + return uart_inner.getchar(); + } else { + None + } +} + +/// probe virtio console directly +pub fn directional_probing() { + info!("Initiating VirtIO Console ..."); + let mut uart_drv = UART.lock(); + if let Some(dev) = probe_mmio(VIRTIO_CONSOLE_BASE, VIRTIO_CONSOLE_REG) { + uart_drv.inner = Some(dev); + uart_drv.addr = VIRTIO_CONSOLE_BASE; + } + info!("Output now redirected to VirtIO Console!"); +} + +/// enable virtio console interrupt +#[cfg(feature = "irq")] +pub fn enable_interrupt() { + #[cfg(target_arch = "aarch64")] + { + info!("Initiating VirtIO Console interrupt ..."); + info!("IRQ ID: {}", VIRTIO_CONSOLE_IRQ_NUM); + crate::irq::register_handler(VIRTIO_CONSOLE_IRQ_NUM, irq_handler); + crate::irq::set_enable(VIRTIO_CONSOLE_IRQ_NUM, true); + ack_interrupt(); + info!("Interrupt enabled!"); + return; + } + #[cfg(not(target_arch = "aarch64"))] + warn!("Interrupt is not supported on this platform!"); +} + +/// virtio console interrupt handler +#[cfg(feature = "irq")] +pub fn irq_handler() { + let mut uart_drv = UART.lock(); + if let Some(ref mut uart_inner) = uart_drv.inner { + let uart = uart_inner; + if uart.ack_interrupt().unwrap() { + if let Some(c) = uart.getchar() { + uart_drv.irq_buffer.push(c); + } + } + } +} + +/// Acknowledge the interrupt +#[cfg(feature = "irq")] +pub fn ack_interrupt() { + info!("ack interrupt"); + let mut uart_drv = UART.lock(); + if let Some(ref mut uart_inner) = uart_drv.inner { + let uart = uart_inner; + uart.ack_interrupt() + .expect("Virtio_console ack interrupt error"); + } +} + +/// Check if the address is the probe address +pub fn is_probe(addr: usize) -> bool { + let uart_drv = UART.lock(); + addr == uart_drv.addr +} + +/// Probe the virtio console +fn probe_mmio( + mmio_base: usize, + mmio_size: usize, +) -> Option> { + let base_vaddr = phys_to_virt(mmio_base.into()); + if let Some((ty, transport)) = + driver_virtio::probe_mmio_device(base_vaddr.as_mut_ptr(), mmio_size) + { + if ty == driver_common::DeviceType::Char { + info!( + "VirtIO Console found at {:#x} size {:#x}", + mmio_base, mmio_size + ); + return match VirtIoConsoleDev::try_new(transport) { + Ok(dev) => Some(dev), + Err(_e) => None, + }; + } + } + None +} + +/// Virtio transport type +type VirtIoTransport = driver_virtio::MmioTransport; diff --git a/modules/ruxhal/src/virtio/virtio_hal.rs b/modules/ruxhal/src/virtio/virtio_hal.rs new file mode 100644 index 000000000..48d4f4881 --- /dev/null +++ b/modules/ruxhal/src/virtio/virtio_hal.rs @@ -0,0 +1,57 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Ruxos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +//! virtio-hal implementation for RuxOS. + +use crate::mem::{direct_virt_to_phys, phys_to_virt, virt_to_phys}; +use axalloc::global_allocator; +use core::ptr::NonNull; +use driver_virtio::VirtIoHal; +use virtio_drivers::{BufferDirection, PhysAddr}; + +/// virtio-hal struct define +pub struct VirtIoHalImpl; + +/// virtio-hal trait implement +unsafe impl VirtIoHal for VirtIoHalImpl { + /// Allocate DMA buffer + fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull) { + let vaddr = if let Ok(vaddr) = global_allocator().alloc_pages(pages, 0x1000) { + vaddr + } else { + return (0, NonNull::dangling()); + }; + let paddr = direct_virt_to_phys(vaddr.into()); + let ptr = NonNull::new(vaddr as _).unwrap(); + (paddr.as_usize(), ptr) + } + + /// Deallocate DMA buffer + unsafe fn dma_dealloc(_paddr: PhysAddr, vaddr: NonNull, pages: usize) -> i32 { + global_allocator().dealloc_pages(vaddr.as_ptr() as usize, pages); + 0 + } + + /// Convert physical address to virtual address + #[inline] + unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull { + NonNull::new(phys_to_virt(paddr.into()).as_mut_ptr()).unwrap() + } + + /// Share DMA buffer + #[inline] + unsafe fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr { + let vaddr = buffer.as_ptr() as *mut u8 as usize; + virt_to_phys(vaddr.into()).into() + } + + /// Unshare DMA buffer + #[inline] + unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {} +} diff --git a/modules/ruxruntime/Cargo.toml b/modules/ruxruntime/Cargo.toml index 84f0d5ede..632445922 100644 --- a/modules/ruxruntime/Cargo.toml +++ b/modules/ruxruntime/Cargo.toml @@ -22,6 +22,7 @@ tls = ["ruxhal/tls", "ruxtask?/tls"] alloc = ["axalloc", "dtb"] paging = ["ruxhal/paging", "lazy_init"] rtc = ["ruxhal/rtc"] +virtio_console = [] multitask = ["ruxtask/multitask", "dep:ruxfutex", "rand"] rand = ["dep:ruxrand"] diff --git a/modules/ruxruntime/src/lib.rs b/modules/ruxruntime/src/lib.rs index 0aa59f75d..71cb1d228 100644 --- a/modules/ruxruntime/src/lib.rs +++ b/modules/ruxruntime/src/lib.rs @@ -65,14 +65,14 @@ use self::env::{boot_add_environ, init_argv}; use core::ffi::{c_char, c_int}; const LOGO: &str = r#" -8888888b. .d88888b. .d8888b. -888 Y88b d88P" "Y88b d88P Y88b -888 888 888 888 Y88b. -888 d88P 888 888 888 888 888 888 "Y888b. -8888888P" 888 888 `Y8bd8P' 888 888 "Y88b. -888 T88b 888 888 X88K 888 888 "888 -888 T88b Y88b 888 .d8""8b. Y88b. .d88P Y88b d88P -888 T88b "Y88888 888 888 "Y88888P" "Y8888P" +8888888b. .d88888b. .d8888b. +888 Y88b d88P" "Y88b d88P Y88b +888 888 888 888 Y88b. +888 d88P 888 888 888 888 888 888 "Y888b. +8888888P" 888 888 `Y8bd8P' 888 888 "Y88b. +888 T88b 888 888 X88K 888 888 "888 +888 T88b Y88b 888 .d8""8b. Y88b. .d88P Y88b d88P +888 T88b "Y88888 888 888 "Y88888P" "Y8888P" "#; #[no_mangle] @@ -173,6 +173,13 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { axlog::init(); axlog::set_max_level(option_env!("RUX_LOG").unwrap_or("")); // no effect if set `log-level-*` features info!("Logging is enabled."); + + #[cfg(feature = "alloc")] + init_allocator(); + + #[cfg(feature = "virtio_console")] + ruxhal::virtio::virtio_console::directional_probing(); + info!("Primary CPU {} started, dtb = {:#x}.", cpu_id, dtb); info!("Found physcial memory regions:"); @@ -186,9 +193,6 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { ); } - #[cfg(feature = "alloc")] - init_allocator(); - #[cfg(feature = "paging")] { info!("Initialize kernel page table..."); diff --git a/platforms/aarch64-qemu-virt.toml b/platforms/aarch64-qemu-virt.toml index 03474a9f8..aae7690b7 100644 --- a/platforms/aarch64-qemu-virt.toml +++ b/platforms/aarch64-qemu-virt.toml @@ -81,9 +81,14 @@ pci-ranges = [ ["0x80_0000_0000", "0x80_0000_0000"], # 64-but MMIO space ] # UART Address -uart-paddr = "0x0900_0000" +uart-paddr = "0x9000000" uart-irq = "1" +# Virtio console +virtio-console-paddr = "0xa003e00" +# Virtio console IRQ +virtio-console-irq = "47" + # GICC Address gicc-paddr = "0x0801_0000" gicd-paddr = "0x0800_0000" diff --git a/platforms/aarch64-raspi4.toml b/platforms/aarch64-raspi4.toml index ef2e20cc8..933598730 100644 --- a/platforms/aarch64-raspi4.toml +++ b/platforms/aarch64-raspi4.toml @@ -31,6 +31,11 @@ virtio-mmio-regions = [] uart-paddr = "0xFE20_1000" uart-irq = "0x79" +# Virtio console +virtio-console-paddr = "0xFFFFFFFF" +# Virtio console irq +virtio-console-irq = "0" + # GIC Address gicc-paddr = "0xFF84_2000" gicd-paddr = "0xFF84_1000" diff --git a/platforms/riscv64-qemu-virt.toml b/platforms/riscv64-qemu-virt.toml index 3589913f2..2d76864b6 100644 --- a/platforms/riscv64-qemu-virt.toml +++ b/platforms/riscv64-qemu-virt.toml @@ -57,5 +57,10 @@ pci-ranges = [ ["0x4_0000_0000", "0x4_0000_0000"], # 64-but MMIO space ] +# Virtio console +virtio-console-paddr = "0xFFFFFFFF" +# Virtio console irq +virtio-console-irq = "0" + # Timer interrupt frequency in Hz. timer-frequency = "10_000_000" # 10MHz diff --git a/platforms/x86_64-qemu-q35.toml b/platforms/x86_64-qemu-q35.toml index a3a119758..135615880 100644 --- a/platforms/x86_64-qemu-q35.toml +++ b/platforms/x86_64-qemu-q35.toml @@ -38,5 +38,10 @@ pci-bus-end = "0xff" # PCI device memory ranges (not used on x86). pci-ranges = [] +# Virtio console +virtio-console-paddr = "0xFFFFFFFF" +# Virtio console irq +virtio-console-irq = "0" + # Timer interrupt frequencyin Hz. timer-frequency = "4_000_000_000" # 4.0GHz diff --git a/scripts/make/qemu.mk b/scripts/make/qemu.mk index 5a6340438..7d99e4dff 100644 --- a/scripts/make/qemu.mk +++ b/scripts/make/qemu.mk @@ -29,9 +29,17 @@ qemu_args-aarch64 := \ -machine virt \ -kernel $(OUT_BIN) + qemu_args-y := -m 2G -smp $(SMP) $(qemu_args-$(ARCH)) \ -append ";$(ARGS);$(ENVS)" +qemu_args-$(CONSOLE) += \ + -global virtio-mmio.force-legacy=false \ + -device virtio-serial-device,id=virtio-serial0 \ + -chardev stdio,id=char0,mux=on\ + -device virtconsole,chardev=char0 \ + -serial chardev:char0 + qemu_args-$(BLK) += \ -device virtio-blk-$(vdev-suffix),drive=disk0 \ -drive id=disk0,if=none,format=raw,file=$(DISK_IMG) @@ -59,7 +67,9 @@ qemu_args-$(GRAPHIC) += \ -device virtio-gpu-$(vdev-suffix) -vga none \ -serial mon:stdio -ifeq ($(GRAPHIC), n) +ifeq ($(CONSOLE), y) + qemu_args-y += -display none +else ifeq ($(GRAPHIC), n) qemu_args-y += -nographic endif diff --git a/ulib/axstd/Cargo.toml b/ulib/axstd/Cargo.toml index 8f57a458c..7c604d674 100644 --- a/ulib/axstd/Cargo.toml +++ b/ulib/axstd/Cargo.toml @@ -50,6 +50,7 @@ fs = ["arceos_api/fs", "ruxfeat/fs"] myfs = ["arceos_api/myfs", "ruxfeat/myfs"] blkfs = ["ruxfeat/blkfs"] virtio-9p = ["ruxfeat/virtio-9p"] +virtio_console = ["ruxfeat/virtio_console"] net-9p = ["ruxfeat/net-9p"] # Networking