diff --git a/Cargo.lock b/Cargo.lock index 59273691f6..4e2017a6db 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", @@ -1784,6 +1796,7 @@ name = "virtio-netd" version = "0.1.0" dependencies = [ "common", + "driver-network", "futures", "log", "netutils", 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..eec2fc1fcb --- /dev/null +++ b/driver-network/src/lib.rs @@ -0,0 +1,260 @@ +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_name: String, + 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 { + assert_eq!(scheme_name, "network"); // FIXME update fpath before removing this assertion + + 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_name: scheme_name.to_owned(), + 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 { + // FIXME use self.scheme_name instead of hardcoding "network" + 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..690dfb1be0 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, + mac_address: [u8; 6], } 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] { + self.mac_address } - 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,7 @@ impl Intel8259x { transmit_ring_free: 32, transmit_index: 0, transmit_clean_index: 0, - next_id: 0, - handles: BTreeMap::new(), + mac_address: [0; 6], }; module.init(); @@ -245,7 +193,7 @@ impl Intel8259x { /// Sets the mac address of this device. #[allow(dead_code)] - pub fn set_mac_addr(&self, mac: [u8; 6]) { + pub fn set_mac_addr(&mut self, mac: [u8; 6]) { let low: u32 = u32::from(mac[0]) + (u32::from(mac[1]) << 8) + (u32::from(mac[2]) << 16) @@ -254,6 +202,8 @@ impl Intel8259x { self.write_reg(IXGBE_RAL(0), low); self.write_reg(IXGBE_RAH(0), high); + + self.mac_address = mac; } /// Returns the register at `self.base` + `register`. @@ -342,6 +292,7 @@ impl Intel8259x { mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ), ); + self.mac_address = mac; // section 4.6.3 - wait for EEPROM auto read completion self.wait_write_reg(IXGBE_EEC, IXGBE_EEC_ARD); 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..746ecd5646 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 + mac_address: [u8; 6], } -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] { + self.mac_address } - 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,7 @@ impl Rtl8139 { .try_into() .unwrap_or_else(|_| unreachable!()), transmit_i: 0, - next_id: 0, - handles: BTreeMap::new(), + mac_address: [0; 6], }; module.init(); @@ -325,6 +273,7 @@ impl Rtl8139 { (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value println!(" - Reset"); 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..5dd76a8504 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 + mac_address: [u8; 6], } -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] { + self.mac_address } - 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,7 @@ 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(), + mac_address: [0; 6], }; module.init(); @@ -288,6 +233,7 @@ impl Rtl8168 { (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value println!(" - Reset"); 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() { diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index cf5d40fe74..ae6927fb33 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -11,6 +11,7 @@ futures = { version = "0.3.28", features = ["executor"] } virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } common = { path = "../common" } +driver-network = { path = "../driver-network" } redox-daemon = "0.1" redox_syscall = "0.4" diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index c3113ed753..ecda97d2cd 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -2,15 +2,12 @@ mod scheme; use std::fs::File; use std::io::{Read, Write}; -use std::os::fd::{FromRawFd, RawFd}; +use std::mem; +use driver_network::NetworkScheme; use pcid_interface::PcidServerHandle; -use syscall::{Packet, SchemeBlockMut}; - -use virtio_core::transport::{Error, Transport}; - -use scheme::NetworkScheme; +use scheme::VirtioNet; pub const VIRTIO_NET_F_MAC: u32 = 5; @@ -30,7 +27,7 @@ static_assertions::const_assert_eq!(core::mem::size_of::(), 12); const MAX_BUFFER_LEN: usize = 65535; -fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { +fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box> { let mut pcid_handle = PcidServerHandle::connect_default()?; // Double check that we have the right device. @@ -45,20 +42,30 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { let device_space = device.device_space; // Negotiate device features: - let mac_addr = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { - let mac = (0..6) - .map(|i| unsafe { core::ptr::read_volatile(device_space.add(i)) }) - .collect::>(); + let mac_address = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { + let mac = unsafe { + [ + core::ptr::read_volatile(device_space.add(0)), + core::ptr::read_volatile(device_space.add(1)), + core::ptr::read_volatile(device_space.add(2)), + core::ptr::read_volatile(device_space.add(3)), + core::ptr::read_volatile(device_space.add(4)), + core::ptr::read_volatile(device_space.add(5)), + ] + }; - let mac_str = format!( - "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + log::info!( + "virtio-net: device MAC is {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] ); - log::info!("virtio-net: device MAC is {mac_str}"); - device.transport.ack_driver_feature(VIRTIO_NET_F_MAC); - mac_str + mac } else { unimplemented!() }; @@ -85,35 +92,38 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { let mut name = pci_config.func.name(); name.push_str("_virtio_net"); - // Create the network scheme. - // - // FIXME(andypython): It should be fine to have multiple network devices. - let socket_fd = syscall::open( - &format!(":network"), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, - ) - .map_err(Error::SyscallError)?; + let device = VirtioNet::new(mac_address, rx_queue, tx_queue); + let mut scheme = NetworkScheme::new(device, "network"); - let mut socket_fd = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let mut scheme = NetworkScheme::new(rx_queue, tx_queue); + let _ = netutils::setcfg( + "mac", + &format!( + "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac_address[0], + mac_address[1], + mac_address[2], + mac_address[3], + mac_address[4], + mac_address[5] + ), + ); - let _ = netutils::setcfg("mac", &mac_addr); + let mut event_queue = File::open("event:")?; + event_queue.write(&syscall::Event { + id: scheme.event_handle() as usize, + flags: syscall::EVENT_READ, + data: 0, + })?; - deamon.ready().expect("virtio-netd: failed to deamonize"); + syscall::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); + + daemon.ready().expect("virtio-netd: failed to daemonize"); + + scheme.tick()?; loop { - let mut packet = Packet::default(); - socket_fd - .read(&mut packet) - .expect("virtio-netd: failed to read packet"); - - let result = scheme.handle(&mut packet); - // `packet.a` contains the return value. - packet.a = result.expect("virtio-netd: failed to handle packet"); - - socket_fd - .write(&packet) - .expect("virtio-netd: failed to write packet"); + event_queue.read(&mut [0; mem::size_of::()])?; // Wait for event + scheme.tick()?; } } diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index 5a48cba19f..59b3b93e20 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -1,9 +1,6 @@ -use std::collections::BTreeMap; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use syscall::Error as SysError; -use syscall::*; +use driver_network::NetworkAdapter; use common::dma::Dma; @@ -12,26 +9,29 @@ use virtio_core::transport::Queue; use crate::{VirtHeader, MAX_BUFFER_LEN}; -pub struct NetworkScheme<'a> { +pub struct VirtioNet<'a> { + mac_address: [u8; 6], + /// Reciever Queue. rx: Arc>, rx_buffers: Vec>, /// Transmiter Queue. tx: Arc>, - /// File descriptor handles. - handles: BTreeMap, - next_id: AtomicUsize, recv_head: u16, } -impl<'a> NetworkScheme<'a> { - pub fn new(rx: Arc>, tx: Arc>) -> Self { +impl<'a> VirtioNet<'a> { + pub fn new(mac_address: [u8; 6], rx: Arc>, tx: Arc>) -> Self { // Populate all of the `rx_queue` with buffers to maximize performence. let mut rx_buffers = vec![]; for i in 0..(rx.descriptor_len() as usize) { - rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN).unwrap().assume_init() }); + rx_buffers.push(unsafe { + Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN) + .unwrap() + .assume_init() + }); let chain = ChainBuilder::new() .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) @@ -41,13 +41,12 @@ impl<'a> NetworkScheme<'a> { } Self { + mac_address, + rx, rx_buffers, tx, - handles: BTreeMap::new(), - next_id: AtomicUsize::new(0), - recv_head: 0, } } @@ -82,45 +81,27 @@ impl<'a> NetworkScheme<'a> { } } -impl<'a> SchemeBlockMut for NetworkScheme<'a> { - fn open( - &mut self, - _path: &str, - flags: usize, - uid: u32, - _gid: u32, - ) -> syscall::Result> { - if uid != 0 { - return Err(SysError::new(EACCES)); - } - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(id, flags); - - Ok(Some(id)) +impl<'a> NetworkAdapter for VirtioNet<'a> { + fn mac_address(&mut self) -> [u8; 6] { + self.mac_address } - fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { - let flags = *self.handles.get(&id).ok_or(SysError::new(EBADF))?; + fn available_for_read(&mut self) -> usize { + (self.rx.used.head_index() - self.recv_head).into() + } + + fn read_packet(&mut self, buf: &mut [u8]) -> syscall::Result> { let bytes = self.try_recv(buf); if bytes != 0 { // We read some bytes. Ok(Some(bytes)) - } else if flags & O_NONBLOCK == O_NONBLOCK { - // We are in non-blocking mode. - Err(SysError::new(EWOULDBLOCK)) } else { - // Block - unimplemented!() + Ok(None) } } - fn write(&mut self, id: usize, buffer: &[u8]) -> syscall::Result> { - if self.handles.get(&id).is_none() { - return Err(SysError::new(EBADF)); - } - + fn write_packet(&mut self, buffer: &[u8]) -> syscall::Result { let header = unsafe { Dma::::zeroed()?.assume_init() }; let mut payload = unsafe { Dma::<[u8]>::zeroed_slice(buffer.len())?.assume_init() }; @@ -132,34 +113,6 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { .build(); futures::executor::block_on(self.tx.send(chain)); - Ok(Some(buffer.len())) - } - - fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result> { - unimplemented!() - } - - fn fevent( - &mut self, - id: usize, - _flags: syscall::EventFlags, - ) -> syscall::Result> { - if self.handles.get(&id).is_none() { - return Err(SysError::new(EBADF)); - } - - Ok(Some(syscall::EventFlags::empty())) - } - - fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { - unimplemented!() - } - - fn fsync(&mut self, _id: usize) -> syscall::Result> { - unimplemented!() - } - - fn close(&mut self, _id: usize) -> syscall::Result> { - unimplemented!() + Ok(buffer.len()) } }