From 899c4f511bd3a8f8fba73959d58c637993021ddf Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 25 Mar 2024 18:58:48 +0100 Subject: [PATCH] Read MAC address from virtio-net-pci device --- Makefile | 2 +- src/sys/net/mod.rs | 10 ++- src/sys/net/nic/mod.rs | 1 + src/sys/net/nic/virtio.rs | 162 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 src/sys/net/nic/virtio.rs diff --git a/Makefile b/Makefile index 40a5c4075..182e61544 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ keyboard = qwerty# qwerty, azerty, dvorak mode = release # Emulation options -nic = rtl8139# rtl8139, pcnet +nic = rtl8139# rtl8139, pcnet, virtio-net audio = sdl# sdl, coreaudio kvm = false pcap = false diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index e7271ce6d..7e26b7dee 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -33,8 +33,8 @@ fn time() -> Instant { pub enum EthernetDevice { RTL8139(nic::rtl8139::Device), PCNET(nic::pcnet::Device), + VirtIO(nic::virtio::Device), //E2000, - //VirtIO, } pub trait EthernetDeviceIO { @@ -50,6 +50,7 @@ impl EthernetDeviceIO for EthernetDevice { match self { EthernetDevice::RTL8139(dev) => dev.config(), EthernetDevice::PCNET(dev) => dev.config(), + EthernetDevice::VirtIO(dev) => dev.config(), } } @@ -57,6 +58,7 @@ impl EthernetDeviceIO for EthernetDevice { match self { EthernetDevice::RTL8139(dev) => dev.stats(), EthernetDevice::PCNET(dev) => dev.stats(), + EthernetDevice::VirtIO(dev) => dev.stats(), } } @@ -64,6 +66,7 @@ impl EthernetDeviceIO for EthernetDevice { match self { EthernetDevice::RTL8139(dev) => dev.receive_packet(), EthernetDevice::PCNET(dev) => dev.receive_packet(), + EthernetDevice::VirtIO(dev) => dev.receive_packet(), } } @@ -71,6 +74,7 @@ impl EthernetDeviceIO for EthernetDevice { match self { EthernetDevice::RTL8139(dev) => dev.transmit_packet(len), EthernetDevice::PCNET(dev) => dev.transmit_packet(len), + EthernetDevice::VirtIO(dev) => dev.transmit_packet(len), } } @@ -78,6 +82,7 @@ impl EthernetDeviceIO for EthernetDevice { match self { EthernetDevice::RTL8139(dev) => dev.next_tx_buffer(len), EthernetDevice::PCNET(dev) => dev.next_tx_buffer(len), + EthernetDevice::VirtIO(dev) => dev.next_tx_buffer(len), } } } @@ -265,4 +270,7 @@ pub fn init() { if let Some(io) = find_pci_io_base(0x1022, 0x2000) { add(EthernetDevice::PCNET(nic::pcnet::Device::new(io)), "PCNET"); } + if let Some(io) = find_pci_io_base(0x1AF4, 0x1000) { + add(EthernetDevice::VirtIO(nic::virtio::Device::new(io)), "VirtIO"); + } } diff --git a/src/sys/net/nic/mod.rs b/src/sys/net/nic/mod.rs index 45a797206..eb6baf3d1 100644 --- a/src/sys/net/nic/mod.rs +++ b/src/sys/net/nic/mod.rs @@ -1,2 +1,3 @@ pub mod pcnet; pub mod rtl8139; +pub mod virtio; diff --git a/src/sys/net/nic/virtio.rs b/src/sys/net/nic/virtio.rs new file mode 100644 index 000000000..219bd9fb2 --- /dev/null +++ b/src/sys/net/nic/virtio.rs @@ -0,0 +1,162 @@ +use crate::sys::allocator::PhysBuf; +use crate::sys::net::{EthernetDeviceIO, Config, Stats}; + +use alloc::sync::Arc; +use alloc::vec::Vec; +use smoltcp::wire::EthernetAddress; +use x86_64::instructions::port::Port; + +// https://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf +// https://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html + +const ACKNOWLEDGE: u8 = 1; +const DRIVER: u8 = 2; +const DRIVER_OK: u8 = 4; +const FAILED: u8 = 128; + +#[derive(Clone)] +pub struct Ports { + pub device_features: Port, // r + pub driver_features: Port, // r+w + pub queue_addr: Port, // r+w + pub queue_size: Port, // r + pub queue_select: Port, // r+w + pub queue_notify: Port, // r+w + pub device_status: Port, // r+w + pub isr_status: Port, // r + pub mac: [Port; 6], +} + +impl Ports { + pub fn new(io_base: u16) -> Self { + Self { + device_features: Port::new(io_base + 0x00), + driver_features: Port::new(io_base + 0x04), + queue_addr: Port::new(io_base + 0x08), + queue_size: Port::new(io_base + 0x0C), + queue_select: Port::new(io_base + 0x0E), + queue_notify: Port::new(io_base + 0x10), + device_status: Port::new(io_base + 0x12), + isr_status: Port::new(io_base + 0x13), + mac: [ + Port::new(io_base + 0x14), + Port::new(io_base + 0x15), + Port::new(io_base + 0x16), + Port::new(io_base + 0x17), + Port::new(io_base + 0x18), + Port::new(io_base + 0x19), + ], + } + } + + fn mac(&mut self) -> [u8; 6] { + unsafe { + [ + self.mac[0].read(), + self.mac[1].read(), + self.mac[2].read(), + self.mac[3].read(), + self.mac[4].read(), + self.mac[5].read(), + ] + } + } +} + +#[derive(Clone)] +pub struct Device { + config: Arc, + stats: Arc, + ports: Ports, + + rx_buffer: PhysBuf, + tx_buffer: PhysBuf, +} + +impl Device { + pub fn new(io_base: u16) -> Self { + let mut device = Self { + ports: Ports::new(io_base), + config: Arc::new(Config::new()), + stats: Arc::new(Stats::new()), + rx_buffer: PhysBuf::new((4096 * 5) / 8), + tx_buffer: PhysBuf::new((4096 * 5) / 8), + }; + device.init(); + device + } + + fn init(&mut self) { + unsafe { + self.ports.device_status.write(0); // Reset + + let device_status = self.ports.device_status.read(); + self.ports.device_status.write(device_status | ACKNOWLEDGE); + + let device_status = self.ports.device_status.read(); + self.ports.device_status.write(device_status | DRIVER); + } + + let device_features = unsafe { self.ports.device_features.read() }; + debug!("VirtIO Net: device features: {:#X}", device_features); + + + let device_status = unsafe { self.ports.device_status.read() }; + debug!("VirtIO Net: device status: {:#X}", device_status); + + // RX + unsafe { + let queue_index = 0; + self.ports.queue_select.write(queue_index); + let queue_size = self.ports.queue_size.read() as usize; + debug!("VirtIO Net: queue({}) size: {}", queue_index, queue_size); + } + + // TX + unsafe { + let queue_index = 1; + self.ports.queue_select.write(queue_index); + let queue_size = self.ports.queue_size.read() as usize; + debug!("VirtIO Net: queue({}) size: {}", queue_index, queue_size); + }; + + self.config.update_mac(EthernetAddress::from_bytes(&self.ports.mac())); + + unsafe { + let device_status = self.ports.device_status.read(); + self.ports.device_status.write(device_status | DRIVER_OK); + } + } + + fn read(&self, addr: u16) -> u32 { + debug!("READ: {:#X}", addr); + 0 + } + + fn write(&self, addr: u16, data: u32) { + debug!("WRITE: {:#X}", addr); + } +} + +impl EthernetDeviceIO for Device { + fn config(&self) -> Arc { + self.config.clone() + } + + fn stats(&self) -> Arc { + self.stats.clone() + } + + fn receive_packet(&mut self) -> Option> { + debug!("RECV"); + None + } + + fn transmit_packet(&mut self, len: usize) { + debug!("SEND"); + } + + fn next_tx_buffer(&mut self, len: usize) -> &mut [u8] { + &mut self.tx_buffer[0..len] // FIXME + } +}