From a0d9a8b2de95bb51e93ced88b5243dd004f7af9f Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Wed, 20 Mar 2019 13:00:19 +0800 Subject: [PATCH] Detach driver from the device in sys_map_pci_driver --- kernel/src/drivers/block/virtio_blk.rs | 5 ++++ kernel/src/drivers/bus/pci.rs | 24 +++++++-------- kernel/src/drivers/gpu/virtio_gpu.rs | 5 ++++ kernel/src/drivers/input/virtio_input.rs | 4 +++ kernel/src/drivers/mod.rs | 6 +++- kernel/src/drivers/net/e1000.rs | 5 +++- kernel/src/drivers/net/ixgbe.rs | 38 ++++++++++++++++++++---- kernel/src/drivers/net/virtio_net.rs | 4 +++ kernel/src/syscall/custom.rs | 7 ++++- 9 files changed, 77 insertions(+), 21 deletions(-) diff --git a/kernel/src/drivers/block/virtio_blk.rs b/kernel/src/drivers/block/virtio_blk.rs index eef098a2..fcdd1cdf 100644 --- a/kernel/src/drivers/block/virtio_blk.rs +++ b/kernel/src/drivers/block/virtio_blk.rs @@ -1,4 +1,5 @@ use alloc::sync::Arc; +use alloc::string::String; use core::cmp::min; use core::mem::{size_of}; use core::slice; @@ -107,6 +108,10 @@ impl Driver for VirtIOBlkDriver { fn device_type(&self) -> DeviceType { DeviceType::Block } + + fn get_id(&self) -> String { + format!("virtio_block") + } } impl BlockDevice for VirtIOBlkDriver { diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs index 2e3cfeac..ac115194 100644 --- a/kernel/src/drivers/bus/pci.rs +++ b/kernel/src/drivers/bus/pci.rs @@ -3,8 +3,8 @@ use crate::drivers::{Driver, DRIVERS, NET_DRIVERS}; use alloc::collections::BTreeMap; use alloc::string::String; use alloc::sync::Arc; -use spin::Mutex; use core::cmp::Ordering; +use spin::Mutex; use x86_64::instructions::port::Port; const PCI_VENDOR: u32 = 0x00; @@ -44,7 +44,6 @@ const PCI_BASE_ADDRESS_MEM_MASK: u32 = 0xfffffff0; #[derive(Copy, Clone)] pub struct PciTag(u32); - impl Ord for PciTag { fn cmp(&self, other: &PciTag) -> Ordering { self.0.cmp(&other.0) @@ -57,8 +56,7 @@ impl PartialOrd for PciTag { } } -impl Eq for PciTag { -} +impl Eq for PciTag {} impl PartialEq for PciTag { fn eq(&self, other: &PciTag) -> bool { @@ -296,23 +294,22 @@ pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) { // 82599ES 10-Gigabit SFI/SFP+ Network Connection if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } { let irq = unsafe { tag.enable() }; - PCI_DRIVERS.lock() + PCI_DRIVERS + .lock() .insert(tag, 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)) { +pub fn detach_driver(tag: &PciTag) -> bool { + match PCI_DRIVERS.lock().remove(tag) { Some(driver) => { - DRIVERS.write().retain(|dri| !Arc::ptr_eq(&driver, dri)); - NET_DRIVERS.write().retain(|dri| !Arc::ptr_eq(&driver, dri)); + DRIVERS.write().retain(|dri| dri.get_id() != driver.get_id()); + NET_DRIVERS.write().retain(|dri| dri.get_id() != driver.get_id()); true } - None => { - false - } + None => false, } } @@ -362,5 +359,6 @@ pub fn find_device(vendor: u32, product: u32) -> Option { } lazy_static! { - pub static ref PCI_DRIVERS: Arc>>> = Arc::new(Mutex::new(BTreeMap::new())); + pub static ref PCI_DRIVERS: Arc>>> = + Arc::new(Mutex::new(BTreeMap::new())); } diff --git a/kernel/src/drivers/gpu/virtio_gpu.rs b/kernel/src/drivers/gpu/virtio_gpu.rs index 7eb0f19a..4ad7d443 100644 --- a/kernel/src/drivers/gpu/virtio_gpu.rs +++ b/kernel/src/drivers/gpu/virtio_gpu.rs @@ -1,4 +1,5 @@ use alloc::alloc::{GlobalAlloc, Layout}; +use alloc::string::String; use alloc::sync::Arc; use core::slice; @@ -214,6 +215,10 @@ impl Driver for VirtIOGpuDriver { fn device_type(&self) -> DeviceType { DeviceType::Gpu } + + fn get_id(&self) -> String { + format!("virtio_gpu") + } } fn request(driver: &mut VirtIOGpu) { diff --git a/kernel/src/drivers/input/virtio_input.rs b/kernel/src/drivers/input/virtio_input.rs index de1954de..3c76348a 100644 --- a/kernel/src/drivers/input/virtio_input.rs +++ b/kernel/src/drivers/input/virtio_input.rs @@ -172,6 +172,10 @@ impl Driver for VirtIOInputDriver { fn device_type(&self) -> DeviceType { DeviceType::Input } + + fn get_id(&self) -> String { + String::from("virtio_input") + } } pub fn virtio_input_init(node: &Node) { diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index 2320951f..ae9e532c 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -6,7 +6,7 @@ use smoltcp::wire::{EthernetAddress, Ipv4Address}; use smoltcp::socket::SocketSet; use spin::RwLock; -use crate::sync::{Condvar, MutexGuard, SpinNoIrq}; +use crate::sync::Condvar; use self::block::virtio_blk::VirtIOBlkDriver; mod device_tree; @@ -39,6 +39,10 @@ pub trait Driver : Send + Sync { // return the correspondent device type, see DeviceType fn device_type(&self) -> DeviceType; + // get unique identifier for this device + // should be different for each instance + fn get_id(&self) -> String; + // Rust trait is still too restricted... // network related drivers should implement these // get mac address for this device diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index b97b9afe..3e76f568 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -16,7 +16,6 @@ use rcore_memory::paging::PageTable; use rcore_memory::PAGE_SIZE; use smoltcp::iface::*; use smoltcp::phy::{self, DeviceCapabilities}; -use smoltcp::socket::*; use smoltcp::time::Instant; use smoltcp::wire::EthernetAddress; use smoltcp::wire::*; @@ -123,6 +122,10 @@ impl Driver for E1000Interface { DeviceType::Net } + fn get_id(&self) -> String { + format!("e1000") + } + fn get_mac(&self) -> EthernetAddress { self.iface.lock().ethernet_addr() } diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 55e5869f..c1c38fe3 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -145,8 +145,9 @@ const IXGBE_EEC: usize = 0x10010 / 4; pub struct IXGBEInterface { iface: Mutex>, driver: IXGBEDriver, - name: String, + ifname: String, irq: Option, + id: String, } impl Driver for IXGBEInterface { @@ -180,10 +181,10 @@ impl Driver for IXGBEInterface { let status = ixgbe[IXGBE_LINKS].read(); if status & (1 << 7) != 0 { // link up - info!("ixgbe: interface {} link up", &self.name); + info!("ixgbe: interface {} link up", &self.ifname); } else { // link down - info!("ixgbe: interface {} link down", &self.name); + info!("ixgbe: interface {} link down", &self.ifname); } } if icr & (1 << 0) != 0 { @@ -217,12 +218,16 @@ impl Driver for IXGBEInterface { DeviceType::Net } + fn get_id(&self) -> String { + self.ifname.clone() + } + fn get_mac(&self) -> EthernetAddress { self.iface.lock().ethernet_addr() } fn get_ifname(&self) -> String { - self.name.clone() + self.ifname.clone() } fn ipv4_address(&self) -> Option { @@ -789,7 +794,8 @@ pub fn ixgbe_init(name: String, irq: Option, header: usize, size: usize) -> let ixgbe_iface = IXGBEInterface { iface: Mutex::new(iface), driver: net_driver.clone(), - name, + ifname: name.clone(), + id: name, irq, }; @@ -801,6 +807,28 @@ pub fn ixgbe_init(name: String, irq: Option, header: usize, size: usize) -> impl Drop for IXGBE { fn drop(&mut self) { + debug!("ixgbe: interface detaching"); + + if let None = active_table().get_entry(self.header) { + let mut current_addr = self.header; + while current_addr < self.header + self.size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + } + + let ixgbe = unsafe { + slice::from_raw_parts_mut(self.header as *mut Volatile, self.size / 4) + }; + // 1. Disable interrupts. + ixgbe[IXGBE_EIMC].write(!0); + ixgbe[IXGBE_EIMC1].write(!0); + ixgbe[IXGBE_EIMC2].write(!0); + + // 2. Issue a global reset. + // reset: LRST | RST + ixgbe[IXGBE_CTRL].write(1 << 3 | 1 << 26); + while ixgbe[IXGBE_CTRL].read() & (1 << 3 | 1 << 26) != 0 {} 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()); diff --git a/kernel/src/drivers/net/virtio_net.rs b/kernel/src/drivers/net/virtio_net.rs index 453d4e6c..7b151b93 100644 --- a/kernel/src/drivers/net/virtio_net.rs +++ b/kernel/src/drivers/net/virtio_net.rs @@ -65,6 +65,10 @@ impl Driver for VirtIONetDriver { DeviceType::Net } + fn get_id(&self) -> String { + format!("virtio_net") + } + fn get_mac(&self) -> EthernetAddress { self.0.lock().mac } diff --git a/kernel/src/syscall/custom.rs b/kernel/src/syscall/custom.rs index ece5c376..d5b4a859 100644 --- a/kernel/src/syscall/custom.rs +++ b/kernel/src/syscall/custom.rs @@ -9,11 +9,16 @@ use super::*; pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { use crate::drivers::bus::pci; info!( - "map_pci_device: vendor: {}, product: {}", + "map_pci_device: vendor: {:x}, product: {:x}", vendor, product ); + let tag = pci::find_device(vendor as u32, product as u32) .ok_or(SysError::ENOENT)?; + if pci::detach_driver(&tag) { + info!("Kernel driver detached"); + } + // Get BAR0 memory let (base, len) = unsafe { tag.get_bar_mem(0) } .ok_or(SysError::ENOENT)?;