Merge branch 'unify_network_drivers' into 'master'
Unify the scheme handling of all network drivers See merge request redox-os/drivers!141
This commit is contained in:
Generated
+13
@@ -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",
|
||||
|
||||
@@ -7,6 +7,7 @@ members = [
|
||||
"bgad",
|
||||
"block-io-wrapper",
|
||||
"common",
|
||||
"driver-network",
|
||||
"e1000d",
|
||||
"fbcond",
|
||||
"ided",
|
||||
|
||||
@@ -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"
|
||||
@@ -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<Option<usize>>;
|
||||
|
||||
/// 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<usize>;
|
||||
}
|
||||
|
||||
pub struct NetworkScheme<T: NetworkAdapter> {
|
||||
adapter: T,
|
||||
_scheme_name: String,
|
||||
scheme: File,
|
||||
next_id: usize,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
todo_packets: Vec<Packet>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Handle {
|
||||
Data { flags: usize },
|
||||
Mac { offset: usize },
|
||||
}
|
||||
|
||||
impl<T: NetworkAdapter> NetworkScheme<T> {
|
||||
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<T: NetworkAdapter> SchemeBlockMut for NetworkScheme<T> {
|
||||
fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<EventFlags>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
fn close(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
self.handles.remove(&id).ok_or(Error::new(EBADF))?;
|
||||
Ok(Some(0))
|
||||
}
|
||||
}
|
||||
@@ -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" }
|
||||
|
||||
+15
-116
@@ -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<usize, Handle>,
|
||||
}
|
||||
|
||||
#[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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<usize> {
|
||||
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<Option<EventFlags>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
fn close(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
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)
|
||||
}
|
||||
|
||||
+51
-152
@@ -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<Packet>,
|
||||
) -> Result<bool> {
|
||||
// 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::<usize>::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::<Infallible>::new().expect("e1000d: failed to create event queue");
|
||||
|
||||
let todo = Arc::new(RefCell::new(Vec::<Packet>::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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -11,4 +11,5 @@ redox_syscall = "0.4"
|
||||
redox-daemon = "0.1"
|
||||
|
||||
common = { path = "../common" }
|
||||
driver-network = { path = "../driver-network" }
|
||||
pcid = { path = "../pcid" }
|
||||
|
||||
+17
-66
@@ -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<usize, usize>,
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?;
|
||||
|
||||
fn read_packet(&mut self, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?;
|
||||
|
||||
fn write_packet(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
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<Option<EventFlags>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?;
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
fn close(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
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);
|
||||
|
||||
+58
-163
@@ -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<Packet>,
|
||||
) -> Result<bool> {
|
||||
// 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::<usize>::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::<Packet>::new()));
|
||||
let mut event_queue =
|
||||
EventQueue::<Infallible>::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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@ redox-daemon = "0.1"
|
||||
redox-log = "0.1"
|
||||
|
||||
common = { path = "../common" }
|
||||
driver-network = { path = "../driver-network" }
|
||||
pcid = { path = "../pcid" }
|
||||
|
||||
+13
-64
@@ -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<u8>; 1792]>; 4],
|
||||
transmit_i: usize,
|
||||
next_id: usize,
|
||||
pub handles: BTreeMap<usize, usize>
|
||||
mac_address: [u8; 6],
|
||||
}
|
||||
|
||||
impl SchemeBlockMut for Rtl8139 {
|
||||
fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
fn read_packet(&mut self, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
fn write_packet(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
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<Option<EventFlags>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
fn close(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
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");
|
||||
|
||||
+53
-154
@@ -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<Packet>,
|
||||
) -> Result<bool> {
|
||||
// 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::<usize>::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::<Infallible>::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::<Packet>::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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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() {
|
||||
|
||||
@@ -13,4 +13,5 @@ redox-daemon = "0.1"
|
||||
redox-log = "0.1"
|
||||
|
||||
common = { path = "../common" }
|
||||
driver-network = { path = "../driver-network" }
|
||||
pcid = { path = "../pcid" }
|
||||
|
||||
+13
-67
@@ -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<u8>; 7552]>; 1],
|
||||
transmit_ring_h: Dma<[Td; 1]>,
|
||||
next_id: usize,
|
||||
pub handles: BTreeMap<usize, usize>
|
||||
mac_address: [u8; 6],
|
||||
}
|
||||
|
||||
impl SchemeBlockMut for Rtl8168 {
|
||||
fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
fn read_packet(&mut self, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
fn write_packet(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
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<Option<EventFlags>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
fn close(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
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");
|
||||
|
||||
+48
-152
@@ -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<Packet>,
|
||||
) -> Result<bool> {
|
||||
// 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::<usize>::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::<Infallible>::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::<Packet>::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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<Infallible>> {
|
||||
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() {
|
||||
|
||||
@@ -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"
|
||||
|
||||
+51
-41
@@ -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::<VirtHeader>(), 12);
|
||||
|
||||
const MAX_BUFFER_LEN: usize = 65535;
|
||||
|
||||
fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> {
|
||||
fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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::<Vec<u8>>();
|
||||
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::<syscall::Event>()])?; // Wait for event
|
||||
scheme.tick()?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-71
@@ -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<Queue<'a>>,
|
||||
rx_buffers: Vec<Dma<[u8]>>,
|
||||
|
||||
/// Transmiter Queue.
|
||||
tx: Arc<Queue<'a>>,
|
||||
/// File descriptor handles.
|
||||
handles: BTreeMap<usize, usize>,
|
||||
next_id: AtomicUsize,
|
||||
|
||||
recv_head: u16,
|
||||
}
|
||||
|
||||
impl<'a> NetworkScheme<'a> {
|
||||
pub fn new(rx: Arc<Queue<'a>>, tx: Arc<Queue<'a>>) -> Self {
|
||||
impl<'a> VirtioNet<'a> {
|
||||
pub fn new(mac_address: [u8; 6], rx: Arc<Queue<'a>>, tx: Arc<Queue<'a>>) -> 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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
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<Option<usize>> {
|
||||
if self.handles.get(&id).is_none() {
|
||||
return Err(SysError::new(EBADF));
|
||||
}
|
||||
|
||||
fn write_packet(&mut self, buffer: &[u8]) -> syscall::Result<usize> {
|
||||
let header = unsafe { Dma::<VirtHeader>::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<Option<usize>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn fevent(
|
||||
&mut self,
|
||||
id: usize,
|
||||
_flags: syscall::EventFlags,
|
||||
) -> syscall::Result<Option<syscall::EventFlags>> {
|
||||
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<Option<usize>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn fsync(&mut self, _id: usize) -> syscall::Result<Option<usize>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn close(&mut self, _id: usize) -> syscall::Result<Option<usize>> {
|
||||
unimplemented!()
|
||||
Ok(buffer.len())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user