Implement PCI driver detach and merge NetDriver trait into Driver

master
Jiajie Chen 6 years ago
parent cf3b183311
commit 960ef2e1f8

@ -6,9 +6,9 @@ Rust version of THU [uCore OS Plus](https://github.com/chyyuu/ucore_os_plus).
Going to be the next generation teaching operating system. Going to be the next generation teaching operating system.
Supported architectures: x86_64, RISCV32/64, AArch64 Supported architectures: x86_64, RISCV32/64, AArch64, MIPS (planned)
Tested boards: QEMU, PC, Raspberry Pi 3B+ Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+
[Dev docs](https://rucore.gitbook.io/rust-os-docs/) (in Chinese) [Dev docs](https://rucore.gitbook.io/rust-os-docs/) (in Chinese)
@ -24,20 +24,22 @@ Tested boards: QEMU, PC, Raspberry Pi 3B+
* [bootimage](https://github.com/rust-osdev/bootimage) (for x86_64) * [bootimage](https://github.com/rust-osdev/bootimage) (for x86_64)
* [RISCV64 GNU toolchain](https://www.sifive.com/boards) (for riscv32/64) * [RISCV64 GNU toolchain](https://www.sifive.com/boards) (for riscv32/64)
* [AArch64 GNU toolchain](https://cs140e.sergio.bz/assignments/0-blinky/) (for aarch64) * [AArch64 GNU toolchain](https://cs140e.sergio.bz/assignments/0-blinky/) (for aarch64)
* [musl-cross-make](https://github.com/richfelker/musl-cross-make) (for userland musl)
See [Travis script](./.travis.yml) for details. See [Travis script](./.travis.yml) for details.
### How to run ### How to run
```bash ```bash
rustup component add rust-src $ rustup component add rust-src
cargo install cargo-xbuild bootimage $ cargo install cargo-xbuild bootimage
``` ```
```bash ```bash
git clone https://github.com/rcore-os/rCore.git --recursive $ git clone https://github.com/rcore-os/rCore.git --recursive
cd rCore/kernel $ cd rCore/kernel
make run arch={riscv32,riscv64,x86_64,aarch64} $ make sfsimg arch={riscv32,riscv64,x86_64,aarch64} # requires musl-cross-make
$ make run arch={riscv32,riscv64,x86_64,aarch64}
``` ```
## History ## History

@ -1,3 +1,3 @@
pub mod virtio_mmio;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub mod pci; pub mod pci;
pub mod virtio_mmio;

@ -1,6 +1,11 @@
use crate::drivers::net::*; use crate::drivers::net::*;
use x86_64::instructions::port::Port; use crate::drivers::{Driver, DRIVERS, NET_DRIVERS};
use alloc::collections::BTreeMap;
use alloc::string::String; use alloc::string::String;
use alloc::sync::Arc;
use spin::Mutex;
use core::cmp::Ordering;
use x86_64::instructions::port::Port;
const PCI_VENDOR: u32 = 0x00; const PCI_VENDOR: u32 = 0x00;
const PCI_DEVICE: u32 = 0x02; const PCI_DEVICE: u32 = 0x02;
@ -39,6 +44,28 @@ const PCI_BASE_ADDRESS_MEM_MASK: u32 = 0xfffffff0;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct PciTag(u32); pub struct PciTag(u32);
impl Ord for PciTag {
fn cmp(&self, other: &PciTag) -> Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for PciTag {
fn partial_cmp(&self, other: &PciTag) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Eq for PciTag {
}
impl PartialEq for PciTag {
fn eq(&self, other: &PciTag) -> bool {
self.0 == other.0
}
}
impl PciTag { impl PciTag {
pub fn new(bus: u32, dev: u32, func: u32) -> PciTag { pub fn new(bus: u32, dev: u32, func: u32) -> PciTag {
assert!(bus < 256); assert!(bus < 256);
@ -135,10 +162,9 @@ impl PciTag {
max_base |= (max_base_hi as usize) << 32; max_base |= (max_base_hi as usize) << 32;
address_mark = !0; address_mark = !0;
} }
_ => unimplemented!("pci bar mem type") _ => unimplemented!("pci bar mem type"),
} }
if max_base == 0 { if max_base == 0 {
return None; return None;
} }
@ -191,7 +217,6 @@ impl PciTag {
} }
} }
/// Enable the pci tag and its interrupt /// Enable the pci tag and its interrupt
/// Return assigned MSI interrupt number when applicable /// Return assigned MSI interrupt number when applicable
pub unsafe fn enable(&self) -> Option<u32> { pub unsafe fn enable(&self) -> Option<u32> {
@ -221,11 +246,18 @@ impl PciTag {
// enable MSI interrupt, assuming 64bit for now // enable MSI interrupt, assuming 64bit for now
let orig_ctrl = self.read(cap_ptr + PCI_MSI_CTRL_CAP, 4); let orig_ctrl = self.read(cap_ptr + PCI_MSI_CTRL_CAP, 4);
self.write(cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); self.write(cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
debug!("MSI control {:#b}, enabling MSI interrupts", orig_ctrl >> 16); debug!(
"MSI control {:#b}, enabling MSI interrupts",
orig_ctrl >> 16
);
msi_found = true; msi_found = true;
break; break;
} }
debug!("PCI device has cap id {} at {:#X}", self.read(cap_ptr, 1), cap_ptr); debug!(
"PCI device has cap id {} at {:#X}",
self.read(cap_ptr, 1),
cap_ptr
);
cap_ptr = self.read(cap_ptr + 1, 1); cap_ptr = self.read(cap_ptr + 1, 1);
} }
@ -235,7 +267,10 @@ impl PciTag {
self.write(PCI_COMMAND, orig | 0xf); self.write(PCI_COMMAND, orig | 0xf);
let line = self.read(PCI_INTERRUPT_LINE, 1); let line = self.read(PCI_INTERRUPT_LINE, 1);
let pin = self.read(PCI_INTERRUPT_PIN, 1); let pin = self.read(PCI_INTERRUPT_PIN, 1);
debug!("MSI not found, using PCI interrupt line {} pin {}", line, pin); debug!(
"MSI not found, using PCI interrupt line {} pin {}",
line, pin
);
} }
assigned_irq assigned_irq
@ -260,15 +295,27 @@ pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) {
} else if did == 0x10fb { } else if did == 0x10fb {
// 82599ES 10-Gigabit SFI/SFP+ Network Connection // 82599ES 10-Gigabit SFI/SFP+ Network Connection
if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } {
let irq = unsafe { let irq = unsafe { tag.enable() };
tag.enable() PCI_DRIVERS.lock()
}; .insert(tag, ixgbe::ixgbe_init(name, irq, addr, len));
ixgbe::ixgbe_init(name, irq, addr, len);
} }
} }
} }
} }
pub fn detach_driver(bus: u32, dev: u32, func: u32) -> bool {
match PCI_DRIVERS.lock().remove(&PciTag::new(bus, dev, func)) {
Some(driver) => {
DRIVERS.write().retain(|dri| !Arc::ptr_eq(&driver, dri));
NET_DRIVERS.write().retain(|dri| !Arc::ptr_eq(&driver, dri));
true
}
None => {
false
}
}
}
pub fn init() { pub fn init() {
for bus in 0..256 { for bus in 0..256 {
for dev in 0..32 { for dev in 0..32 {
@ -313,3 +360,7 @@ pub fn find_device(vendor: u32, product: u32) -> Option<PciTag> {
} }
None None
} }
lazy_static! {
pub static ref PCI_DRIVERS: Arc<Mutex<BTreeMap<PciTag, Arc<Driver>>>> = Arc::new(Mutex::new(BTreeMap::new()));
}

@ -1,20 +1,20 @@
use alloc::{vec, vec::Vec};
use alloc::alloc::{GlobalAlloc, Layout}; use alloc::alloc::{GlobalAlloc, Layout};
use alloc::{vec, vec::Vec};
use core::mem::size_of; use core::mem::size_of;
use core::slice; use core::slice;
use core::sync::atomic::{fence, Ordering}; use core::sync::atomic::{fence, Ordering};
use bitflags::*; use bitflags::*;
use device_tree::Node;
use device_tree::util::SliceRead; use device_tree::util::SliceRead;
use device_tree::Node;
use log::*; use log::*;
use rcore_memory::PAGE_SIZE;
use rcore_memory::paging::PageTable; use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use volatile::{ReadOnly, Volatile, WriteOnly}; use volatile::{ReadOnly, Volatile, WriteOnly};
use crate::HEAP_ALLOCATOR;
use crate::memory::active_table;
use crate::arch::consts::{KERNEL_OFFSET, MEMORY_OFFSET}; use crate::arch::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::memory::active_table;
use crate::HEAP_ALLOCATOR;
use super::super::block::virtio_blk; use super::super::block::virtio_blk;
use super::super::gpu::virtio_gpu; use super::super::gpu::virtio_gpu;
@ -25,28 +25,28 @@ use super::super::net::virtio_net;
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct VirtIOHeader { pub struct VirtIOHeader {
magic: ReadOnly<u32>, // 0x000 magic: ReadOnly<u32>, // 0x000
version: ReadOnly<u32>, // 0x004 version: ReadOnly<u32>, // 0x004
device_id: ReadOnly<u32>, // 0x008 device_id: ReadOnly<u32>, // 0x008
vendor_id: ReadOnly<u32>, // 0x00c vendor_id: ReadOnly<u32>, // 0x00c
pub device_features: ReadOnly<u32>, // 0x010 pub device_features: ReadOnly<u32>, // 0x010
pub device_features_sel: WriteOnly<u32>, // 0x014 pub device_features_sel: WriteOnly<u32>, // 0x014
__r1: [ReadOnly<u32>; 2], __r1: [ReadOnly<u32>; 2],
pub driver_features: WriteOnly<u32>, // 0x020 pub driver_features: WriteOnly<u32>, // 0x020
pub driver_features_sel: WriteOnly<u32>, // 0x024 pub driver_features_sel: WriteOnly<u32>, // 0x024
pub guest_page_size: WriteOnly<u32>, // 0x028 pub guest_page_size: WriteOnly<u32>, // 0x028
__r2: ReadOnly<u32>, __r2: ReadOnly<u32>,
pub queue_sel: WriteOnly<u32>, // 0x030 pub queue_sel: WriteOnly<u32>, // 0x030
pub queue_num_max: ReadOnly<u32>, // 0x034 pub queue_num_max: ReadOnly<u32>, // 0x034
pub queue_num: WriteOnly<u32>, // 0x038 pub queue_num: WriteOnly<u32>, // 0x038
pub queue_align: WriteOnly<u32>, // 0x03c pub queue_align: WriteOnly<u32>, // 0x03c
pub queue_pfn: Volatile<u32>, // 0x040 pub queue_pfn: Volatile<u32>, // 0x040
queue_ready: Volatile<u32>, // new interface only queue_ready: Volatile<u32>, // new interface only
__r3: [ReadOnly<u32>; 2], __r3: [ReadOnly<u32>; 2],
pub queue_notify: WriteOnly<u32>, // 0x050 pub queue_notify: WriteOnly<u32>, // 0x050
__r4: [ReadOnly<u32>; 3], __r4: [ReadOnly<u32>; 3],
pub interrupt_status: ReadOnly<u32>, // 0x060 pub interrupt_status: ReadOnly<u32>, // 0x060
pub interrupt_ack: WriteOnly<u32>, // 0x064 pub interrupt_ack: WriteOnly<u32>, // 0x064
__r5: [ReadOnly<u32>; 2], __r5: [ReadOnly<u32>; 2],
pub status: Volatile<u32>, // 0x070 pub status: Volatile<u32>, // 0x070
__r6: [ReadOnly<u32>; 3], __r6: [ReadOnly<u32>; 3],
@ -59,7 +59,7 @@ pub struct VirtIOHeader {
queue_used_low: WriteOnly<u32>, queue_used_low: WriteOnly<u32>,
queue_used_high: WriteOnly<u32>, queue_used_high: WriteOnly<u32>,
__r9: [ReadOnly<u32>; 21], __r9: [ReadOnly<u32>; 21],
config_generation: ReadOnly<u32> config_generation: ReadOnly<u32>,
} }
#[repr(C)] #[repr(C)]
@ -68,9 +68,9 @@ pub struct VirtIOVirtqueue {
queue_address: usize, queue_address: usize,
queue_num: usize, queue_num: usize,
queue: usize, queue: usize,
desc: usize, // *mut VirtIOVirtqueueDesc, desc: usize, // *mut VirtIOVirtqueueDesc,
avail: usize, // *mut VirtIOVirtqueueAvailableRing, avail: usize, // *mut VirtIOVirtqueueAvailableRing,
used: usize, // *mut VirtIOVirtqueueUsedRing, used: usize, // *mut VirtIOVirtqueueUsedRing,
desc_state: Vec<usize>, desc_state: Vec<usize>,
num_used: usize, num_used: usize,
free_head: usize, free_head: usize,
@ -90,16 +90,19 @@ impl VirtIOVirtqueue {
let size = virtqueue_size(queue_num, align); let size = virtqueue_size(queue_num, align);
assert!(size % align == 0); assert!(size % align == 0);
// alloc continuous pages // alloc continuous pages
let address = unsafe { let address =
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(size, align).unwrap()) unsafe { HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(size, align).unwrap()) }
} as usize; as usize;
header.queue_num.write(queue_num as u32); header.queue_num.write(queue_num as u32);
header.queue_align.write(align as u32); header.queue_align.write(align as u32);
header.queue_pfn.write(((address - KERNEL_OFFSET + MEMORY_OFFSET) as u32) >> 12); header
.queue_pfn
.write(((address - KERNEL_OFFSET + MEMORY_OFFSET) as u32) >> 12);
// link desc together // link desc together
let desc = unsafe { slice::from_raw_parts_mut(address as *mut VirtIOVirtqueueDesc, queue_num) }; let desc =
unsafe { slice::from_raw_parts_mut(address as *mut VirtIOVirtqueueDesc, queue_num) };
for i in 0..(queue_num - 1) { for i in 0..(queue_num - 1) {
desc[i].next.write((i + 1) as u16); desc[i].next.write((i + 1) as u16);
} }
@ -133,25 +136,35 @@ impl VirtIOVirtqueue {
return false; return false;
} }
let desc = unsafe { slice::from_raw_parts_mut(self.desc as *mut VirtIOVirtqueueDesc, self.queue_num) }; let desc = unsafe {
slice::from_raw_parts_mut(self.desc as *mut VirtIOVirtqueueDesc, self.queue_num)
};
let head = self.free_head; let head = self.free_head;
let mut prev = 0; let mut prev = 0;
let mut cur = self.free_head; let mut cur = self.free_head;
for i in 0..output.len() { for i in 0..output.len() {
desc[cur].flags.write(VirtIOVirtqueueFlag::NEXT.bits()); desc[cur].flags.write(VirtIOVirtqueueFlag::NEXT.bits());
desc[cur].addr.write(output[i].as_ptr() as u64 - KERNEL_OFFSET as u64 + MEMORY_OFFSET as u64); desc[cur]
.addr
.write(output[i].as_ptr() as u64 - KERNEL_OFFSET as u64 + MEMORY_OFFSET as u64);
desc[cur].len.write(output[i].len() as u32); desc[cur].len.write(output[i].len() as u32);
prev = cur; prev = cur;
cur = desc[cur].next.read() as usize; cur = desc[cur].next.read() as usize;
} }
for i in 0..input.len() { for i in 0..input.len() {
desc[cur].flags.write((VirtIOVirtqueueFlag::NEXT | VirtIOVirtqueueFlag::WRITE).bits()); desc[cur]
desc[cur].addr.write(input[i].as_ptr() as u64 - KERNEL_OFFSET as u64 + MEMORY_OFFSET as u64); .flags
.write((VirtIOVirtqueueFlag::NEXT | VirtIOVirtqueueFlag::WRITE).bits());
desc[cur]
.addr
.write(input[i].as_ptr() as u64 - KERNEL_OFFSET as u64 + MEMORY_OFFSET as u64);
desc[cur].len.write(input[i].len() as u32); desc[cur].len.write(input[i].len() as u32);
prev = cur; prev = cur;
cur = desc[cur].next.read() as usize; cur = desc[cur].next.read() as usize;
} }
desc[prev].flags.write(desc[prev].flags.read() & !(VirtIOVirtqueueFlag::NEXT.bits())); desc[prev]
.flags
.write(desc[prev].flags.read() & !(VirtIOVirtqueueFlag::NEXT.bits()));
self.num_used += input.len() + output.len(); self.num_used += input.len() + output.len();
self.free_head = cur; self.free_head = cur;
@ -189,7 +202,7 @@ impl VirtIOVirtqueue {
pub fn get(&mut self) -> Option<(Vec<&'static [u8]>, Vec<&'static [u8]>, usize, usize)> { pub fn get(&mut self) -> Option<(Vec<&'static [u8]>, Vec<&'static [u8]>, usize, usize)> {
let used = unsafe { &mut *(self.used as *mut VirtIOVirtqueueUsedRing) }; let used = unsafe { &mut *(self.used as *mut VirtIOVirtqueueUsedRing) };
if self.last_used_idx == used.idx.read() { if self.last_used_idx == used.idx.read() {
return None return None;
} }
// read barrier // read barrier
fence(Ordering::SeqCst); fence(Ordering::SeqCst);
@ -202,13 +215,16 @@ impl VirtIOVirtqueue {
self.desc_state[last_used_slot] = 0; self.desc_state[last_used_slot] = 0;
let mut cur = index; let mut cur = index;
let desc = unsafe { slice::from_raw_parts_mut(self.desc as *mut VirtIOVirtqueueDesc, self.queue_num) }; let desc = unsafe {
slice::from_raw_parts_mut(self.desc as *mut VirtIOVirtqueueDesc, self.queue_num)
};
let mut input = Vec::new(); let mut input = Vec::new();
let mut output = Vec::new(); let mut output = Vec::new();
loop { loop {
let flags = VirtIOVirtqueueFlag::from_bits_truncate(desc[cur].flags.read()); let flags = VirtIOVirtqueueFlag::from_bits_truncate(desc[cur].flags.read());
let addr = desc[cur].addr.read() as u64 - MEMORY_OFFSET as u64 + KERNEL_OFFSET as u64; let addr = desc[cur].addr.read() as u64 - MEMORY_OFFSET as u64 + KERNEL_OFFSET as u64;
let buffer = unsafe { slice::from_raw_parts(addr as *const u8, desc[cur].len.read() as usize) }; let buffer =
unsafe { slice::from_raw_parts(addr as *const u8, desc[cur].len.read() as usize) };
if flags.contains(VirtIOVirtqueueFlag::WRITE) { if flags.contains(VirtIOVirtqueueFlag::WRITE) {
input.push(buffer); input.push(buffer);
} else { } else {
@ -221,7 +237,7 @@ impl VirtIOVirtqueue {
} else { } else {
desc[cur].next.write(self.free_head as u16); desc[cur].next.write(self.free_head as u16);
self.num_used -= 1; self.num_used -= 1;
break break;
} }
} }
@ -263,9 +279,11 @@ impl VirtIOHeader {
pub fn write_driver_features(&mut self, driver_features: u64) { pub fn write_driver_features(&mut self, driver_features: u64) {
self.driver_features_sel.write(0); // driver features [0, 32) self.driver_features_sel.write(0); // driver features [0, 32)
self.driver_features.write((driver_features & 0xFFFFFFFF) as u32); self.driver_features
.write((driver_features & 0xFFFFFFFF) as u32);
self.driver_features_sel.write(1); // driver features [32, 64) self.driver_features_sel.write(1); // driver features [32, 64)
self.driver_features.write(((driver_features & 0xFFFFFFFF00000000) >> 32) as u32); self.driver_features
.write(((driver_features & 0xFFFFFFFF00000000) >> 32) as u32);
} }
} }
@ -286,7 +304,7 @@ pub struct VirtIOVirtqueueDesc {
pub addr: Volatile<u64>, pub addr: Volatile<u64>,
pub len: Volatile<u32>, pub len: Volatile<u32>,
pub flags: Volatile<u16>, pub flags: Volatile<u16>,
pub next: Volatile<u16> pub next: Volatile<u16>,
} }
bitflags! { bitflags! {
@ -303,14 +321,14 @@ pub struct VirtIOVirtqueueAvailableRing {
pub flags: Volatile<u16>, pub flags: Volatile<u16>,
pub idx: Volatile<u16>, pub idx: Volatile<u16>,
pub ring: [Volatile<u16>; 32], // actual size: queue_size pub ring: [Volatile<u16>; 32], // actual size: queue_size
used_event: Volatile<u16> // unused used_event: Volatile<u16>, // unused
} }
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct VirtIOVirtqueueUsedElem { pub struct VirtIOVirtqueueUsedElem {
id: Volatile<u32>, id: Volatile<u32>,
len: Volatile<u32> len: Volatile<u32>,
} }
#[repr(C)] #[repr(C)]
@ -319,17 +337,19 @@ pub struct VirtIOVirtqueueUsedRing {
pub flags: Volatile<u16>, pub flags: Volatile<u16>,
pub idx: Volatile<u16>, pub idx: Volatile<u16>,
pub ring: [VirtIOVirtqueueUsedElem; 32], // actual size: queue_size pub ring: [VirtIOVirtqueueUsedElem; 32], // actual size: queue_size
avail_event: Volatile<u16> // unused avail_event: Volatile<u16>, // unused
} }
// virtio 2.4.2 Legacy Interfaces: A Note on Virtqueue Layout // virtio 2.4.2 Legacy Interfaces: A Note on Virtqueue Layout
pub fn virtqueue_size(num: usize, align: usize) -> usize { pub fn virtqueue_size(num: usize, align: usize) -> usize {
(((size_of::<VirtIOVirtqueueDesc>() * num + size_of::<u16>() * (3 + num)) + align) & !(align-1)) + (((size_of::<VirtIOVirtqueueDesc>() * num + size_of::<u16>() * (3 + num)) + align)
(((size_of::<u16>() * 3 + size_of::<VirtIOVirtqueueUsedElem>() * num) + align) & !(align-1)) & !(align - 1))
+ (((size_of::<u16>() * 3 + size_of::<VirtIOVirtqueueUsedElem>() * num) + align)
& !(align - 1))
} }
pub fn virtqueue_used_elem_offset(num: usize, align: usize) -> usize { pub fn virtqueue_used_elem_offset(num: usize, align: usize) -> usize {
((size_of::<VirtIOVirtqueueDesc>() * num + size_of::<u16>() * (3 + num)) + align) & !(align-1) ((size_of::<VirtIOVirtqueueDesc>() * num + size_of::<u16>() * (3 + num)) + align) & !(align - 1)
} }
pub fn virtio_probe(node: &Node) { pub fn virtio_probe(node: &Node) {
@ -344,19 +364,27 @@ pub fn virtio_probe(node: &Node) {
let version = header.version.read(); let version = header.version.read();
let device_id = header.device_id.read(); let device_id = header.device_id.read();
// only support legacy device // only support legacy device
if magic == 0x74726976 && version == 1 && device_id != 0 { // "virt" magic if magic == 0x74726976 && version == 1 && device_id != 0 {
info!("Detected virtio device with vendor id {:#X}", header.vendor_id.read()); // "virt" magic
info!(
"Detected virtio device with vendor id {:#X}",
header.vendor_id.read()
);
info!("Device tree node {:?}", node); info!("Device tree node {:?}", node);
// virtio 3.1.1 Device Initialization // virtio 3.1.1 Device Initialization
header.status.write(0); header.status.write(0);
header.status.write(VirtIODeviceStatus::ACKNOWLEDGE.bits()); header.status.write(VirtIODeviceStatus::ACKNOWLEDGE.bits());
if device_id == 1 { // net device if device_id == 1 {
// net device
virtio_net::virtio_net_init(node); virtio_net::virtio_net_init(node);
} else if device_id == 2 { // blk device } else if device_id == 2 {
// blk device
virtio_blk::virtio_blk_init(node); virtio_blk::virtio_blk_init(node);
} else if device_id == 16 { // gpu device } else if device_id == 16 {
// gpu device
virtio_gpu::virtio_gpu_init(node); virtio_gpu::virtio_gpu_init(node);
} else if device_id == 18 { // input device } else if device_id == 18 {
// input device
virtio_input::virtio_input_init(node); virtio_input::virtio_input_init(node);
} else { } else {
println!("Unrecognized virtio device {}", device_id); println!("Unrecognized virtio device {}", device_id);

@ -38,27 +38,35 @@ pub trait Driver : Send + Sync {
// return the correspondent device type, see DeviceType // return the correspondent device type, see DeviceType
fn device_type(&self) -> DeviceType; fn device_type(&self) -> DeviceType;
}
pub trait NetDriver : Driver { // Rust trait is still too restricted...
// network related drivers should implement these
// get mac address for this device // get mac address for this device
fn get_mac(&self) -> EthernetAddress; fn get_mac(&self) -> EthernetAddress {
unimplemented!("not a net driver")
}
// get interface name for this device // get interface name for this device
fn get_ifname(&self) -> String; fn get_ifname(&self) -> String {
unimplemented!("not a net driver")
}
// get ipv4 address // get ipv4 address
fn ipv4_address(&self) -> Option<Ipv4Address>; fn ipv4_address(&self) -> Option<Ipv4Address> {
unimplemented!("not a net driver")
}
// manually trigger a poll, use it after sending packets // manually trigger a poll, use it after sending packets
fn poll(&self); fn poll(&self) {
unimplemented!("not a net driver")
}
} }
lazy_static! { lazy_static! {
// NOTE: RwLock only write when initializing drivers // NOTE: RwLock only write when initializing drivers
pub static ref DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new()); pub static ref DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
pub static ref NET_DRIVERS: RwLock<Vec<Arc<NetDriver>>> = RwLock::new(Vec::new()); pub static ref NET_DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
pub static ref BLK_DRIVERS: RwLock<Vec<Arc<VirtIOBlkDriver>>> = RwLock::new(Vec::new()); pub static ref BLK_DRIVERS: RwLock<Vec<Arc<VirtIOBlkDriver>>> = RwLock::new(Vec::new());
} }

@ -1,4 +1,5 @@
//! Intel PRO/1000 Network Adapter i.e. e1000 network driver //! Intel PRO/1000 Network Adapter i.e. e1000 network driver
//! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
use alloc::alloc::{GlobalAlloc, Layout}; use alloc::alloc::{GlobalAlloc, Layout};
use alloc::format; use alloc::format;
@ -28,7 +29,7 @@ use crate::sync::SpinNoIrqLock as Mutex;
use crate::sync::{MutexGuard, SpinNoIrq}; use crate::sync::{MutexGuard, SpinNoIrq};
use crate::HEAP_ALLOCATOR; use crate::HEAP_ALLOCATOR;
use super::super::{DeviceType, Driver, NetDriver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
// At the beginning, all transmit descriptors have there status non-zero, // At the beginning, all transmit descriptors have there status non-zero,
// so we need to track whether we are using the descriptor for the first time. // so we need to track whether we are using the descriptor for the first time.
@ -121,9 +122,7 @@ impl Driver for E1000Interface {
fn device_type(&self) -> DeviceType { fn device_type(&self) -> DeviceType {
DeviceType::Net DeviceType::Net
} }
}
impl NetDriver for E1000Interface {
fn get_mac(&self) -> EthernetAddress { fn get_mac(&self) -> EthernetAddress {
self.iface.lock().ethernet_addr() self.iface.lock().ethernet_addr()
} }

@ -1,4 +1,5 @@
//! Intel 10Gb Network Adapter 82599 i.e. ixgbe network driver //! Intel 10Gb Network Adapter 82599 i.e. ixgbe network driver
//! Datasheet: https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82599-10-gbe-controller-datasheet.pdf
use alloc::alloc::{GlobalAlloc, Layout}; use alloc::alloc::{GlobalAlloc, Layout};
use alloc::prelude::*; use alloc::prelude::*;
@ -27,7 +28,7 @@ use crate::sync::SpinNoIrqLock as Mutex;
use crate::sync::{MutexGuard, SpinNoIrq}; use crate::sync::{MutexGuard, SpinNoIrq};
use crate::HEAP_ALLOCATOR; use crate::HEAP_ALLOCATOR;
use super::super::{DeviceType, Driver, NetDriver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
// At the beginning, all transmit descriptors have there status non-zero, // At the beginning, all transmit descriptors have there status non-zero,
// so we need to track whether we are using the descriptor for the first time. // so we need to track whether we are using the descriptor for the first time.
@ -215,9 +216,7 @@ impl Driver for IXGBEInterface {
fn device_type(&self) -> DeviceType { fn device_type(&self) -> DeviceType {
DeviceType::Net DeviceType::Net
} }
}
impl NetDriver for IXGBEInterface {
fn get_mac(&self) -> EthernetAddress { fn get_mac(&self) -> EthernetAddress {
self.iface.lock().ethernet_addr() self.iface.lock().ethernet_addr()
} }
@ -360,7 +359,7 @@ impl<'a> phy::Device<'a> for IXGBEDriver {
fn capabilities(&self) -> DeviceCapabilities { fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default(); let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = IXGBE_MTU; // max MTU caps.max_transmission_unit = IXGBE_MTU; // max MTU
caps.max_burst_size = Some(64); caps.max_burst_size = Some(256);
// IP Rx checksum is offloaded with RXCSUM // IP Rx checksum is offloaded with RXCSUM
caps.checksum.ipv4 = Checksum::Tx; caps.checksum.ipv4 = Checksum::Tx;
caps caps
@ -442,7 +441,7 @@ bitflags! {
} }
} }
pub fn ixgbe_init(name: String, irq: Option<u32>, header: usize, size: usize) { pub fn ixgbe_init(name: String, irq: Option<u32>, header: usize, size: usize) -> Arc<IXGBEInterface> {
assert_eq!(size_of::<IXGBESendDesc>(), 16); assert_eq!(size_of::<IXGBESendDesc>(), 16);
assert_eq!(size_of::<IXGBERecvDesc>(), 16); assert_eq!(size_of::<IXGBERecvDesc>(), 16);
@ -796,5 +795,21 @@ pub fn ixgbe_init(name: String, irq: Option<u32>, header: usize, size: usize) {
let driver = Arc::new(ixgbe_iface); let driver = Arc::new(ixgbe_iface);
DRIVERS.write().push(driver.clone()); DRIVERS.write().push(driver.clone());
NET_DRIVERS.write().push(driver); NET_DRIVERS.write().push(driver.clone());
driver
}
impl Drop for IXGBE {
fn drop(&mut self) {
unsafe {
HEAP_ALLOCATOR.dealloc(self.send_page as *mut u8, Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap());
HEAP_ALLOCATOR.dealloc(self.recv_page as *mut u8, Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap());
for send_buffer in self.send_buffers.iter() {
HEAP_ALLOCATOR.dealloc(*send_buffer as *mut u8, Layout::from_size_align(IXGBE_BUFFER_SIZE, PAGE_SIZE).unwrap());
}
for recv_buffer in self.recv_buffers.iter() {
HEAP_ALLOCATOR.dealloc(*recv_buffer as *mut u8, Layout::from_size_align(IXGBE_BUFFER_SIZE, PAGE_SIZE).unwrap());
}
}
}
} }

@ -24,7 +24,7 @@ use crate::sync::{MutexGuard, SpinNoIrq};
use crate::HEAP_ALLOCATOR; use crate::HEAP_ALLOCATOR;
use super::super::bus::virtio_mmio::*; use super::super::bus::virtio_mmio::*;
use super::super::{DeviceType, Driver, NetDriver, DRIVERS, NET_DRIVERS}; use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS};
pub struct VirtIONet { pub struct VirtIONet {
interrupt_parent: u32, interrupt_parent: u32,
@ -64,19 +64,7 @@ impl Driver for VirtIONetDriver {
fn device_type(&self) -> DeviceType { fn device_type(&self) -> DeviceType {
DeviceType::Net DeviceType::Net
} }
}
impl VirtIONet {
fn transmit_available(&self) -> bool {
self.queues[VIRTIO_QUEUE_TRANSMIT].can_add(1, 0)
}
fn receive_available(&self) -> bool {
self.queues[VIRTIO_QUEUE_RECEIVE].can_get()
}
}
impl NetDriver for VirtIONetDriver {
fn get_mac(&self) -> EthernetAddress { fn get_mac(&self) -> EthernetAddress {
self.0.lock().mac self.0.lock().mac
} }
@ -94,6 +82,16 @@ impl NetDriver for VirtIONetDriver {
} }
} }
impl VirtIONet {
fn transmit_available(&self) -> bool {
self.queues[VIRTIO_QUEUE_TRANSMIT].can_add(1, 0)
}
fn receive_available(&self) -> bool {
self.queues[VIRTIO_QUEUE_RECEIVE].can_get()
}
}
pub struct VirtIONetRxToken(VirtIONetDriver); pub struct VirtIONetRxToken(VirtIONetDriver);
pub struct VirtIONetTxToken(VirtIONetDriver); pub struct VirtIONetTxToken(VirtIONetDriver);

@ -1,4 +1,4 @@
use crate::drivers::NetDriver; use crate::drivers::Driver;
use crate::drivers::NET_DRIVERS; use crate::drivers::NET_DRIVERS;
use crate::net::SOCKETS; use crate::net::SOCKETS;
use crate::thread; use crate::thread;

@ -11,7 +11,6 @@ use crate::arch::interrupt::{Context, TrapFrame};
use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet};
use crate::fs::{FileHandle, OpenOptions}; use crate::fs::{FileHandle, OpenOptions};
use crate::sync::Condvar; use crate::sync::Condvar;
use crate::drivers::NET_DRIVERS;
use crate::net::{SocketWrapper, SOCKETS}; use crate::net::{SocketWrapper, SOCKETS};
use super::abi::{self, ProcInitInfo}; use super::abi::{self, ProcInitInfo};

@ -3,6 +3,8 @@ use rcore_memory::memory_set::handler::Linear;
use rcore_memory::memory_set::MemoryAttr; use rcore_memory::memory_set::MemoryAttr;
use super::*; use super::*;
/// Allocate this PCI device to user space
/// The kernel driver using the PCI device will be unloaded
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult {
use crate::drivers::bus::pci; use crate::drivers::bus::pci;

@ -1,7 +1,7 @@
//! Syscalls for networking //! Syscalls for networking
use super::*; use super::*;
use crate::drivers::{NET_DRIVERS, SOCKET_ACTIVITY}; use crate::drivers::SOCKET_ACTIVITY;
use crate::net::{ use crate::net::{
get_ephemeral_port, poll_ifaces, SocketType, SocketWrapper, TcpSocketState, UdpSocketState, get_ephemeral_port, poll_ifaces, SocketType, SocketWrapper, TcpSocketState, UdpSocketState,
SOCKETS, SOCKETS,

Loading…
Cancel
Save