Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ crate-type = ["staticlib"]
[dependencies]
x86_64 = "0.14.10"
bitflags = "1.3.2"
virtio-drivers = "0.2.0"
virtio-drivers = "0.3.0"
# 一个无锁MPSC队列
thingbuf = { version = "0.1.3", default-features = false, features = ["alloc"] }
# smoltcp 0.9.1
Expand Down
35 changes: 31 additions & 4 deletions kernel/src/driver/pci/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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,
);
}
1 change: 0 additions & 1 deletion kernel/src/driver/virtio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub mod transport_pci;
pub mod virtio;
pub mod virtio_impl;
pub mod volatile;
56 changes: 39 additions & 17 deletions kernel/src/driver/virtio/transport_pci.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
//! 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},
ptr::{self, addr_of_mut, NonNull},
};
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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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
Expand All @@ -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()
}
2 changes: 1 addition & 1 deletion kernel/src/driver/virtio/virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
35 changes: 29 additions & 6 deletions kernel/src/driver/virtio/virtio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
53 changes: 20 additions & 33 deletions kernel/src/driver/virtio/virtio_impl.rs
Original file line number Diff line number Diff line change
@@ -1,74 +1,61 @@
/// 为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) {
// 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
}
Loading