From 26d84a31393c50063ff416bc509316e8d342028c Mon Sep 17 00:00:00 2001 From: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> Date: Sat, 11 Mar 2023 21:09:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EVirtIO=E7=BD=91=E5=8D=A1?= =?UTF-8?q?=E9=A9=B1=E5=8A=A8=20(#194)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修复内存bug与grub安装脚本的错误 * 修改小bug * PCI增加功能与virtio-net驱动 * little fix * virtio-net小修改 --- .vscode/settings.json | 3 +- kernel/Cargo.toml | 3 + kernel/src/arch/x86_64/x86_64_pci.c | 0 kernel/src/arch/x86_64/x86_64_pci.h | 0 kernel/src/driver/Makefile | 4 +- kernel/src/driver/mod.rs | 2 + kernel/src/driver/pci/mod.rs | 1 + kernel/src/driver/pci/msi.c | 2 +- kernel/src/driver/pci/pci.rs | 495 +++++++++++++++++++++ kernel/src/driver/usb/xhci/xhci.c | 2 + kernel/src/driver/virtio/Makefile | 7 + kernel/src/driver/virtio/mod.rs | 4 + kernel/src/driver/virtio/transport_pci.rs | 515 ++++++++++++++++++++++ kernel/src/driver/virtio/virtio.c | 46 ++ kernel/src/driver/virtio/virtio.h | 12 + kernel/src/driver/virtio/virtio.rs | 136 ++++++ kernel/src/driver/virtio/virtio_impl.rs | 75 ++++ kernel/src/driver/virtio/volatile.rs | 104 +++++ kernel/src/include/bindings/wrapper.h | 4 + kernel/src/main.c | 7 +- kernel/src/mm/mm.c | 2 +- kernel/src/process/process.c | 2 + 22 files changed, 1416 insertions(+), 10 deletions(-) create mode 100644 kernel/src/arch/x86_64/x86_64_pci.c create mode 100644 kernel/src/arch/x86_64/x86_64_pci.h create mode 100644 kernel/src/driver/pci/mod.rs create mode 100644 kernel/src/driver/pci/pci.rs create mode 100644 kernel/src/driver/virtio/Makefile create mode 100644 kernel/src/driver/virtio/mod.rs create mode 100644 kernel/src/driver/virtio/transport_pci.rs create mode 100644 kernel/src/driver/virtio/virtio.c create mode 100644 kernel/src/driver/virtio/virtio.h create mode 100644 kernel/src/driver/virtio/virtio.rs create mode 100644 kernel/src/driver/virtio/virtio_impl.rs create mode 100644 kernel/src/driver/virtio/volatile.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 125b95af..86abb35f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -169,7 +169,8 @@ "acpi.h": "c", "assert.h": "c", "sys_version.h": "c", - "cmd.h": "c" + "cmd.h": "c", + "net.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "esbonio.sphinx.confDir": "", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index df84b3e4..b1f312fa 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -11,6 +11,8 @@ crate-type = ["staticlib"] # 运行时依赖项 [dependencies] x86_64 = "0.14.10" +virtio-drivers = "0.2.0" +bitflags = "1.3" # 构建时依赖项 [build-dependencies] @@ -22,3 +24,4 @@ version = "1.4.0" features = ["spin_no_std"] + diff --git a/kernel/src/arch/x86_64/x86_64_pci.c b/kernel/src/arch/x86_64/x86_64_pci.c new file mode 100644 index 00000000..e69de29b diff --git a/kernel/src/arch/x86_64/x86_64_pci.h b/kernel/src/arch/x86_64/x86_64_pci.h new file mode 100644 index 00000000..e69de29b diff --git a/kernel/src/driver/Makefile b/kernel/src/driver/Makefile index a20d91ec..82f1ef39 100644 --- a/kernel/src/driver/Makefile +++ b/kernel/src/driver/Makefile @@ -1,7 +1,7 @@ CFLAGS += -I . -kernel_driver_subdirs:=video interrupt usb pci acpi disk keyboard mouse multiboot2 timers tty hid +kernel_driver_subdirs:=video interrupt usb pci acpi disk keyboard mouse multiboot2 timers tty hid virtio ECHO: @echo "$@" @@ -14,4 +14,4 @@ all: $(kernel_driver_subdirs) clean: - echo "Done." \ No newline at end of file + echo "Done." diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 4b1cb990..17902371 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -1,2 +1,4 @@ +pub mod pci; pub mod timers; pub mod uart; +pub mod virtio; diff --git a/kernel/src/driver/pci/mod.rs b/kernel/src/driver/pci/mod.rs new file mode 100644 index 00000000..7652d2c4 --- /dev/null +++ b/kernel/src/driver/pci/mod.rs @@ -0,0 +1 @@ +pub mod pci; diff --git a/kernel/src/driver/pci/msi.c b/kernel/src/driver/pci/msi.c index 1149e65a..6f249eeb 100644 --- a/kernel/src/driver/pci/msi.c +++ b/kernel/src/driver/pci/msi.c @@ -71,7 +71,7 @@ static __always_inline struct pci_msi_cap_t __msi_read_cap_list(struct msi_desc_ } /** - * @brief 映射设备的msix表 + * @brief 映射设备的msix表 //MSIX表不再单独映射(To do) * * @param pci_dev pci设备信息结构体 * @param msix_cap msix capability list的结构体 diff --git a/kernel/src/driver/pci/pci.rs b/kernel/src/driver/pci/pci.rs new file mode 100644 index 00000000..39d4e355 --- /dev/null +++ b/kernel/src/driver/pci/pci.rs @@ -0,0 +1,495 @@ +use crate::include::bindings::bindings::{ + initial_mm, mm_map, mm_struct, pci_read_config, pci_write_config, VM_DONTCOPY, VM_IO, +}; +use crate::mm::mmio_buddy::MMIO_POOL; +use crate::{kdebug, kerror, kwarn}; +use bitflags::bitflags; +use core::{ + convert::TryFrom, + fmt::{self, Display, Formatter}, + ptr::NonNull, +}; +//Bar0寄存器的offset +const BAR0_OFFSET: u8 = 0x10; +//Status、Command寄存器的offset +const STATUS_COMMAND_OFFSET: u8 = 0x04; +/// ID for vendor-specific PCI capabilities.(Virtio Capabilities) +pub const PCI_CAP_ID_VNDR: u8 = 0x09; + +bitflags! { + /// The status register in PCI configuration space. + pub struct Status: u16 { + // Bits 0-2 are reserved. + /// The state of the device's INTx# signal. + const INTERRUPT_STATUS = 1 << 3; + /// The device has a linked list of capabilities. + const CAPABILITIES_LIST = 1 << 4; + /// The device is capabile of running at 66 MHz rather than 33 MHz. + const MHZ_66_CAPABLE = 1 << 5; + // Bit 6 is reserved. + /// The device can accept fast back-to-back transactions not from the same agent. + const FAST_BACK_TO_BACK_CAPABLE = 1 << 7; + /// The bus agent observed a parity error (if parity error handling is enabled). + const MASTER_DATA_PARITY_ERROR = 1 << 8; + // Bits 9-10 are DEVSEL timing. + /// A target device terminated a transaction with target-abort. + const SIGNALED_TARGET_ABORT = 1 << 11; + /// A master device transaction was terminated with target-abort. + const RECEIVED_TARGET_ABORT = 1 << 12; + /// A master device transaction was terminated with master-abort. + const RECEIVED_MASTER_ABORT = 1 << 13; + /// A device asserts SERR#. + const SIGNALED_SYSTEM_ERROR = 1 << 14; + /// The device detects a parity error, even if parity error handling is disabled. + const DETECTED_PARITY_ERROR = 1 << 15; + } +} + +bitflags! { + /// The command register in PCI configuration space. + pub struct Command: u16 { + /// The device can respond to I/O Space accesses. + const IO_SPACE = 1 << 0; + /// The device can respond to Memory Space accesses. + const MEMORY_SPACE = 1 << 1; + /// The device can behave as a bus master. + const BUS_MASTER = 1 << 2; + /// The device can monitor Special Cycle operations. + const SPECIAL_CYCLES = 1 << 3; + /// The device can generate the Memory Write and Invalidate command. + const MEMORY_WRITE_AND_INVALIDATE_ENABLE = 1 << 4; + /// The device will snoop palette register data. + const VGA_PALETTE_SNOOP = 1 << 5; + /// The device should take its normal action when a parity error is detected. + const PARITY_ERROR_RESPONSE = 1 << 6; + // Bit 7 is reserved. + /// The SERR# driver is enabled. + const SERR_ENABLE = 1 << 8; + /// The device is allowed to generate fast back-to-back transactions. + const FAST_BACK_TO_BACK_ENABLE = 1 << 9; + /// Assertion of the device's INTx# signal is disabled. + const INTERRUPT_DISABLE = 1 << 10; + } +} + +/// Gets the capabilities 'pointer' for the device function, if any. +///@brief 获取第一个capability 的offset +///@param device_function PCI设备的唯一标识 +///@return Option offset +pub fn capabilities_offset(device_function: DeviceFunction) -> Option { + let status: Status = unsafe { + let temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + STATUS_COMMAND_OFFSET, + ); + Status::from_bits_truncate((temp >> 16) as u16) + }; + if status.contains(Status::CAPABILITIES_LIST) { + let cap_pointer = unsafe { + let temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + 0x34, + ); + temp as u8 & 0xFC + }; + Some(cap_pointer) + } else { + None + } +} +/// An identifier for a PCI bus, device and function. +/// PCI设备的唯一标识 +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct DeviceFunction { + /// The PCI bus number, between 0 and 255. + pub bus: u8, + /// The device number on the bus, between 0 and 31. + pub device: u8, + /// The function number of the device, between 0 and 7. + pub function: u8, +} +///PCI的Error +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PciError { + /// The device reported an invalid BAR type. + InvalidBarType, + CreateMmioError, +} +///实现PciError的Display trait,使其可以直接输出 +impl Display for PciError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::InvalidBarType => write!(f, "Invalid PCI BAR type."), + Self::CreateMmioError => write!(f, "Error occurred while creating mmio"), + } + } +} + +impl DeviceFunction { + /// Returns whether the device and function numbers are valid, i.e. the device is between 0 and + /// 31, and the function is between 0 and 7. + ///@brief 检测DeviceFunction实例是否有效 + ///@param self + ///@return bool 是否有效 + pub fn valid(&self) -> bool { + self.device < 32 && self.function < 8 + } +} +///实现DeviceFunction的Display trait,使其可以直接输出 +impl Display for DeviceFunction { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{:02x}:{:02x}.{}", self.bus, self.device, self.function) + } +} +/// The location allowed for a memory BAR. +/// memory BAR的三种情况 +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum MemoryBarType { + /// The BAR has a 32-bit address and can be mapped anywhere in 32-bit address space. + Width32, + /// The BAR must be mapped below 1MiB. + Below1MiB, + /// The BAR has a 64-bit address and can be mapped anywhere in 64-bit address space. + Width64, +} +///实现MemoryBarType与u8的类型转换 +impl From for u8 { + fn from(bar_type: MemoryBarType) -> Self { + match bar_type { + MemoryBarType::Width32 => 0, + MemoryBarType::Below1MiB => 1, + MemoryBarType::Width64 => 2, + } + } +} +///实现MemoryBarType与u8的类型转换 +impl TryFrom for MemoryBarType { + type Error = PciError; + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Width32), + 1 => Ok(Self::Below1MiB), + 2 => Ok(Self::Width64), + _ => Err(PciError::InvalidBarType), + } + } +} + +/// Information about a PCI Base Address Register. +/// BAR的三种类型 Memory/IO/Unused +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum BarInfo { + /// The BAR is for a memory region. + Memory { + /// The size of the BAR address and where it can be located. + address_type: MemoryBarType, + /// If true, then reading from the region doesn't have side effects. The CPU may cache reads + /// and merge repeated stores. + prefetchable: bool, + /// The memory address, always 16-byte aligned. + address: u64, + /// The size of the BAR in bytes. + size: u32, + /// The virtaddress for a memory bar(mapped). + virtaddress: u64, + }, + /// The BAR is for an I/O region. + IO { + /// The I/O address, always 4-byte aligned. + address: u32, + /// The size of the BAR in bytes. + size: u32, + }, + Unused, +} + +impl BarInfo { + /// Returns the address and size of this BAR if it is a memory bar, or `None` if it is an IO + /// BAR. + ///@brief 得到某个bar的memory_address与size(前提是他的类型为Memory Bar) + ///@param self + ///@return Option<(u64, u32) 是Memory Bar返回内存地址与大小,不是则返回None + pub fn memory_address_size(&self) -> Option<(u64, u32)> { + if let Self::Memory { address, size, .. } = self { + Some((*address, *size)) + } else { + None + } + } + ///@brief 得到某个bar的virtaddress(前提是他的类型为Memory Bar) + ///@param self + ///@return Option<(u64) 是Memory Bar返回映射的虚拟地址,不是则返回None + pub fn virtual_address(&self) -> Option { + if let Self::Memory { virtaddress, .. } = self { + Some(*virtaddress) + } else { + None + } + } +} +///实现BarInfo的Display trait,使其可以直接输出 +impl Display for BarInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::Memory { + address_type, + prefetchable, + address, + size, + virtaddress, + } => write!( + f, + "Memory space at {:#010x}, size {}, type {:?}, prefetchable {},mapped at {:#x}", + address, size, address_type, prefetchable, virtaddress + ), + Self::IO { address, size } => { + write!(f, "I/O space at {:#010x}, size {}", address, size) + } + Self::Unused => { + write!(f, "Unused bar") + } + } + } +} +///一个PCI设备有6个BAR寄存器,PciDeviceBar存储其全部信息 +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PciDeviceBar { + bar0: BarInfo, + bar1: BarInfo, + bar2: BarInfo, + bar3: BarInfo, + bar4: BarInfo, + bar5: BarInfo, +} + +impl PciDeviceBar { + ///@brief 得到某个bar的barinfo + ///@param self ,bar_index(0-5) + ///@return Result<&BarInfo, PciError> bar_index在0-5则返回对应的bar_info结构体,超出范围则返回错误 + pub fn get_bar(&self, bar_index: u8) -> Result<&BarInfo, PciError> { + match bar_index { + 0 => Ok(&self.bar0), + 1 => Ok(&self.bar1), + 2 => Ok(&self.bar2), + 3 => Ok(&self.bar3), + 4 => Ok(&self.bar4), + _ => Err(PciError::InvalidBarType), + } + } +} +///实现PciDeviceBar的Display trait,使其可以直接输出 +impl Display for PciDeviceBar { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "\r\nBar0:{}\r\n Bar1:{}\r\n Bar2:{}\r\n Bar3:{}\r\nBar4:{}\r\nBar5:{}", + self.bar0, self.bar1, self.bar2, self.bar3, self.bar4, self.bar5 + ) + } +} +///实现PciDeviceBar的Default trait,使其可以简单初始化 +impl Default for PciDeviceBar { + fn default() -> Self { + PciDeviceBar { + bar0: BarInfo::Unused, + bar1: BarInfo::Unused, + bar2: BarInfo::Unused, + bar3: BarInfo::Unused, + bar4: BarInfo::Unused, + bar5: BarInfo::Unused, + } + } +} + +///@brief 将某个pci设备的bar全部初始化,memory +///@param self ,device_function PCI设备的唯一标识符 +///@return Result 成功则返回对应的PciDeviceBar结构体,失败则返回错误类型 +pub fn pci_bar_init(device_function: DeviceFunction) -> Result { + let mut device_bar: PciDeviceBar = PciDeviceBar::default(); + let mut bar_index_ignore: u8 = 255; + for bar_index in 0..6 { + if bar_index == bar_index_ignore { + continue; + } + let bar_info; + let mut virtaddress: u64 = 0; + let bar_orig = unsafe { + let bar_temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + BAR0_OFFSET + 4 * bar_index, + ); + bar_temp + }; + unsafe { + pci_write_config( + device_function.bus, + device_function.device, + device_function.function, + BAR0_OFFSET + 4 * bar_index, + 0xffffffff, + ); + } + let size_mask = unsafe { + let bar_temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + BAR0_OFFSET + 4 * bar_index, + ); + bar_temp + }; + // A wrapping add is necessary to correctly handle the case of unused BARs, which read back + // as 0, and should be treated as size 0. + let size = (!(size_mask & 0xfffffff0)).wrapping_add(1); + //kdebug!("bar_orig:{:#x},size: {:#x}", bar_orig,size); + // Restore the original value. + unsafe { + pci_write_config( + device_function.bus, + device_function.device, + device_function.function, + BAR0_OFFSET + 4 * bar_index, + bar_orig, + ); + } + if size == 0 { + continue; + } + if bar_orig & 0x00000001 == 0x00000001 { + // I/O space + let address = bar_orig & 0xfffffffc; + bar_info = BarInfo::IO { address, size }; + } else { + // Memory space + let mut address = u64::from(bar_orig & 0xfffffff0); + let prefetchable = bar_orig & 0x00000008 != 0; + let address_type = MemoryBarType::try_from(((bar_orig & 0x00000006) >> 1) as u8)?; + if address_type == MemoryBarType::Width64 { + if bar_index >= 5 { + return Err(PciError::InvalidBarType); + } + let address_top = unsafe { + let bar_temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + BAR0_OFFSET + 4 * (bar_index + 1), + ); + bar_temp + }; + address |= u64::from(address_top) << 32; + bar_index_ignore = bar_index + 1; //下个bar跳过,因为64位的memory bar覆盖了两个bar + } + //kdebug!("address={:#x},size={:#x}",address,size); + unsafe { + let vaddr_ptr = &mut virtaddress as *mut u64; + let mut virtsize: u64 = 0; + let virtsize_ptr = &mut virtsize as *mut u64; + let initial_mm_ptr = &mut initial_mm as *mut mm_struct; + //kdebug!("size want={:#x}", size); + if let Err(_) = MMIO_POOL.create_mmio( + size, + (VM_IO | VM_DONTCOPY) as u64, + vaddr_ptr, + virtsize_ptr, + ) { + kerror!("Create mmio failed when initing pci bar"); + return Err(PciError::CreateMmioError); + }; + //kdebug!("virtaddress={:#x},virtsize={:#x}",virtaddress,virtsize); + mm_map(initial_mm_ptr, virtaddress, size as u64, address); + } + bar_info = BarInfo::Memory { + address_type, + prefetchable, + address, + size, + virtaddress, + }; + } + match bar_index { + 0 => { + device_bar.bar0 = bar_info; + } + 1 => { + device_bar.bar1 = bar_info; + } + 2 => { + device_bar.bar2 = bar_info; + } + 3 => { + device_bar.bar3 = bar_info; + } + 4 => { + device_bar.bar4 = bar_info; + } + 5 => { + device_bar.bar5 = bar_info; + } + _ => {} + } + } + kdebug!("pci_device_bar:{}", device_bar); + return Ok(device_bar); +} + +/// Information about a PCI device capability. +/// PCI设备的capability的信息 +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct CapabilityInfo { + /// The offset of the capability in the PCI configuration space of the device function. + pub offset: u8, + /// The ID of the capability. + pub id: u8, + /// The third and fourth bytes of the capability, to save reading them again. + pub private_header: u16, +} +/// Iterator over capabilities for a device. +/// 创建迭代器以遍历PCI设备的capability +#[derive(Debug)] +pub struct CapabilityIterator { + pub device_function: DeviceFunction, + pub next_capability_offset: Option, +} + +impl Iterator for CapabilityIterator { + type Item = CapabilityInfo; + fn next(&mut self) -> Option { + let offset = self.next_capability_offset?; + + // Read the first 4 bytes of the capability. + let capability_header = unsafe { + let temp = pci_read_config( + self.device_function.bus, + self.device_function.device, + self.device_function.function, + offset, + ); + temp + }; + let id = capability_header as u8; + let next_offset = (capability_header >> 8) as u8; + let private_header = (capability_header >> 16) as u16; + + self.next_capability_offset = if next_offset == 0 { + None + } else if next_offset < 64 || next_offset & 0x3 != 0 { + kwarn!("Invalid next capability offset {:#04x}", next_offset); + None + } else { + Some(next_offset) + }; + + Some(CapabilityInfo { + offset, + id, + private_header, + }) + } +} diff --git a/kernel/src/driver/usb/xhci/xhci.c b/kernel/src/driver/usb/xhci/xhci.c index 7d45fdd5..5c970362 100644 --- a/kernel/src/driver/usb/xhci/xhci.c +++ b/kernel/src/driver/usb/xhci/xhci.c @@ -640,6 +640,8 @@ uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg) msi_desc.pci.msi_attribute.is_64 = 1; msi_desc.pci.msi_attribute.is_msix = 1; io_mfence(); + //因pci_enable_msi不再单独映射MSIX表,所以需要对pci设备的bar进行映射 + int retval = pci_enable_msi(&msi_desc); return 0; diff --git a/kernel/src/driver/virtio/Makefile b/kernel/src/driver/virtio/Makefile new file mode 100644 index 00000000..d7148862 --- /dev/null +++ b/kernel/src/driver/virtio/Makefile @@ -0,0 +1,7 @@ +all: virtio.o + +CFLAGS += -I . + +virtio.o: virtio.c + $(CC) $(CFLAGS) -c virtio.c -o virtio.o + diff --git a/kernel/src/driver/virtio/mod.rs b/kernel/src/driver/virtio/mod.rs new file mode 100644 index 00000000..ec15e36c --- /dev/null +++ b/kernel/src/driver/virtio/mod.rs @@ -0,0 +1,4 @@ +pub mod transport_pci; +pub mod virtio; +pub mod virtio_impl; +pub mod volatile; diff --git a/kernel/src/driver/virtio/transport_pci.rs b/kernel/src/driver/virtio/transport_pci.rs new file mode 100644 index 00000000..cdd1ad62 --- /dev/null +++ b/kernel/src/driver/virtio/transport_pci.rs @@ -0,0 +1,515 @@ +//! PCI transport for VirtIO. +use super::volatile::{ + volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly, +}; +use crate::driver::pci::pci::{ + capabilities_offset, pci_bar_init, CapabilityIterator, DeviceFunction, PciDeviceBar, PciError, + PCI_CAP_ID_VNDR, +}; +use crate::include::bindings::bindings::pci_read_config; +use core::{ + fmt::{self, Display, Formatter}, + mem::{align_of, size_of}, + ptr::{self, addr_of_mut, NonNull}, +}; +use virtio_drivers::{ + transport::{DeviceStatus, DeviceType, Transport}, + Error, Hal, PhysAddr, VirtAddr, +}; + +/// The PCI vendor ID for VirtIO devices. +/// PCI Virtio设备的vendor ID +const VIRTIO_VENDOR_ID: u16 = 0x1af4; + +/// The offset to add to a VirtIO device ID to get the corresponding PCI device ID. +/// PCI Virtio设备的DEVICE_ID 的offset +const PCI_DEVICE_ID_OFFSET: u16 = 0x1040; +/// PCI Virtio 设备的DEVICE_ID及其对应的设备类型 +const TRANSITIONAL_NETWORK: u16 = 0x1000; +const TRANSITIONAL_BLOCK: u16 = 0x1001; +const TRANSITIONAL_MEMORY_BALLOONING: u16 = 0x1002; +const TRANSITIONAL_CONSOLE: u16 = 0x1003; +const TRANSITIONAL_SCSI_HOST: u16 = 0x1004; +const TRANSITIONAL_ENTROPY_SOURCE: u16 = 0x1005; +const TRANSITIONAL_9P_TRANSPORT: u16 = 0x1009; + +/// The offset of the bar field within `virtio_pci_cap`. +const CAP_BAR_OFFSET: u8 = 4; +/// The offset of the offset field with `virtio_pci_cap`. +const CAP_BAR_OFFSET_OFFSET: u8 = 8; +/// The offset of the `length` field within `virtio_pci_cap`. +const CAP_LENGTH_OFFSET: u8 = 12; +/// The offset of the`notify_off_multiplier` field within `virtio_pci_notify_cap`. +const CAP_NOTIFY_OFF_MULTIPLIER_OFFSET: u8 = 16; + +/// Common configuration. +const VIRTIO_PCI_CAP_COMMON_CFG: u8 = 1; +/// Notifications. +const VIRTIO_PCI_CAP_NOTIFY_CFG: u8 = 2; +/// ISR Status. +const VIRTIO_PCI_CAP_ISR_CFG: u8 = 3; +/// Device specific configuration. +const VIRTIO_PCI_CAP_DEVICE_CFG: u8 = 4; + +///@brief device id 转换为设备类型 +///@param pci_device_id,device_id +///@return DeviceType 对应的设备类型 +fn device_type(pci_device_id: u16) -> DeviceType { + match pci_device_id { + TRANSITIONAL_NETWORK => DeviceType::Network, + TRANSITIONAL_BLOCK => DeviceType::Block, + TRANSITIONAL_MEMORY_BALLOONING => DeviceType::MemoryBalloon, + TRANSITIONAL_CONSOLE => DeviceType::Console, + TRANSITIONAL_SCSI_HOST => DeviceType::ScsiHost, + TRANSITIONAL_ENTROPY_SOURCE => DeviceType::EntropySource, + TRANSITIONAL_9P_TRANSPORT => DeviceType::_9P, + id if id >= PCI_DEVICE_ID_OFFSET => DeviceType::from(id - PCI_DEVICE_ID_OFFSET), + _ => DeviceType::Invalid, + } +} + +/// PCI transport for VirtIO. +/// +/// Ref: 4.1 Virtio Over PCI Bus +#[derive(Debug)] +pub struct PciTransport { + device_type: DeviceType, + /// The bus, device and function identifier for the VirtIO device. + device_function: DeviceFunction, + /// The common configuration structure within some BAR. + common_cfg: NonNull, + /// The start of the queue notification region within some BAR. + notify_region: NonNull<[WriteOnly]>, + notify_off_multiplier: u32, + /// The ISR status register within some BAR. + isr_status: NonNull>, + /// The VirtIO device-specific configuration within some BAR. + config_space: Option>, +} + +impl PciTransport { + /// Construct a new PCI VirtIO device driver for the given device function on the given PCI + /// root controller. + /// + /// The PCI device must already have had its BARs allocated. + pub fn new(device_function: DeviceFunction) -> Result { + let device_vendor = unsafe { + let bar_temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + 0, + ); + bar_temp + }; + let device_id = (device_vendor >> 16) as u16; + let vendor_id = device_vendor as u16; + if vendor_id != VIRTIO_VENDOR_ID { + return Err(VirtioPciError::InvalidVendorId(vendor_id)); + } + let device_type = device_type(device_id); + // Find the PCI capabilities we need. + let mut common_cfg = None; + let mut notify_cfg = None; + let mut notify_off_multiplier = 0; + let mut isr_cfg = None; + let mut device_cfg = None; + //device_capability为迭代器,遍历其相当于遍历所有的cap空间 + let device_capability = CapabilityIterator { + device_function: device_function, + next_capability_offset: capabilities_offset(device_function), + }; + let device_bar = pci_bar_init(device_function)?; + + for capability in device_capability { + if capability.id != PCI_CAP_ID_VNDR { + continue; + } + let cap_len = capability.private_header as u8; + let cfg_type = (capability.private_header >> 8) as u8; + if cap_len < 16 { + continue; + } + let struct_info = VirtioCapabilityInfo { + bar: unsafe { + let temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + capability.offset + CAP_BAR_OFFSET, + ); + temp as u8 + }, + offset: unsafe { + let temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + capability.offset + CAP_BAR_OFFSET_OFFSET, + ); + temp + }, + length: unsafe { + let temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + capability.offset + CAP_LENGTH_OFFSET, + ); + temp + }, + }; + + match cfg_type { + VIRTIO_PCI_CAP_COMMON_CFG if common_cfg.is_none() => { + common_cfg = Some(struct_info); + } + VIRTIO_PCI_CAP_NOTIFY_CFG if cap_len >= 20 && notify_cfg.is_none() => { + notify_cfg = Some(struct_info); + notify_off_multiplier = unsafe { + let temp = pci_read_config( + device_function.bus, + device_function.device, + device_function.function, + capability.offset + CAP_NOTIFY_OFF_MULTIPLIER_OFFSET, + ); + temp + }; + } + VIRTIO_PCI_CAP_ISR_CFG if isr_cfg.is_none() => { + isr_cfg = Some(struct_info); + } + VIRTIO_PCI_CAP_DEVICE_CFG if device_cfg.is_none() => { + device_cfg = Some(struct_info); + } + _ => {} + } + } + + let common_cfg = get_bar_region::<_>( + &device_bar, + &common_cfg.ok_or(VirtioPciError::MissingCommonConfig)?, + )?; + + let notify_cfg = notify_cfg.ok_or(VirtioPciError::MissingNotifyConfig)?; + if notify_off_multiplier % 2 != 0 { + return Err(VirtioPciError::InvalidNotifyOffMultiplier( + notify_off_multiplier, + )); + } + let notify_region = get_bar_region_slice::<_>(&device_bar, ¬ify_cfg)?; + let isr_status = get_bar_region::<_>( + &device_bar, + &isr_cfg.ok_or(VirtioPciError::MissingIsrConfig)?, + )?; + let config_space = if let Some(device_cfg) = device_cfg { + Some(get_bar_region_slice::<_>(&device_bar, &device_cfg)?) + } else { + None + }; + Ok(Self { + device_type, + device_function, + common_cfg, + notify_region, + notify_off_multiplier, + isr_status, + config_space, + }) + } +} + +impl Transport for PciTransport { + fn device_type(&self) -> DeviceType { + self.device_type + } + + fn read_device_features(&mut self) -> u64 { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + unsafe { + volwrite!(self.common_cfg, device_feature_select, 0); + let mut device_features_bits = volread!(self.common_cfg, device_feature) as u64; + volwrite!(self.common_cfg, device_feature_select, 1); + device_features_bits |= (volread!(self.common_cfg, device_feature) as u64) << 32; + device_features_bits + } + } + + fn write_driver_features(&mut self, driver_features: u64) { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + unsafe { + volwrite!(self.common_cfg, driver_feature_select, 0); + volwrite!(self.common_cfg, driver_feature, driver_features as u32); + volwrite!(self.common_cfg, driver_feature_select, 1); + volwrite!( + self.common_cfg, + driver_feature, + (driver_features >> 32) as u32 + ); + } + } + + fn max_queue_size(&self) -> u32 { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + unsafe { volread!(self.common_cfg, queue_size) }.into() + } + + fn notify(&mut self, queue: u16) { + // Safe because the common config and notify region pointers are valid and we checked in + // get_bar_region that they were aligned. + unsafe { + volwrite!(self.common_cfg, queue_select, queue); + // TODO: Consider caching this somewhere (per queue). + let queue_notify_off = volread!(self.common_cfg, queue_notify_off); + + let offset_bytes = usize::from(queue_notify_off) * self.notify_off_multiplier as usize; + let index = offset_bytes / size_of::(); + addr_of_mut!((*self.notify_region.as_ptr())[index]).vwrite(queue); + } + } + + fn set_status(&mut self, status: DeviceStatus) { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + unsafe { + volwrite!(self.common_cfg, device_status, status.bits() as u8); + } + } + + fn set_guest_page_size(&mut self, _guest_page_size: u32) { + // No-op, the PCI transport doesn't care. + } + + fn queue_set( + &mut self, + queue: u16, + size: u32, + descriptors: PhysAddr, + driver_area: PhysAddr, + device_area: PhysAddr, + ) { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + unsafe { + volwrite!(self.common_cfg, queue_select, queue); + volwrite!(self.common_cfg, queue_size, size as u16); + volwrite!(self.common_cfg, queue_desc, descriptors as u64); + volwrite!(self.common_cfg, queue_driver, driver_area as u64); + volwrite!(self.common_cfg, queue_device, device_area as u64); + volwrite!(self.common_cfg, queue_enable, 1); + } + } + + fn queue_unset(&mut self, queue: u16) { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + unsafe { + volwrite!(self.common_cfg, queue_enable, 0); + volwrite!(self.common_cfg, queue_select, queue); + volwrite!(self.common_cfg, queue_size, 0); + volwrite!(self.common_cfg, queue_desc, 0); + volwrite!(self.common_cfg, queue_driver, 0); + volwrite!(self.common_cfg, queue_device, 0); + } + } + + fn queue_used(&mut self, queue: u16) -> bool { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + unsafe { + volwrite!(self.common_cfg, queue_select, queue); + volread!(self.common_cfg, queue_enable) == 1 + } + } + + fn ack_interrupt(&mut self) -> bool { + // Safe because the common config pointer is valid and we checked in get_bar_region that it + // was aligned. + // Reading the ISR status resets it to 0 and causes the device to de-assert the interrupt. + let isr_status = unsafe { self.isr_status.as_ptr().vread() }; + // TODO: Distinguish between queue interrupt and device configuration interrupt. + isr_status & 0x3 != 0 + } + + fn config_space(&self) -> Result, Error> { + if let Some(config_space) = self.config_space { + if size_of::() > config_space.len() * size_of::() { + Err(Error::ConfigSpaceTooSmall) + } else if align_of::() > 4 { + // Panic as this should only happen if the driver is written incorrectly. + panic!( + "Driver expected config space alignment of {} bytes, but VirtIO only guarantees 4 byte alignment.", + align_of::() + ); + } else { + // TODO: Use NonNull::as_non_null_ptr once it is stable. + let config_space_ptr = NonNull::new(config_space.as_ptr() as *mut u32).unwrap(); + Ok(config_space_ptr.cast()) + } + } else { + Err(Error::ConfigSpaceMissing) + } + } +} + +/// `virtio_pci_common_cfg`, see 4.1.4.3 "Common configuration structure layout". +/// +#[repr(C)] +struct CommonCfg { + device_feature_select: Volatile, + device_feature: ReadOnly, + driver_feature_select: Volatile, + driver_feature: Volatile, + msix_config: Volatile, + num_queues: ReadOnly, + device_status: Volatile, + config_generation: ReadOnly, + queue_select: Volatile, + queue_size: Volatile, + queue_msix_vector: Volatile, + queue_enable: Volatile, + queue_notify_off: Volatile, + queue_desc: Volatile, + queue_driver: Volatile, + queue_device: Volatile, +} + +/// Information about a VirtIO structure within some BAR, as provided by a `virtio_pci_cap`. +///cfg空间在哪个bar的多少偏移处,长度多少 +#[derive(Clone, Debug, Eq, PartialEq)] +struct VirtioCapabilityInfo { + /// The bar in which the structure can be found. + bar: u8, + /// The offset within the bar. + offset: u32, + /// The length in bytes of the structure within the bar. + length: u32, +} + +/// An error encountered initialising a VirtIO PCI transport. +/// VirtIO PCI transport 初始化时的错误 +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum VirtioPciError { + /// PCI device vender ID was not the VirtIO vendor ID. + InvalidVendorId(u16), + /// No valid `VIRTIO_PCI_CAP_COMMON_CFG` capability was found. + MissingCommonConfig, + /// No valid `VIRTIO_PCI_CAP_NOTIFY_CFG` capability was found. + MissingNotifyConfig, + /// `VIRTIO_PCI_CAP_NOTIFY_CFG` capability has a `notify_off_multiplier` that is not a multiple + /// of 2. + InvalidNotifyOffMultiplier(u32), + /// No valid `VIRTIO_PCI_CAP_ISR_CFG` capability was found. + MissingIsrConfig, + /// An IO BAR was provided rather than a memory BAR. + UnexpectedBarType, + /// A BAR which we need was not allocated an address. + BarNotAllocated(u8), + /// The offset for some capability was greater than the length of the BAR. + BarOffsetOutOfRange, + /// The virtual address was not aligned as expected. + Misaligned { + /// The virtual address in question. + vaddr: VirtAddr, + /// The expected alignment in bytes. + alignment: usize, + }, + ///获取虚拟地址失败 + BarGetVaddrFailed, + /// A generic PCI error, + Pci(PciError), +} + +impl Display for VirtioPciError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::InvalidVendorId(vendor_id) => write!( + f, + "PCI device vender ID {:#06x} was not the VirtIO vendor ID {:#06x}.", + vendor_id, VIRTIO_VENDOR_ID + ), + Self::MissingCommonConfig => write!( + f, + "No valid `VIRTIO_PCI_CAP_COMMON_CFG` capability was found." + ), + Self::MissingNotifyConfig => write!( + f, + "No valid `VIRTIO_PCI_CAP_NOTIFY_CFG` capability was found." + ), + Self::InvalidNotifyOffMultiplier(notify_off_multiplier) => { + write!( + f, + "`VIRTIO_PCI_CAP_NOTIFY_CFG` capability has a `notify_off_multiplier` that is not a multiple of 2: {}", + notify_off_multiplier + ) + } + Self::MissingIsrConfig => { + write!(f, "No valid `VIRTIO_PCI_CAP_ISR_CFG` capability was found.") + } + Self::UnexpectedBarType => write!(f, "Unexpected BAR (expected memory BAR)."), + Self::BarNotAllocated(bar_index) => write!(f, "Bar {} not allocated.", bar_index), + Self::BarOffsetOutOfRange => write!(f, "Capability offset greater than BAR length."), + Self::Misaligned { vaddr, alignment } => write!( + f, + "Virtual address {:#018x} was not aligned to a {} byte boundary as expected.", + vaddr, alignment + ), + Self::BarGetVaddrFailed => write!(f, "Get bar virtaddress failed"), + Self::Pci(pci_error) => pci_error.fmt(f), + } + } +} +///PCI error到VirtioPciError的转换,层层上报 +impl From for VirtioPciError { + fn from(error: PciError) -> Self { + Self::Pci(error) + } +} + +///@brief 获取虚拟地址并将其转化为对应类型的指针 +///@param device_bar 存储bar信息的结构体 struct_info 存储cfg空间的位置信息 +///@return Result, VirtioPciError> 成功则返回对应类型的指针,失败则返回Error +fn get_bar_region( + device_bar: &PciDeviceBar, + struct_info: &VirtioCapabilityInfo, +) -> Result, VirtioPciError> { + let bar_info = device_bar.get_bar(struct_info.bar)?; + let (bar_address, bar_size) = bar_info + .memory_address_size() + .ok_or(VirtioPciError::UnexpectedBarType)?; + if bar_address == 0 { + return Err(VirtioPciError::BarNotAllocated(struct_info.bar)); + } + if struct_info.offset + struct_info.length > bar_size + || size_of::() > struct_info.length as usize + { + return Err(VirtioPciError::BarOffsetOutOfRange); + } + let vaddr = (bar_info + .virtual_address() + .ok_or(VirtioPciError::BarGetVaddrFailed)?) as usize + + struct_info.offset as usize; + if vaddr % align_of::() != 0 { + return Err(VirtioPciError::Misaligned { + vaddr, + alignment: align_of::(), + }); + } + Ok(NonNull::new((vaddr) as _).unwrap()) +} + +///@brief 获取虚拟地址并将其转化为对应类型的指针 +///@param device_bar 存储bar信息的结构体 struct_info 存储cfg空间的位置信息 +///@return Result, VirtioPciError> 成功则返回对应类型的指针切片,失败则返回Error +fn get_bar_region_slice( + device_bar: &PciDeviceBar, + struct_info: &VirtioCapabilityInfo, +) -> Result, VirtioPciError> { + let ptr = get_bar_region::(device_bar, struct_info)?; + let raw_slice = + ptr::slice_from_raw_parts_mut(ptr.as_ptr(), struct_info.length as usize / size_of::()); + Ok(NonNull::new(raw_slice).unwrap()) +} diff --git a/kernel/src/driver/virtio/virtio.c b/kernel/src/driver/virtio/virtio.c new file mode 100644 index 00000000..27ec0e88 --- /dev/null +++ b/kernel/src/driver/virtio/virtio.c @@ -0,0 +1,46 @@ +#include "virtio.h" +#include +#include +#include + +#define MAX_NET_NUM 8 // pci总线上的net设备的最大数量 + +// 在pci总线上寻找到net设备控制器的header +static struct pci_device_structure_header_t *net_pdevs[MAX_NET_NUM]; +static int net_pdevs_count = 0; +static struct pci_device_structure_header_t *virtio_net_pdev; +static int virtio_net_pdev_count = 0; +static uint8_t NETWORK_CLASS = 0x2; +static uint8_t ETHERNET_SUBCLASS = 0x0; + +/** + * @brief 获取virtio-net MMIO映射的虚拟地址 + * @param virt_addr 外部传入的虚拟地址指针 + * @return 获取成功,返回0,失败,返回错误码 + */ +uint8_t get_virtio_net_device(uint8_t * bus, uint8_t *device,uint8_t * function) +{ + // 获取所有net-pci设备的列表 + pci_get_device_structure(NETWORK_CLASS, ETHERNET_SUBCLASS, net_pdevs, &net_pdevs_count); + //检测其中的virt-io-net设备 + for(int i = 0; i < net_pdevs_count;i++) { + struct pci_device_structure_general_device_t *dev = net_pdevs[i]; + if(net_pdevs[i]->Vendor_ID==0x1AF4 && net_pdevs[i]->Device_ID>=0x1000 && net_pdevs[i]->Device_ID<=0x103F && dev->Subsystem_ID==1) + { + virtio_net_pdev=net_pdevs[i]; + virtio_net_pdev_count++; + break; + } + } + if (virtio_net_pdev_count == 0) { + kwarn("There is no virtio-net device in this computer!"); + return NOT_FOUND_DEVICE; + } + if (virtio_net_pdev->Command==0) { + kwarn("The virtio-net device isn't support mmio!"); + return NOT_SUPPORTE_MMIO; + } + *bus=virtio_net_pdev->bus; + *device=virtio_net_pdev->device; + *function=virtio_net_pdev->func; +} \ No newline at end of file diff --git a/kernel/src/driver/virtio/virtio.h b/kernel/src/driver/virtio/virtio.h new file mode 100644 index 00000000..7dc9d54d --- /dev/null +++ b/kernel/src/driver/virtio/virtio.h @@ -0,0 +1,12 @@ +#pragma once +#include + +#define GET_VIRTADDRESS_SUCCESS 0 +#define NOT_FOUND_DEVICE 1 +#define NOT_SUPPORTE_MMIO 2 +#define GET_VIRTADDRESS_FAILURE 3 + +// 获取virtio-net 设备 +uint8_t get_virtio_net_device(uint8_t * bus, uint8_t *device,uint8_t * function); +//寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备后续也可添加) +void c_virtio_probe(); diff --git a/kernel/src/driver/virtio/virtio.rs b/kernel/src/driver/virtio/virtio.rs new file mode 100644 index 00000000..6f81014a --- /dev/null +++ b/kernel/src/driver/virtio/virtio.rs @@ -0,0 +1,136 @@ +use super::transport_pci::PciTransport; +use super::virtio_impl::HalImpl; +use crate::driver::pci::pci::DeviceFunction; +use crate::include::bindings::bindings::get_virtio_net_device; +use crate::{kdebug, kerror, kwarn}; +use alloc::{boxed::Box, collections::LinkedList}; +use virtio_drivers::device::net::VirtIONet; +use virtio_drivers::transport::{DeviceType, Transport}; + +//Virtio设备寻找过程中出现的问题 +enum VirtioError { + VirtioNetNotFound, +} + +///@brief 寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备也可添加)(for c) +#[no_mangle] +pub extern "C" fn c_virtio_probe() { + if let Ok(virtio_list) = virtio_device_search() { + for device_function in virtio_list { + match PciTransport::new::(*device_function) { + Ok(mut transport) => { + kdebug!( + "Detected virtio PCI device with device type {:?}, features {:#018x}", + transport.device_type(), + transport.read_device_features(), + ); + virtio_device(transport); + } + Err(err) => { + kerror!("Pci transport create failed because of error: {}", err); + } + } + } + } else { + kerror!("Error occured when finding virtio device!"); + } +} + +///@brief 寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备也可添加) +fn virtio_probe() { + if let Ok(virtio_list) = virtio_device_search() { + for device_function in virtio_list { + match PciTransport::new::(*device_function) { + Ok(mut transport) => { + kdebug!( + "Detected virtio PCI device with device type {:?}, features {:#018x}", + transport.device_type(), + transport.read_device_features(), + ); + virtio_device(transport); + } + Err(err) => { + kerror!("Pci transport create failed because of error: {}", err); + } + } + } + } else { + kerror!("Error occured when finding virtio device!"); + } +} + +///@brief 为virtio设备寻找对应的驱动进行初始化 +fn virtio_device(transport: impl Transport) { + match transport.device_type() { + DeviceType::Block => { + kwarn!("Not support virtio_block device for now"); + } + DeviceType::GPU => { + kwarn!("Not support virtio_gpu device for now"); + } + DeviceType::Input => { + kwarn!("Not support virtio_input device for now"); + } + DeviceType::Network => virtio_net(transport), + t => { + kwarn!("Unrecognized virtio device: {:?}", t); + } + } +} + +///@brief virtio-net 驱动的初始化与测试 +fn virtio_net(transport: T) { + let mut driver_net = match VirtIONet::::new(transport) { + Ok(mut net) => { + kdebug!("Virtio-net driver init successfully."); + net + } + Err(_) => { + kerror!("VirtIONet init failed"); + return; + } + }; + // let mut buf = [0u8; 0x100]; + // let len = match driver_net.recv(&mut buf) + // { + // Ok(len) =>{len}, + // Err(_) =>{kerror!("virtio_net recv failed");return;} + // }; + // kdebug!("recv: {:?}", &buf[..len]); + // match driver_net.send(&buf[..len]) + // { + // Ok(_) =>{kdebug!("virtio_net send success");}, + // Err(_) =>{kerror!("virtio_net send failed");return;}, + // } + let mac = driver_net.mac(); + kdebug!("virtio_net MAC={:?}", mac); + kdebug!("virtio-net test finished"); +} + +/// @brief 寻找所有的virtio设备 +/// @return Result>,VirtioError> 成功则返回包含所有virtio设备的链表,失败则返回err +/// 该函数主要是为其他virtio设备预留支持 +fn virtio_device_search() -> Result>, VirtioError> { + let mut virtio_list: LinkedList> = LinkedList::new(); + let (bus, device, function) = unsafe { + let mut bus: u8 = 0; + let mut device: u8 = 0; + let mut function: u8 = 0; + let bus_ptr = &mut bus as *mut u8; + let device_ptr = &mut device as *mut u8; + let function_ptr = &mut function as *mut u8; + get_virtio_net_device(bus_ptr, device_ptr, function_ptr); + (bus, device, function) + }; + if bus == 0 && device == 0 && function == 0 { + kdebug!("get_virtio_net_device failed"); + return Err(VirtioError::VirtioNetNotFound); + } + let device_function = DeviceFunction { + bus: bus, + device: device, + function: function, + }; + virtio_list.push_back(Box::new(device_function)); + Ok(virtio_list) +} diff --git a/kernel/src/driver/virtio/virtio_impl.rs b/kernel/src/driver/virtio/virtio_impl.rs new file mode 100644 index 00000000..9201c803 --- /dev/null +++ b/kernel/src/driver/virtio/virtio_impl.rs @@ -0,0 +1,75 @@ +use crate::include::bindings::bindings::{ + alloc_pages, free_pages, memory_management_struct, Page, PAGE_2M_SHIFT, PAGE_2M_SIZE, + PAGE_OFFSET, PAGE_SHARED, ZONE_NORMAL, +}; +use crate::kdebug; +use core::mem::size_of; +use core::{ptr::NonNull}; +use virtio_drivers::{BufferDirection, Hal, PhysAddr, VirtAddr, PAGE_SIZE}; + +pub struct HalImpl; +impl Hal for HalImpl { + /// @brief 申请用于DMA的内存页 + /// @param pages 页数(4k一页) + /// @return PhysAddr 获得的内存页的初始物理地址 + fn dma_alloc(pages: usize) -> PhysAddr { + let reminder = pages * PAGE_SIZE % (PAGE_2M_SIZE as usize); + let page_num = if reminder > 0 { + (pages * PAGE_SIZE / (PAGE_2M_SIZE as usize) + 1) as i32 + } else { + (pages * PAGE_SIZE / (PAGE_2M_SIZE as usize)) as i32 + }; + + unsafe { + let pa = alloc_pages(ZONE_NORMAL, page_num, PAGE_SHARED as u64); + let page = *pa; + //kdebug!("alloc pages num:{},Phyaddr={}",page_num,page.addr_phys); + return page.addr_phys as PhysAddr; + } + } + /// @brief 释放用于DMA的内存页 + /// @param paddr 起始物理地址 pages 页数(4k一页) + /// @return i32 0表示成功 + fn dma_dealloc(paddr: PhysAddr, pages: usize) -> i32 { + let reminder = pages * PAGE_SIZE % (PAGE_2M_SIZE as usize); + let page_num = if reminder > 0 { + (pages * PAGE_SIZE / (PAGE_2M_SIZE as usize) + 1) as i32 + } else { + (pages * PAGE_SIZE / (PAGE_2M_SIZE as usize)) as i32 + }; + unsafe { + let pa = (memory_management_struct.pages_struct as usize + + (paddr >> PAGE_2M_SHIFT) * size_of::()) as *mut Page; + //kdebug!("free pages num:{},Phyaddr={}",page_num,paddr); + free_pages(pa, page_num); + } + return 0; + } + /// @brief 物理地址转换为虚拟地址 + /// @param paddr 起始物理地址 + /// @return VirtAddr 虚拟地址 + fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { + paddr + PAGE_OFFSET as usize + + } + /// @brief 与真实物理设备共享 + /// @param buffer 要共享的buffer _direction:设备到driver或driver到设备 + /// @return buffer在内存中的物理地址 + fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr { + let vaddr = buffer.as_ptr() as *mut u8 as usize; + // Nothing to do, as the host already has access to all memory. + virt_to_phys(vaddr) + } + /// @brief 停止共享(让主机可以访问全部内存的话什么都不用做) + fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) { + // Nothing to do, as the host already has access to all memory and we didn't copy the buffer + // anywhere else. + } +} + +/// @brief 虚拟地址转换为物理地址 +/// @param vaddr 虚拟地址 +/// @return PhysAddr 物理地址 +fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { + vaddr - PAGE_OFFSET as usize +} diff --git a/kernel/src/driver/virtio/volatile.rs b/kernel/src/driver/virtio/volatile.rs new file mode 100644 index 00000000..ff9f095f --- /dev/null +++ b/kernel/src/driver/virtio/volatile.rs @@ -0,0 +1,104 @@ +/// An MMIO register which can only be read from. +#[derive(Default)] +#[repr(transparent)] +pub struct ReadOnly(T); + +impl ReadOnly { + /// Construct a new instance for testing. + pub fn new(value: T) -> Self { + Self(value) + } +} + +/// An MMIO register which can only be written to. +#[derive(Default)] +#[repr(transparent)] +pub struct WriteOnly(T); + +/// An MMIO register which may be both read and written. +#[derive(Default)] +#[repr(transparent)] +pub struct Volatile(T); + +impl Volatile { + /// Construct a new instance for testing. + pub fn new(value: T) -> Self { + Self(value) + } +} + +/// A trait implemented by MMIO registers which may be read from. +pub trait VolatileReadable { + /// Performs a volatile read from the MMIO register. + unsafe fn vread(self) -> T; +} + +impl VolatileReadable for *const ReadOnly { + unsafe fn vread(self) -> T { + self.read_volatile().0 + } +} + +impl VolatileReadable for *const Volatile { + unsafe fn vread(self) -> T { + self.read_volatile().0 + } +} + +/// A trait implemented by MMIO registers which may be written to. +pub trait VolatileWritable { + /// Performs a volatile write to the MMIO register. + unsafe fn vwrite(self, value: T); +} + +impl VolatileWritable for *mut WriteOnly { + unsafe fn vwrite(self, value: T) { + (self as *mut T).write_volatile(value) + } +} + +impl VolatileWritable for *mut Volatile { + unsafe fn vwrite(self, value: T) { + (self as *mut T).write_volatile(value) + } +} + +/// Performs a volatile read from the given field of pointer to a struct representing an MMIO region. +/// +/// # Usage +/// ```compile_fail +/// # use core::ptr::NonNull; +/// # use virtio_drivers::volatile::{ReadOnly, volread}; +/// struct MmioDevice { +/// field: ReadOnly, +/// } +/// +/// let device: NonNull = NonNull::new(0x1234 as *mut MmioDevice).unwrap(); +/// let value = unsafe { volread!(device, field) }; +/// ``` +macro_rules! volread { + ($nonnull:expr, $field:ident) => { + VolatileReadable::vread(core::ptr::addr_of!((*$nonnull.as_ptr()).$field)) + }; +} + +/// Performs a volatile write to the given field of pointer to a struct representing an MMIO region. +/// +/// # Usage +/// ```compile_fail +/// # use core::ptr::NonNull; +/// # use virtio_drivers::volatile::{WriteOnly, volread}; +/// struct MmioDevice { +/// field: WriteOnly, +/// } +/// +/// let device: NonNull = NonNull::new(0x1234 as *mut MmioDevice).unwrap(); +/// unsafe { volwrite!(device, field, 42); } +/// ``` +macro_rules! volwrite { + ($nonnull:expr, $field:ident, $value:expr) => { + VolatileWritable::vwrite(core::ptr::addr_of_mut!((*$nonnull.as_ptr()).$field), $value) + }; +} +pub(crate) use volread; +pub(crate) use volwrite; diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h index 214c3eeb..52d9e9f2 100644 --- a/kernel/src/include/bindings/wrapper.h +++ b/kernel/src/include/bindings/wrapper.h @@ -31,9 +31,13 @@ #include #include #include +#include #include #include #include #include