Skip to main content

strat9_kernel/hardware/nic/
rtl8139_drv.rs

1// RTL8139 Ethernet Controller Driver
2// Reference: RTL8139/RTL8100 Series Data Sheet
3
4use crate::{
5    hardware::{
6        nic::NetworkDevice,
7        pci_client::{self as pci, Bar, ProbeCriteria},
8    },
9    memory::{allocate_zeroed_frame, phys_to_virt},
10};
11use alloc::{format, string::String, sync::Arc, vec::Vec};
12use core::sync::atomic::{AtomicUsize, Ordering};
13use spin::Mutex;
14
15use crate::hardware::nic::NetError;
16
17const RX_BUFFER_SIZE: usize = 8192;
18const RX_BUFFER_PAD: usize = 16;
19const TX_BUFFER_SIZE: usize = 2048;
20const TX_BUFFERS_COUNT: usize = 4;
21const MTU: usize = 1536;
22
23const CR_RST: u8 = 1 << 4;
24const CR_RE: u8 = 1 << 3;
25const CR_TE: u8 = 1 << 2;
26const CR_BUFE: u8 = 1 << 0;
27
28const RCR_WRAP: u32 = 1 << 7;
29const RCR_AB: u32 = 1 << 3;
30const RCR_AM: u32 = 1 << 2;
31const RCR_APM: u32 = 1 << 1;
32const RCR_AAP: u32 = 1 << 0;
33const RCR_RBLEN: u32 = 0 << 11;
34
35const TCR_IFG: u32 = 3 << 24;
36const TCR_MXDMA: u32 = 7 << 8;
37
38const ISR_ROK: u16 = 1 << 0;
39const ISR_TOK: u16 = 1 << 2;
40
41#[allow(dead_code)]
42const TOK: u32 = 1 << 15;
43const OWN: u32 = 1 << 13;
44
45struct Ports {
46    io_base: u16,
47}
48
49impl Ports {
50    /// Creates a new instance.
51    fn new(io_base: u16) -> Self {
52        Self { io_base }
53    }
54
55    /// Performs the read8 operation.
56    #[inline]
57    fn read8(&self, offset: u16) -> u8 {
58        unsafe {
59            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).read()
60        }
61    }
62
63    /// Performs the write8 operation.
64    #[inline]
65    fn write8(&mut self, offset: u16, value: u8) {
66        unsafe {
67            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).write(value)
68        }
69    }
70
71    /// Performs the read16 operation.
72    #[inline]
73    #[allow(dead_code)]
74    fn read16(&self, offset: u16) -> u16 {
75        unsafe {
76            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).read()
77        }
78    }
79
80    /// Performs the write16 operation.
81    #[inline]
82    fn write16(&mut self, offset: u16, value: u16) {
83        unsafe {
84            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).write(value)
85        }
86    }
87
88    /// Performs the read32 operation.
89    #[inline]
90    fn read32(&self, offset: u16) -> u32 {
91        unsafe {
92            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).read()
93        }
94    }
95
96    /// Performs the write32 operation.
97    #[inline]
98    fn write32(&mut self, offset: u16, value: u32) {
99        unsafe {
100            crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).write(value)
101        }
102    }
103
104    /// Performs the mac operation.
105    fn mac(&mut self) -> [u8; 6] {
106        [
107            self.read8(0x00),
108            self.read8(0x01),
109            self.read8(0x02),
110            self.read8(0x03),
111            self.read8(0x04),
112            self.read8(0x05),
113        ]
114    }
115}
116
117pub struct Rtl8139Device {
118    ports: Mutex<Ports>,
119    rx_buffer: *mut u8,
120    rx_phys: u64,
121    rx_offset: AtomicUsize,
122    tx_buffers: [*mut u8; TX_BUFFERS_COUNT],
123    tx_phys: [u64; TX_BUFFERS_COUNT],
124    tx_id: AtomicUsize,
125    mac: [u8; 6],
126    name: String,
127}
128
129unsafe impl Send for Rtl8139Device {}
130unsafe impl Sync for Rtl8139Device {}
131
132impl Rtl8139Device {
133    /// Creates a new instance.
134    pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Self, &'static str> {
135        let io_base = match pci_dev.read_bar(0) {
136            Some(Bar::Io { port }) => port as u16,
137            _ => return Err("Invalid BAR"),
138        };
139
140        let mut ports = Ports::new(io_base);
141        let mac = ports.mac();
142        let name = format!("rtl8139_{:02x}{:02x}{:02x}", mac[3], mac[4], mac[5]);
143
144        let rx_frame = allocate_zeroed_frame().ok_or("Failed to allocate RX buffer")?;
145        let rx_phys = rx_frame.start_address.as_u64();
146        let rx_buffer = phys_to_virt(rx_phys) as *mut u8;
147        core::ptr::write_bytes(rx_buffer, 0, RX_BUFFER_SIZE + RX_BUFFER_PAD + MTU);
148
149        let mut tx_buffers = [core::ptr::null_mut(); TX_BUFFERS_COUNT];
150        let mut tx_phys = [0u64; TX_BUFFERS_COUNT];
151        for i in 0..TX_BUFFERS_COUNT {
152            let frame = allocate_zeroed_frame().ok_or("Failed to allocate TX buffer")?;
153            tx_phys[i] = frame.start_address.as_u64();
154            tx_buffers[i] = phys_to_virt(tx_phys[i]) as *mut u8;
155            core::ptr::write_bytes(tx_buffers[i], 0, TX_BUFFER_SIZE);
156        }
157
158        let mut device = Self {
159            ports: Mutex::new(ports),
160            rx_buffer,
161            rx_phys,
162            rx_offset: AtomicUsize::new(0),
163            tx_buffers,
164            tx_phys,
165            tx_id: AtomicUsize::new(TX_BUFFERS_COUNT - 1),
166            mac,
167            name,
168        };
169
170        device.init();
171        Ok(device)
172    }
173
174    /// Performs the init operation.
175    fn init(&mut self) {
176        let mut ports = self.ports.lock();
177
178        ports.write8(0x37, CR_RST);
179        core::hint::spin_loop();
180
181        for _ in 0..1000 {
182            if (ports.read8(0x37) & CR_RST) == 0 {
183                break;
184            }
185            core::hint::spin_loop();
186        }
187
188        ports.write32(
189            0x44,
190            RCR_WRAP | RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_RBLEN,
191        );
192        ports.write32(0x40, TCR_IFG | TCR_MXDMA);
193        ports.write32(0x30, self.rx_phys as u32);
194
195        for i in 0..TX_BUFFERS_COUNT {
196            ports.write32(0x20 + (i as u16) * 4, self.tx_phys[i] as u32);
197        }
198
199        ports.write16(0x3C, ISR_ROK | ISR_TOK);
200        ports.write8(0x37, CR_RE | CR_TE | CR_BUFE);
201
202        log::info!(
203            "RTL8139: MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
204            self.mac[0],
205            self.mac[1],
206            self.mac[2],
207            self.mac[3],
208            self.mac[4],
209            self.mac[5]
210        );
211    }
212
213    /// Performs the receive packet operation.
214    #[allow(dead_code)]
215    fn receive_packet(&self) -> Option<Vec<u8>> {
216        self.receive_inner()
217    }
218
219    /// Performs the transmit packet operation.
220    #[allow(dead_code)]
221    fn transmit_packet(&self, data: &[u8]) -> Result<(), NetError> {
222        self.transmit_inner(data)
223    }
224
225    /// Performs the receive inner operation.
226    fn receive_inner(&self) -> Option<Vec<u8>> {
227        let mut ports = self.ports.lock();
228        let rx_offset = self.rx_offset.load(Ordering::Relaxed);
229
230        let status = unsafe { (self.rx_buffer.add(rx_offset) as *const u32).read_volatile() };
231
232        if (status & OWN) != 0 {
233            return None;
234        }
235
236        if (status & 0x0001) != 0 {
237            let length = ((status >> 16) & 0x1FFF) as usize - 4;
238            if length <= MTU {
239                let packet_start = unsafe { self.rx_buffer.add(rx_offset + 4) };
240                let mut buf = Vec::with_capacity(length);
241                unsafe {
242                    core::ptr::copy_nonoverlapping(packet_start, buf.as_mut_ptr(), length);
243                    buf.set_len(length);
244                }
245
246                let new_offset = ((rx_offset + length + 4 + RX_BUFFER_PAD) & !(RX_BUFFER_PAD - 1))
247                    % RX_BUFFER_SIZE;
248                self.rx_offset.store(new_offset, Ordering::Relaxed);
249                ports.write16(0x38, (new_offset - RX_BUFFER_PAD) as u16);
250
251                return Some(buf);
252            }
253        }
254
255        ports.write8(0x37, CR_RE | CR_TE);
256        self.rx_offset.store(0, Ordering::Relaxed);
257        None
258    }
259
260    /// Performs the transmit inner operation.
261    fn transmit_inner(&self, data: &[u8]) -> Result<(), NetError> {
262        if data.len() > MTU {
263            return Err(NetError::BufferTooSmall);
264        }
265
266        let id = self.tx_id.fetch_add(1, Ordering::SeqCst) % TX_BUFFERS_COUNT;
267        let mut ports = self.ports.lock();
268
269        let tx_status = ports.read32(0x10 + (id as u16) * 4);
270        if (tx_status & OWN) == 0 {
271            let mut timeout = 10000;
272            while (ports.read32(0x10 + (id as u16) * 4) & OWN) == 0 {
273                core::hint::spin_loop();
274                timeout -= 1;
275                if timeout == 0 {
276                    return Err(NetError::NotReady);
277                }
278            }
279        }
280
281        unsafe {
282            core::ptr::copy_nonoverlapping(data.as_ptr(), self.tx_buffers[id], data.len());
283        }
284
285        ports.write32(0x10 + (id as u16) * 4, data.len() as u32);
286
287        Ok(())
288    }
289}
290
291impl NetworkDevice for Rtl8139Device {
292    /// Performs the name operation.
293    fn name(&self) -> &str {
294        &self.name
295    }
296
297    /// Performs the mac address operation.
298    fn mac_address(&self) -> [u8; 6] {
299        self.mac
300    }
301
302    /// Performs the link up operation.
303    fn link_up(&self) -> bool {
304        let ports = self.ports.lock();
305        (ports.read8(0x58) & 0x80) != 0
306    }
307
308    /// Performs the receive operation.
309    fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
310        if let Some(packet) = self.receive_inner() {
311            let len = core::cmp::min(packet.len(), buf.len());
312            buf[..len].copy_from_slice(&packet[..len]);
313            Ok(len)
314        } else {
315            Err(NetError::NoPacket)
316        }
317    }
318
319    /// Performs the transmit operation.
320    fn transmit(&self, data: &[u8]) -> Result<(), NetError> {
321        self.transmit_inner(data)
322    }
323}
324
325static RTL8139_DEVICES: Mutex<Vec<Arc<Rtl8139Device>>> = Mutex::new(Vec::new());
326
327/// Performs the init operation.
328pub fn init() {
329    log::info!("[RTL8139] Scanning for RTL8139 devices...");
330
331    let candidates = pci::probe_all(ProbeCriteria {
332        vendor_id: Some(0x10EC),
333        device_id: None,
334        class_code: Some(pci::class::NETWORK),
335        subclass: Some(pci::net_subclass::ETHERNET),
336        prog_if: None,
337    });
338
339    for pci_dev in candidates.into_iter() {
340        if pci_dev.device_id != 0x8139 {
341            continue;
342        }
343
344        log::info!(
345            "RTL8139: Found device at {:?} (VEN:{:04x} DEV:{:04x})",
346            pci_dev.address,
347            pci_dev.vendor_id,
348            pci_dev.device_id
349        );
350
351        pci_dev.enable_bus_master();
352
353        match unsafe { Rtl8139Device::new(pci_dev) } {
354            Ok(device) => {
355                let arc = Arc::new(device);
356                RTL8139_DEVICES.lock().push(arc.clone());
357                let _iface = crate::hardware::nic::register_device(arc);
358            }
359            Err(e) => {
360                log::warn!("RTL8139: Failed to initialize device: {}", e);
361            }
362        }
363    }
364
365    log::info!("[RTL8139] Found {} device(s)", RTL8139_DEVICES.lock().len());
366}