feature: virtio console support (#1113)

feat(virtio): add virtio console driver support

- Implement virtio console driver with TTY interface
- Add HVC device support for console output
- Update devfs to handle HVC devices
- Fix virtio driver registration and initialization
- Improve virtio net driver interrupt handling
- Clean up block device naming implementation
- Add clippy lint checks to multiple crates
- Fix slab allocator alignment issues
- Update QEMU run script for virtio consoleagonOS.org>

---------

Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
LoGin
2025-03-27 20:48:40 +08:00
committed by GitHub
parent 3d663af8a2
commit b6db20c072
31 changed files with 974 additions and 141 deletions

1
.gitignore vendored
View File

@ -19,3 +19,4 @@ cppcheck.xml
.cache
compile_commands.json
/logs/
*.log

View File

@ -57,7 +57,7 @@ system_error = { path = "crates/system_error" }
uefi = { version = "=0.26.0", features = ["alloc"] }
uefi-raw = "=0.5.0"
unified-init = { path = "crates/unified-init" }
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "f91c807965" }
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "415ab38ff9" }
wait_queue_macros = { path = "crates/wait_queue_macros" }
paste = "=1.0.14"
slabmalloc = { path = "crates/rust-slabmalloc" }

View File

@ -7,6 +7,12 @@ pub struct BitMapCore<T: BitOps> {
phantom: PhantomData<T>,
}
impl<T: BitOps> Default for BitMapCore<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: BitOps> BitMapCore<T> {
pub const fn new() -> Self {
Self {

View File

@ -2,6 +2,7 @@
#![feature(core_intrinsics)]
#![allow(incomplete_features)] // for const generics
#![feature(generic_const_exprs)]
#![deny(clippy::all)]
#![allow(internal_features)]
#![allow(clippy::needless_return)]

View File

@ -23,7 +23,8 @@
#![crate_name = "slabmalloc"]
#![crate_type = "lib"]
#![feature(maybe_uninit_as_bytes)]
#![deny(clippy::all)]
#![allow(clippy::needless_return)]
extern crate alloc;
mod pages;

View File

@ -33,7 +33,7 @@ impl Bitfield for [AtomicU64] {
fn initialize(&mut self, for_size: usize, capacity: usize) {
// Set everything to allocated
for bitmap in self.iter_mut() {
*bitmap = AtomicU64::new(u64::max_value());
*bitmap = AtomicU64::new(u64::MAX);
}
// Mark actual slots as free
@ -56,7 +56,7 @@ impl Bitfield for [AtomicU64] {
) -> Option<(usize, usize)> {
for (base_idx, b) in self.iter().enumerate() {
let bitval = b.load(Ordering::Relaxed);
if bitval == u64::max_value() {
if bitval == u64::MAX {
continue;
} else {
let negated = !bitval;
@ -117,7 +117,7 @@ impl Bitfield for [AtomicU64] {
#[inline(always)]
fn is_full(&self) -> bool {
self.iter()
.filter(|&x| x.load(Ordering::Relaxed) != u64::max_value())
.filter(|&x| x.load(Ordering::Relaxed) != u64::MAX)
.count()
== 0
}
@ -268,10 +268,10 @@ impl<'a> ObjectPage<'a> {
}
// These needs some more work to be really safe...
unsafe impl<'a> Send for ObjectPage<'a> {}
unsafe impl<'a> Sync for ObjectPage<'a> {}
unsafe impl Send for ObjectPage<'_> {}
unsafe impl Sync for ObjectPage<'_> {}
impl<'a> AllocablePage for ObjectPage<'a> {
impl AllocablePage for ObjectPage<'_> {
const SIZE: usize = OBJECT_PAGE_SIZE;
fn bitfield(&self) -> &[AtomicU64; 8] {
@ -296,7 +296,7 @@ impl<'a> Default for ObjectPage<'a> {
}
}
impl<'a> fmt::Debug for ObjectPage<'a> {
impl fmt::Debug for ObjectPage<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ObjectPage")
}
@ -401,6 +401,8 @@ impl<'a, T: AllocablePage> PageList<'a, T> {
});
self.elements -= 1;
#[allow(clippy::manual_inspect)]
new_head.map(|node| {
*node.prev() = Rawlink::none();
*node.next() = Rawlink::none();
@ -434,6 +436,7 @@ impl<'a, P: AllocablePage + 'a> Iterator for ObjectPageIterMut<'a, P> {
#[inline]
fn next(&mut self) -> Option<&'a mut P> {
unsafe {
#[allow(clippy::manual_inspect)]
self.head.resolve_mut().map(|next| {
self.head = match next.next().resolve_mut() {
None => Rawlink::none(),

View File

@ -71,7 +71,7 @@ macro_rules! new_sc_allocator {
SCAllocator {
size: $size,
allocation_count: 0,
obj_per_page: obj_per_page,
obj_per_page,
empty_slabs: PageList::new(),
slabs: PageList::new(),
full_slabs: PageList::new(),

View File

@ -3,7 +3,7 @@ use crate::driver::{
base::{
device::{
device_number::{DeviceNumber, Major},
Device, DeviceError, IdTable, BLOCKDEVS,
DevName, Device, DeviceError, IdTable, BLOCKDEVS,
},
map::{
DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
@ -13,8 +13,8 @@ use crate::driver::{
block::cache::{cached_block_device::BlockCache, BlockCacheError, BLOCK_SIZE},
};
use alloc::{string::String, sync::Arc, vec::Vec};
use core::{any::Any, fmt::Display, ops::Deref};
use alloc::{sync::Arc, vec::Vec};
use core::any::Any;
use log::error;
use system_error::SystemError;
@ -221,74 +221,11 @@ pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId {
return lba_id * blk_size;
}
/// 块设备的名字
pub struct BlockDevName {
name: Arc<String>,
id: usize,
}
impl BlockDevName {
pub fn new(name: String, id: usize) -> Self {
return BlockDevName {
name: Arc::new(name),
id,
};
}
#[inline]
pub fn id(&self) -> usize {
return self.id;
}
}
impl core::fmt::Debug for BlockDevName {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
return write!(f, "{}", self.name);
}
}
impl Display for BlockDevName {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
return write!(f, "{}", self.name);
}
}
impl Clone for BlockDevName {
fn clone(&self) -> Self {
return BlockDevName {
name: self.name.clone(),
id: self.id,
};
}
}
impl core::hash::Hash for BlockDevName {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl Deref for BlockDevName {
type Target = String;
fn deref(&self) -> &Self::Target {
return self.name.as_ref();
}
}
impl PartialEq for BlockDevName {
fn eq(&self, other: &Self) -> bool {
return self.name == other.name;
}
}
impl Eq for BlockDevName {}
/// @brief 块设备应该实现的操作
pub trait BlockDevice: Device {
/// # dev_name
/// 返回块设备的名字
fn dev_name(&self) -> &BlockDevName;
fn dev_name(&self) -> &DevName;
fn blkdev_meta(&self) -> &BlockDevMeta;

View File

@ -6,14 +6,14 @@ use system_error::SystemError;
use unified_init::macros::unified_init;
use crate::{
driver::base::block::gendisk::GenDisk,
driver::base::{block::gendisk::GenDisk, device::DevName},
filesystem::mbr::MbrDiskPartionTable,
init::initcall::INITCALL_POSTCORE,
libs::spinlock::{SpinLock, SpinLockGuard},
};
use super::{
block_device::{BlockDevName, BlockDevice, GeneralBlockRange},
block_device::{BlockDevice, GeneralBlockRange},
gendisk::GenDiskMap,
};
@ -38,7 +38,7 @@ pub struct BlockDevManager {
}
struct InnerBlockDevManager {
disks: HashMap<BlockDevName, Arc<dyn BlockDevice>>,
disks: HashMap<DevName, Arc<dyn BlockDevice>>,
}
impl BlockDevManager {
pub fn new() -> Self {
@ -207,7 +207,7 @@ impl BlockDevManager {
}
pub struct BlockDevMeta {
pub devname: BlockDevName,
pub devname: DevName,
inner: SpinLock<InnerBlockDevMeta>,
}
@ -216,7 +216,7 @@ pub struct InnerBlockDevMeta {
}
impl BlockDevMeta {
pub fn new(devname: BlockDevName) -> Self {
pub fn new(devname: DevName) -> Self {
BlockDevMeta {
devname,
inner: SpinLock::new(InnerBlockDevMeta {

View File

@ -24,6 +24,8 @@ impl Major {
pub const UNIX98_PTY_SLAVE_MAJOR: Self =
Self::new(Self::UNIX98_PTY_MASTER_MAJOR.0 + Self::UNIX98_PTY_MAJOR_COUNT.0);
pub const HVC_MAJOR: Self = Self::new(229);
pub const fn new(x: u32) -> Self {
Major(x)
}

View File

@ -26,8 +26,8 @@ use crate::{
},
};
use core::intrinsics::unlikely;
use core::{any::Any, fmt::Debug};
use core::{fmt::Display, intrinsics::unlikely, ops::Deref};
use system_error::SystemError;
use self::{
@ -124,6 +124,69 @@ unsafe fn set_sys_devices_virtual_kset(kset: Arc<KSet>) {
DEVICES_VIRTUAL_KSET_INSTANCE = Some(kset);
}
/// /dev下面的设备的名字
pub struct DevName {
name: Arc<String>,
id: usize,
}
impl DevName {
pub fn new(name: String, id: usize) -> Self {
return DevName {
name: Arc::new(name),
id,
};
}
#[inline]
pub fn id(&self) -> usize {
return self.id;
}
}
impl core::fmt::Debug for DevName {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
return write!(f, "{}", self.name);
}
}
impl Display for DevName {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
return write!(f, "{}", self.name);
}
}
impl Clone for DevName {
fn clone(&self) -> Self {
return DevName {
name: self.name.clone(),
id: self.id,
};
}
}
impl core::hash::Hash for DevName {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl Deref for DevName {
type Target = String;
fn deref(&self) -> &Self::Target {
return self.name.as_ref();
}
}
impl PartialEq for DevName {
fn eq(&self, other: &Self) -> bool {
return self.name == other.name;
}
}
impl Eq for DevName {}
/// 设备应该实现的操作
///
/// ## 注意

View File

@ -1,7 +1,6 @@
use core::{any::Any, fmt::Debug};
use alloc::{
collections::LinkedList,
string::{String, ToString},
sync::{Arc, Weak},
vec::Vec,
@ -16,7 +15,7 @@ use crate::{
driver::{
base::{
block::{
block_device::{BlockDevName, BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE},
block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE},
disk_info::Partition,
manager::{block_dev_manager, BlockDevMeta},
},
@ -24,7 +23,7 @@ use crate::{
device::{
bus::Bus,
driver::{Driver, DriverCommonData},
Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
},
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
kset::KSet,
@ -103,7 +102,7 @@ pub struct VirtIOBlkManager {
struct InnerVirtIOBlkManager {
id_bmp: bitmap::StaticBitmap<{ VirtIOBlkManager::MAX_DEVICES }>,
devname: [Option<BlockDevName>; VirtIOBlkManager::MAX_DEVICES],
devname: [Option<DevName>; VirtIOBlkManager::MAX_DEVICES],
}
impl VirtIOBlkManager {
@ -122,7 +121,7 @@ impl VirtIOBlkManager {
self.inner.lock()
}
pub fn alloc_id(&self) -> Option<BlockDevName> {
pub fn alloc_id(&self) -> Option<DevName> {
let mut inner = self.inner();
let idx = inner.id_bmp.first_false_index()?;
inner.id_bmp.set(idx, true);
@ -132,9 +131,9 @@ impl VirtIOBlkManager {
}
/// Generate a new block device name like 'vda', 'vdb', etc.
fn format_name(id: usize) -> BlockDevName {
fn format_name(id: usize) -> DevName {
let x = (b'a' + id as u8) as char;
BlockDevName::new(format!("vd{}", x), id)
DevName::new(format!("vd{}", x), id)
}
#[allow(dead_code)]
@ -204,7 +203,7 @@ impl VirtIOBlkDevice {
}
impl BlockDevice for VirtIOBlkDevice {
fn dev_name(&self) -> &BlockDevName {
fn dev_name(&self) -> &DevName {
&self.blkdev_meta.devname
}
@ -349,7 +348,7 @@ impl VirtIODevice for VirtIOBlkDevice {
impl Device for VirtIOBlkDevice {
fn dev_type(&self) -> DeviceType {
DeviceType::Net
DeviceType::Block
}
fn id_table(&self) -> IdTable {
@ -479,7 +478,7 @@ fn virtio_blk_driver_init() -> Result<(), SystemError> {
let driver = VirtIOBlkDriver::new();
virtio_driver_manager()
.register(driver.clone() as Arc<dyn VirtIODriver>)
.expect("Add virtio net driver failed");
.expect("Add virtio blk driver failed");
unsafe {
VIRTIO_BLK_DRIVER = Some(driver);
}
@ -546,12 +545,12 @@ impl VirtIODriver for VirtIOBlkDriver {
return Ok(());
}
fn virtio_id_table(&self) -> LinkedList<crate::driver::virtio::VirtioDeviceId> {
fn virtio_id_table(&self) -> Vec<crate::driver::virtio::VirtioDeviceId> {
self.inner().virtio_driver_common.id_table.clone()
}
fn add_virtio_id(&self, id: VirtioDeviceId) {
self.inner().virtio_driver_common.id_table.push_back(id);
self.inner().virtio_driver_common.id_table.push(id);
}
}

View File

@ -0,0 +1 @@
pub mod virtio_console;

View File

@ -0,0 +1,736 @@
use crate::{
driver::{
base::{
class::Class,
device::{
bus::Bus,
device_number::Major,
driver::{Driver, DriverCommonData},
DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
},
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
kset::KSet,
},
tty::{
console::ConsoleSwitch,
kthread::send_to_tty_refresh_thread,
termios::{WindowSize, TTY_STD_TERMIOS},
tty_core::{TtyCore, TtyCoreData},
tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation},
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, VirtConsole},
},
video::console::dummycon::dummy_console,
virtio::{
sysfs::{virtio_bus, virtio_device_manager, virtio_driver_manager},
transport::VirtIOTransport,
virtio_drivers_error_to_system_error,
virtio_impl::HalImpl,
VirtIODevice, VirtIODeviceIndex, VirtIODriver, VirtIODriverCommonData, VirtioDeviceId,
VIRTIO_VENDOR_ID,
},
},
exception::{irqdesc::IrqReturn, IrqNumber},
filesystem::kernfs::KernFSInode,
init::initcall::INITCALL_POSTCORE,
libs::{
lazy_init::Lazy,
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
spinlock::{SpinLock, SpinLockGuard},
},
};
use alloc::string::String;
use alloc::string::ToString;
use alloc::sync::{Arc, Weak};
use alloc::vec::Vec;
use bitmap::traits::BitMapOps;
use core::fmt::Debug;
use core::fmt::Formatter;
use core::{
any::Any,
sync::atomic::{compiler_fence, Ordering},
};
use system_error::SystemError;
use unified_init::macros::unified_init;
use virtio_drivers::device::console::VirtIOConsole;
const VIRTIO_CONSOLE_BASENAME: &str = "virtio_console";
const HVC_MINOR: u32 = 0;
static mut VIRTIO_CONSOLE_DRIVER: Option<Arc<VirtIOConsoleDriver>> = None;
static mut TTY_HVC_DRIVER: Option<Arc<TtyDriver>> = None;
#[inline(always)]
fn tty_hvc_driver() -> &'static Arc<TtyDriver> {
unsafe { TTY_HVC_DRIVER.as_ref().unwrap() }
}
pub fn virtio_console(
transport: VirtIOTransport,
dev_id: Arc<DeviceId>,
dev_parent: Option<Arc<dyn Device>>,
) {
log::debug!(
"virtio_console: dev_id: {:?}, parent: {:?}",
dev_id,
dev_parent
);
let device = VirtIOConsoleDevice::new(transport, dev_id.clone());
if device.is_none() {
return;
}
let device = device.unwrap();
if let Some(dev_parent) = dev_parent {
device.set_dev_parent(Some(Arc::downgrade(&dev_parent)));
}
virtio_device_manager()
.device_add(device.clone() as Arc<dyn VirtIODevice>)
.expect("Add virtio console failed");
}
//
#[derive(Debug)]
#[cast_to([sync] VirtIODevice)]
#[cast_to([sync] Device)]
pub struct VirtIOConsoleDevice {
dev_name: Lazy<DevName>,
dev_id: Arc<DeviceId>,
_self_ref: Weak<Self>,
locked_kobj_state: LockedKObjectState,
inner: SpinLock<InnerVirtIOConsoleDevice>,
}
unsafe impl Send for VirtIOConsoleDevice {}
unsafe impl Sync for VirtIOConsoleDevice {}
impl VirtIOConsoleDevice {
pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
// 设置中断
if let Err(err) = transport.setup_irq(dev_id.clone()) {
log::error!(
"VirtIOConsoleDevice '{dev_id:?}' setup_irq failed: {:?}",
err
);
return None;
}
let irq = Some(transport.irq());
let device_inner = VirtIOConsole::<HalImpl, VirtIOTransport>::new(transport);
if let Err(e) = device_inner {
log::error!("VirtIOConsoleDevice '{dev_id:?}' create failed: {:?}", e);
return None;
}
let mut device_inner: VirtIOConsole<HalImpl, VirtIOTransport> = device_inner.unwrap();
device_inner.enable_interrupts();
let dev = Arc::new_cyclic(|self_ref| Self {
dev_id,
dev_name: Lazy::new(),
_self_ref: self_ref.clone(),
locked_kobj_state: LockedKObjectState::default(),
inner: SpinLock::new(InnerVirtIOConsoleDevice {
device_inner,
name: None,
virtio_index: None,
device_common: DeviceCommonData::default(),
kobject_common: KObjectCommonData::default(),
irq,
}),
});
Some(dev)
}
fn inner(&self) -> SpinLockGuard<InnerVirtIOConsoleDevice> {
self.inner.lock_irqsave()
}
}
struct InnerVirtIOConsoleDevice {
device_inner: VirtIOConsole<HalImpl, VirtIOTransport>,
virtio_index: Option<VirtIODeviceIndex>,
name: Option<String>,
device_common: DeviceCommonData,
kobject_common: KObjectCommonData,
irq: Option<IrqNumber>,
}
impl Debug for InnerVirtIOConsoleDevice {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("InnerVirtIOConsoleDevice")
.field("virtio_index", &self.virtio_index)
.field("name", &self.name)
.field("device_common", &self.device_common)
.field("kobject_common", &self.kobject_common)
.field("irq", &self.irq)
.finish()
}
}
impl KObject for VirtIOConsoleDevice {
fn as_any_ref(&self) -> &dyn Any {
self
}
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
self.inner().kobject_common.kern_inode = inode;
}
fn inode(&self) -> Option<Arc<KernFSInode>> {
self.inner().kobject_common.kern_inode.clone()
}
fn parent(&self) -> Option<Weak<dyn KObject>> {
self.inner().kobject_common.parent.clone()
}
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
self.inner().kobject_common.parent = parent;
}
fn kset(&self) -> Option<Arc<KSet>> {
self.inner().kobject_common.kset.clone()
}
fn set_kset(&self, kset: Option<Arc<KSet>>) {
self.inner().kobject_common.kset = kset;
}
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
self.inner().kobject_common.kobj_type
}
fn name(&self) -> String {
self.device_name()
}
fn set_name(&self, _name: String) {
// do nothing
}
fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
self.locked_kobj_state.read()
}
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
self.locked_kobj_state.write()
}
fn set_kobj_state(&self, state: KObjectState) {
*self.locked_kobj_state.write() = state;
}
fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) {
self.inner().kobject_common.kobj_type = ktype;
}
}
impl Device for VirtIOConsoleDevice {
fn dev_type(&self) -> DeviceType {
DeviceType::Char
}
fn id_table(&self) -> IdTable {
IdTable::new(VIRTIO_CONSOLE_BASENAME.to_string(), None)
}
fn bus(&self) -> Option<Weak<dyn Bus>> {
self.inner().device_common.bus.clone()
}
fn set_bus(&self, bus: Option<Weak<dyn Bus>>) {
self.inner().device_common.bus = bus;
}
fn class(&self) -> Option<Arc<dyn Class>> {
let mut guard = self.inner();
let r = guard.device_common.class.clone()?.upgrade();
if r.is_none() {
guard.device_common.class = None;
}
return r;
}
fn set_class(&self, class: Option<Weak<dyn Class>>) {
self.inner().device_common.class = class;
}
fn driver(&self) -> Option<Arc<dyn Driver>> {
let r = self.inner().device_common.driver.clone()?.upgrade();
if r.is_none() {
self.inner().device_common.driver = None;
}
return r;
}
fn set_driver(&self, driver: Option<Weak<dyn Driver>>) {
self.inner().device_common.driver = driver;
}
fn is_dead(&self) -> bool {
false
}
fn can_match(&self) -> bool {
self.inner().device_common.can_match
}
fn set_can_match(&self, can_match: bool) {
self.inner().device_common.can_match = can_match;
}
fn state_synced(&self) -> bool {
true
}
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
self.inner().device_common.get_parent_weak_or_clear()
}
fn set_dev_parent(&self, parent: Option<Weak<dyn Device>>) {
self.inner().device_common.parent = parent;
}
}
impl VirtIODevice for VirtIOConsoleDevice {
fn handle_irq(&self, _irq: IrqNumber) -> Result<IrqReturn, SystemError> {
let mut buf = [0u8; 8];
let mut index = 0;
// Read up to the size of the buffer
while index < buf.len() {
if let Ok(Some(c)) = self.inner().device_inner.recv(true) {
buf[index] = c;
index += 1;
} else {
break; // No more bytes to read
}
}
send_to_tty_refresh_thread(&buf[0..index]);
Ok(IrqReturn::Handled)
}
fn dev_id(&self) -> &Arc<DeviceId> {
&self.dev_id
}
fn set_device_name(&self, name: String) {
self.inner().name = Some(name);
}
fn device_name(&self) -> String {
self.inner()
.name
.clone()
.unwrap_or_else(|| VIRTIO_CONSOLE_BASENAME.to_string())
}
fn set_virtio_device_index(&self, index: VirtIODeviceIndex) {
self.inner().virtio_index = Some(index);
}
fn virtio_device_index(&self) -> Option<VirtIODeviceIndex> {
self.inner().virtio_index
}
fn device_type_id(&self) -> u32 {
virtio_drivers::transport::DeviceType::Console as u32
}
fn vendor(&self) -> u32 {
VIRTIO_VENDOR_ID.into()
}
fn irq(&self) -> Option<IrqNumber> {
self.inner().irq
}
}
#[derive(Debug)]
#[cast_to([sync] VirtIODriver)]
#[cast_to([sync] Driver)]
struct VirtIOConsoleDriver {
inner: SpinLock<InnerVirtIOConsoleDriver>,
devices: RwLock<[Option<Arc<VirtIOConsoleDevice>>; Self::MAX_DEVICES]>,
kobj_state: LockedKObjectState,
}
impl VirtIOConsoleDriver {
const MAX_DEVICES: usize = 32;
pub fn new() -> Arc<Self> {
let inner = InnerVirtIOConsoleDriver {
virtio_driver_common: VirtIODriverCommonData::default(),
driver_common: DriverCommonData::default(),
kobj_common: KObjectCommonData::default(),
id_bmp: bitmap::StaticBitmap::new(),
devname: [const { None }; Self::MAX_DEVICES],
};
let id_table = VirtioDeviceId::new(
virtio_drivers::transport::DeviceType::Console as u32,
VIRTIO_VENDOR_ID.into(),
);
let result = VirtIOConsoleDriver {
inner: SpinLock::new(inner),
kobj_state: LockedKObjectState::default(),
devices: RwLock::new([const { None }; Self::MAX_DEVICES]),
};
result.add_virtio_id(id_table);
Arc::new(result)
}
fn inner(&self) -> SpinLockGuard<InnerVirtIOConsoleDriver> {
self.inner.lock()
}
fn do_install(
&self,
driver: Arc<TtyDriver>,
tty: Arc<TtyCore>,
vc: Arc<VirtConsole>,
) -> Result<(), SystemError> {
driver.standard_install(tty.clone())?;
vc.port().setup_internal_tty(Arc::downgrade(&tty));
tty.set_port(vc.port());
vc.devfs_setup()?;
Ok(())
}
}
#[derive(Debug)]
struct InnerVirtIOConsoleDriver {
id_bmp: bitmap::StaticBitmap<{ VirtIOConsoleDriver::MAX_DEVICES }>,
devname: [Option<DevName>; VirtIOConsoleDriver::MAX_DEVICES],
virtio_driver_common: VirtIODriverCommonData,
driver_common: DriverCommonData,
kobj_common: KObjectCommonData,
}
impl InnerVirtIOConsoleDriver {
fn alloc_id(&mut self) -> Option<DevName> {
let idx = self.id_bmp.first_false_index()?;
self.id_bmp.set(idx, true);
let name = Self::format_name(idx);
self.devname[idx] = Some(name.clone());
Some(name)
}
fn format_name(id: usize) -> DevName {
DevName::new(format!("vport{}", id), id)
}
fn free_id(&mut self, id: usize) {
if id >= VirtIOConsoleDriver::MAX_DEVICES {
return;
}
self.id_bmp.set(id, false);
self.devname[id] = None;
}
}
impl TtyOperation for VirtIOConsoleDriver {
fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> {
Ok(())
}
fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
if nr > buf.len() {
return Err(SystemError::EINVAL);
}
let index = tty.index();
if index >= VirtIOConsoleDriver::MAX_DEVICES {
return Err(SystemError::ENODEV);
}
let dev = self.devices.read()[index]
.clone()
.ok_or(SystemError::ENODEV)?;
let mut cnt = 0;
let mut inner = dev.inner();
for c in buf[0..nr].iter() {
if let Err(e) = inner.device_inner.send(*c) {
if cnt > 0 {
return Ok(cnt);
}
return Err(virtio_drivers_error_to_system_error(e));
} else {
cnt += 1;
}
}
Ok(cnt)
}
fn flush_chars(&self, _tty: &TtyCoreData) {
// do nothing
}
fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> {
Err(SystemError::ENOIOCTLCMD)
}
fn close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError> {
Ok(())
}
fn resize(&self, tty: Arc<TtyCore>, winsize: WindowSize) -> Result<(), SystemError> {
*tty.core().window_size_write() = winsize;
Ok(())
}
fn install(&self, driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
if tty.core().index() >= VirtIOConsoleDriver::MAX_DEVICES {
return Err(SystemError::ENODEV);
}
let dev = self.devices.read()[tty.core().index()]
.clone()
.ok_or(SystemError::ENODEV)?;
let info = dev.inner().device_inner.info();
let winsize = WindowSize::new(info.rows, info.columns, 1, 1);
*tty.core().window_size_write() = winsize;
let vc_data = Arc::new(SpinLock::new(VirtualConsoleData::new(usize::MAX)));
let mut vc_data_guard = vc_data.lock_irqsave();
vc_data_guard.set_driver_funcs(Arc::downgrade(&dummy_console()) as Weak<dyn ConsoleSwitch>);
vc_data_guard.init(
Some(tty.core().window_size().row.into()),
Some(tty.core().window_size().col.into()),
true,
);
drop(vc_data_guard);
let vc = VirtConsole::new(Some(vc_data));
let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
self.do_install(driver, tty, vc.clone()).inspect_err(|_| {
vc_manager().free(vc_index);
})?;
Ok(())
}
}
impl VirtIODriver for VirtIOConsoleDriver {
fn probe(&self, device: &Arc<dyn VirtIODevice>) -> Result<(), SystemError> {
log::debug!("VirtIOConsoleDriver::probe()");
let _dev = device
.clone()
.arc_any()
.downcast::<VirtIOConsoleDevice>()
.map_err(|_| {
log::error!(
"VirtIOConsoleDriver::probe() failed: device is not a VirtIO console device. Device: '{:?}'",
device.name()
);
SystemError::EINVAL
})?;
log::debug!("VirtIOConsoleDriver::probe() succeeded");
Ok(())
}
fn virtio_id_table(&self) -> Vec<VirtioDeviceId> {
self.inner().virtio_driver_common.id_table.clone()
}
fn add_virtio_id(&self, id: VirtioDeviceId) {
self.inner().virtio_driver_common.id_table.push(id);
}
}
impl Driver for VirtIOConsoleDriver {
fn id_table(&self) -> Option<IdTable> {
Some(IdTable::new(VIRTIO_CONSOLE_BASENAME.to_string(), None))
}
// todo: 添加错误时,资源释放的逻辑
fn add_device(&self, device: Arc<dyn Device>) {
log::debug!("virtio console: add_device");
let virtio_con_dev = device.arc_any().downcast::<VirtIOConsoleDevice>().expect(
"VirtIOConsoleDriver::add_device() failed: device is not a VirtIOConsoleDevice",
);
if virtio_con_dev.dev_name.initialized() {
panic!("VirtIOConsoleDriver::add_device() failed: dev_name has already initialized for device: '{:?}'",
virtio_con_dev.dev_id(),
);
}
log::debug!("virtio console: add_device: to lock inner");
let mut inner = self.inner();
log::debug!("virtio console: add_device: inner.locked");
let dev_name = inner.alloc_id();
if dev_name.is_none() {
panic!("Failed to allocate ID for VirtIO console device: '{:?}', virtio console device limit exceeded.", virtio_con_dev.dev_id())
}
let dev_name = dev_name.unwrap();
virtio_con_dev.dev_name.init(dev_name);
inner
.driver_common
.devices
.push(virtio_con_dev.clone() as Arc<dyn Device>);
// avoid deadlock in `init_tty_device`
drop(inner);
let mut devices_fast_guard = self.devices.write();
let index = virtio_con_dev.dev_name.get().id();
if devices_fast_guard[index].is_none() {
devices_fast_guard[index] = Some(virtio_con_dev.clone());
} else {
panic!("VirtIOConsoleDriver::add_device() failed: device slot already occupied at index: {}", index);
}
// avoid deadlock in `init_tty_device`
drop(devices_fast_guard);
log::debug!("virtio console: add_device: to init tty device");
let r = tty_hvc_driver().init_tty_device(Some(index));
log::debug!(
"virtio console: add_device: init tty device done, index: {}, dev_name: {:?}",
index,
virtio_con_dev.dev_name.get(),
);
if let Err(e) = r {
log::error!(
"Failed to init tty device for virtio console device, index: {}, dev_name: {:?}, err: {:?}",
index,
virtio_con_dev.dev_name.get(),
e,
);
return;
}
}
fn delete_device(&self, device: &Arc<dyn Device>) {
let virtio_con_dev = device
.clone()
.arc_any()
.downcast::<VirtIOConsoleDevice>()
.expect(
"VirtIOConsoleDriver::delete_device() failed: device is not a VirtIOConsoleDevice",
);
let mut guard = self.inner();
let mut devices_fast_guard = self.devices.write();
let index = guard
.driver_common
.devices
.iter()
.position(|dev| Arc::ptr_eq(device, dev))
.expect("VirtIOConsoleDriver::delete_device() failed: device not found");
guard.driver_common.devices.remove(index);
guard.free_id(virtio_con_dev.dev_name.get().id());
devices_fast_guard[index] = None;
}
fn devices(&self) -> Vec<Arc<dyn Device>> {
self.inner().driver_common.devices.clone()
}
fn bus(&self) -> Option<Weak<dyn Bus>> {
Some(Arc::downgrade(&virtio_bus()) as Weak<dyn Bus>)
}
fn set_bus(&self, _bus: Option<Weak<dyn Bus>>) {
// do nothing
}
}
impl KObject for VirtIOConsoleDriver {
fn as_any_ref(&self) -> &dyn Any {
self
}
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
self.inner().kobj_common.kern_inode = inode;
}
fn inode(&self) -> Option<Arc<KernFSInode>> {
self.inner().kobj_common.kern_inode.clone()
}
fn parent(&self) -> Option<Weak<dyn KObject>> {
self.inner().kobj_common.parent.clone()
}
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
self.inner().kobj_common.parent = parent;
}
fn kset(&self) -> Option<Arc<KSet>> {
self.inner().kobj_common.kset.clone()
}
fn set_kset(&self, kset: Option<Arc<KSet>>) {
self.inner().kobj_common.kset = kset;
}
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
self.inner().kobj_common.kobj_type
}
fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) {
self.inner().kobj_common.kobj_type = ktype;
}
fn name(&self) -> String {
VIRTIO_CONSOLE_BASENAME.to_string()
}
fn set_name(&self, _name: String) {
// do nothing
}
fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
self.kobj_state.read()
}
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
self.kobj_state.write()
}
fn set_kobj_state(&self, state: KObjectState) {
*self.kobj_state.write() = state;
}
}
#[unified_init(INITCALL_POSTCORE)]
fn virtio_console_driver_init() -> Result<(), SystemError> {
let driver = VirtIOConsoleDriver::new();
virtio_driver_manager()
.register(driver.clone() as Arc<dyn VirtIODriver>)
.expect("Add virtio console driver failed");
unsafe {
VIRTIO_CONSOLE_DRIVER = Some(driver.clone());
}
let hvc_tty_driver = TtyDriver::new(
VirtIOConsoleDriver::MAX_DEVICES.try_into().unwrap(),
"hvc",
0,
Major::HVC_MAJOR,
HVC_MINOR,
TtyDriverType::System,
*TTY_STD_TERMIOS,
driver.clone(),
None,
);
let hvc_tty_driver = TtyDriverManager::tty_register_driver(hvc_tty_driver)?;
compiler_fence(Ordering::SeqCst);
unsafe {
TTY_HVC_DRIVER = Some(hvc_tty_driver);
}
compiler_fence(Ordering::SeqCst);
return Ok(());
}

View File

@ -1,15 +1,13 @@
use super::{_port, hba::HbaCmdTable};
use crate::arch::MMArch;
use crate::driver::base::block::block_device::{
BlockDevName, BlockDevice, BlockId, GeneralBlockRange,
};
use crate::driver::base::block::block_device::{BlockDevice, BlockId, GeneralBlockRange};
use crate::driver::base::block::disk_info::Partition;
use crate::driver::base::block::manager::BlockDevMeta;
use crate::driver::base::class::Class;
use crate::driver::base::device::bus::Bus;
use crate::driver::base::device::driver::Driver;
use crate::driver::base::device::{Device, DeviceType, IdTable};
use crate::driver::base::device::{DevName, Device, DeviceType, IdTable};
use crate::driver::base::kobject::{KObjType, KObject, KObjectState};
use crate::driver::base::kset::KSet;
use crate::driver::disk::ahci::HBA_PxIS_TFES;
@ -520,7 +518,7 @@ impl Device for LockedAhciDisk {
}
impl BlockDevice for LockedAhciDisk {
fn dev_name(&self) -> &BlockDevName {
fn dev_name(&self) -> &DevName {
&self.blkdev_meta.devname
}

View File

@ -1,6 +1,7 @@
pub mod acpi;
pub mod base;
pub mod block;
pub mod char;
pub mod clocksource;
pub mod disk;
pub mod firmware;

View File

@ -587,11 +587,13 @@ impl Drop for E1000EDevice {
pub fn e1000e_init() {
match e1000e_probe() {
Ok(_code) => {
info!("Successfully init e1000e device!");
Ok(code) => {
if code == 1 {
info!("Successfully init e1000e device!");
}
}
Err(_error) => {
info!("Error occurred!");
Err(error) => {
info!("Failed to init e1000e device: {error:?}");
}
}
}
@ -602,6 +604,7 @@ pub fn e1000e_probe() -> Result<u64, E1000EPciError> {
if result.is_empty() {
return Ok(0);
}
let mut initialized = false;
for device in result {
let standard_device = device.as_standard_device().unwrap();
if standard_device.common_header.vendor_id == 0x8086 {
@ -625,11 +628,16 @@ pub fn e1000e_probe() -> Result<u64, E1000EPciError> {
.unwrap(),
)?;
e1000e_driver_init(e1000e);
initialized = true;
}
}
}
return Ok(1);
if initialized {
Ok(1)
} else {
Ok(0)
}
}
// 用到的e1000e寄存器结构体
@ -787,6 +795,7 @@ const E1000E_TXD_CMD_RS: u8 = 1 << 3;
/// E1000E驱动初始化过程中可能的错误
#[allow(dead_code)]
#[derive(Debug)]
pub enum E1000EPciError {
// 获取到错误类型的BARIO BAR
// An IO BAR was provided rather than a memory BAR.

View File

@ -6,7 +6,6 @@ use core::{
};
use alloc::{
collections::LinkedList,
string::{String, ToString},
sync::{Arc, Weak},
vec::Vec,
@ -108,7 +107,7 @@ impl VirtIONetDevice {
let mac = wire::EthernetAddress::from_bytes(&driver_net.mac_address());
debug!("VirtIONetDevice mac: {:?}", mac);
let device_inner = VirtIONicDeviceInner::new(driver_net);
device_inner.inner.lock_irqsave().enable_interrupts();
let dev = Arc::new(Self {
dev_id,
inner: SpinLock::new(InnerVirtIONetDevice {
@ -259,7 +258,9 @@ impl Device for VirtIONetDevice {
impl VirtIODevice for VirtIONetDevice {
fn handle_irq(&self, _irq: IrqNumber) -> Result<IrqReturn, SystemError> {
poll_ifaces_try_lock_onetime().ok();
if poll_ifaces_try_lock_onetime().is_err() {
log::error!("virtio_net: try lock failed");
}
return Ok(IrqReturn::Handled);
}
@ -865,12 +866,12 @@ impl VirtIODriver for VirtIONetDriver {
return Ok(());
}
fn virtio_id_table(&self) -> LinkedList<VirtioDeviceId> {
fn virtio_id_table(&self) -> Vec<VirtioDeviceId> {
self.inner().virtio_driver_common.id_table.clone()
}
fn add_virtio_id(&self, id: VirtioDeviceId) {
self.inner().virtio_driver_common.id_table.push_back(id);
self.inner().virtio_driver_common.id_table.push(id);
}
}

View File

@ -7,7 +7,7 @@ use crate::{
libs::spinlock::{SpinLock, SpinLockGuard},
};
use super::base::block::block_device::BlockDevName;
use super::base::device::DevName;
static mut SCSI_MANAGER: Option<ScsiManager> = None;
@ -30,7 +30,7 @@ pub struct ScsiManager {
struct InnerScsiManager {
id_bmp: bitmap::StaticBitmap<{ ScsiManager::MAX_DEVICES }>,
devname: [Option<BlockDevName>; ScsiManager::MAX_DEVICES],
devname: [Option<DevName>; ScsiManager::MAX_DEVICES],
}
impl ScsiManager {
@ -49,7 +49,7 @@ impl ScsiManager {
self.inner.lock()
}
pub fn alloc_id(&self) -> Option<BlockDevName> {
pub fn alloc_id(&self) -> Option<DevName> {
let mut inner = self.inner();
let idx = inner.id_bmp.first_false_index()?;
inner.id_bmp.set(idx, true);
@ -59,9 +59,9 @@ impl ScsiManager {
}
/// Generate a new block device name like 'sda', 'sdb', etc.
fn format_name(id: usize) -> BlockDevName {
fn format_name(id: usize) -> DevName {
let x = (b'a' + id as u8) as char;
BlockDevName::new(format!("sd{}", x), id)
DevName::new(format!("sd{}", x), id)
}
#[allow(dead_code)]

View File

@ -50,6 +50,7 @@ impl Drop for TtyCore {
}
impl TtyCore {
#[inline(never)]
pub fn new(driver: Arc<TtyDriver>, index: usize) -> Arc<Self> {
let name = driver.tty_line_name(index);
let device_number = driver
@ -76,7 +77,6 @@ impl TtyCore {
device_number,
privete_fields: SpinLock::new(None),
};
return Arc::new(Self {
core,
line_discipline: Arc::new(NTtyLinediscipline {

View File

@ -309,10 +309,16 @@ impl TtyDriver {
} else {
idx = self.ida.lock().alloc().ok_or(SystemError::EBUSY)?;
}
log::debug!("init_tty_device: create TtyCore");
let tty = TtyCore::new(self.self_ref(), idx);
log::debug!("init_tty_device: to driver_install_tty");
self.driver_install_tty(tty.clone())?;
log::debug!(
"init_tty_device: driver_install_tty done, index: {}, dev_name: {:?}",
idx,
tty.core().name(),
);
let core = tty.core();
@ -321,18 +327,20 @@ impl TtyDriver {
ports[core.index()].setup_internal_tty(Arc::downgrade(&tty));
tty.set_port(ports[core.index()].clone());
}
log::debug!("init_tty_device: to ldisc_setup");
TtyLdiscManager::ldisc_setup(tty.clone(), tty.core().link())?;
// 在devfs创建对应的文件
log::debug!("init_tty_device: to new tty device");
let device = TtyDevice::new(
core.name().clone(),
IdTable::new(self.tty_line_name(idx), Some(*core.device_number())),
super::tty_device::TtyType::Tty,
);
log::debug!("init_tty_device: to devfs_register");
devfs_register(device.name_ref(), device.clone())?;
log::debug!("init_tty_device: to device_register");
device_register(device)?;
Ok(tty)
}
@ -473,8 +481,8 @@ pub trait TtyOperation: Sync + Send + Debug {
fn flush_chars(&self, tty: &TtyCoreData);
fn put_char(&self, _tty: &TtyCoreData, _ch: u8) -> Result<(), SystemError> {
Err(SystemError::ENOSYS)
fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
self.write(tty, &[ch], 1).map(|_| ())
}
fn start(&self, _tty: &TtyCoreData) -> Result<(), SystemError> {

View File

@ -58,6 +58,8 @@ lazy_static! {
static ref VC_MANAGER: VirtConsoleManager = VirtConsoleManager::new();
}
kernel_cmdline_param_kv!(CONSOLE_PARAM, console, "");
/// 获取虚拟终端管理器
#[inline]
pub fn vc_manager() -> &'static VirtConsoleManager {
@ -228,12 +230,29 @@ impl VirtConsoleManager {
}
pub fn setup_default_vc(&self) {
// todo: 从内核启动参数中获取
for name in Self::DEFAULT_VC_NAMES.iter() {
if let Some(vc) = self.lookup_vc_by_tty_name(name) {
log::info!("Set default vc with tty device: {}", name);
let mut console_value_str = CONSOLE_PARAM.value_str().unwrap_or("").trim();
if !console_value_str.is_empty() {
// 删除前缀/dev/
console_value_str = console_value_str
.strip_prefix("/dev/")
.unwrap_or(console_value_str);
if let Some(vc) = self.lookup_vc_by_tty_name(console_value_str) {
log::info!("Set vc by cmdline: {}", console_value_str);
self.set_current_vc(vc);
return;
} else {
panic!(
"virt console: set vc by cmdline failed, name: {}",
console_value_str
);
}
} else {
for name in Self::DEFAULT_VC_NAMES.iter() {
if let Some(vc) = self.lookup_vc_by_tty_name(name) {
log::info!("Set default vc with tty device: {}", name);
self.set_current_vc(vc);
return;
}
}
}

View File

@ -1,4 +1,4 @@
use alloc::{collections::LinkedList, string::String, sync::Arc};
use alloc::{string::String, sync::Arc, vec::Vec};
use system_error::SystemError;
use crate::exception::{irqdesc::IrqReturn, IrqNumber};
@ -51,7 +51,7 @@ pub trait VirtIODevice: Device {
pub trait VirtIODriver: Driver {
fn probe(&self, device: &Arc<dyn VirtIODevice>) -> Result<(), SystemError>;
fn virtio_id_table(&self) -> LinkedList<VirtioDeviceId>;
fn virtio_id_table(&self) -> Vec<VirtioDeviceId>;
fn add_virtio_id(&self, id: VirtioDeviceId);
}
@ -60,7 +60,7 @@ int_like!(VirtIODeviceIndex, usize);
#[derive(Debug, Default)]
pub struct VirtIODriverCommonData {
pub id_table: LinkedList<VirtioDeviceId>,
pub id_table: Vec<VirtioDeviceId>,
}
/// 参考https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/mod_devicetable.h#449
@ -75,3 +75,19 @@ impl VirtioDeviceId {
Self { device, vendor }
}
}
pub fn virtio_drivers_error_to_system_error(error: virtio_drivers::Error) -> SystemError {
match error {
virtio_drivers::Error::QueueFull => SystemError::ENOBUFS,
virtio_drivers::Error::NotReady => SystemError::EAGAIN_OR_EWOULDBLOCK,
virtio_drivers::Error::WrongToken => SystemError::EINVAL,
virtio_drivers::Error::AlreadyUsed => SystemError::EBUSY,
virtio_drivers::Error::InvalidParam => SystemError::EINVAL,
virtio_drivers::Error::DmaError => SystemError::ENOMEM,
virtio_drivers::Error::IoError => SystemError::EIO,
virtio_drivers::Error::Unsupported => SystemError::ENOSYS,
virtio_drivers::Error::ConfigSpaceTooSmall => SystemError::EINVAL,
virtio_drivers::Error::ConfigSpaceMissing => SystemError::EINVAL,
virtio_drivers::Error::SocketDeviceError(_) => SystemError::EIO,
}
}

View File

@ -196,11 +196,14 @@ impl VirtIODeviceManager {
dev.set_virtio_device_index(virtio_index);
dev.set_device_name(format!("virtio{}", virtio_index.data()));
log::debug!("virtio_device_add: dev: {:?}", dev);
// 添加设备到设备管理器
device_manager().add_device(dev.clone() as Arc<dyn Device>)?;
let r = device_manager()
.add_groups(&(dev.clone() as Arc<dyn Device>), &[&VirtIODeviceAttrGroup]);
log::debug!("virtio_device_add: to setup irq");
self.setup_irq(&dev).ok();
log::debug!("virtio_device_add: setup irq done");
return r;
}

View File

@ -4,6 +4,7 @@ use super::virtio_impl::HalImpl;
use crate::driver::base::device::bus::Bus;
use crate::driver::base::device::{Device, DeviceId};
use crate::driver::block::virtio_blk::virtio_blk;
use crate::driver::char::virtio_console::virtio_console;
use crate::driver::net::virtio_net::virtio_net;
use crate::driver::pci::pci::{
get_pci_device_structures_mut_by_vendor_id, PciDeviceStructureGeneralDevice,
@ -11,18 +12,24 @@ use crate::driver::pci::pci::{
};
use crate::driver::pci::subsys::pci_bus;
use crate::driver::virtio::transport::VirtIOTransport;
use crate::init::initcall::INITCALL_DEVICE;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use log::{debug, error, warn};
use system_error::SystemError;
use unified_init::macros::unified_init;
use virtio_drivers::transport::{DeviceType, Transport};
///@brief 寻找并加载所有virtio设备的驱动目前只有virtio-net但其他virtio设备也可添加
pub fn virtio_probe() {
#[unified_init(INITCALL_DEVICE)]
fn virtio_probe() -> Result<(), SystemError> {
#[cfg(not(target_arch = "riscv64"))]
virtio_probe_pci();
virtio_probe_mmio();
Ok(())
}
#[allow(dead_code)]
@ -63,6 +70,7 @@ pub(super) fn virtio_device_init(
DeviceType::GPU => {
warn!("Not support virtio_gpu device for now");
}
DeviceType::Console => virtio_console(transport, dev_id, dev_parent),
DeviceType::Input => {
warn!("Not support virtio_input device for now");
}

View File

@ -141,16 +141,21 @@ impl DevFS {
.as_any_ref()
.downcast_ref::<LockedDevFSInode>()
.unwrap();
// 在 /dev/char 下创建设备节点
dev_char_inode.add_dev(name, device.clone())?;
// 特殊处理 tty 设备,挂载在 /dev 下
if name.starts_with("tty") && name.len() > 3 {
dev_root_inode.add_dev(name, device.clone())?;
}
// ptmx设备
if name == "ptmx" {
} else if name.starts_with("hvc") && name.len() > 3 {
// 特殊处理 hvc 设备,挂载在 /dev 下
dev_root_inode.add_dev(name, device.clone())?;
} else if name == "console" {
dev_root_inode.add_dev(name, device.clone())?;
} else if name == "ptmx" {
// ptmx设备
dev_root_inode.add_dev(name, device.clone())?;
} else {
// 在 /dev/char 下创建设备节点
dev_char_inode.add_dev(name, device.clone())?;
}
device.set_fs(dev_char_inode.0.lock().fs.clone());
}

View File

@ -8,7 +8,7 @@ use system_error::SystemError;
use crate::{
arch::{interrupt::TrapFrame, process::arch_switch_to_user},
driver::{net::e1000e::e1000e::e1000e_init, virtio::virtio::virtio_probe},
driver::net::e1000e::e1000e::e1000e_init,
filesystem::vfs::core::mount_root_fs,
namespaces::NsProxy,
net::net_core::net_init,
@ -45,7 +45,7 @@ fn kernel_init() -> Result<(), SystemError> {
crate::driver::disk::ahci::ahci_init()
.inspect_err(|e| log::error!("ahci_init failed: {:?}", e))
.ok();
virtio_probe();
mount_root_fs().expect("Failed to mount root fs");
e1000e_init();
net_init().unwrap_or_else(|err| {

View File

@ -35,6 +35,10 @@ impl SlabAllocator {
Ok(nptr) => nptr.as_ptr(),
Err(AllocationError::OutOfMemory) => {
let boxed_page = ObjectPage::new();
assert_eq!(
(boxed_page.as_ref() as *const ObjectPage as usize) & (MMArch::PAGE_SIZE - 1),
0
);
let leaked_page = Box::leak(boxed_page);
self.zone
.refill(layout, leaked_page)

View File

@ -92,7 +92,8 @@ impl FsStruct {
impl Namespace for MntNamespace {
fn ns_common_to_ns(ns_common: Arc<NsCommon>) -> Arc<Self> {
let ns_common_ptr = Arc::as_ptr(&ns_common);
container_of!(ns_common_ptr, MntNamespace, ns_common)
// container_of!(ns_common_ptr, MntNamespace, ns_common)
panic!("not implemented")
}
}

View File

@ -82,11 +82,14 @@ QEMU_SERIAL_LOG_FILE="../serial_opt.txt"
QEMU_SERIAL="-serial file:${QEMU_SERIAL_LOG_FILE}"
QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
QEMU_ACCELARATE=""
QEMU_ARGUMENT=""
QEMU_ARGUMENT=" -no-reboot "
QEMU_DEVICES=""
KERNEL_CMDLINE=""
BIOS_TYPE=""
#这个变量为true则使用virtio磁盘
VIRTIO_BLK_DEVICE=false
VIRTIO_BLK_DEVICE=true
# 如果qemu_accel不为空
if [ -n "${qemu_accel}" ]; then
QEMU_ACCELARATE=" -machine accel=${qemu_accel} "
@ -139,9 +142,13 @@ while true;do
;;
nographic)
QEMU_SERIAL=" -serial chardev:mux -monitor chardev:mux -chardev stdio,id=mux,mux=on,signal=off,logfile=${QEMU_SERIAL_LOG_FILE} "
# 添加 virtio console 设备
QEMU_DEVICES+=" -device virtio-serial -device virtconsole,chardev=mux "
KERNEL_CMDLINE+=" console=/dev/hvc0 "
QEMU_MONITOR=""
QEMU_ARGUMENT+=" --nographic "
QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf "
QEMU_ARGUMENT+="-append ${KERNEL_CMDLINE}"
;;
esac;shift 2;;
@ -156,12 +163,15 @@ QEMU_DEVICES+="${QEMU_DEVICES_DISK} "
QEMU_DEVICES+=" -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 "
# E1000E
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 "
QEMU_ARGUMENT+="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d ${QEMU_MONITOR} -d ${qemu_trace_std} "
QEMU_ARGUMENT+="-s ${QEMU_MACHINE} ${QEMU_CPU_FEATURES} ${QEMU_RTC_CLOCK} ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES} "
QEMU_ARGUMENT+=" ${QEMU_SHM_OBJECT} "
QEMU_ARGUMENT+=" ${QEMU_ACCELARATE} "
QEMU_ARGUMENT+=" -D ../qemu.log "
# 安装riscv64的uboot