mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
feat(virtio): riscv: 添加virtio-blk driver,并在riscv下能够正确挂载FAT32 (#761)
This commit is contained in:
parent
0c1ef30087
commit
731bc2b32d
@ -47,12 +47,13 @@ num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num
|
|||||||
smoltcp = { version = "=0.11.0", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
smoltcp = { version = "=0.11.0", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
||||||
system_error = { path = "crates/system_error" }
|
system_error = { path = "crates/system_error" }
|
||||||
unified-init = { path = "crates/unified-init" }
|
unified-init = { path = "crates/unified-init" }
|
||||||
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers.git", rev = "61ece509c4" }
|
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "448a781" }
|
||||||
fdt = "=0.1.5"
|
fdt = "=0.1.5"
|
||||||
uefi = { version = "=0.26.0", features = ["alloc"] }
|
uefi = { version = "=0.26.0", features = ["alloc"] }
|
||||||
uefi-raw = "=0.5.0"
|
uefi-raw = "=0.5.0"
|
||||||
paste = "=1.0.14"
|
paste = "=1.0.14"
|
||||||
slabmalloc = { path = "crates/rust-slabmalloc" }
|
slabmalloc = { path = "crates/rust-slabmalloc" }
|
||||||
|
log = "0.4.21"
|
||||||
|
|
||||||
|
|
||||||
# target为x86_64时,使用下面的依赖
|
# target为x86_64时,使用下面的依赖
|
||||||
|
@ -110,7 +110,7 @@ impl MemoryManagementArch for RiscV64MMArch {
|
|||||||
const ENTRY_FLAG_READWRITE: usize = (1 << 2) | (1 << 1);
|
const ENTRY_FLAG_READWRITE: usize = (1 << 2) | (1 << 1);
|
||||||
|
|
||||||
const ENTRY_FLAG_USER: usize = (1 << 4);
|
const ENTRY_FLAG_USER: usize = (1 << 4);
|
||||||
|
const ENTRY_ADDRESS_MASK: usize = Self::ENTRY_ADDRESS_SIZE - (1 << 10);
|
||||||
const ENTRY_FLAG_WRITE_THROUGH: usize = (2 << 61);
|
const ENTRY_FLAG_WRITE_THROUGH: usize = (2 << 61);
|
||||||
|
|
||||||
const ENTRY_FLAG_CACHE_DISABLE: usize = (2 << 61);
|
const ENTRY_FLAG_CACHE_DISABLE: usize = (2 << 61);
|
||||||
|
@ -5,10 +5,9 @@ use crate::{
|
|||||||
arch::TraitPciArch,
|
arch::TraitPciArch,
|
||||||
driver::{
|
driver::{
|
||||||
open_firmware::fdt::open_firmware_fdt_driver,
|
open_firmware::fdt::open_firmware_fdt_driver,
|
||||||
pci::pci::{pci_init, BusDeviceFunction, PciAddr, PciError, SegmentGroupNumber},
|
pci::pci::{pci_init, BusDeviceFunction, PciAddr},
|
||||||
},
|
},
|
||||||
init::{boot_params, initcall::INITCALL_SUBSYS},
|
init::initcall::INITCALL_SUBSYS,
|
||||||
kwarn,
|
|
||||||
mm::PhysAddr,
|
mm::PhysAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -18,11 +17,11 @@ mod pci_host_ecam;
|
|||||||
|
|
||||||
pub struct RiscV64PciArch;
|
pub struct RiscV64PciArch;
|
||||||
impl TraitPciArch for RiscV64PciArch {
|
impl TraitPciArch for RiscV64PciArch {
|
||||||
fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 {
|
fn read_config(_bus_device_function: &BusDeviceFunction, _offset: u8) -> u32 {
|
||||||
unimplemented!("RiscV64PciArch::read_config")
|
unimplemented!("RiscV64PciArch::read_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_config(bus_device_function: &BusDeviceFunction, offset: u8, data: u32) {
|
fn write_config(_bus_device_function: &BusDeviceFunction, _offset: u8, _data: u32) {
|
||||||
unimplemented!("RiscV64pci_root_0().write_config")
|
unimplemented!("RiscV64pci_root_0().write_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,10 @@ impl DeviceManager {
|
|||||||
|
|
||||||
if dev.driver().is_some() {
|
if dev.driver().is_some() {
|
||||||
if self.device_is_bound(dev) {
|
if self.device_is_bound(dev) {
|
||||||
|
kdebug!(
|
||||||
|
"do_device_attach: device '{}' is already bound.",
|
||||||
|
dev.name()
|
||||||
|
);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +86,7 @@ impl DeviceManager {
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
kdebug!("do_device_attach: device '{}' is not bound.", dev.name());
|
||||||
let bus = dev
|
let bus = dev
|
||||||
.bus()
|
.bus()
|
||||||
.and_then(|bus| bus.upgrade())
|
.and_then(|bus| bus.upgrade())
|
||||||
@ -198,15 +203,9 @@ impl DeviceManager {
|
|||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/dd.c#496
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/dd.c#496
|
||||||
pub fn device_bind_driver(&self, dev: &Arc<dyn Device>) -> Result<(), SystemError> {
|
pub fn device_bind_driver(&self, dev: &Arc<dyn Device>) -> Result<(), SystemError> {
|
||||||
let r = driver_manager().driver_sysfs_add(dev);
|
let r = driver_manager().driver_sysfs_add(dev);
|
||||||
if let Err(e) = r {
|
if r.is_ok() {
|
||||||
kerror!(
|
|
||||||
"device_bind_driver: driver_sysfs_add failed, dev: '{}', err: {:?}",
|
|
||||||
dev.name(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
self.device_links_force_bind(dev);
|
self.device_links_force_bind(dev);
|
||||||
driver_manager().driver_bound(dev);
|
driver_manager().driver_bound(dev);
|
||||||
return Err(e);
|
|
||||||
} else if let Some(bus) = dev.bus().and_then(|bus| bus.upgrade()) {
|
} else if let Some(bus) = dev.bus().and_then(|bus| bus.upgrade()) {
|
||||||
bus.subsystem().bus_notifier().call_chain(
|
bus.subsystem().bus_notifier().call_chain(
|
||||||
BusNotifyEvent::DriverNotBound,
|
BusNotifyEvent::DriverNotBound,
|
||||||
@ -214,6 +213,14 @@ impl DeviceManager {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(e) = r.as_ref() {
|
||||||
|
kerror!(
|
||||||
|
"device_bind_driver: driver_sysfs_add failed, dev: '{}', err: {:?}",
|
||||||
|
dev.name(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,7 +806,7 @@ impl DeviceManager {
|
|||||||
|
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/core.c?fi=device_links_force_bind#1226
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/core.c?fi=device_links_force_bind#1226
|
||||||
pub fn device_links_force_bind(&self, _dev: &Arc<dyn Device>) {
|
pub fn device_links_force_bind(&self, _dev: &Arc<dyn Device>) {
|
||||||
todo!("device_links_force_bind")
|
kwarn!("device_links_force_bind not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 把device对象的一些结构进行默认初始化
|
/// 把device对象的一些结构进行默认初始化
|
||||||
|
@ -1 +1,2 @@
|
|||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
pub mod virtio_blk;
|
||||||
|
526
kernel/src/driver/block/virtio_blk.rs
Normal file
526
kernel/src/driver/block/virtio_blk.rs
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
use core::{any::Any, fmt::Debug};
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
string::{String, ToString},
|
||||||
|
sync::{Arc, Weak},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use system_error::SystemError;
|
||||||
|
use unified_init::macros::unified_init;
|
||||||
|
use virtio_drivers::device::blk::VirtIOBlk;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
driver::{
|
||||||
|
base::{
|
||||||
|
block::{
|
||||||
|
block_device::{BlockDevice, BlockId, LBA_SIZE},
|
||||||
|
disk_info::Partition,
|
||||||
|
},
|
||||||
|
class::Class,
|
||||||
|
device::{
|
||||||
|
bus::Bus,
|
||||||
|
driver::{Driver, DriverCommonData},
|
||||||
|
Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
||||||
|
},
|
||||||
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
|
kset::KSet,
|
||||||
|
},
|
||||||
|
virtio::{
|
||||||
|
sysfs::{virtio_bus, virtio_device_manager, virtio_driver_manager},
|
||||||
|
transport::VirtIOTransport,
|
||||||
|
virtio_impl::HalImpl,
|
||||||
|
VirtIODevice, VirtIODeviceIndex, VirtIODriver, VIRTIO_VENDOR_ID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
filesystem::{kernfs::KernFSInode, mbr::MbrDiskPartionTable},
|
||||||
|
init::initcall::INITCALL_POSTCORE,
|
||||||
|
libs::{
|
||||||
|
rwlock::{RwLockReadGuard, RwLockWriteGuard},
|
||||||
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const VIRTIO_BLK_BASENAME: &str = "virtio_blk";
|
||||||
|
|
||||||
|
static mut VIRTIO_BLK_DRIVER: Option<Arc<VirtIOBlkDriver>> = None;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn virtio_blk_driver() -> Arc<VirtIOBlkDriver> {
|
||||||
|
unsafe { VIRTIO_BLK_DRIVER.as_ref().unwrap().clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the first virtio block device
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn virtio_blk_0() -> Option<Arc<VirtIOBlkDevice>> {
|
||||||
|
virtio_blk_driver()
|
||||||
|
.devices()
|
||||||
|
.first()
|
||||||
|
.cloned()
|
||||||
|
.map(|dev| dev.arc_any().downcast().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn virtio_blk(transport: VirtIOTransport, dev_id: Arc<DeviceId>) {
|
||||||
|
let device = VirtIOBlkDevice::new(transport, dev_id);
|
||||||
|
if let Some(device) = device {
|
||||||
|
kdebug!("VirtIOBlkDevice '{:?}' created", device.dev_id);
|
||||||
|
virtio_device_manager()
|
||||||
|
.device_add(device.clone() as Arc<dyn VirtIODevice>)
|
||||||
|
.expect("Add virtio blk failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// virtio block device
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cast_to([sync] VirtIODevice)]
|
||||||
|
#[cast_to([sync] Device)]
|
||||||
|
pub struct VirtIOBlkDevice {
|
||||||
|
dev_id: Arc<DeviceId>,
|
||||||
|
inner: SpinLock<InnerVirtIOBlkDevice>,
|
||||||
|
locked_kobj_state: LockedKObjectState,
|
||||||
|
self_ref: Weak<Self>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for VirtIOBlkDevice {}
|
||||||
|
unsafe impl Sync for VirtIOBlkDevice {}
|
||||||
|
|
||||||
|
impl VirtIOBlkDevice {
|
||||||
|
pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
|
||||||
|
let device_inner = VirtIOBlk::<HalImpl, VirtIOTransport>::new(transport);
|
||||||
|
if let Err(e) = device_inner {
|
||||||
|
kerror!("VirtIOBlkDevice '{dev_id:?}' create failed: {:?}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// !!!! 在这里临时测试virtio-blk的读写功能,后续需要删除 !!!!
|
||||||
|
// 目前read会报错 `NotReady`
|
||||||
|
let device_inner: VirtIOBlk<HalImpl, VirtIOTransport> = device_inner.unwrap();
|
||||||
|
|
||||||
|
let dev = Arc::new_cyclic(|self_ref| Self {
|
||||||
|
self_ref: self_ref.clone(),
|
||||||
|
dev_id,
|
||||||
|
locked_kobj_state: LockedKObjectState::default(),
|
||||||
|
inner: SpinLock::new(InnerVirtIOBlkDevice {
|
||||||
|
device_inner,
|
||||||
|
name: None,
|
||||||
|
virtio_index: None,
|
||||||
|
device_common: DeviceCommonData::default(),
|
||||||
|
kobject_common: KObjectCommonData::default(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
dev.set_driver(Some(Arc::downgrade(
|
||||||
|
&(virtio_blk_driver() as Arc<dyn Driver>),
|
||||||
|
)));
|
||||||
|
|
||||||
|
Some(dev)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner(&self) -> SpinLockGuard<InnerVirtIOBlkDevice> {
|
||||||
|
self.inner.lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockDevice for VirtIOBlkDevice {
|
||||||
|
fn read_at_sync(
|
||||||
|
&self,
|
||||||
|
lba_id_start: BlockId,
|
||||||
|
count: usize,
|
||||||
|
buf: &mut [u8],
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
let mut inner = self.inner();
|
||||||
|
|
||||||
|
inner
|
||||||
|
.device_inner
|
||||||
|
.read_blocks(lba_id_start, &mut buf[..count * LBA_SIZE])
|
||||||
|
.map_err(|e| {
|
||||||
|
kerror!(
|
||||||
|
"VirtIOBlkDevice '{:?}' read_at_sync failed: {:?}",
|
||||||
|
self.dev_id,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
SystemError::EIO
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_at_sync(
|
||||||
|
&self,
|
||||||
|
lba_id_start: BlockId,
|
||||||
|
count: usize,
|
||||||
|
buf: &[u8],
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
self.inner()
|
||||||
|
.device_inner
|
||||||
|
.write_blocks(lba_id_start, &buf[..count * LBA_SIZE])
|
||||||
|
.map_err(|_| SystemError::EIO)?;
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync(&self) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blk_size_log2(&self) -> u8 {
|
||||||
|
9
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_ref(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device(&self) -> Arc<dyn Device> {
|
||||||
|
self.self_ref.upgrade().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_size(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn partitions(&self) -> Vec<Arc<Partition>> {
|
||||||
|
let device = self.self_ref.upgrade().unwrap() as Arc<dyn BlockDevice>;
|
||||||
|
let mbr_table = MbrDiskPartionTable::from_disk(device.clone())
|
||||||
|
.expect("Failed to get MBR partition table");
|
||||||
|
mbr_table.partitions(Arc::downgrade(&device))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InnerVirtIOBlkDevice {
|
||||||
|
device_inner: VirtIOBlk<HalImpl, VirtIOTransport>,
|
||||||
|
name: Option<String>,
|
||||||
|
virtio_index: Option<VirtIODeviceIndex>,
|
||||||
|
device_common: DeviceCommonData,
|
||||||
|
kobject_common: KObjectCommonData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for InnerVirtIOBlkDevice {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("InnerVirtIOBlkDevice").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtIODevice for VirtIOBlkDevice {
|
||||||
|
fn handle_irq(
|
||||||
|
&self,
|
||||||
|
_irq: crate::exception::IrqNumber,
|
||||||
|
) -> Result<crate::exception::irqdesc::IrqReturn, system_error::SystemError> {
|
||||||
|
todo!("VirtIOBlkDevice::handle_irq")
|
||||||
|
}
|
||||||
|
|
||||||
|
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_BLK_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::Block as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vendor(&self) -> u32 {
|
||||||
|
VIRTIO_VENDOR_ID.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for VirtIOBlkDevice {
|
||||||
|
fn dev_type(&self) -> DeviceType {
|
||||||
|
DeviceType::Net
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_table(&self) -> IdTable {
|
||||||
|
IdTable::new(VIRTIO_BLK_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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KObject for VirtIOBlkDevice {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unified_init(INITCALL_POSTCORE)]
|
||||||
|
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");
|
||||||
|
unsafe {
|
||||||
|
VIRTIO_BLK_DRIVER = Some(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cast_to([sync] VirtIODriver)]
|
||||||
|
#[cast_to([sync] Driver)]
|
||||||
|
struct VirtIOBlkDriver {
|
||||||
|
inner: SpinLock<InnerVirtIOBlkDriver>,
|
||||||
|
kobj_state: LockedKObjectState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtIOBlkDriver {
|
||||||
|
pub fn new() -> Arc<Self> {
|
||||||
|
let inner = InnerVirtIOBlkDriver {
|
||||||
|
driver_common: DriverCommonData::default(),
|
||||||
|
kobj_common: KObjectCommonData::default(),
|
||||||
|
};
|
||||||
|
Arc::new(VirtIOBlkDriver {
|
||||||
|
inner: SpinLock::new(inner),
|
||||||
|
kobj_state: LockedKObjectState::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner(&self) -> SpinLockGuard<InnerVirtIOBlkDriver> {
|
||||||
|
return self.inner.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct InnerVirtIOBlkDriver {
|
||||||
|
driver_common: DriverCommonData,
|
||||||
|
kobj_common: KObjectCommonData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtIODriver for VirtIOBlkDriver {
|
||||||
|
fn probe(&self, device: &Arc<dyn VirtIODevice>) -> Result<(), SystemError> {
|
||||||
|
let _dev = device
|
||||||
|
.clone()
|
||||||
|
.arc_any()
|
||||||
|
.downcast::<VirtIOBlkDevice>()
|
||||||
|
.map_err(|_| {
|
||||||
|
kerror!(
|
||||||
|
"VirtIOBlkDriver::probe() failed: device is not a VirtIO block device. Device: '{:?}'",
|
||||||
|
device.name()
|
||||||
|
);
|
||||||
|
SystemError::EINVAL
|
||||||
|
})?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for VirtIOBlkDriver {
|
||||||
|
fn id_table(&self) -> Option<IdTable> {
|
||||||
|
Some(IdTable::new(VIRTIO_BLK_BASENAME.to_string(), None))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_device(&self, device: Arc<dyn Device>) {
|
||||||
|
let iface = device
|
||||||
|
.arc_any()
|
||||||
|
.downcast::<VirtIOBlkDevice>()
|
||||||
|
.expect("VirtIOBlkDriver::add_device() failed: device is not a VirtIOBlkDevice");
|
||||||
|
|
||||||
|
self.inner()
|
||||||
|
.driver_common
|
||||||
|
.devices
|
||||||
|
.push(iface as Arc<dyn Device>);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_device(&self, device: &Arc<dyn Device>) {
|
||||||
|
let _iface = device
|
||||||
|
.clone()
|
||||||
|
.arc_any()
|
||||||
|
.downcast::<VirtIOBlkDevice>()
|
||||||
|
.expect("VirtIOBlkDriver::delete_device() failed: device is not a VirtIOBlkDevice");
|
||||||
|
|
||||||
|
let mut guard = self.inner();
|
||||||
|
let index = guard
|
||||||
|
.driver_common
|
||||||
|
.devices
|
||||||
|
.iter()
|
||||||
|
.position(|dev| Arc::ptr_eq(device, dev))
|
||||||
|
.expect("VirtIOBlkDriver::delete_device() failed: device not found");
|
||||||
|
|
||||||
|
guard.driver_common.devices.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 VirtIOBlkDriver {
|
||||||
|
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_BLK_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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
use super::{_port, hba::HbaCmdTable, virt_2_phys};
|
use super::{_port, hba::HbaCmdTable, virt_2_phys};
|
||||||
use crate::driver::base::block::block_device::{BlockDevice, BlockId};
|
use crate::driver::base::block::block_device::{BlockDevice, BlockId};
|
||||||
use crate::driver::base::block::disk_info::Partition;
|
use crate::driver::base::block::disk_info::Partition;
|
||||||
use crate::driver::base::block::SeekFrom;
|
|
||||||
use crate::driver::base::class::Class;
|
use crate::driver::base::class::Class;
|
||||||
use crate::driver::base::device::bus::Bus;
|
use crate::driver::base::device::bus::Bus;
|
||||||
|
|
||||||
@ -14,9 +13,8 @@ use crate::driver::disk::ahci::HBA_PxIS_TFES;
|
|||||||
use crate::filesystem::kernfs::KernFSInode;
|
use crate::filesystem::kernfs::KernFSInode;
|
||||||
use crate::filesystem::mbr::MbrDiskPartionTable;
|
use crate::filesystem::mbr::MbrDiskPartionTable;
|
||||||
|
|
||||||
use crate::kdebug;
|
|
||||||
use crate::libs::rwlock::{RwLockReadGuard, RwLockWriteGuard};
|
use crate::libs::rwlock::{RwLockReadGuard, RwLockWriteGuard};
|
||||||
use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
|
use crate::libs::spinlock::SpinLock;
|
||||||
use crate::mm::{phys_2_virt, verify_area, VirtAddr};
|
use crate::mm::{phys_2_virt, verify_area, VirtAddr};
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::disk::ahci::hba::{
|
driver::disk::ahci::hba::{
|
||||||
@ -69,7 +67,7 @@ impl AhciDisk {
|
|||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
) -> Result<usize, SystemError> {
|
) -> Result<usize, SystemError> {
|
||||||
assert!((buf.len() & 511) == 0);
|
assert!((buf.len() & 511) == 0);
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
let check_length = ((count - 1) >> 4) + 1; // prdt length
|
let check_length = ((count - 1) >> 4) + 1; // prdt length
|
||||||
if count * 512 > buf.len() || check_length > 8_usize {
|
if count * 512 > buf.len() || check_length > 8_usize {
|
||||||
kerror!("ahci read: e2big");
|
kerror!("ahci read: e2big");
|
||||||
@ -204,7 +202,7 @@ impl AhciDisk {
|
|||||||
buf.copy_from_slice(kbuf.as_ref().unwrap());
|
buf.copy_from_slice(kbuf.as_ref().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
// successfully read
|
// successfully read
|
||||||
return Ok(count * 512);
|
return Ok(count * 512);
|
||||||
}
|
}
|
||||||
@ -216,7 +214,7 @@ impl AhciDisk {
|
|||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
) -> Result<usize, SystemError> {
|
) -> Result<usize, SystemError> {
|
||||||
assert!((buf.len() & 511) == 0);
|
assert!((buf.len() & 511) == 0);
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
let check_length = ((count - 1) >> 4) + 1; // prdt length
|
let check_length = ((count - 1) >> 4) + 1; // prdt length
|
||||||
if count * 512 > buf.len() || check_length > 8 {
|
if count * 512 > buf.len() || check_length > 8 {
|
||||||
// 不可能的操作
|
// 不可能的操作
|
||||||
@ -235,7 +233,7 @@ impl AhciDisk {
|
|||||||
return Err(SystemError::EIO);
|
return Err(SystemError::EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
#[allow(unused_unsafe)]
|
#[allow(unused_unsafe)]
|
||||||
let cmdheader: &mut HbaCmdHeader = unsafe {
|
let cmdheader: &mut HbaCmdHeader = unsafe {
|
||||||
(phys_2_virt(
|
(phys_2_virt(
|
||||||
@ -244,7 +242,7 @@ impl AhciDisk {
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
volatile_write_bit!(
|
volatile_write_bit!(
|
||||||
cmdheader.cfl,
|
cmdheader.cfl,
|
||||||
@ -256,7 +254,7 @@ impl AhciDisk {
|
|||||||
volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
|
volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
|
||||||
|
|
||||||
// 设置数据存放地址
|
// 设置数据存放地址
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
let mut buf_ptr = buf as *const [u8] as *mut usize as usize;
|
let mut buf_ptr = buf as *const [u8] as *mut usize as usize;
|
||||||
|
|
||||||
// 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
|
// 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
|
||||||
@ -282,7 +280,7 @@ impl AhciDisk {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
let mut tmp_count = count;
|
let mut tmp_count = count;
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// 清空整个table的旧数据
|
// 清空整个table的旧数据
|
||||||
@ -343,7 +341,7 @@ impl AhciDisk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
// successfully read
|
// successfully read
|
||||||
return Ok(count * 512);
|
return Ok(count * 512);
|
||||||
}
|
}
|
||||||
@ -362,70 +360,29 @@ impl LockedAhciDisk {
|
|||||||
port_num: u8,
|
port_num: u8,
|
||||||
) -> Result<Arc<LockedAhciDisk>, SystemError> {
|
) -> Result<Arc<LockedAhciDisk>, SystemError> {
|
||||||
// 构建磁盘结构体
|
// 构建磁盘结构体
|
||||||
let result: Arc<LockedAhciDisk> = Arc::new(LockedAhciDisk(SpinLock::new(AhciDisk {
|
let result: Arc<LockedAhciDisk> = Arc::new_cyclic(|self_ref| {
|
||||||
name,
|
LockedAhciDisk(SpinLock::new(AhciDisk {
|
||||||
flags,
|
name,
|
||||||
partitions: Default::default(),
|
flags,
|
||||||
ctrl_num,
|
partitions: Default::default(),
|
||||||
port_num,
|
ctrl_num,
|
||||||
self_ref: Weak::default(),
|
port_num,
|
||||||
})));
|
self_ref: self_ref.clone(),
|
||||||
|
}))
|
||||||
|
});
|
||||||
let table: MbrDiskPartionTable = result.read_mbr_table()?;
|
let table: MbrDiskPartionTable = result.read_mbr_table()?;
|
||||||
|
|
||||||
// 求出有多少可用分区
|
// 求出有多少可用分区
|
||||||
for i in 0..4 {
|
let partitions = table.partitions(Arc::downgrade(&result) as Weak<dyn BlockDevice>);
|
||||||
compiler_fence(Ordering::SeqCst);
|
result.0.lock().partitions = partitions;
|
||||||
if table.dpte[i].part_type != 0 {
|
|
||||||
let w = Arc::downgrade(&result);
|
|
||||||
result.0.lock().partitions.push(Partition::new(
|
|
||||||
table.dpte[i].starting_sector() as u64,
|
|
||||||
table.dpte[i].starting_lba as u64,
|
|
||||||
table.dpte[i].total_sectors as u64,
|
|
||||||
w,
|
|
||||||
i as u16,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.0.lock().self_ref = Arc::downgrade(&result);
|
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 从磁盘中读取 MBR 分区表结构体 TODO: Cursor
|
/// @brief: 从磁盘中读取 MBR 分区表结构体
|
||||||
pub fn read_mbr_table(&self) -> Result<MbrDiskPartionTable, SystemError> {
|
pub fn read_mbr_table(&self) -> Result<MbrDiskPartionTable, SystemError> {
|
||||||
let mut table: MbrDiskPartionTable = Default::default();
|
let disk = self.0.lock().self_ref.upgrade().unwrap() as Arc<dyn BlockDevice>;
|
||||||
|
MbrDiskPartionTable::from_disk(disk)
|
||||||
// 数据缓冲区
|
|
||||||
let mut buf: Vec<u8> = vec![0; size_of::<MbrDiskPartionTable>()];
|
|
||||||
buf.resize(size_of::<MbrDiskPartionTable>(), 0);
|
|
||||||
|
|
||||||
self.read_at_sync(0, 1, &mut buf)?;
|
|
||||||
// 创建 Cursor 用于按字节读取
|
|
||||||
let mut cursor = VecCursor::new(buf);
|
|
||||||
cursor.seek(SeekFrom::SeekCurrent(446))?;
|
|
||||||
|
|
||||||
for i in 0..4 {
|
|
||||||
kdebug!("infomation of partition {}:\n", i);
|
|
||||||
|
|
||||||
table.dpte[i].flags = cursor.read_u8()?;
|
|
||||||
table.dpte[i].starting_head = cursor.read_u8()?;
|
|
||||||
table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
|
|
||||||
table.dpte[i].part_type = cursor.read_u8()?;
|
|
||||||
table.dpte[i].ending_head = cursor.read_u8()?;
|
|
||||||
table.dpte[i].ending_sector_cylingder = cursor.read_u16()?;
|
|
||||||
table.dpte[i].starting_lba = cursor.read_u32()?;
|
|
||||||
table.dpte[i].total_sectors = cursor.read_u32()?;
|
|
||||||
|
|
||||||
kdebug!("dpte[i] = {:?}", table.dpte[i]);
|
|
||||||
}
|
|
||||||
table.bs_trailsig = cursor.read_u16()?;
|
|
||||||
// kdebug!("bs_trailsig = {}", unsafe {
|
|
||||||
// read_unaligned(addr_of!(table.bs_trailsig))
|
|
||||||
// });
|
|
||||||
|
|
||||||
return Ok(table);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ pub trait SerioDriver: Driver {
|
|||||||
|
|
||||||
///todo: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/input/serio/serio.c#810
|
///todo: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/input/serio/serio.c#810
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn serio_driver_manager() -> &'static SerioDriverManager {
|
pub fn serio_driver_manager() -> &'static SerioDriverManager {
|
||||||
&SerioDriverManager
|
&SerioDriverManager
|
||||||
|
@ -128,6 +128,7 @@ impl Debug for VirtIONicDeviceInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cast_to([sync] VirtIODevice)]
|
#[cast_to([sync] VirtIODevice)]
|
||||||
|
#[cast_to([sync] Device)]
|
||||||
pub struct VirtioInterface {
|
pub struct VirtioInterface {
|
||||||
device_inner: VirtIONicDeviceInnerWrapper,
|
device_inner: VirtIONicDeviceInnerWrapper,
|
||||||
iface_id: usize,
|
iface_id: usize,
|
||||||
@ -293,7 +294,7 @@ impl Device for VirtioInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn can_match(&self) -> bool {
|
fn can_match(&self) -> bool {
|
||||||
true
|
self.inner().device_common.can_match
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_can_match(&self, can_match: bool) {
|
fn set_can_match(&self, can_match: bool) {
|
||||||
@ -552,8 +553,10 @@ fn virtio_net_driver_init() -> Result<(), SystemError> {
|
|||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cast_to([sync] VirtIODriver)]
|
#[cast_to([sync] VirtIODriver)]
|
||||||
|
#[cast_to([sync] Driver)]
|
||||||
struct VirtIONetDriver {
|
struct VirtIONetDriver {
|
||||||
inner: SpinLock<InnerVirtIODriver>,
|
inner: SpinLock<InnerVirtIODriver>,
|
||||||
kobj_state: LockedKObjectState,
|
kobj_state: LockedKObjectState,
|
||||||
|
@ -76,7 +76,7 @@ impl OpenFirmwareFdtDriver {
|
|||||||
|
|
||||||
/// 获取FDT的引用
|
/// 获取FDT的引用
|
||||||
pub fn fdt_ref(&self) -> Result<Fdt<'static>, SystemError> {
|
pub fn fdt_ref(&self) -> Result<Fdt<'static>, SystemError> {
|
||||||
let fdt_vaddr = boot_params().read().fdt().unwrap();
|
let fdt_vaddr = boot_params().read().fdt().ok_or(SystemError::ENODEV)?;
|
||||||
let fdt: Fdt<'_> = unsafe {
|
let fdt: Fdt<'_> = unsafe {
|
||||||
fdt::Fdt::from_ptr(fdt_vaddr.as_ptr()).map_err(|e| {
|
fdt::Fdt::from_ptr(fdt_vaddr.as_ptr()).map_err(|e| {
|
||||||
kerror!("failed to parse fdt, err={:?}", e);
|
kerror!("failed to parse fdt, err={:?}", e);
|
||||||
@ -213,10 +213,7 @@ impl OpenFirmwareFdtDriver {
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::MMArch,
|
arch::MMArch,
|
||||||
libs::align::page_align_down,
|
libs::align::page_align_down,
|
||||||
mm::{
|
mm::{memblock::MemBlockManager, MemoryManagementArch},
|
||||||
memblock::{mem_block_manager, MemBlockManager},
|
|
||||||
MemoryManagementArch, PhysAddr,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut base = base as usize;
|
let mut base = base as usize;
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod hpet;
|
pub mod hpet;
|
||||||
|
@ -1,3 +1,30 @@
|
|||||||
|
use fdt::node::FdtNode;
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::driver::{
|
||||||
|
open_firmware::fdt::open_firmware_fdt_driver, virtio::transport_mmio::VirtIOMmioTransport,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{transport::VirtIOTransport, virtio::virtio_device_init};
|
||||||
|
|
||||||
pub(super) fn virtio_probe_mmio() {
|
pub(super) fn virtio_probe_mmio() {
|
||||||
// todo: implement virtio_probe_mmio
|
if let Err(e) = do_probe_virtio_mmio() {
|
||||||
|
kerror!("virtio_probe_mmio failed: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_probe_virtio_mmio() -> Result<(), SystemError> {
|
||||||
|
let fdt = open_firmware_fdt_driver().fdt_ref()?;
|
||||||
|
|
||||||
|
let do_check = |node: FdtNode| -> Result<(), SystemError> {
|
||||||
|
let mmio_transport = VirtIOMmioTransport::new(node)?;
|
||||||
|
let device_id = mmio_transport.device_id();
|
||||||
|
virtio_device_init(VirtIOTransport::Mmio(mmio_transport), device_id);
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
for node in open_firmware_fdt_driver().find_node_by_compatible(&fdt, "virtio,mmio") {
|
||||||
|
do_check(node).ok();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ pub(super) mod irq;
|
|||||||
pub mod mmio;
|
pub mod mmio;
|
||||||
pub mod sysfs;
|
pub mod sysfs;
|
||||||
pub mod transport;
|
pub mod transport;
|
||||||
|
pub mod transport_mmio;
|
||||||
pub mod transport_pci;
|
pub mod transport_pci;
|
||||||
#[allow(clippy::module_inception)]
|
#[allow(clippy::module_inception)]
|
||||||
pub mod virtio;
|
pub mod virtio;
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
use virtio_drivers::transport::Transport;
|
use virtio_drivers::transport::Transport;
|
||||||
|
|
||||||
use super::transport_pci::PciTransport;
|
use super::{transport_mmio::VirtIOMmioTransport, transport_pci::PciTransport};
|
||||||
|
|
||||||
pub enum VirtIOTransport {
|
pub enum VirtIOTransport {
|
||||||
Pci(PciTransport),
|
Pci(PciTransport),
|
||||||
|
Mmio(VirtIOMmioTransport),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for VirtIOTransport {
|
impl core::fmt::Debug for VirtIOTransport {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(_) => write!(f, "VirtIOTransport::Pci"),
|
VirtIOTransport::Pci(_) => write!(f, "VirtIOTransport::Pci"),
|
||||||
|
VirtIOTransport::Mmio(_) => write!(f, "VirtIOTransport::Mmio"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,6 +21,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn finish_init(&mut self) {
|
fn finish_init(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.finish_init(),
|
VirtIOTransport::Pci(transport) => transport.finish_init(),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.finish_init(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,6 +29,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn device_type(&self) -> virtio_drivers::transport::DeviceType {
|
fn device_type(&self) -> virtio_drivers::transport::DeviceType {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.device_type(),
|
VirtIOTransport::Pci(transport) => transport.device_type(),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.device_type(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +37,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn read_device_features(&mut self) -> u64 {
|
fn read_device_features(&mut self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.read_device_features(),
|
VirtIOTransport::Pci(transport) => transport.read_device_features(),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.read_device_features(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +45,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn write_driver_features(&mut self, driver_features: u64) {
|
fn write_driver_features(&mut self, driver_features: u64) {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.write_driver_features(driver_features),
|
VirtIOTransport::Pci(transport) => transport.write_driver_features(driver_features),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.write_driver_features(driver_features),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +53,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn max_queue_size(&mut self, queue: u16) -> u32 {
|
fn max_queue_size(&mut self, queue: u16) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.max_queue_size(queue),
|
VirtIOTransport::Pci(transport) => transport.max_queue_size(queue),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.max_queue_size(queue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +61,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn notify(&mut self, queue: u16) {
|
fn notify(&mut self, queue: u16) {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.notify(queue),
|
VirtIOTransport::Pci(transport) => transport.notify(queue),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.notify(queue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +69,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn get_status(&self) -> virtio_drivers::transport::DeviceStatus {
|
fn get_status(&self) -> virtio_drivers::transport::DeviceStatus {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.get_status(),
|
VirtIOTransport::Pci(transport) => transport.get_status(),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.get_status(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +77,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn set_status(&mut self, status: virtio_drivers::transport::DeviceStatus) {
|
fn set_status(&mut self, status: virtio_drivers::transport::DeviceStatus) {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.set_status(status),
|
VirtIOTransport::Pci(transport) => transport.set_status(status),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.set_status(status),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +85,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn set_guest_page_size(&mut self, guest_page_size: u32) {
|
fn set_guest_page_size(&mut self, guest_page_size: u32) {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.set_guest_page_size(guest_page_size),
|
VirtIOTransport::Pci(transport) => transport.set_guest_page_size(guest_page_size),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.set_guest_page_size(guest_page_size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +93,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn requires_legacy_layout(&self) -> bool {
|
fn requires_legacy_layout(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.requires_legacy_layout(),
|
VirtIOTransport::Pci(transport) => transport.requires_legacy_layout(),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.requires_legacy_layout(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +110,9 @@ impl Transport for VirtIOTransport {
|
|||||||
VirtIOTransport::Pci(transport) => {
|
VirtIOTransport::Pci(transport) => {
|
||||||
transport.queue_set(queue, size, descriptors, driver_area, device_area)
|
transport.queue_set(queue, size, descriptors, driver_area, device_area)
|
||||||
}
|
}
|
||||||
|
VirtIOTransport::Mmio(transport) => {
|
||||||
|
transport.queue_set(queue, size, descriptors, driver_area, device_area)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +120,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn queue_unset(&mut self, queue: u16) {
|
fn queue_unset(&mut self, queue: u16) {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.queue_unset(queue),
|
VirtIOTransport::Pci(transport) => transport.queue_unset(queue),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.queue_unset(queue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +128,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn queue_used(&mut self, queue: u16) -> bool {
|
fn queue_used(&mut self, queue: u16) -> bool {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.queue_used(queue),
|
VirtIOTransport::Pci(transport) => transport.queue_used(queue),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.queue_used(queue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +136,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn ack_interrupt(&mut self) -> bool {
|
fn ack_interrupt(&mut self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.ack_interrupt(),
|
VirtIOTransport::Pci(transport) => transport.ack_interrupt(),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.ack_interrupt(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +144,7 @@ impl Transport for VirtIOTransport {
|
|||||||
fn config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>> {
|
fn config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>> {
|
||||||
match self {
|
match self {
|
||||||
VirtIOTransport::Pci(transport) => transport.config_space(),
|
VirtIOTransport::Pci(transport) => transport.config_space(),
|
||||||
|
VirtIOTransport::Mmio(transport) => transport.config_space(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
157
kernel/src/driver/virtio/transport_mmio.rs
Normal file
157
kernel/src/driver/virtio/transport_mmio.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use fdt::node::FdtNode;
|
||||||
|
use system_error::SystemError;
|
||||||
|
use virtio_drivers::transport::{
|
||||||
|
mmio::{MmioTransport, VirtIOHeader},
|
||||||
|
Transport,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::MMArch,
|
||||||
|
driver::base::device::DeviceId,
|
||||||
|
exception::HardwareIrqNumber,
|
||||||
|
libs::align::page_align_up,
|
||||||
|
mm::{
|
||||||
|
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
||||||
|
MemoryManagementArch, PhysAddr,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct VirtIOMmioTransport {
|
||||||
|
mmio_transport: MmioTransport,
|
||||||
|
_mmio_guard: MMIOSpaceGuard,
|
||||||
|
irq: HardwareIrqNumber,
|
||||||
|
device_id: Arc<DeviceId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtIOMmioTransport {
|
||||||
|
pub fn new(node: FdtNode) -> Result<Self, SystemError> {
|
||||||
|
let reg = node
|
||||||
|
.reg()
|
||||||
|
.ok_or(SystemError::EINVAL)?
|
||||||
|
.next()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
let paddr = reg.starting_address as usize;
|
||||||
|
let size = reg.size.unwrap_or(0);
|
||||||
|
let page_offset = paddr % MMArch::PAGE_SIZE;
|
||||||
|
let paddr = paddr - page_offset;
|
||||||
|
let size = page_align_up(size + page_offset);
|
||||||
|
let irq = node
|
||||||
|
.interrupts()
|
||||||
|
.ok_or(SystemError::EINVAL)?
|
||||||
|
.next()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
let device_id = DeviceId::new(None, Some(format!("virtio_mmio_{:#X}", paddr))).unwrap();
|
||||||
|
|
||||||
|
let mmio_guard = mmio_pool().create_mmio(size)?;
|
||||||
|
unsafe { mmio_guard.map_phys(PhysAddr::new(paddr), size) }?;
|
||||||
|
|
||||||
|
let vaddr = mmio_guard.vaddr() + page_offset;
|
||||||
|
let header = NonNull::new(vaddr.data() as *mut VirtIOHeader).unwrap();
|
||||||
|
|
||||||
|
match unsafe { MmioTransport::new(header) } {
|
||||||
|
Ok(mmio_transport) => {
|
||||||
|
kinfo!( "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}, hw irq: {}",
|
||||||
|
mmio_transport.vendor_id(),
|
||||||
|
mmio_transport.device_type(),
|
||||||
|
mmio_transport.version(),
|
||||||
|
irq as u32
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
mmio_transport,
|
||||||
|
_mmio_guard: mmio_guard,
|
||||||
|
irq: HardwareIrqNumber::new(irq as u32),
|
||||||
|
device_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// kwarn!("MmioTransport::new failed: {:?}", e);
|
||||||
|
Err(SystemError::EINVAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
pub fn irq(&self) -> HardwareIrqNumber {
|
||||||
|
self.irq
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_id(&self) -> Arc<DeviceId> {
|
||||||
|
self.device_id.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transport for VirtIOMmioTransport {
|
||||||
|
fn device_type(&self) -> virtio_drivers::transport::DeviceType {
|
||||||
|
self.mmio_transport.device_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_device_features(&mut self) -> u64 {
|
||||||
|
self.mmio_transport.read_device_features()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_driver_features(&mut self, driver_features: u64) {
|
||||||
|
self.mmio_transport.write_driver_features(driver_features)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_queue_size(&mut self, queue: u16) -> u32 {
|
||||||
|
self.mmio_transport.max_queue_size(queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notify(&mut self, queue: u16) {
|
||||||
|
self.mmio_transport.notify(queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_status(&self) -> virtio_drivers::transport::DeviceStatus {
|
||||||
|
self.mmio_transport.get_status()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_status(&mut self, status: virtio_drivers::transport::DeviceStatus) {
|
||||||
|
self.mmio_transport.set_status(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_guest_page_size(&mut self, guest_page_size: u32) {
|
||||||
|
self.mmio_transport.set_guest_page_size(guest_page_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn requires_legacy_layout(&self) -> bool {
|
||||||
|
self.mmio_transport.requires_legacy_layout()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queue_set(
|
||||||
|
&mut self,
|
||||||
|
queue: u16,
|
||||||
|
size: u32,
|
||||||
|
descriptors: virtio_drivers::PhysAddr,
|
||||||
|
driver_area: virtio_drivers::PhysAddr,
|
||||||
|
device_area: virtio_drivers::PhysAddr,
|
||||||
|
) {
|
||||||
|
self.mmio_transport
|
||||||
|
.queue_set(queue, size, descriptors, driver_area, device_area)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queue_unset(&mut self, queue: u16) {
|
||||||
|
self.mmio_transport.queue_unset(queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queue_used(&mut self, queue: u16) -> bool {
|
||||||
|
self.mmio_transport.queue_used(queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ack_interrupt(&mut self) -> bool {
|
||||||
|
self.mmio_transport.ack_interrupt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>> {
|
||||||
|
self.mmio_transport.config_space()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_init(&mut self) {
|
||||||
|
self.mmio_transport.finish_init()
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ use super::mmio::virtio_probe_mmio;
|
|||||||
use super::transport_pci::PciTransport;
|
use super::transport_pci::PciTransport;
|
||||||
use super::virtio_impl::HalImpl;
|
use super::virtio_impl::HalImpl;
|
||||||
use crate::driver::base::device::DeviceId;
|
use crate::driver::base::device::DeviceId;
|
||||||
|
use crate::driver::block::virtio_blk::virtio_blk;
|
||||||
use crate::driver::net::virtio_net::virtio_net;
|
use crate::driver::net::virtio_net::virtio_net;
|
||||||
use crate::driver::pci::pci::{
|
use crate::driver::pci::pci::{
|
||||||
get_pci_device_structures_mut_by_vendor_id, PciDeviceStructure,
|
get_pci_device_structures_mut_by_vendor_id, PciDeviceStructure,
|
||||||
@ -17,10 +18,12 @@ use virtio_drivers::transport::{DeviceType, Transport};
|
|||||||
|
|
||||||
///@brief 寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备也可添加)
|
///@brief 寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备也可添加)
|
||||||
pub fn virtio_probe() {
|
pub fn virtio_probe() {
|
||||||
|
#[cfg(not(target_arch = "riscv64"))]
|
||||||
virtio_probe_pci();
|
virtio_probe_pci();
|
||||||
virtio_probe_mmio();
|
virtio_probe_mmio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn virtio_probe_pci() {
|
fn virtio_probe_pci() {
|
||||||
let mut list = PCI_DEVICE_LINKEDLIST.write();
|
let mut list = PCI_DEVICE_LINKEDLIST.write();
|
||||||
let virtio_list = virtio_device_search(&mut list);
|
let virtio_list = virtio_device_search(&mut list);
|
||||||
@ -45,11 +48,9 @@ fn virtio_probe_pci() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///@brief 为virtio设备寻找对应的驱动进行初始化
|
///@brief 为virtio设备寻找对应的驱动进行初始化
|
||||||
fn virtio_device_init(transport: VirtIOTransport, dev_id: Arc<DeviceId>) {
|
pub(super) fn virtio_device_init(transport: VirtIOTransport, dev_id: Arc<DeviceId>) {
|
||||||
match transport.device_type() {
|
match transport.device_type() {
|
||||||
DeviceType::Block => {
|
DeviceType::Block => virtio_blk(transport, dev_id),
|
||||||
kwarn!("Not support virtio_block device for now");
|
|
||||||
}
|
|
||||||
DeviceType::GPU => {
|
DeviceType::GPU => {
|
||||||
kwarn!("Not support virtio_gpu device for now");
|
kwarn!("Not support virtio_gpu device for now");
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,8 @@ unsafe impl Hal for HalImpl {
|
|||||||
/// @brief mmio物理地址转换为虚拟地址,不需要使用
|
/// @brief mmio物理地址转换为虚拟地址,不需要使用
|
||||||
/// @param paddr 起始物理地址
|
/// @param paddr 起始物理地址
|
||||||
/// @return NonNull<u8> 虚拟地址的指针
|
/// @return NonNull<u8> 虚拟地址的指针
|
||||||
unsafe fn mmio_phys_to_virt(_paddr: virtio_drivers::PhysAddr, _size: usize) -> NonNull<u8> {
|
unsafe fn mmio_phys_to_virt(paddr: virtio_drivers::PhysAddr, _size: usize) -> NonNull<u8> {
|
||||||
NonNull::new((0) as _).unwrap()
|
NonNull::new((MMArch::phys_2_virt(PhysAddr::new(paddr))).unwrap().data() as _).unwrap()
|
||||||
}
|
}
|
||||||
/// @brief 与真实物理设备共享
|
/// @brief 与真实物理设备共享
|
||||||
/// @param buffer 要共享的buffer _direction:设备到driver或driver到设备
|
/// @param buffer 要共享的buffer _direction:设备到driver或driver到设备
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
#![allow(dead_code)]
|
use core::{default::Default, mem::size_of};
|
||||||
use core::default::Default;
|
|
||||||
|
use alloc::{
|
||||||
|
sync::{Arc, Weak},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
driver::base::block::{block_device::BlockDevice, disk_info::Partition, SeekFrom},
|
||||||
|
libs::vec_cursor::VecCursor,
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief MBR硬盘分区表项的结构
|
/// @brief MBR硬盘分区表项的结构
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
@ -10,23 +20,33 @@ pub struct MbrDiskPartitionTableEntry {
|
|||||||
pub starting_sector_cylinder: u16, // sector : 低6, cylinder : 高10; 起始扇区号 + 起始柱面号
|
pub starting_sector_cylinder: u16, // sector : 低6, cylinder : 高10; 起始扇区号 + 起始柱面号
|
||||||
pub part_type: u8, // 分区类型ID
|
pub part_type: u8, // 分区类型ID
|
||||||
pub ending_head: u8, // 结束磁头号
|
pub ending_head: u8, // 结束磁头号
|
||||||
pub ending_sector_cylingder: u16, // ending_sector : 低6, ending_cylinder : 高10; 结束扇区号 + 结束柱面号
|
pub ending_sector_cylinder: u16, // ending_sector : 低6, ending_cylinder : 高10; 结束扇区号 + 结束柱面号
|
||||||
pub starting_lba: u32, // 起始逻辑扇区
|
pub starting_lba: u32, // 起始逻辑扇区
|
||||||
pub total_sectors: u32, // 分区占用的磁盘扇区数
|
pub total_sectors: u32, // 分区占用的磁盘扇区数
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MbrDiskPartitionTableEntry {
|
impl MbrDiskPartitionTableEntry {
|
||||||
pub fn starting_sector(&self) -> u16 {
|
pub fn starting_sector(&self) -> u32 {
|
||||||
return self.starting_sector_cylinder & ((1 << 6) - 1) as u16;
|
return (self.starting_sector_cylinder & ((1 << 6) - 1)).into();
|
||||||
}
|
}
|
||||||
pub fn starting_cylinder(&self) -> u16 {
|
pub fn starting_cylinder(&self) -> u16 {
|
||||||
return (self.starting_sector_cylinder >> 6) & ((1 << 10) - 1) as u16;
|
return (self.starting_sector_cylinder >> 6) & ((1 << 10) - 1) as u16;
|
||||||
}
|
}
|
||||||
pub fn ending_sector(&self) -> u16 {
|
pub fn ending_sector(&self) -> u32 {
|
||||||
return self.ending_sector_cylingder & ((1 << 6) - 1) as u16;
|
self.starting_sector() + self.total_sectors - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ending_cylinder(&self) -> u16 {
|
pub fn ending_cylinder(&self) -> u16 {
|
||||||
return (self.ending_sector_cylingder >> 6) & ((1 << 10) - 1) as u16;
|
return (self.ending_sector_cylinder >> 6) & ((1 << 10) - 1) as u16;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
// 其他更多的可能判断条件
|
||||||
|
self.starting_sector() <= self.ending_sector()
|
||||||
|
&& self.starting_cylinder() <= self.ending_cylinder()
|
||||||
|
&& self.starting_lba != 0
|
||||||
|
&& self.total_sectors != 0
|
||||||
|
&& self.part_type != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,3 +68,86 @@ impl Default for MbrDiskPartionTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MbrDiskPartionTable {
|
||||||
|
/// # 从磁盘读取MBR分区表 - 从磁盘设备中读取并解析MBR分区表
|
||||||
|
///
|
||||||
|
/// 这个函数从提供的磁盘设备中读取MBR分区表,并将其解析为一个`MbrDiskPartionTable`实例。
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `disk`: Arc<dyn BlockDevice> - 一个磁盘设备的共享引用,用于从磁盘读取数据。
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
///
|
||||||
|
/// - `Ok(MbrDiskPartionTable)`: 成功解析的分区表实例。
|
||||||
|
/// - `Err(SystemError)`: 读取磁盘失败或其他系统错误。
|
||||||
|
pub fn from_disk(disk: Arc<dyn BlockDevice>) -> Result<MbrDiskPartionTable, SystemError> {
|
||||||
|
let mut table: MbrDiskPartionTable = Default::default();
|
||||||
|
|
||||||
|
// 数据缓冲区
|
||||||
|
let mut buf: Vec<u8> = vec![0; size_of::<MbrDiskPartionTable>()];
|
||||||
|
buf.resize(size_of::<MbrDiskPartionTable>(), 0);
|
||||||
|
|
||||||
|
disk.read_at_sync(0, 1, &mut buf)?;
|
||||||
|
|
||||||
|
// 创建 Cursor 用于按字节读取
|
||||||
|
let mut cursor = VecCursor::new(buf);
|
||||||
|
cursor.seek(SeekFrom::SeekCurrent(446))?;
|
||||||
|
|
||||||
|
for i in 0..4 {
|
||||||
|
table.dpte[i].flags = cursor.read_u8()?;
|
||||||
|
table.dpte[i].starting_head = cursor.read_u8()?;
|
||||||
|
table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
|
||||||
|
table.dpte[i].part_type = cursor.read_u8()?;
|
||||||
|
table.dpte[i].ending_head = cursor.read_u8()?;
|
||||||
|
table.dpte[i].ending_sector_cylinder = cursor.read_u16()?;
|
||||||
|
table.dpte[i].starting_lba = cursor.read_u32()?;
|
||||||
|
table.dpte[i].total_sectors = cursor.read_u32()?;
|
||||||
|
|
||||||
|
kdebug!("dpte[{i}] = {:?}", table.dpte[i]);
|
||||||
|
}
|
||||||
|
table.bs_trailsig = cursor.read_u16()?;
|
||||||
|
// kdebug!("bs_trailsig = {}", unsafe {
|
||||||
|
// read_unaligned(addr_of!(table.bs_trailsig))
|
||||||
|
// });
|
||||||
|
|
||||||
|
if !table.is_valid() {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # partitions - 获取磁盘的分区信息
|
||||||
|
///
|
||||||
|
/// 该函数用于获取指定磁盘的分区信息,并将这些分区信息以分区对象的向量形式返回。分区对象包含了分区的类型、起始扇区和总扇区数等信息。
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `disk`: Weak<dyn BlockDevice>: 一个对磁盘设备的弱引用。这个磁盘设备必须实现`BlockDevice` trait。
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
///
|
||||||
|
/// 返回一个包含分区信息的`Vec`。每个分区都是一个`Arc<Partition>`,它表示分区的一个强引用。
|
||||||
|
///
|
||||||
|
pub fn partitions(&self, disk: Weak<dyn BlockDevice>) -> Vec<Arc<Partition>> {
|
||||||
|
let mut partitions: Vec<Arc<Partition>> = Vec::new();
|
||||||
|
for i in 0..4 {
|
||||||
|
if self.dpte[i].is_valid() {
|
||||||
|
partitions.push(Partition::new(
|
||||||
|
self.dpte[i].starting_sector() as u64,
|
||||||
|
self.dpte[i].starting_lba as u64,
|
||||||
|
self.dpte[i].total_sectors as u64,
|
||||||
|
disk.clone(),
|
||||||
|
i as u16,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return partitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
self.bs_trailsig == 0xAA55
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -113,14 +113,36 @@ fn migrate_virtual_filesystem(new_fs: Arc<dyn FileSystem>) -> Result<(), SystemE
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn root_partition() -> Arc<Partition> {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
{
|
||||||
|
return ahci::get_disks_by_name("ahci_disk_0".to_string())
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.lock()
|
||||||
|
.partitions[0]
|
||||||
|
.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
{
|
||||||
|
use crate::driver::base::block::block_device::BlockDevice;
|
||||||
|
|
||||||
|
let virtio0 = crate::driver::block::virtio_blk::virtio_blk_0();
|
||||||
|
if virtio0.is_none() {
|
||||||
|
kerror!("Failed to get virtio_blk_0");
|
||||||
|
loop {
|
||||||
|
spin_loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let virtio0 = virtio0.unwrap();
|
||||||
|
return virtio0.partitions()[0].clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn mount_root_fs() -> Result<(), SystemError> {
|
pub fn mount_root_fs() -> Result<(), SystemError> {
|
||||||
kinfo!("Try to mount FAT32 as root fs...");
|
kinfo!("Try to mount FAT32 as root fs...");
|
||||||
let partiton: Arc<Partition> = ahci::get_disks_by_name("ahci_disk_0".to_string())
|
let partiton: Arc<Partition> = root_partition();
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.lock()
|
|
||||||
.partitions[0]
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let fatfs: Result<Arc<FATFileSystem>, SystemError> = FATFileSystem::new(partiton);
|
let fatfs: Result<Arc<FATFileSystem>, SystemError> = FATFileSystem::new(partiton);
|
||||||
if fatfs.is_err() {
|
if fatfs.is_err() {
|
||||||
|
@ -7,7 +7,6 @@ use crate::{
|
|||||||
driver::{base::init::driver_init, serial::serial_early_init, video::VideoRefreshManager},
|
driver::{base::init::driver_init, serial::serial_early_init, video::VideoRefreshManager},
|
||||||
exception::{init::irq_init, softirq::softirq_init, InterruptArch},
|
exception::{init::irq_init, softirq::softirq_init, InterruptArch},
|
||||||
filesystem::vfs::core::vfs_init,
|
filesystem::vfs::core::vfs_init,
|
||||||
include::bindings::bindings::acpi_init,
|
|
||||||
init::init_intertrait,
|
init::init_intertrait,
|
||||||
libs::{
|
libs::{
|
||||||
futex::futex::Futex,
|
futex::futex::Futex,
|
||||||
@ -15,6 +14,7 @@ use crate::{
|
|||||||
screen_manager::{scm_init, scm_reinit},
|
screen_manager::{scm_init, scm_reinit},
|
||||||
textui::textui_init,
|
textui::textui_init,
|
||||||
},
|
},
|
||||||
|
printk::early_init_logging,
|
||||||
},
|
},
|
||||||
mm::init::mm_init,
|
mm::init::mm_init,
|
||||||
process::{kthread::kthread_init, process_init, ProcessManager},
|
process::{kthread::kthread_init, process_init, ProcessManager},
|
||||||
@ -45,6 +45,7 @@ pub fn start_kernel() -> ! {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn do_start_kernel() {
|
fn do_start_kernel() {
|
||||||
init_before_mem_init();
|
init_before_mem_init();
|
||||||
|
early_init_logging();
|
||||||
|
|
||||||
early_setup_arch().expect("setup_arch failed");
|
early_setup_arch().expect("setup_arch failed");
|
||||||
unsafe { mm_init() };
|
unsafe { mm_init() };
|
||||||
@ -58,7 +59,7 @@ fn do_start_kernel() {
|
|||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
unsafe {
|
unsafe {
|
||||||
acpi_init()
|
crate::include::bindings::bindings::acpi_init()
|
||||||
};
|
};
|
||||||
crate::sched::sched_init();
|
crate::sched::sched_init();
|
||||||
process_init();
|
process_init();
|
||||||
|
@ -5,9 +5,7 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::process::arch_switch_to_user,
|
arch::process::arch_switch_to_user,
|
||||||
driver::{
|
driver::{net::e1000e::e1000e::e1000e_init, virtio::virtio::virtio_probe},
|
||||||
disk::ahci::ahci_init, net::e1000e::e1000e::e1000e_init, virtio::virtio::virtio_probe,
|
|
||||||
},
|
|
||||||
filesystem::vfs::core::mount_root_fs,
|
filesystem::vfs::core::mount_root_fs,
|
||||||
kdebug, kerror,
|
kdebug, kerror,
|
||||||
net::net_core::net_init,
|
net::net_core::net_init,
|
||||||
@ -35,11 +33,11 @@ fn kernel_init() -> Result<(), SystemError> {
|
|||||||
// scm_enable_double_buffer().expect("Failed to enable double buffer");
|
// scm_enable_double_buffer().expect("Failed to enable double buffer");
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
ahci_init().expect("Failed to initialize AHCI");
|
crate::driver::disk::ahci::ahci_init().expect("Failed to initialize AHCI");
|
||||||
|
|
||||||
mount_root_fs().expect("Failed to mount root fs");
|
|
||||||
|
|
||||||
virtio_probe();
|
virtio_probe();
|
||||||
|
mount_root_fs().expect("Failed to mount root fs");
|
||||||
|
|
||||||
e1000e_init();
|
e1000e_init();
|
||||||
net_init().unwrap_or_else(|err| {
|
net_init().unwrap_or_else(|err| {
|
||||||
kerror!("Failed to initialize network: {:?}", err);
|
kerror!("Failed to initialize network: {:?}", err);
|
||||||
|
@ -4,6 +4,7 @@ use core::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
|
use log::{info, Log};
|
||||||
|
|
||||||
use super::lib_ui::textui::{textui_putstr, FontColor};
|
use super::lib_ui::textui::{textui_putstr, FontColor};
|
||||||
|
|
||||||
@ -129,3 +130,42 @@ impl Logger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 内核自定义日志器
|
||||||
|
///
|
||||||
|
/// todo: 完善他的功能,并且逐步把kinfo等宏,迁移到这个logger上面来。
|
||||||
|
struct CustomLogger;
|
||||||
|
|
||||||
|
impl Log for CustomLogger {
|
||||||
|
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
||||||
|
// 这里可以自定义日志过滤规则
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &log::Record) {
|
||||||
|
if self.enabled(record.metadata()) {
|
||||||
|
// todo: 接入kmsg
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
PrintkWriter,
|
||||||
|
"[ {} ] {} ({}:{}) {}",
|
||||||
|
record.level(),
|
||||||
|
record.target(),
|
||||||
|
record.file().unwrap_or(""),
|
||||||
|
record.line().unwrap_or(0),
|
||||||
|
record.args()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {
|
||||||
|
// 如果需要的话,可以在这里实现缓冲区刷新逻辑
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn early_init_logging() {
|
||||||
|
log::set_logger(&CustomLogger).unwrap();
|
||||||
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
|
info!("Logging initialized");
|
||||||
|
}
|
||||||
|
@ -676,6 +676,7 @@ impl MMIOSpaceGuard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let flags = PageFlags::mmio_flags();
|
let flags = PageFlags::mmio_flags();
|
||||||
|
|
||||||
let mut kernel_mapper = KernelMapper::lock();
|
let mut kernel_mapper = KernelMapper::lock();
|
||||||
let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
|
let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
|
||||||
return r;
|
return r;
|
||||||
|
@ -676,6 +676,11 @@ impl<Arch: MemoryManagementArch> PageFlags<Arch> {
|
|||||||
return self.update_flags(Arch::ENTRY_FLAG_WRITE_THROUGH, value);
|
return self.update_flags(Arch::ENTRY_FLAG_WRITE_THROUGH, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_page_global(self, value: bool) -> Self {
|
||||||
|
return self.update_flags(MMArch::ENTRY_FLAG_GLOBAL, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// 获取当前页表项的写穿策略
|
/// 获取当前页表项的写穿策略
|
||||||
///
|
///
|
||||||
/// ## 返回值
|
/// ## 返回值
|
||||||
@ -724,7 +729,8 @@ impl<Arch: MemoryManagementArch> PageFlags<Arch> {
|
|||||||
.set_write(true)
|
.set_write(true)
|
||||||
.set_execute(true)
|
.set_execute(true)
|
||||||
.set_page_cache_disable(true)
|
.set_page_cache_disable(true)
|
||||||
.set_page_write_through(true);
|
.set_page_write_through(true)
|
||||||
|
.set_page_global(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,6 +1105,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
|||||||
return self
|
return self
|
||||||
.visit(virt, |p1, i| {
|
.visit(virt, |p1, i| {
|
||||||
let mut entry = p1.entry(i)?;
|
let mut entry = p1.entry(i)?;
|
||||||
|
|
||||||
entry.set_flags(flags);
|
entry.set_flags(flags);
|
||||||
p1.set_entry(i, entry);
|
p1.set_entry(i, entry);
|
||||||
Some(PageFlush::new(virt))
|
Some(PageFlush::new(virt))
|
||||||
|
@ -6,7 +6,6 @@ use core::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{ipc::signal::SigSet, syscall::nr::*},
|
arch::{ipc::signal::SigSet, syscall::nr::*},
|
||||||
driver::base::device::device_number::DeviceNumber,
|
|
||||||
filesystem::vfs::syscall::{PosixStatfs, PosixStatx},
|
filesystem::vfs::syscall::{PosixStatfs, PosixStatx},
|
||||||
ipc::shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey},
|
ipc::shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey},
|
||||||
libs::{futex::constant::FutexFlag, rand::GRandFlags},
|
libs::{futex::constant::FutexFlag, rand::GRandFlags},
|
||||||
@ -662,7 +661,11 @@ impl Syscall {
|
|||||||
let flags = args[1];
|
let flags = args[1];
|
||||||
let dev_t = args[2];
|
let dev_t = args[2];
|
||||||
let flags: ModeType = ModeType::from_bits_truncate(flags as u32);
|
let flags: ModeType = ModeType::from_bits_truncate(flags as u32);
|
||||||
Self::mknod(path as *const u8, flags, DeviceNumber::from(dev_t as u32))
|
Self::mknod(
|
||||||
|
path as *const u8,
|
||||||
|
flags,
|
||||||
|
crate::driver::base::device::device_number::DeviceNumber::from(dev_t as u32),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SYS_CLONE => {
|
SYS_CLONE => {
|
||||||
@ -1059,6 +1062,7 @@ impl Syscall {
|
|||||||
Err(SystemError::EINVAL)
|
Err(SystemError::EINVAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
SYS_ALARM => {
|
SYS_ALARM => {
|
||||||
let second = args[0] as u32;
|
let second = args[0] as u32;
|
||||||
Self::alarm(second)
|
Self::alarm(second)
|
||||||
|
@ -76,7 +76,7 @@ QEMU_SERIAL="-serial file:../serial_opt.txt"
|
|||||||
QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
|
QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
|
||||||
QEMU_ACCELARATE=""
|
QEMU_ACCELARATE=""
|
||||||
QEMU_ARGUMENT=""
|
QEMU_ARGUMENT=""
|
||||||
QEMU_DEVICES=
|
QEMU_DEVICES=""
|
||||||
|
|
||||||
# 如果qemu_accel不为空
|
# 如果qemu_accel不为空
|
||||||
if [ -n "${qemu_accel}" ]; then
|
if [ -n "${qemu_accel}" ]; then
|
||||||
|
Loading…
x
Reference in New Issue
Block a user