mirror of https://github.com/vinc/moros.git
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:
parent
50a48fcb75
commit
a7cb32a5c2
|
@ -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"
|
||||
|
|
10
Makefile
10
Makefile
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue