VirtIO网卡能够正常发送、接收数据 (#204)

* virtio-net小修改

* 移动volatile.rs到libs文件夹

* 使用virtio-drivers 0.3.0

* bugfix: 初始化BAR之后,未正确设置command register的问题


---------

Co-authored-by: longjin <longjin@dragonos.org>
This commit is contained in:
YJwu2023
2023-03-18 20:43:37 +08:00
committed by GitHub
parent 4454d1a2dd
commit 73c607aadd
13 changed files with 216 additions and 121 deletions

View File

@ -46,7 +46,7 @@ bitflags! {
bitflags! {
/// The command register in PCI configuration space.
pub struct Command: u16 {
pub struct CommandRegister: u16 {
/// The device can respond to I/O Space accesses.
const IO_SPACE = 1 << 0;
/// The device can respond to Memory Space accesses.
@ -131,9 +131,10 @@ impl Display for PciError {
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 是否有效
/// @brief 检测DeviceFunction实例是否有效
/// @param self
/// @return bool 是否有效
#[allow(dead_code)]
pub fn valid(&self) -> bool {
self.device < 32 && self.function < 8
}
@ -449,6 +450,7 @@ pub struct CapabilityInfo {
/// 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)]
@ -492,3 +494,28 @@ impl Iterator for CapabilityIterator {
})
}
}
/// @brief 设置PCI Config Space里面的Command Register
///
/// @param device_function 设备
/// @param value command register要被设置成的值
pub fn set_command_register(device_function: &DeviceFunction, value: CommandRegister) {
unsafe {
pci_write_config(
device_function.bus,
device_function.device,
device_function.function,
STATUS_COMMAND_OFFSET,
value.bits().into(),
);
}
}
/// @brief 使能对PCI Memory/IO空间的写入使能PCI设备作为主设备(主动进行Memory的写入等msix中断使用到)
///
/// @param device_function 设备
pub fn pci_enable_master(device_function: DeviceFunction) {
set_command_register(
&device_function,
CommandRegister::IO_SPACE | CommandRegister::MEMORY_SPACE | CommandRegister::BUS_MASTER,
);
}

View File

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

View File

@ -1,12 +1,13 @@
//! 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,
capabilities_offset, pci_bar_init, pci_enable_master, CapabilityIterator, DeviceFunction,
PciDeviceBar, PciError, PCI_CAP_ID_VNDR,
};
use crate::include::bindings::bindings::pci_read_config;
use crate::libs::volatile::{
volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly,
};
use core::{
fmt::{self, Display, Formatter},
mem::{align_of, size_of},
@ -14,9 +15,10 @@ use core::{
};
use virtio_drivers::{
transport::{DeviceStatus, DeviceType, Transport},
Error, Hal, PhysAddr, VirtAddr,
Error, Hal, PhysAddr,
};
type VirtAddr = usize;
/// The PCI vendor ID for VirtIO devices.
/// PCI Virtio设备的vendor ID
const VIRTIO_VENDOR_ID: u16 = 0x1af4;
@ -119,8 +121,9 @@ impl PciTransport {
device_function: device_function,
next_capability_offset: capabilities_offset(device_function),
};
let device_bar = pci_bar_init(device_function)?;
let device_bar = pci_bar_init(device_function)?;
pci_enable_master(device_function);
for capability in device_capability {
if capability.id != PCI_CAP_ID_VNDR {
continue;
@ -197,6 +200,7 @@ impl PciTransport {
notify_off_multiplier,
));
}
//kdebug!("notify.offset={},notify.length={}",notify_cfg.offset,notify_cfg.length);
let notify_region = get_bar_region_slice::<_>(&device_bar, &notify_cfg)?;
let isr_status = get_bar_region::<_>(
&device_bar,
@ -282,7 +286,9 @@ impl Transport for PciTransport {
fn set_guest_page_size(&mut self, _guest_page_size: u32) {
// No-op, the PCI transport doesn't care.
}
fn requires_legacy_layout(&self) -> bool {
false
}
fn queue_set(
&mut self,
queue: u16,
@ -293,6 +299,10 @@ impl Transport for PciTransport {
) {
// Safe because the common config pointer is valid and we checked in get_bar_region that it
// was aligned.
// kdebug!("queue_select={}",queue);
// kdebug!("queue_size={}",size as u16);
// kdebug!("queue_desc={:#x}",descriptors as u64);
// kdebug!("driver_area={:#x}",driver_area);
unsafe {
volwrite!(self.common_cfg, queue_select, queue);
volwrite!(self.common_cfg, queue_size, size as u16);
@ -307,7 +317,6 @@ impl Transport for PciTransport {
// 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);
@ -355,8 +364,13 @@ impl Transport for PciTransport {
}
}
/// `virtio_pci_common_cfg`, see 4.1.4.3 "Common configuration structure layout".
///
impl Drop for PciTransport {
fn drop(&mut self) {
// Reset the device when the transport is dropped.
self.set_status(DeviceStatus::empty())
}
}
#[repr(C)]
struct CommonCfg {
device_feature_select: Volatile<u32>,
@ -488,6 +502,7 @@ fn get_bar_region<T>(
{
return Err(VirtioPciError::BarOffsetOutOfRange);
}
//kdebug!("Chossed bar ={},used={}",struct_info.bar,struct_info.offset + struct_info.length);
let vaddr = (bar_info
.virtual_address()
.ok_or(VirtioPciError::BarGetVaddrFailed)?) as usize
@ -498,18 +513,25 @@ fn get_bar_region<T>(
alignment: align_of::<T>(),
});
}
Ok(NonNull::new((vaddr) as _).unwrap())
let vaddr = NonNull::new(vaddr as *mut u8).unwrap();
Ok(vaddr.cast())
}
///@brief 获取虚拟地址并将其转化为对应类型的指针
///@param device_bar 存储bar信息的结构体 struct_info 存储cfg空间的位置信息
///@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())
// let raw_slice =
// ptr::slice_from_raw_parts_mut(ptr.as_ptr(), struct_info.length as usize / size_of::<T>());
Ok(nonnull_slice_from_raw_parts(
ptr,
struct_info.length as usize / size_of::<T>(),
))
}
fn nonnull_slice_from_raw_parts<T>(data: NonNull<T>, len: usize) -> NonNull<[T]> {
NonNull::new(ptr::slice_from_raw_parts_mut(data.as_ptr(), len)).unwrap()
}

View File

@ -9,4 +9,4 @@
// 获取virtio-net 设备
uint8_t get_virtio_net_device(uint8_t * bus, uint8_t *device,uint8_t * function);
//寻找并加载所有virtio设备的驱动目前只有virtio-net但其他virtio设备后续也可添加
extern void c_virtio_probe();
void c_virtio_probe();

View File

@ -90,18 +90,41 @@ fn virtio_net<T: Transport>(transport: T) {
return;
}
};
// let mut buf = [0u8; 0x100];
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;},
match driver_net.can_send() {
true => {
kdebug!("Virtio-net can send");
}
false => {
kdebug!("Virtio-net can not send");
}
}
// match driver_net.can_recv() {
// true => {
// kdebug!("can recv")
// }
// false => {
// kdebug!("can not recv");
// }
// }
let len = 100;
//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");

View File

@ -1,63 +1,57 @@
/// 为virtio-drivers库提供的操作系统接口
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::mm::virt_2_phys;
use core::mem::size_of;
use core::ptr::NonNull;
use virtio_drivers::{BufferDirection, Hal, PhysAddr, VirtAddr, PAGE_SIZE};
use virtio_drivers::{BufferDirection, Hal, PhysAddr, 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
};
fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull<u8>) {
let page_num = (pages * PAGE_SIZE - 1 + PAGE_2M_SIZE as usize) / PAGE_2M_SIZE as usize;
unsafe {
let pa = alloc_pages(ZONE_NORMAL, page_num, PAGE_SHARED as u64);
let pa = alloc_pages(ZONE_NORMAL, page_num as i32, PAGE_SHARED as u64);
let page = *pa;
//kdebug!("alloc pages num:{},Phyaddr={}",page_num,page.addr_phys);
return page.addr_phys as PhysAddr;
//kdebug!("alloc pages num:{},Phyaddr={:#x}",pages,page.addr_phys);
(
page.addr_phys as PhysAddr,
NonNull::new((page.addr_phys as PhysAddr + PAGE_OFFSET as usize) as _).unwrap(),
)
}
}
/// @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
};
fn dma_dealloc(paddr: PhysAddr, _vaddr: NonNull<u8>, pages: usize) -> i32 {
let page_num = (pages * PAGE_SIZE - 1 + PAGE_2M_SIZE as usize) / PAGE_2M_SIZE as usize;
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);
free_pages(pa, page_num as i32);
}
return 0;
}
/// @brief 物理地址转换为虚拟地址
/// @brief mmio物理地址转换为虚拟地址,不需要使用
/// @param paddr 起始物理地址
/// @return VirtAddr 虚拟地址
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
paddr + PAGE_OFFSET as usize
/// @return NonNull<u8> 虚拟地址的指针
fn mmio_phys_to_virt(_paddr: PhysAddr, _size: usize) -> NonNull<u8> {
NonNull::new((0) as _).unwrap()
}
/// @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;
//kdebug!("virt:{:x}", vaddr);
// Nothing to do, as the host already has access to all memory.
virt_to_phys(vaddr)
virt_2_phys(vaddr)
}
/// @brief 停止共享(让主机可以访问全部内存的话什么都不用做)
fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {
@ -65,10 +59,3 @@ impl Hal for HalImpl {
// anywhere else.
}
}
/// @brief 虚拟地址转换为物理地址
/// @param vaddr 虚拟地址
/// @return PhysAddr 物理地址
fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
vaddr - PAGE_OFFSET as usize
}

View File

@ -1,104 +0,0 @@
/// 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;