Rewrite network interface (#334)

* Rewrite network interface

* Fix issue when cloning RLT8139 device

* Add Interface struct wrapping smoltcp iface

* Revert "Add Interface struct wrapping smoltcp iface"

This reverts commit ede7d5d0c9.

* Add back device stats

* Move stats code

* Rename eth_addr field to mac

* Add device config struct

* Fix usage of config and stats

* Make device init private

* Remove InnerStats and use Arc<Stats> directly

* Remove nic feature
This commit is contained in:
Vincent Ollivier 2022-05-05 23:05:39 +02:00 committed by GitHub
parent 50a48fcb75
commit a7cb32a5c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 338 additions and 393 deletions

View File

@ -10,11 +10,9 @@ readme = "README.md"
default-run = "moros"
[features]
default = ["video", "rtl8139"]
default = ["video"]
video = []
serial = []
rtl8139 = []
pcnet = []
[dependencies]
acpi = "4.1.0"

View File

@ -7,9 +7,9 @@ setup:
rustup default nightly
cargo install bootimage
output = video
keyboard = qwerty
nic = rtl8139
output = video, # video, serial
keyboard = qwerty # qwerty, azerty, dvorak
nic = rtl8139 # rtl8139, pcnet
export MOROS_KEYBOARD = $(keyboard)
@ -38,7 +38,7 @@ $(img):
image: $(img)
touch src/lib.rs
env | grep MOROS
cargo bootimage --no-default-features --features $(output),$(nic) --release
cargo bootimage --no-default-features --features $(output) --release
dd conv=notrunc if=$(bin) of=$(img)
opts = -m 32 -cpu max -nic model=$(nic) -hda $(img) -soundhw pcspk
@ -50,7 +50,7 @@ qemu:
qemu-system-x86_64 $(opts)
test:
cargo test --release --lib --no-default-features --features serial,$(nic) -- \
cargo test --release --lib --no-default-features --features serial -- \
-m 32 -display none -serial stdio -device isa-debug-exit,iobase=0xf4,iosize=0x04
clean:

View File

@ -67,7 +67,7 @@ Install the required tools with `make setup` or the following commands:
Build the image to `disk.img`:
$ make image output=video keyboard=qwerty nic=rtl8139
$ make image output=video keyboard=qwerty
Run MOROS in QEMU:

View File

@ -1,45 +1,186 @@
use crate::{sys, usr};
use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use core::sync::atomic::{AtomicU64, Ordering};
use alloc::vec::Vec;
use alloc::vec;
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use lazy_static::lazy_static;
use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes};
use smoltcp::phy::DeviceCapabilities;
use smoltcp::phy::{Device, Medium};
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address};
use spin::Mutex;
// TODO: Support dyn Interface
pub type Interface<T> = smoltcp::iface::Interface<'static, T>;
mod rtl8139;
mod pcnet;
#[cfg(feature = "rtl8139")]
pub mod rtl8139;
pub type Interface = smoltcp::iface::Interface<'static, EthernetDevice>;
#[cfg(feature = "rtl8139")]
lazy_static! {
pub static ref IFACE: Mutex<Option<Interface<rtl8139::RTL8139>>> = Mutex::new(None);
pub static ref IFACE: Mutex<Option<Interface>> = Mutex::new(None);
}
#[cfg(feature = "rtl8139")]
pub fn init() {
rtl8139::init();
#[derive(Clone)]
pub enum EthernetDevice {
RTL8139(rtl8139::Device),
PCNET(pcnet::Device),
//E2000,
//VirtIO,
}
#[cfg(feature = "pcnet")]
pub mod pcnet;
#[cfg(feature = "pcnet")]
lazy_static! {
pub static ref IFACE: Mutex<Option<Interface<pcnet::PCNET>>> = Mutex::new(None);
pub trait EthernetDeviceIO {
fn config(&self) -> Arc<Config>;
fn stats(&self) -> Arc<Stats>;
fn receive_packet(&mut self) -> Option<Vec<u8>>;
fn transmit_packet(&mut self, len: usize);
fn next_tx_buffer(&mut self, len: usize) -> &mut [u8];
}
#[cfg(feature = "pcnet")]
pub fn init() {
pcnet::init();
impl EthernetDeviceIO for EthernetDevice {
fn config(&self) -> Arc<Config> {
match self {
EthernetDevice::RTL8139(dev) => dev.config(),
EthernetDevice::PCNET(dev) => dev.config(),
}
}
fn stats(&self) -> Arc<Stats> {
match self {
EthernetDevice::RTL8139(dev) => dev.stats(),
EthernetDevice::PCNET(dev) => dev.stats(),
}
}
fn receive_packet(&mut self) -> Option<Vec<u8>> {
match self {
EthernetDevice::RTL8139(dev) => dev.receive_packet(),
EthernetDevice::PCNET(dev) => dev.receive_packet(),
}
}
fn transmit_packet(&mut self, len: usize) {
match self {
EthernetDevice::RTL8139(dev) => dev.transmit_packet(len),
EthernetDevice::PCNET(dev) => dev.transmit_packet(len),
}
}
fn next_tx_buffer(&mut self, len: usize) -> &mut [u8] {
match self {
EthernetDevice::RTL8139(dev) => dev.next_tx_buffer(len),
EthernetDevice::PCNET(dev) => dev.next_tx_buffer(len),
}
}
}
struct InnerStats {
impl<'a> smoltcp::phy::Device<'a> for EthernetDevice {
type RxToken = RxToken;
type TxToken = TxToken;
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = 1500;
caps.max_burst_size = Some(1);
caps
}
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
if let Some(buffer) = self.receive_packet() {
if self.config().is_debug_enabled() {
debug!("NET Packet Received");
usr::hex::print_hex(&buffer);
}
self.stats().rx_add(buffer.len() as u64);
let rx = RxToken { buffer };
let tx = TxToken { device: self.clone() };
Some((rx, tx))
} else {
None
}
}
fn transmit(&'a mut self) -> Option<Self::TxToken> {
let tx = TxToken { device: self.clone() };
Some(tx)
}
}
#[doc(hidden)]
pub struct RxToken {
buffer: Vec<u8>,
}
impl smoltcp::phy::RxToken for RxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> smoltcp::Result<R> where F: FnOnce(&mut [u8]) -> smoltcp::Result<R> {
f(&mut self.buffer)
}
}
#[doc(hidden)]
pub struct TxToken {
device: EthernetDevice,
}
impl smoltcp::phy::TxToken for TxToken {
fn consume<R, F>(mut self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result<R> where F: FnOnce(&mut [u8]) -> smoltcp::Result<R> {
let config = self.device.config();
let mut buf = self.device.next_tx_buffer(len);
let res = f(&mut buf);
if res.is_ok() {
if config.is_debug_enabled() {
debug!("NET Packet Transmitted");
usr::hex::print_hex(&buf);
}
self.device.transmit_packet(len);
self.device.stats().tx_add(len as u64);
}
res
}
}
pub struct Config {
debug: AtomicBool,
mac: Mutex<Option<EthernetAddress>>,
}
impl Config {
fn new() -> Self {
Self {
debug: AtomicBool::new(false),
mac: Mutex::new(None),
}
}
fn is_debug_enabled(&self) -> bool {
self.debug.load(Ordering::Relaxed)
}
pub fn enable_debug(&self) {
self.debug.store(true, Ordering::Relaxed);
}
pub fn disable_debug(&self) {
self.debug.store(false, Ordering::Relaxed)
}
fn mac(&self) -> Option<EthernetAddress> {
*self.mac.lock()
}
fn update_mac(&self, mac: EthernetAddress) {
*self.mac.lock() = Some(mac);
}
}
pub struct Stats {
rx_bytes_count: AtomicU64,
tx_bytes_count: AtomicU64,
rx_packets_count: AtomicU64,
tx_packets_count: AtomicU64,
}
impl InnerStats {
impl Stats {
fn new() -> Self {
Self {
rx_bytes_count: AtomicU64::new(0),
@ -48,43 +189,64 @@ impl InnerStats {
tx_packets_count: AtomicU64::new(0),
}
}
}
#[derive(Clone)]
pub struct Stats {
stats: Arc<InnerStats>
}
impl Stats {
fn new() -> Self {
Self {
stats: Arc::new(InnerStats::new())
}
}
pub fn rx_bytes_count(&self) -> u64 {
self.stats.rx_bytes_count.load(Ordering::Relaxed)
self.rx_bytes_count.load(Ordering::Relaxed)
}
pub fn tx_bytes_count(&self) -> u64 {
self.stats.tx_bytes_count.load(Ordering::Relaxed)
self.tx_bytes_count.load(Ordering::Relaxed)
}
pub fn rx_packets_count(&self) -> u64 {
self.stats.rx_packets_count.load(Ordering::Relaxed)
self.rx_packets_count.load(Ordering::Relaxed)
}
pub fn tx_packets_count(&self) -> u64 {
self.stats.tx_packets_count.load(Ordering::Relaxed)
self.tx_packets_count.load(Ordering::Relaxed)
}
pub fn rx_add(&self, bytes_count: u64) {
self.stats.rx_packets_count.fetch_add(1, Ordering::SeqCst);
self.stats.rx_bytes_count.fetch_add(bytes_count, Ordering::SeqCst);
self.rx_packets_count.fetch_add(1, Ordering::SeqCst);
self.rx_bytes_count.fetch_add(bytes_count, Ordering::SeqCst);
}
pub fn tx_add(&self, bytes_count: u64) {
self.stats.tx_packets_count.fetch_add(1, Ordering::SeqCst);
self.stats.tx_bytes_count.fetch_add(bytes_count, Ordering::SeqCst);
self.tx_packets_count.fetch_add(1, Ordering::SeqCst);
self.tx_bytes_count.fetch_add(bytes_count, Ordering::SeqCst);
}
}
fn find_pci_io_base(vendor_id: u16, device_id: u16) -> Option<u16> {
if let Some(mut pci_device) = sys::pci::find_device(vendor_id, device_id) {
pci_device.enable_bus_mastering();
let io_base = (pci_device.base_addresses[0] as u16) & 0xFFF0;
Some(io_base)
} else {
None
}
}
pub fn init() {
let add_interface = |device: EthernetDevice, name| {
if let Some(mac) = device.config().mac() {
log!("NET {} MAC {}\n", name, mac);
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let routes = Routes::new(BTreeMap::new());
let ip_addrs = [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)];
let medium = device.capabilities().medium;
let mut builder = InterfaceBuilder::new(device, vec![]).ip_addrs(ip_addrs).routes(routes);
if medium == Medium::Ethernet {
builder = builder.hardware_addr(mac.into()).neighbor_cache(neighbor_cache);
}
let iface = builder.finalize();
*IFACE.lock() = Some(iface);
}
};
if let Some(io_base) = find_pci_io_base(0x10EC, 0x8139) {
add_interface(EthernetDevice::RTL8139(rtl8139::Device::new(io_base)), "RTL8139");
}
if let Some(io_base) = find_pci_io_base(0x1022, 0x2000) {
add_interface(EthernetDevice::PCNET(pcnet::Device::new(io_base)), "PCNET");
}
}

View File

@ -1,19 +1,12 @@
use crate::{sys, usr};
use crate::sys;
use crate::sys::allocator::PhysBuf;
use crate::sys::net::Stats;
use crate::sys::net::{EthernetDeviceIO, Config, Stats};
use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use bit_field::BitField;
use core::sync::atomic::{AtomicUsize, Ordering};
use smoltcp::Result;
use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes};
use smoltcp::phy::{Device, DeviceCapabilities, Medium};
use smoltcp::phy;
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address};
use smoltcp::wire::EthernetAddress;
use x86_64::instructions::port::Port;
const CSR0_INIT: usize = 0;
@ -134,11 +127,10 @@ fn is_buffer_owner(des: &PhysBuf, i: usize) -> bool {
}
#[derive(Clone)]
pub struct PCNET {
pub debug_mode: bool,
pub stats: Stats,
pub struct Device {
config: Arc<Config>,
stats: Arc<Stats>,
ports: Ports,
eth_addr: Option<EthernetAddress>,
rx_buffers: [PhysBuf; RX_BUFFERS_COUNT],
tx_buffers: [PhysBuf; TX_BUFFERS_COUNT],
@ -148,50 +140,27 @@ pub struct PCNET {
tx_id: Arc<AtomicUsize>,
}
impl PCNET {
impl Device {
pub fn new(io_base: u16) -> Self {
Self {
debug_mode: false,
stats: Stats::new(),
let mut device = Self {
config: Arc::new(Config::new()),
stats: Arc::new(Stats::new()),
ports: Ports::new(io_base),
eth_addr: None,
rx_buffers: [(); RX_BUFFERS_COUNT].map(|_| PhysBuf::new(MTU)),
tx_buffers: [(); TX_BUFFERS_COUNT].map(|_| PhysBuf::new(MTU)),
rx_des: PhysBuf::new(RX_BUFFERS_COUNT * DE_LEN),
tx_des: PhysBuf::new(TX_BUFFERS_COUNT * DE_LEN),
rx_id: Arc::new(AtomicUsize::new(0)),
tx_id: Arc::new(AtomicUsize::new(0)),
}
}
fn init_descriptor_entry(&mut self, i: usize, is_rx: bool) {
let des = if is_rx { &mut self.rx_des } else { &mut self.tx_des };
// Set buffer address
let addr = if is_rx {
self.rx_buffers[i].addr().to_le_bytes()
} else {
self.tx_buffers[i].addr().to_le_bytes()
};
des[DE_LEN * i + 0] = addr[0];
des[DE_LEN * i + 1] = addr[1];
des[DE_LEN * i + 2] = addr[2];
des[DE_LEN * i + 3] = addr[3];
// Set buffer byte count (0..12 BCNT + 12..16 ONES)
let bcnt = (0xF000 | (0x0FFF & (1 + !(MTU as u16)))).to_le_bytes();
des[DE_LEN * i + 4] = bcnt[0];
des[DE_LEN * i + 5] = bcnt[1];
if is_rx {
des[DE_LEN * i + 7].set_bit(DE_OWN, true); // Set ownership to card
}
device.init();
device
}
pub fn init(&mut self) {
fn init(&mut self) {
// Read MAC addr
let mac = self.ports.mac();
self.eth_addr = Some(EthernetAddress::from_bytes(&mac));
self.config.update_mac(EthernetAddress::from_bytes(&mac));
// Reset to 16-bit access
unsafe {
@ -266,30 +235,45 @@ impl PCNET {
self.ports.write_csr_32(0, 1 << CSR0_STRT);
assert!(self.ports.read_csr_32(0) == 0b110110011); // IDON + INTR + RXON + TXON + STRT + INIT
}
fn init_descriptor_entry(&mut self, i: usize, is_rx: bool) {
let des = if is_rx { &mut self.rx_des } else { &mut self.tx_des };
// Set buffer address
let addr = if is_rx {
self.rx_buffers[i].addr().to_le_bytes()
} else {
self.tx_buffers[i].addr().to_le_bytes()
};
des[DE_LEN * i + 0] = addr[0];
des[DE_LEN * i + 1] = addr[1];
des[DE_LEN * i + 2] = addr[2];
des[DE_LEN * i + 3] = addr[3];
// Set buffer byte count (0..12 BCNT + 12..16 ONES)
let bcnt = (0xF000 | (0x0FFF & (1 + !(MTU as u16)))).to_le_bytes();
des[DE_LEN * i + 4] = bcnt[0];
des[DE_LEN * i + 5] = bcnt[1];
if is_rx {
des[DE_LEN * i + 7].set_bit(DE_OWN, true); // Set ownership to card
}
}
}
impl<'a> Device<'a> for PCNET {
type RxToken = RxToken;
type TxToken = TxToken;
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(1);
caps
impl EthernetDeviceIO for Device {
fn config(&self) -> Arc<Config> {
self.config.clone()
}
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
fn stats(&self) -> Arc<Stats> {
self.stats.clone()
}
fn receive_packet(&mut self) -> Option<Vec<u8>> {
let mut packet = Vec::new();
let mut rx_id = self.rx_id.load(Ordering::SeqCst);
while is_buffer_owner(&self.rx_des, rx_id) {
if self.debug_mode {
printk!("{}\n", "-".repeat(66));
log!("NET PCNET Receiving:\n");
//printk!("CSR0: {:016b}\n", self.ports.read_csr_32(0));
//printk!("RX Buffer: {}\n", rx_id);
}
let rmd1 = self.rx_des[rx_id * DE_LEN + 7];
let end_of_packet = rmd1.get_bit(DE_ENP);
@ -301,7 +285,7 @@ impl<'a> Device<'a> for PCNET {
let crc_error = rmd1.get_bit(DE_CRC) && !rmd1.get_bit(DE_OFLO) && rmd1.get_bit(DE_ENP);
let framing_error = rmd1.get_bit(DE_FRAM) && !rmd1.get_bit(DE_OFLO) && rmd1.get_bit(DE_ENP);
if self.debug_mode {
if self.config.is_debug_enabled() {
printk!("Flags: ");
if start_of_packet {
printk!("start_of_packet ");
@ -343,120 +327,32 @@ impl<'a> Device<'a> for PCNET {
}
if !packet.is_empty() {
self.stats.rx_add(packet.len() as u64);
if self.debug_mode {
//printk!("Size: {} bytes\n", packet.len());
usr::hex::print_hex(&packet);
//printk!("CSR0: {:016b}\n", self.ports.read_csr_32(0));
//printk!("RDTE: {:016b}\n", self.rx_des[rx_id * DE_LEN + 7]);
}
let rx = RxToken { packet };
let tx = TxToken { device: self.clone() };
Some((rx, tx))
Some(packet)
} else {
None
}
}
fn transmit(&'a mut self) -> Option<Self::TxToken> {
fn transmit_packet(&mut self, len: usize) {
let tx_id = self.tx_id.load(Ordering::SeqCst);
if is_buffer_owner(&self.tx_des, tx_id) {
if self.debug_mode {
printk!("{}\n", "-".repeat(66));
log!("NET PCNET Transmitting:\n");
//printk!("TX Buffer: {}\n", tx_id);
//printk!("CSR0: {:016b}\n", self.ports.read_csr_32(0));
}
self.tx_des[tx_id * DE_LEN + 7].set_bit(DE_STP, true); // Set start of packet
self.tx_des[tx_id * DE_LEN + 7].set_bit(DE_ENP, true); // Set end of packet
// Set buffer byte count (0..12 BCNT + 12..16 ONES)
let bcnt = (0xF000 | (0x0FFF & (1 + !(len as u16)))).to_le_bytes();
self.tx_des[tx_id * DE_LEN + 4] = bcnt[0];
self.tx_des[tx_id * DE_LEN + 5] = bcnt[1];
// Give back ownership to the card
self.tx_des[tx_id * DE_LEN + 7].set_bit(DE_OWN, true);
self.tx_id.store((tx_id + 1) % TX_BUFFERS_COUNT, Ordering::Relaxed);
let tx = TxToken {
device: self.clone()
};
Some(tx)
} else {
if !is_buffer_owner(&self.tx_des, tx_id) {
self.ports.write_csr_32(0, 1 << CSR0_TDMD); // Send all buffers
None
}
}
}
#[doc(hidden)]
pub struct RxToken {
packet: Vec<u8>,
}
impl phy::RxToken for RxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R> where F: FnOnce(&mut [u8]) -> Result<R> {
f(&mut self.packet)
}
}
#[doc(hidden)]
pub struct TxToken {
device: PCNET
}
impl phy::TxToken for TxToken {
fn consume<R, F>(mut self, _timestamp: Instant, len: usize, f: F) -> Result<R> where F: FnOnce(&mut [u8]) -> Result<R> {
let tx_id = self.device.tx_id.load(Ordering::SeqCst);
let mut buf = &mut self.device.tx_buffers[tx_id][0..len];
// 1. Copy the packet to a physically contiguous buffer in memory.
let res = f(&mut buf);
if res.is_ok() {
self.device.tx_des[tx_id * DE_LEN + 7].set_bit(DE_STP, true); // Set start of packet
self.device.tx_des[tx_id * DE_LEN + 7].set_bit(DE_ENP, true); // Set end of packet
// Set buffer byte count (0..12 BCNT + 12..16 ONES)
let bcnt = (0xF000 | (0x0FFF & (1 + !(len as u16)))).to_le_bytes();
self.device.tx_des[tx_id * DE_LEN + 4] = bcnt[0];
self.device.tx_des[tx_id * DE_LEN + 5] = bcnt[1];
// Give back ownership to the card
self.device.tx_des[tx_id * DE_LEN + 7].set_bit(DE_OWN, true);
self.device.tx_id.store((tx_id + 1) % TX_BUFFERS_COUNT, Ordering::Relaxed);
}
self.device.stats.tx_add(len as u64);
if self.device.debug_mode {
//printk!("Size: {} bytes\n", len);
usr::hex::print_hex(&buf);
//printk!("CSR0: {:016b}\n", self.device.ports.read_csr_32(0));
}
res
}
}
pub fn init() {
if let Some(mut pci_device) = sys::pci::find_device(0x1022, 0x2000) {
pci_device.enable_bus_mastering();
let io_base = (pci_device.base_addresses[0] as u16) & 0xFFF0;
let mut device = PCNET::new(io_base);
device.init();
if let Some(eth_addr) = device.eth_addr {
log!("NET PCNET MAC {}\n", eth_addr);
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let routes = Routes::new(BTreeMap::new());
let ip_addrs = [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)];
let medium = device.capabilities().medium;
let mut builder = InterfaceBuilder::new(device, vec![]).ip_addrs(ip_addrs).routes(routes);
if medium == Medium::Ethernet {
builder = builder.hardware_addr(eth_addr.into()).neighbor_cache(neighbor_cache);
}
let iface = builder.finalize();
*sys::net::IFACE.lock() = Some(iface);
}
fn next_tx_buffer(&mut self, len: usize) -> &mut [u8] {
let tx_id = self.tx_id.load(Ordering::SeqCst);
&mut self.tx_buffers[tx_id][0..len]
}
}

View File

@ -1,16 +1,11 @@
use crate::{sys, usr};
use crate::sys::allocator::PhysBuf;
use crate::sys::net::Stats;
use alloc::collections::BTreeMap;
use alloc::vec;
use crate::sys::net::{EthernetDeviceIO, Config, Stats};
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::convert::TryInto;
use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes};
use smoltcp::phy;
use smoltcp::phy::{Device, DeviceCapabilities, Medium};
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address};
use smoltcp::Result;
use core::sync::atomic::{AtomicUsize, Ordering};
use smoltcp::wire::EthernetAddress;
use x86_64::instructions::port::Port;
// 00 = 8K + 16 bytes
@ -67,6 +62,14 @@ const TCR_MXDMA2: u32 = 1 << 10;
const IMR_TOK: u16 = 1 << 2; // Transmit OK Interrupt
const IMR_ROK: u16 = 1 << 0; // Receive OK Interrupt
//const CRS: u32 = 1 << 31; // Carrier Sense Lost
//const TAB: u32 = 1 << 30; // Transmit Abort
//const OWC: u32 = 1 << 29; // Out of Window Collision
//const CDH: u32 = 1 << 28; // CD Heart Beat
const TOK: u32 = 1 << 15; // Transmit OK
//const TUN: u32 = 1 << 14; // Transmit FIFO Underrun
const OWN: u32 = 1 << 13; // DMA operation completed
#[derive(Clone)]
pub struct Ports {
pub mac: [Port<u8>; 6], // ID Registers (IDR0 ... IDR5)
@ -133,25 +136,23 @@ impl Ports {
}
#[derive(Clone)]
pub struct RTL8139 {
pub debug_mode: bool,
pub stats: Stats,
pub struct Device {
config: Arc<Config>,
stats: Arc<Stats>,
ports: Ports,
eth_addr: Option<EthernetAddress>,
rx_buffer: PhysBuf,
rx_offset: usize,
tx_buffers: [PhysBuf; TX_BUFFERS_COUNT],
tx_id: usize,
tx_id: Arc<AtomicUsize>,
}
impl RTL8139 {
impl Device {
pub fn new(io_base: u16) -> Self {
Self {
debug_mode: false,
stats: Stats::new(),
let mut device = Self {
config: Arc::new(Config::new()),
stats: Arc::new(Stats::new()),
ports: Ports::new(io_base),
eth_addr: None,
// Add MTU to RX_BUFFER_LEN if RCR_WRAP is set
rx_buffer: PhysBuf::new(RX_BUFFER_LEN + MTU),
@ -161,11 +162,13 @@ impl RTL8139 {
// Before a transmission begin the id is incremented,
// so the first transimission will start at 0.
tx_id: TX_BUFFERS_COUNT - 1,
}
tx_id: Arc::new(AtomicUsize::new(TX_BUFFERS_COUNT - 1)),
};
device.init();
device
}
pub fn init(&mut self) {
fn init(&mut self) {
// Power on
unsafe { self.ports.config1.write(0) }
@ -179,7 +182,7 @@ impl RTL8139 {
unsafe { self.ports.cmd.write(CR_RE | CR_TE) }
// Read MAC addr
self.eth_addr = Some(EthernetAddress::from_bytes(&self.ports.mac()));
self.config.update_mac(EthernetAddress::from_bytes(&self.ports.mac()));
// Get physical address of rx_buffer
let rx_addr = self.rx_buffer.addr();
@ -206,15 +209,13 @@ impl RTL8139 {
}
}
impl<'a> Device<'a> for RTL8139 {
type RxToken = RxToken;
type TxToken = TxToken;
impl EthernetDeviceIO for Device {
fn config(&self) -> Arc<Config> {
self.config.clone()
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(1);
caps
fn stats(&self) -> Arc<Stats> {
self.stats.clone()
}
// RxToken buffer, when not empty, will contains:
@ -222,7 +223,7 @@ impl<'a> Device<'a> for RTL8139 {
// [length (2 bytes)]
// [packet (length - 4 bytes)]
// [crc (4 bytes)]
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
fn receive_packet(&mut self) -> Option<Vec<u8>> {
let cmd = unsafe { self.ports.cmd.read() };
if (cmd & CR_BUFE) == CR_BUFE {
return None;
@ -235,15 +236,6 @@ impl<'a> Device<'a> for RTL8139 {
let offset = ((capr as usize) + RX_BUFFER_PAD) % (1 << 16);
let header = u16::from_le_bytes(self.rx_buffer[(offset + 0)..(offset + 2)].try_into().unwrap());
if self.debug_mode {
printk!("{}\n", "-".repeat(66));
log!("NET RTL8139 Receiving:\n");
//printk!("Command Register: {:#02X}\n", cmd);
//printk!("Interrupt Status Register: {:#02X}\n", isr);
//printk!("CAPR: {}\n", capr);
//printk!("CBR: {}\n", cbr);
//printk!("Header: {:#04X}\n", header);
}
if header & ROK != ROK {
unsafe { self.ports.capr.write(cbr) };
return None;
@ -251,14 +243,6 @@ impl<'a> Device<'a> for RTL8139 {
let n = u16::from_le_bytes(self.rx_buffer[(offset + 2)..(offset + 4)].try_into().unwrap()) as usize;
//let crc = u32::from_le_bytes(self.rx_buffer[(offset + n)..(offset + n + 4)].try_into().unwrap());
let len = n - 4;
if self.debug_mode {
//printk!("Size: {} bytes\n", len);
//printk!("CRC: {:#08X}\n", crc);
//printk!("RX Offset: {}\n", offset);
usr::hex::print_hex(&self.rx_buffer[(offset + 4)..(offset + n)]);
}
self.stats.rx_add(len as u64);
// Update buffer read pointer
self.rx_offset = (offset + n + 4 + 3) & !3;
@ -266,131 +250,37 @@ impl<'a> Device<'a> for RTL8139 {
self.ports.capr.write((self.rx_offset - RX_BUFFER_PAD) as u16);
}
let rx = RxToken {
buffer: self.rx_buffer[(offset + 4)..(offset + n)].to_vec()
};
let tx = TxToken {
device: self.clone()
};
Some((rx, tx))
Some(self.rx_buffer[(offset + 4)..(offset + n)].to_vec())
}
fn transmit(&'a mut self) -> Option<Self::TxToken> {
//let isr = unsafe { self.ports.isr.read() };
self.tx_id = (self.tx_id + 1) % TX_BUFFERS_COUNT;
fn transmit_packet(&mut self, len: usize) {
let tx_id = self.tx_id.load(Ordering::SeqCst);
let mut cmd_port = self.ports.tx_cmds[tx_id].clone();
unsafe {
// Fill in Transmit Status: the size of this packet, the early
// transmit threshold, and clear OWN bit in TSD (this starts the
// PCI operation).
// NOTE: The length of the packet use the first 13 bits (but should
// not exceed 1792 bytes), and a value of 0x000000 for the early
// transmit threshold means 8 bytes. So we just write the size of
// the packet.
cmd_port.write(0x1FFF & len as u32);
if self.debug_mode {
printk!("{}\n", "-".repeat(66));
log!("NET RTL8139 Transmitting:\n");
//printk!("TX Buffer: {}\n", self.tx_id);
//printk!("Interrupt Status Register: {:#02X}\n", isr);
// When the whole packet is moved to FIFO, the OWN bit is set to 1
while cmd_port.read() & OWN != OWN {}
// When the whole packet is moved to line, the TOK bit is set to 1
while cmd_port.read() & TOK != TOK {}
}
}
let tx = TxToken {
device: self.clone()
};
Some(tx)
}
}
#[doc(hidden)]
pub struct RxToken {
buffer: Vec<u8>,
}
impl phy::RxToken for RxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R> where F: FnOnce(&mut [u8]) -> Result<R> {
f(&mut self.buffer)
}
}
#[doc(hidden)]
pub struct TxToken {
device: RTL8139
}
//const CRS: u32 = 1 << 31; // Carrier Sense Lost
//const TAB: u32 = 1 << 30; // Transmit Abort
//const OWC: u32 = 1 << 29; // Out of Window Collision
//const CDH: u32 = 1 << 28; // CD Heart Beat
const TOK: u32 = 1 << 15; // Transmit OK
//const TUN: u32 = 1 << 14; // Transmit FIFO Underrun
const OWN: u32 = 1 << 13; // DMA operation completed
impl phy::TxToken for TxToken {
fn consume<R, F>(mut self, _timestamp: Instant, len: usize, f: F) -> Result<R> where F: FnOnce(&mut [u8]) -> Result<R> {
let tx_id = self.device.tx_id;
let buf = &mut self.device.tx_buffers[tx_id][0..len];
// 1. Copy the packet to a physically contiguous buffer in memory.
let res = f(buf);
// 2. Fill in Start Address(physical address) of this buffer.
// NOTE: This has was done during init
if res.is_ok() {
let mut cmd_port = self.device.ports.tx_cmds[tx_id].clone();
unsafe {
// 3. Fill in Transmit Status: the size of this packet, the
// early transmit threshold, and clear OWN bit in TSD (this
// starts the PCI operation).
// NOTE: The length of the packet use the first 13 bits (but
// should not exceed 1792 bytes), and a value of 0x000000
// for the early transmit threshold means 8 bytes. So we
// just write the size of the packet.
cmd_port.write(0x1FFF & len as u32);
// 4. When the whole packet is moved to FIFO, the OWN bit is
// set to 1.
while cmd_port.read() & OWN != OWN {}
// 5. When the whole packet is moved to line, the TOK bit is
// set to 1.
while cmd_port.read() & TOK != TOK {}
}
}
self.device.stats.tx_add(len as u64);
if self.device.debug_mode {
//printk!("Size: {} bytes\n", len);
usr::hex::print_hex(&buf[0..len]);
}
res
}
}
pub fn init() {
if let Some(mut pci_device) = sys::pci::find_device(0x10EC, 0x8139) {
pci_device.enable_bus_mastering();
let io_base = (pci_device.base_addresses[0] as u16) & 0xFFF0;
let mut device = RTL8139::new(io_base);
device.init();
if let Some(eth_addr) = device.eth_addr {
log!("NET RTL8139 MAC {}\n", eth_addr);
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let routes = Routes::new(BTreeMap::new());
let ip_addrs = [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)];
let medium = device.capabilities().medium;
let mut builder = InterfaceBuilder::new(device, vec![]).ip_addrs(ip_addrs).routes(routes);
if medium == Medium::Ethernet {
builder = builder.hardware_addr(eth_addr.into()).neighbor_cache(neighbor_cache);
}
let iface = builder.finalize();
*sys::net::IFACE.lock() = Some(iface);
}
//let irq = pci_device.interrupt_line;
//sys::idt::set_irq_handler(irq, interrupt_handler);
fn next_tx_buffer(&mut self, len: usize) -> &mut [u8] {
let tx_id = (self.tx_id.load(Ordering::SeqCst) + 1) % TX_BUFFERS_COUNT;
self.tx_id.store(tx_id, Ordering::Relaxed);
&mut self.tx_buffers[tx_id][0..len]
}
}
/*
pub fn interrupt_handler() {
printk!("RTL8139 interrupt!\n");
if let Some(mut guard) = sys::net::IFACE.try_lock() {
@ -399,3 +289,4 @@ pub fn interrupt_handler() {
}
}
}
*/

View File

@ -3,6 +3,7 @@ use alloc::format;
use crate::api::syscall;
use crate::api::fs;
use crate::api::console::Style;
use crate::sys::net::EthernetDeviceIO;
use alloc::borrow::ToOwned;
use alloc::string::ToString;
@ -40,7 +41,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
}
"stat" => {
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
let stats = iface.device().stats.clone();
let stats = iface.device().stats();
let csi_color = Style::color("LightCyan");
let csi_reset = Style::reset();
println!("{}rx:{} {} packets ({} bytes)", csi_color, csi_reset, stats.rx_packets_count(), stats.rx_bytes_count());
@ -51,7 +52,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
}
"monitor" => {
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
iface.device_mut().debug_mode = true;
iface.device_mut().config().enable_debug();
let mtu = iface.device().capabilities().max_transmission_unit;
let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; mtu]);
@ -189,13 +190,10 @@ pub fn set_config(attribute: &str, value: &str) {
match attribute {
"debug" => {
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
iface.device_mut().debug_mode = match value {
"1" | "true" => true,
"0" | "false" => false,
_ => {
error!("Invalid config value");
false
}
match value {
"1" | "true" => iface.device_mut().config().enable_debug(),
"0" | "false" => iface.device_mut().config().disable_debug(),
_ => error!("Invalid config value"),
}
} else {
error!("Network error");