From 3751c915fe5b077d399e5220b6fc002c7127da52 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:43:41 +0100 Subject: [PATCH] Unify the scheme handling of all network drivers This deduplicates a fair bit of non-trivial logic and makes it easier to keep all network drivers in sync when the interface changes. --- Cargo.lock | 12 ++ Cargo.toml | 1 + driver-network/Cargo.toml | 8 ++ driver-network/src/lib.rs | 255 ++++++++++++++++++++++++++++++++++++++ e1000d/Cargo.toml | 1 + e1000d/src/device.rs | 131 +++----------------- e1000d/src/main.rs | 203 ++++++++---------------------- ixgbed/Cargo.toml | 1 + ixgbed/src/device.rs | 77 ++---------- ixgbed/src/main.rs | 221 +++++++++------------------------ rtl8139d/Cargo.toml | 1 + rtl8139d/src/device.rs | 75 ++--------- rtl8139d/src/main.rs | 207 ++++++++----------------------- rtl8168d/Cargo.toml | 1 + rtl8168d/src/device.rs | 78 ++---------- rtl8168d/src/main.rs | 200 +++++++----------------------- 16 files changed, 539 insertions(+), 933 deletions(-) create mode 100644 driver-network/Cargo.toml create mode 100644 driver-network/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 59273691f6..a5accc366e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,12 +372,21 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "driver-network" +version = "0.1.0" +dependencies = [ + "redox_event 0.1.0", + "redox_syscall 0.4.1", +] + [[package]] name = "e1000d" version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "netutils", "pcid", "redox-daemon", @@ -664,6 +673,7 @@ version = "1.0.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "netutils", "pcid", "redox-daemon", @@ -1218,6 +1228,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "log", "netutils", "pcid", @@ -1233,6 +1244,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "log", "netutils", "pcid", diff --git a/Cargo.toml b/Cargo.toml index bd8c75cf68..275cb4b681 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "bgad", "block-io-wrapper", "common", + "driver-network", "e1000d", "fbcond", "ided", diff --git a/driver-network/Cargo.toml b/driver-network/Cargo.toml new file mode 100644 index 0000000000..47be9d3175 --- /dev/null +++ b/driver-network/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "driver-network" +version = "0.1.0" +edition = "2021" + +[dependencies] +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_syscall = "0.4" diff --git a/driver-network/src/lib.rs b/driver-network/src/lib.rs new file mode 100644 index 0000000000..23fcc38135 --- /dev/null +++ b/driver-network/src/lib.rs @@ -0,0 +1,255 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::io::{ErrorKind, Read, Write}; +use std::os::fd::{AsRawFd, FromRawFd, RawFd}; +use std::{cmp, io}; + +use syscall::{ + Error, EventFlags, Packet, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EWOULDBLOCK, + MODE_FILE, O_NONBLOCK, +}; + +pub trait NetworkAdapter { + /// The [MAC address](https://en.wikipedia.org/wiki/MAC_address) of this + /// network adapter. + fn mac_address(&mut self) -> [u8; 6]; + + /// The amount of network packets that can be read without blocking. + fn available_for_read(&mut self) -> usize; + + /// Attempt to read a network packet without blocking. + /// + /// Returns `Ok(None)` when there is no pending network packet. + fn read_packet(&mut self, buf: &mut [u8]) -> Result>; + + /// Write a single network packet. + // FIXME support back pressure on writes by returning EWOULDBLOCK or not + // returning from the write syscall until there is room. + fn write_packet(&mut self, buf: &[u8]) -> Result; +} + +pub struct NetworkScheme { + adapter: T, + scheme: File, + next_id: usize, + handles: BTreeMap, + todo_packets: Vec, +} + +#[derive(Copy, Clone)] +enum Handle { + Data { flags: usize }, + Mac { offset: usize }, +} + +impl NetworkScheme { + pub fn new(adapter: T, scheme_name: &str) -> Self { + let scheme_fd = syscall::open( + format!(":{scheme_name}"), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("e1000d: failed to create network scheme"); + let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) }; + + NetworkScheme { + adapter, + scheme, + next_id: 0, + handles: BTreeMap::new(), + todo_packets: vec![], + } + } + + pub fn event_handle(&self) -> RawFd { + self.scheme.as_raw_fd() + } + + pub fn adapter(&self) -> &T { + &self.adapter + } + + pub fn adapter_mut(&mut self) -> &mut T { + &mut self.adapter + } + + /// Process pending and new packets. + /// + /// This needs to be called each time there is a new event on the scheme + /// file and each time a new network packet has been received by the + /// driver. + // FIXME maybe split into one method for events on the scheme fd and one + // to call when an irq is received to indicate that blocked packets can + // be processed. + pub fn tick(&mut self) -> io::Result<()> { + // Handle any blocked packets + let mut i = 0; + while i < self.todo_packets.len() { + let mut packet = self.todo_packets[i].clone(); + if let Some(a) = self.handle(&packet) { + self.todo_packets.remove(i); + packet.a = a; + self.scheme.write(&packet)?; + } else { + i += 1; + } + } + + // Handle new scheme packets + loop { + let mut packet = Packet::default(); + match self.scheme.read(&mut packet) { + Ok(0) => { + return Err(io::Error::new( + ErrorKind::BrokenPipe, + "scheme has been closed by the kernel", + )); + } + Ok(_) => {} + Err(err) if err.kind() == ErrorKind::WouldBlock => break, + Err(err) => { + return Err(err); + } + } + + if let Some(a) = self.handle(&packet) { + packet.a = a; + self.scheme.write(&packet)?; + } else { + self.todo_packets.push(packet); + } + } + + // Notify readers about incoming events + let available_for_read = self.adapter.available_for_read(); + if available_for_read > 0 { + for &handle_id in self.handles.keys() { + self.scheme.write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: handle_id, + c: syscall::flag::EVENT_READ.bits(), + d: available_for_read, + })?; + } + return Ok(()); + } + + Ok(()) + } +} + +impl SchemeBlockMut for NetworkScheme { + fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { + if uid != 0 { + return Err(Error::new(EACCES)); + } + + let handle = match path { + "" => Handle::Data { flags }, + "mac" => Handle::Mac { offset: 0 }, + _ => return Err(Error::new(EINVAL)), + }; + + self.next_id += 1; + self.handles.insert(self.next_id, handle); + Ok(Some(self.next_id)) + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if !buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let handle = *self.handles.get(&id).ok_or(Error::new(EBADF))?; + self.next_id += 1; + self.handles.insert(self.next_id, handle); + Ok(Some(self.next_id)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let flags = match *handle { + Handle::Data { flags } => flags, + Handle::Mac { ref mut offset } => { + let data = &self.adapter.mac_address()[*offset..]; + let i = cmp::min(buf.len(), data.len()); + buf[..i].copy_from_slice(&data[..i]); + *offset += i; + return Ok(Some(i)); + } + }; + + match self.adapter.read_packet(buf)? { + Some(count) => Ok(Some(count)), + None => { + if flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EWOULDBLOCK)) + } else { + Ok(None) + } + } + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle { + Handle::Data { .. } => {} + Handle::Mac { .. } => return Err(Error::new(EINVAL)), + } + + Ok(Some(self.adapter.write_packet(buf)?)) + } + + fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(Some(EventFlags::empty())) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let scheme_path = match handle { + Handle::Data { .. } => &b"network:"[..], + Handle::Mac { .. } => &b"network:mac"[..], + }; + + let mut i = 0; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(Some(i)) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle { + Handle::Data { .. } => { + stat.st_mode = MODE_FILE | 0o700; + } + Handle::Mac { .. } => { + stat.st_mode = MODE_FILE | 0o400; + stat.st_size = 6; + } + } + + Ok(Some(0)) + } + + fn fsync(&mut self, id: usize) -> Result> { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(Some(0)) + } + + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; + Ok(Some(0)) + } +} diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 90b9367de0..8a958db6ca 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -11,4 +11,5 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index e90f172a58..d6e89495f8 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,13 +1,10 @@ -use std::collections::BTreeMap; use std::convert::TryInto; use std::{cmp, mem, ptr, slice}; +use driver_network::NetworkAdapter; use netutils::setcfg; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; -use syscall::flag::{EventFlags, MODE_FILE, O_NONBLOCK}; -use syscall::scheme::SchemeBlockMut; -use syscall::Stat; +use syscall::error::Result; use common::dma::Dma; @@ -109,8 +106,6 @@ pub struct Intel8254x { transmit_ring_free: usize, transmit_index: usize, transmit_clean_index: usize, - next_id: usize, - pub handles: BTreeMap, } #[derive(Copy, Clone)] @@ -123,48 +118,22 @@ fn wrap_ring(index: usize, ring_size: usize) -> usize { (index + 1) & (ring_size - 1) } -impl SchemeBlockMut for Intel8254x { - fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid != 0 { - return Err(Error::new(EACCES)); - } - - let handle = match path { - "" => Handle::Data { flags }, - "mac" => Handle::Mac { offset: 0 }, - _ => return Err(Error::new(EINVAL)), - }; - - self.next_id += 1; - self.handles.insert(self.next_id, handle); - Ok(Some(self.next_id)) +impl NetworkAdapter for Intel8254x { + fn mac_address(&mut self) -> [u8; 6] { + self.mac_address } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); + fn available_for_read(&mut self) -> usize { + let desc = unsafe { &*(self.receive_ring.as_ptr().add(self.receive_index) as *const Rd) }; + + if desc.status & RD_DD == RD_DD { + return desc.length as usize; } - let handle = *self.handles.get(&id).ok_or(Error::new(EBADF))?; - self.next_id += 1; - self.handles.insert(self.next_id, handle); - Ok(Some(self.next_id)) + 0 } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let flags = match *handle { - Handle::Data { flags } => flags, - Handle::Mac { ref mut offset } => { - let data = &self.mac_address[*offset..]; - let i = cmp::min(buf.len(), data.len()); - buf[..i].copy_from_slice(&data[..i]); - *offset += i; - return Ok(Some(i)); - } - }; - + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { let desc = unsafe { &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut Rd) }; if desc.status & RD_DD == RD_DD { @@ -181,21 +150,10 @@ impl SchemeBlockMut for Intel8254x { return Ok(Some(i)); } - if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) - } else { - Ok(None) - } + Ok(None) } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - match handle { - Handle::Data { .. } => {} - Handle::Mac { .. } => return Err(Error::new(EINVAL)), - } - + fn write_packet(&mut self, buf: &[u8]) -> Result { if self.transmit_ring_free == 0 { loop { let desc = unsafe { @@ -245,54 +203,7 @@ impl SchemeBlockMut for Intel8254x { unsafe { self.write_reg(TDT, self.transmit_index as u32) }; - Ok(Some(i)) - } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let scheme_path = match handle { - Handle::Data { .. } => &b"network:"[..], - Handle::Mac { .. } => &b"network:mac"[..], - }; - - let mut i = 0; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(Some(i)) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - match handle { - Handle::Data { .. } => { - stat.st_mode = MODE_FILE | 0o700; - } - Handle::Mac { .. } => { - stat.st_mode = MODE_FILE | 0o400; - stat.st_size = 6; - } - } - - Ok(Some(0)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) + Ok(i) } } @@ -317,8 +228,6 @@ impl Intel8254x { transmit_ring_free: 16, transmit_index: 0, transmit_clean_index: 0, - next_id: 0, - handles: BTreeMap::new(), }; module.init(); @@ -331,16 +240,6 @@ impl Intel8254x { icr != 0 } - pub fn next_read(&self) -> usize { - let desc = unsafe { &*(self.receive_ring.as_ptr().add(self.receive_index) as *const Rd) }; - - if desc.status & RD_DD == RD_DD { - return desc.length as usize; - } - - 0 - } - pub unsafe fn read_reg(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 1746883701..2f141219ff 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -1,63 +1,16 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - use std::cell::RefCell; -use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::process; -use std::sync::Arc; +use std::convert::Infallible; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; use pcid_interface::PcidServerHandle; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use syscall::EventFlags; pub mod device; -fn handle_update( - socket: &mut File, - device: &mut device::Intel8254x, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn main() { let mut pcid_handle = PcidServerHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); @@ -70,122 +23,68 @@ fn main() { let bar = &pci_config.func.bars[0]; - let irq = pci_config.func.legacy_interrupt_line.expect("e1000d: no legacy interrupts supported"); + let irq = pci_config + .func + .legacy_interrupt_line + .expect("e1000d: no legacy interrupts supported"); eprintln!(" + E1000 {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("e1000d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - let mut irq_file = irq.irq_handle("e1000d"); let address = unsafe { bar.physmap_mem("e1000d") } as usize; - { - let device = Arc::new(RefCell::new(unsafe { - device::Intel8254x::new(address).expect("e1000d: failed to allocate device") - })); - let mut event_queue = - EventQueue::::new().expect("e1000d: failed to create event queue"); + let device = + unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; - syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - daemon.ready().expect("e1000d: failed to mark daemon as ready"); + let mut event_queue = + EventQueue::::new().expect("e1000d: failed to create event queue"); - let todo = Arc::new(RefCell::new(Vec::::new())); + syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if unsafe { device_irq.borrow().irq() } { - irq_file.write(&mut irq)?; + daemon + .ready() + .expect("e1000d: failed to mark daemon as ready"); - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { scheme_irq.borrow().adapter().irq() } { + irq_file.write(&mut irq)?; - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("e1000d: failed to catch events on IRQ file"); - - let device_packet = device.clone(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("e1000d: failed to catch events on scheme file"); + }, + ) + .expect("e1000d: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("e1000d: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("e1000d: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("e1000d: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("e1000d: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("e1000d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - send_events(event_count); - } - } - process::exit(0); - }).expect("e1000d: failed to create daemon"); + #[allow(unreachable_code)] + match event_queue.run().expect("e1000d: failed to handle events") {} + }) + .expect("e1000d: failed to create daemon"); } diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 1760a676bc..780fc29e08 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -11,4 +11,5 @@ redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 9d0f59abd4..3fd47e029b 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -1,11 +1,9 @@ -use std::collections::BTreeMap; use std::convert::TryInto; use std::time::{Duration, Instant}; use std::{cmp, mem, ptr, slice, thread}; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; -use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::scheme::SchemeBlockMut; +use driver_network::NetworkAdapter; +use syscall::error::Result; use common::dma::Dma; use netutils::setcfg; @@ -23,42 +21,23 @@ pub struct Intel8259x { transmit_ring_free: usize, transmit_index: usize, transmit_clean_index: usize, - next_id: usize, - pub handles: BTreeMap, } fn wrap_ring(index: usize, ring_size: usize) -> usize { (index + 1) & (ring_size - 1) } -impl SchemeBlockMut for Intel8259x { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) - } else { - Err(Error::new(EACCES)) - } +impl NetworkAdapter for Intel8259x { + fn mac_address(&mut self) -> [u8; 6] { + // FIXME read from the network adapter itself + [0xfe; 6] // FE-FE-FE-FE-FE-FE } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let flags = { - let flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - *flags - }; - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) + fn available_for_read(&mut self) -> usize { + self.next_read() } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { let desc = unsafe { &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut ixgbe_adv_rx_desc) }; @@ -86,16 +65,10 @@ impl SchemeBlockMut for Intel8259x { return Ok(Some(i)); } - if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) - } else { - Ok(None) - } + Ok(None) } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - + fn write_packet(&mut self, buf: &[u8]) -> Result { if self.transmit_ring_free == 0 { loop { let desc = unsafe { @@ -145,31 +118,7 @@ impl SchemeBlockMut for Intel8259x { self.write_reg(IXGBE_TDT(0), self.transmit_index as u32); - Ok(Some(i)) - } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - - let scheme_path = b"network:"; - let i = cmp::min(buf.len(), scheme_path.len()); - buf[..i].copy_from_slice(&scheme_path[..i]); - Ok(Some(i)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or_else(|| Error::new(EBADF))?; - Ok(Some(0)) + Ok(i) } } @@ -196,8 +145,6 @@ impl Intel8259x { transmit_ring_free: 32, transmit_index: 0, transmit_clean_index: 0, - next_id: 0, - handles: BTreeMap::new(), }; module.init(); diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index a5ec7bfa7f..1f09e76b2d 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -1,21 +1,13 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - -// TODO: Migrate to Rust 2018/2021 -extern crate common; - use std::cell::RefCell; -use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::sync::Arc; -use std::thread; +use std::convert::Infallible; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; use pcid_interface::PcidServerHandle; -use std::time::Duration; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use syscall::EventFlags; pub mod device; #[rustfmt::skip] @@ -23,49 +15,6 @@ mod ixgbe; const IXGBE_MMIO_SIZE: usize = 512 * 1024; -fn handle_update( - socket: &mut File, - device: &mut device::Intel8259x, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn main() { let mut pcid_handle = PcidServerHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); @@ -78,130 +27,76 @@ fn main() { let (bar, _) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line.expect("ixgbed: no legacy interrupts supported"); + let irq = pci_config + .func + .legacy_interrupt_line + .expect("ixgbed: no legacy interrupts supported"); println!(" + IXGBE {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("ixgbed: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - - daemon.ready().expect("ixgbed: failed to signal readiness"); - let mut irq_file = irq.irq_handle("ixgbed"); let address = unsafe { - common::physmap(bar, IXGBE_MMIO_SIZE, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("ixgbed: failed to map address") as usize + common::physmap( + bar, + IXGBE_MMIO_SIZE, + common::Prot::RW, + common::MemoryType::Uncacheable, + ) + .expect("ixgbed: failed to map address") as usize }; - { - let device = Arc::new(RefCell::new( - device::Intel8259x::new(address, IXGBE_MMIO_SIZE) - .expect("ixgbed: failed to allocate device") - )); - let mut event_queue = - EventQueue::::new().expect("ixgbed: failed to create event queue"); + let device = device::Intel8259x::new(address, IXGBE_MMIO_SIZE) + .expect("ixgbed: failed to allocate device"); - syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - let todo = Arc::new(RefCell::new(Vec::::new())); + let mut event_queue = + EventQueue::::new().expect("ixgbed: failed to create event queue"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if device_irq.borrow().irq() { - irq_file.write(&irq)?; + syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } + daemon + .ready() + .expect("ixgbed: failed to mark daemon as ready"); - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("ixgbed: failed to catch events on IRQ file"); + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if scheme_irq.borrow().adapter().irq() { + irq_file.write(&mut irq)?; - let device_packet = device.clone(); - let socket_packet = socket.clone(); - - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("ixgbed: failed to catch events on scheme file"); + }, + ) + .expect("ixgbed: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("ixgbed: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("ixgbed: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("ixgbed: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("ixgbed: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("ixgbed: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - - send_events(event_count); - } - } - std::process::exit(0); - }).expect("ixgbed: failed to daemonize"); - - thread::sleep(Duration::from_secs(20)); + #[allow(unreachable_code)] + match event_queue.run().expect("ixgbed: failed to handle events") {} + }) + .expect("ixgbed: failed to create daemon"); } diff --git a/rtl8139d/Cargo.toml b/rtl8139d/Cargo.toml index ff88b0e2dd..e296be4330 100644 --- a/rtl8139d/Cargo.toml +++ b/rtl8139d/Cargo.toml @@ -13,4 +13,5 @@ redox-daemon = "0.1" redox-log = "0.1" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/rtl8139d/src/device.rs b/rtl8139d/src/device.rs index f9bbcac38f..fd64fd294f 100644 --- a/rtl8139d/src/device.rs +++ b/rtl8139d/src/device.rs @@ -1,11 +1,9 @@ use std::mem; use std::convert::TryInto; -use std::collections::BTreeMap; -use syscall::error::{Error, EACCES, EBADF, EINVAL, EIO, EMSGSIZE, EWOULDBLOCK, Result}; -use syscall::flag::{EventFlags, O_NONBLOCK}; +use driver_network::NetworkAdapter; +use syscall::error::{Error, EIO, EMSGSIZE, Result}; use syscall::io::{Mmio, Io, ReadOnly}; -use syscall::scheme::SchemeBlockMut; use common::dma::Dma; use netutils::setcfg; @@ -126,38 +124,20 @@ pub struct Rtl8139 { receive_i: usize, transmit_buffer: [Dma<[Mmio; 1792]>; 4], transmit_i: usize, - next_id: usize, - pub handles: BTreeMap } -impl SchemeBlockMut for Rtl8139 { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) - } else { - Err(Error::new(EACCES)) - } +impl NetworkAdapter for Rtl8139 { + fn mac_address(&mut self) -> [u8; 6] { + // FIXME read from the network adapter itself + [0xfe; 6] // FE-FE-FE-FE-FE-FE } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let flags = { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - *flags - }; - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) + fn available_for_read(&mut self) -> usize { + self.next_read() } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { if !self.regs.cr.readf(CR_BUFE) { let rxsts = (self.rx(0) as u16) | @@ -185,16 +165,12 @@ impl SchemeBlockMut for Rtl8139 { self.regs.capr.write(capr); res - } else if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) } else { Ok(None) } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - + fn write_packet(&mut self, buf: &[u8]) -> Result { loop { if self.transmit_i >= 4 { self.transmit_i = 0; @@ -221,39 +197,12 @@ impl SchemeBlockMut for Rtl8139 { self.transmit_i += 1; - return Ok(Some(i)); + return Ok(i); } std::hint::spin_loop(); } } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - let scheme_path = b"network:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(Some(i)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } } impl Rtl8139 { @@ -272,8 +221,6 @@ impl Rtl8139 { .try_into() .unwrap_or_else(|_| unreachable!()), transmit_i: 0, - next_id: 0, - handles: BTreeMap::new(), }; module.init(); diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 268e1ddf3f..a7b9ca4540 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -1,26 +1,25 @@ #![feature(int_roundings)] -extern crate event; -extern crate netutils; -extern crate syscall; - use std::cell::RefCell; -use std::convert::TryInto; -use std::{env, process}; +use std::convert::{Infallible, TryInto}; use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; use std::ptr::NonNull; -use std::sync::Arc; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; -use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; -use redox_log::{RedoxLogger, OutputBuilder}; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use pcid_interface::{ + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PcidServerHandle, SetFeatureInfo, + SubdriverArguments, +}; +use redox_log::{OutputBuilder, RedoxLogger}; +use syscall::EventFlags; pub mod device; @@ -196,49 +195,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { } } -fn handle_update( - socket: &mut File, - device: &mut device::Rtl8139, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { @@ -275,119 +231,62 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("rtl8139d: failed to map address") as usize }; - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("rtl8139d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); - { - let device = Arc::new(RefCell::new(unsafe { - device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") - })); + let device = + unsafe { device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") }; - let mut event_queue = - EventQueue::::new().expect("rtl8139d: failed to create event queue"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); + let mut event_queue = + EventQueue::::new().expect("rtl8139d: failed to create event queue"); - daemon.ready().expect("rtl8139d: failed to mark daemon as ready"); + syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + daemon + .ready() + .expect("rtl8139d: failed to mark daemon as ready"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - //TODO: This may be causing spurious interrupts - if unsafe { device_irq.borrow_mut().irq() } { - irq_file.write(&mut irq)?; + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + //TODO: This may be causing spurious interrupts + if unsafe { scheme_irq.borrow_mut().adapter_mut().irq() } { + irq_file.write(&mut irq)?; - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } - - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("rtl8139d: failed to catch events on IRQ file"); - - let device_packet = device.clone(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("rtl8139d: failed to catch events on scheme file"); + }, + ) + .expect("rtl8139d: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("rtl8139d: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("rtl8139d: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("rtl8139d: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("rtl8139d: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("rtl8139d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - send_events(event_count); - } - } - process::exit(0); + #[allow(unreachable_code)] + match event_queue + .run() + .expect("rtl8139d: failed to handle events") {} } fn main() { diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index d3cd6495f9..c04b5c8478 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -13,4 +13,5 @@ redox-daemon = "0.1" redox-log = "0.1" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index c3663b8b76..eaff7ea829 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,14 +1,9 @@ -// Supports Realtek RTL8168, RTL8169, and other compatible devices -// See https://people.freebsd.org/~wpaul/RealTek/rtl8169spec-121.pdf - use std::mem; use std::convert::TryInto; -use std::collections::BTreeMap; -use syscall::error::{Error, EACCES, EBADF, EINVAL, EMSGSIZE, EWOULDBLOCK, Result}; -use syscall::flag::{EventFlags, O_NONBLOCK}; +use driver_network::NetworkAdapter; +use syscall::error::{Error, Result, EMSGSIZE}; use syscall::io::{Mmio, Io, ReadOnly}; -use syscall::scheme::SchemeBlockMut; use common::dma::Dma; use netutils::setcfg; @@ -83,38 +78,20 @@ pub struct Rtl8168 { transmit_i: usize, transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], transmit_ring_h: Dma<[Td; 1]>, - next_id: usize, - pub handles: BTreeMap } -impl SchemeBlockMut for Rtl8168 { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) - } else { - Err(Error::new(EACCES)) - } +impl NetworkAdapter for Rtl8168 { + fn mac_address(&mut self) -> [u8; 6] { + // FIXME read from the network adapter itself + [0xfe; 6] // FE-FE-FE-FE-FE-FE } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let flags = { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - *flags - }; - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) + fn available_for_read(&mut self) -> usize { + self.next_read() } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { if self.receive_i >= self.receive_ring.len() { self.receive_i = 0; } @@ -137,16 +114,12 @@ impl SchemeBlockMut for Rtl8168 { self.receive_i += 1; Ok(Some(i)) - } else if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) } else { Ok(None) } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - + fn write_packet(&mut self, buf: &[u8]) -> Result { loop { if self.transmit_i >= self.transmit_ring.len() { self.transmit_i = 0; @@ -177,39 +150,12 @@ impl SchemeBlockMut for Rtl8168 { self.transmit_i += 1; - return Ok(Some(i)); + return Ok(i); } std::hint::spin_loop(); } } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - let scheme_path = b"network:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(Some(i)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } } impl Rtl8168 { @@ -246,8 +192,6 @@ impl Rtl8168 { transmit_i: 0, transmit_buffer_h: [Dma::zeroed()?.assume_init()], transmit_ring_h: Dma::zeroed()?.assume_init(), - next_id: 0, - handles: BTreeMap::new(), }; module.init(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 78fe7185fc..1cfaab1c9e 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -1,16 +1,12 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - use std::cell::RefCell; -use std::convert::TryInto; -use std::{env, process}; +use std::convert::{Infallible, TryInto}; use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; use std::ptr::NonNull; -use std::sync::Arc; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; #[cfg(target_arch = "x86_64")] @@ -18,7 +14,7 @@ use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use syscall::EventFlags; pub mod device; @@ -194,49 +190,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { } } -fn handle_update( - socket: &mut File, - device: &mut device::Rtl8168, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { @@ -273,119 +226,62 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("rtl8168d: failed to map address") as usize }; - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("rtl8168d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); - { - let device = Arc::new(RefCell::new(unsafe { - device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") - })); + let device = + unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") }; - let mut event_queue = - EventQueue::::new().expect("rtl8168d: failed to create event queue"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + let mut event_queue = + EventQueue::::new().expect("rtl8168d: failed to create event queue"); - daemon.ready().expect("rtl8168d: failed to mark daemon as ready"); + syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + daemon + .ready() + .expect("rtl8168d: failed to mark daemon as ready"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - //TODO: This may be causing spurious interrupts - if unsafe { device_irq.borrow_mut().irq() } { - irq_file.write(&mut irq)?; + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + //TODO: This may be causing spurious interrupts + if unsafe { scheme_irq.borrow_mut().adapter_mut().irq() } { + irq_file.write(&mut irq)?; - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } - - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("rtl8168d: failed to catch events on IRQ file"); - - let device_packet = device.clone(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("rtl8168d: failed to catch events on scheme file"); + }, + ) + .expect("rtl8168d: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("rtl8168d: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("rtl8168d: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("rtl8168d: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("rtl8168d: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - send_events(event_count); - } - } - process::exit(0); + #[allow(unreachable_code)] + match event_queue + .run() + .expect("rtl8168d: failed to handle events") {} } fn main() {