新增VirtIO网卡驱动 (#194)

* 修复内存bug与grub安装脚本的错误

* 修改小bug

* PCI增加功能与virtio-net驱动

* little fix

* virtio-net小修改
This commit is contained in:
YJwu2023 2023-03-11 21:09:50 +08:00 committed by GitHub
parent 1d48996375
commit 26d84a3139
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1416 additions and 10 deletions

View File

@ -169,7 +169,8 @@
"acpi.h": "c", "acpi.h": "c",
"assert.h": "c", "assert.h": "c",
"sys_version.h": "c", "sys_version.h": "c",
"cmd.h": "c" "cmd.h": "c",
"net.h": "c"
}, },
"C_Cpp.errorSquiggles": "Enabled", "C_Cpp.errorSquiggles": "Enabled",
"esbonio.sphinx.confDir": "", "esbonio.sphinx.confDir": "",

View File

@ -11,6 +11,8 @@ crate-type = ["staticlib"]
# 运行时依赖项 # 运行时依赖项
[dependencies] [dependencies]
x86_64 = "0.14.10" x86_64 = "0.14.10"
virtio-drivers = "0.2.0"
bitflags = "1.3"
# 构建时依赖项 # 构建时依赖项
[build-dependencies] [build-dependencies]
@ -22,3 +24,4 @@ version = "1.4.0"
features = ["spin_no_std"] features = ["spin_no_std"]

View File

View File

View File

@ -1,7 +1,7 @@
CFLAGS += -I . 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:
@echo "$@" @echo "$@"
@ -14,4 +14,4 @@ all: $(kernel_driver_subdirs)
clean: clean:
echo "Done." echo "Done."

View File

@ -1,2 +1,4 @@
pub mod pci;
pub mod timers; pub mod timers;
pub mod uart; pub mod uart;
pub mod virtio;

View File

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

View File

@ -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 pci_dev pci设备信息结构体
* @param msix_cap msix capability list的结构体 * @param msix_cap msix capability list的结构体

View File

@ -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<u8> offset
pub fn capabilities_offset(device_function: DeviceFunction) -> Option<u8> {
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<MemoryBarType> for u8 {
fn from(bar_type: MemoryBarType) -> Self {
match bar_type {
MemoryBarType::Width32 => 0,
MemoryBarType::Below1MiB => 1,
MemoryBarType::Width64 => 2,
}
}
}
///实现MemoryBarType与u8的类型转换
impl TryFrom<u8> for MemoryBarType {
type Error = PciError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
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<u64> {
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, PciError> 成功则返回对应的PciDeviceBar结构体失败则返回错误类型
pub fn pci_bar_init(device_function: DeviceFunction) -> Result<PciDeviceBar, PciError> {
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<u8>,
}
impl Iterator for CapabilityIterator {
type Item = CapabilityInfo;
fn next(&mut self) -> Option<Self::Item> {
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,
})
}
}

View File

@ -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_64 = 1;
msi_desc.pci.msi_attribute.is_msix = 1; msi_desc.pci.msi_attribute.is_msix = 1;
io_mfence(); io_mfence();
//因pci_enable_msi不再单独映射MSIX表所以需要对pci设备的bar进行映射
int retval = pci_enable_msi(&msi_desc); int retval = pci_enable_msi(&msi_desc);
return 0; return 0;

View File

@ -0,0 +1,7 @@
all: virtio.o
CFLAGS += -I .
virtio.o: virtio.c
$(CC) $(CFLAGS) -c virtio.c -o virtio.o

View File

@ -0,0 +1,4 @@
pub mod transport_pci;
pub mod virtio;
pub mod virtio_impl;
pub mod volatile;

View File

@ -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_iddevice_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<CommonCfg>,
/// The start of the queue notification region within some BAR.
notify_region: NonNull<[WriteOnly<u16>]>,
notify_off_multiplier: u32,
/// The ISR status register within some BAR.
isr_status: NonNull<Volatile<u8>>,
/// The VirtIO device-specific configuration within some BAR.
config_space: Option<NonNull<[u32]>>,
}
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<H: Hal>(device_function: DeviceFunction) -> Result<Self, VirtioPciError> {
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, &notify_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::<u16>();
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<T>(&self) -> Result<NonNull<T>, Error> {
if let Some(config_space) = self.config_space {
if size_of::<T>() > config_space.len() * size_of::<u32>() {
Err(Error::ConfigSpaceTooSmall)
} else if align_of::<T>() > 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::<T>()
);
} 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<u32>,
device_feature: ReadOnly<u32>,
driver_feature_select: Volatile<u32>,
driver_feature: Volatile<u32>,
msix_config: Volatile<u16>,
num_queues: ReadOnly<u16>,
device_status: Volatile<u8>,
config_generation: ReadOnly<u8>,
queue_select: Volatile<u16>,
queue_size: Volatile<u16>,
queue_msix_vector: Volatile<u16>,
queue_enable: Volatile<u16>,
queue_notify_off: Volatile<u16>,
queue_desc: Volatile<u64>,
queue_driver: Volatile<u64>,
queue_device: Volatile<u64>,
}
/// 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<PciError> for VirtioPciError {
fn from(error: PciError) -> Self {
Self::Pci(error)
}
}
///@brief 获取虚拟地址并将其转化为对应类型的指针
///@param device_bar 存储bar信息的结构体 struct_info 存储cfg空间的位置信息
///@return Result<NonNull<T>, VirtioPciError> 成功则返回对应类型的指针失败则返回Error
fn get_bar_region<T>(
device_bar: &PciDeviceBar,
struct_info: &VirtioCapabilityInfo,
) -> Result<NonNull<T>, 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::<T>() > 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::<T>() != 0 {
return Err(VirtioPciError::Misaligned {
vaddr,
alignment: align_of::<T>(),
});
}
Ok(NonNull::new((vaddr) as _).unwrap())
}
///@brief 获取虚拟地址并将其转化为对应类型的指针
///@param device_bar 存储bar信息的结构体 struct_info 存储cfg空间的位置信息
///@return Result<NonNull<[T]>, VirtioPciError> 成功则返回对应类型的指针切片失败则返回Error
fn get_bar_region_slice<T>(
device_bar: &PciDeviceBar,
struct_info: &VirtioCapabilityInfo,
) -> Result<NonNull<[T]>, VirtioPciError> {
let ptr = get_bar_region::<T>(device_bar, struct_info)?;
let raw_slice =
ptr::slice_from_raw_parts_mut(ptr.as_ptr(), struct_info.length as usize / size_of::<T>());
Ok(NonNull::new(raw_slice).unwrap())
}

View File

@ -0,0 +1,46 @@
#include "virtio.h"
#include <common/kprint.h>
#include <common/errno.h>
#include <driver/pci/pci.h>
#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;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <common/glib.h>
#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();

View File

@ -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::<HalImpl>(*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::<HalImpl>(*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<T: Transport>(transport: T) {
let mut driver_net = match VirtIONet::<HalImpl, T>::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<LinkedList<Box<DeviceFunction>>,VirtioError> 成功则返回包含所有virtio设备的链表失败则返回err
/// 该函数主要是为其他virtio设备预留支持
fn virtio_device_search() -> Result<LinkedList<Box<DeviceFunction>>, VirtioError> {
let mut virtio_list: LinkedList<Box<DeviceFunction>> = 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)
}

View File

@ -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::<Page>()) 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
}

View File

@ -0,0 +1,104 @@
/// An MMIO register which can only be read from.
#[derive(Default)]
#[repr(transparent)]
pub struct ReadOnly<T: Copy>(T);
impl<T: Copy> ReadOnly<T> {
/// 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: Copy>(T);
/// An MMIO register which may be both read and written.
#[derive(Default)]
#[repr(transparent)]
pub struct Volatile<T: Copy>(T);
impl<T: Copy> Volatile<T> {
/// 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<T> {
/// Performs a volatile read from the MMIO register.
unsafe fn vread(self) -> T;
}
impl<T: Copy> VolatileReadable<T> for *const ReadOnly<T> {
unsafe fn vread(self) -> T {
self.read_volatile().0
}
}
impl<T: Copy> VolatileReadable<T> for *const Volatile<T> {
unsafe fn vread(self) -> T {
self.read_volatile().0
}
}
/// A trait implemented by MMIO registers which may be written to.
pub trait VolatileWritable<T> {
/// Performs a volatile write to the MMIO register.
unsafe fn vwrite(self, value: T);
}
impl<T: Copy> VolatileWritable<T> for *mut WriteOnly<T> {
unsafe fn vwrite(self, value: T) {
(self as *mut T).write_volatile(value)
}
}
impl<T: Copy> VolatileWritable<T> for *mut Volatile<T> {
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<u32>,
/// }
///
/// let device: NonNull<MmioDevice> = 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<u32>,
/// }
///
/// let device: NonNull<MmioDevice> = 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;

View File

@ -31,9 +31,13 @@
#include <include/DragonOS/refcount.h> #include <include/DragonOS/refcount.h>
#include <include/DragonOS/signal.h> #include <include/DragonOS/signal.h>
#include <mm/mm.h> #include <mm/mm.h>
#include <mm/mmio.h>
#include <mm/slab.h> #include <mm/slab.h>
#include <process/process.h> #include <process/process.h>
#include <sched/sched.h> #include <sched/sched.h>
#include <time/sleep.h> #include <time/sleep.h>
#include <mm/mm-types.h> #include <mm/mm-types.h>
#include <driver/pci/pci.h>
#include <driver/virtio/virtio.h>
#include <smp/smp.h> #include <smp/smp.h>

View File

@ -71,14 +71,11 @@ void reload_idt()
// 初始化系统各模块 // 初始化系统各模块
void system_initialize() void system_initialize()
{ {
c_uart_init(COM1, 115200); c_uart_init(COM1, 115200);
video_init(); video_init();
scm_init(); scm_init();
textui_init(); textui_init();
kinfo("Kernel Starting..."); kinfo("Kernel Starting...");
// 重新加载gdt和idt // 重新加载gdt和idt
ul tss_item_addr = (ul)phys_2_virt(0x7c00); ul tss_item_addr = (ul)phys_2_virt(0x7c00);
@ -165,7 +162,7 @@ void system_initialize()
io_mfence(); io_mfence();
// current_pcb->preempt_count = 0; // current_pcb->preempt_count = 0;
// kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq()); // kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq());
process_init(); process_init();
// 启用double buffer // 启用double buffer
// scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread // scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread
@ -178,7 +175,7 @@ void system_initialize()
apic_timer_init(); apic_timer_init();
io_mfence(); io_mfence();
// 这里不能删除否则在O1会报错 // 这里不能删除否则在O1会报错
// while (1) // while (1)
// pause(); // pause();

View File

@ -199,7 +199,7 @@ void mm_init()
ZONE_NORMAL_INDEX = memory_management_struct.count_zones ; ZONE_NORMAL_INDEX = memory_management_struct.count_zones ;
ZONE_UNMAPPED_INDEX = 0; ZONE_UNMAPPED_INDEX = 0;
// kdebug("ZONE_DMA_INDEX=%d\tZONE_NORMAL_INDEX=%d\tZONE_UNMAPPED_INDEX=%d", ZONE_DMA_INDEX, ZONE_NORMAL_INDEX, ZONE_UNMAPPED_INDEX); //kdebug("ZONE_DMA_INDEX=%d\tZONE_NORMAL_INDEX=%d\tZONE_UNMAPPED_INDEX=%d", ZONE_DMA_INDEX, ZONE_NORMAL_INDEX, ZONE_UNMAPPED_INDEX);
// 设置内存页管理结构的地址,预留了一段空间,防止内存越界。 // 设置内存页管理结构的地址,预留了一段空间,防止内存越界。
memory_management_struct.end_of_struct = (ul)((ul)memory_management_struct.zones_struct + memory_management_struct.zones_struct_len + sizeof(long) * 32) & (~(sizeof(long) - 1)); memory_management_struct.end_of_struct = (ul)((ul)memory_management_struct.zones_struct + memory_management_struct.zones_struct_len + sizeof(long) * 32) & (~(sizeof(long) - 1));

View File

@ -31,6 +31,7 @@
#include <sched/sched.h> #include <sched/sched.h>
#include <syscall/syscall.h> #include <syscall/syscall.h>
#include <syscall/syscall_num.h> #include <syscall/syscall_num.h>
#include <driver/virtio/virtio.h>
extern int __rust_demo_func(); extern int __rust_demo_func();
// #pragma GCC push_options // #pragma GCC push_options
// #pragma GCC optimize("O0") // #pragma GCC optimize("O0")
@ -502,6 +503,7 @@ ul initial_kernel_thread(ul arg)
ahci_init(); ahci_init();
fat32_init(); fat32_init();
rootfs_umount(); rootfs_umount();
c_virtio_probe();
// 使用单独的内核线程来初始化usb驱动程序 // 使用单独的内核线程来初始化usb驱动程序
// 注释由于目前usb驱动程序不完善因此先将其注释掉 // 注释由于目前usb驱动程序不完善因此先将其注释掉