strat9_kernel/hardware/nic/
pcnet_drv.rs1use 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 MTU: usize = 1536;
18const RX_BUFFERS_COUNT: usize = 32;
19const TX_BUFFERS_COUNT: usize = 8;
20const DESC_LEN: usize = 16;
21
22const CSR0_INIT: u32 = 0;
23const CSR0_STRT: u32 = 1;
24const CSR0_TDMD: u32 = 3;
25
26const DE_ENP: usize = 0;
27const DE_STP: usize = 1;
28const DE_OWN: usize = 7;
29
30fn log2(x: u8) -> u8 {
32 8 - 1 - x.leading_zeros() as u8
33}
34
35pub struct PcnetDevice {
36 ports: Mutex<Ports>,
37 rx_buffers: [*mut u8; RX_BUFFERS_COUNT],
38 rx_phys: [u64; RX_BUFFERS_COUNT],
39 tx_buffers: [*mut u8; TX_BUFFERS_COUNT],
40 tx_phys: [u64; TX_BUFFERS_COUNT],
41 rx_des: *mut u8,
42 rx_des_phys: u64,
43 tx_des: *mut u8,
44 tx_des_phys: u64,
45 rx_id: AtomicUsize,
46 tx_id: AtomicUsize,
47 mac: [u8; 6],
48 name: String,
49}
50
51unsafe impl Send for PcnetDevice {}
52unsafe impl Sync for PcnetDevice {}
53
54struct Ports {
55 io_base: u16,
56}
57
58impl Ports {
59 fn new(io_base: u16) -> Self {
61 Self { io_base }
62 }
63
64 #[inline]
66 fn read8(&self, offset: u16) -> u8 {
67 unsafe {
68 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).read()
69 }
70 }
71
72 #[inline]
74 #[allow(dead_code)]
75 fn write8(&mut self, offset: u16, value: u8) {
76 unsafe {
77 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).write(value)
78 }
79 }
80
81 #[inline]
83 fn read32(&self, offset: u16) -> u32 {
84 unsafe {
85 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).read()
86 }
87 }
88
89 #[inline]
91 #[allow(dead_code)]
92 fn write32(&mut self, offset: u16, value: u32) {
93 unsafe {
94 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset).write(value)
95 }
96 }
97
98 fn write_rap(&mut self, val: u32) {
100 unsafe {
101 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x14).write(val)
102 }
103 }
104
105 fn read_rdp(&self) -> u32 {
107 unsafe { crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x10).read() }
108 }
109
110 fn write_rdp(&mut self, val: u32) {
112 unsafe {
113 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x10).write(val)
114 }
115 }
116
117 fn read_bdp(&self) -> u32 {
119 unsafe { crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x1C).read() }
120 }
121
122 fn write_bdp(&mut self, val: u32) {
124 unsafe {
125 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + 0x1C).write(val)
126 }
127 }
128
129 fn read_csr(&mut self, csr: u32) -> u32 {
131 self.write_rap(csr);
132 self.read_rdp()
133 }
134
135 fn write_csr(&mut self, csr: u32, val: u32) {
137 self.write_rap(csr);
138 self.write_rdp(val);
139 }
140
141 fn read_bcr(&mut self, bcr: u32) -> u32 {
143 self.write_rap(bcr);
144 self.read_bdp()
145 }
146
147 fn write_bcr(&mut self, bcr: u32, val: u32) {
149 self.write_rap(bcr);
150 self.write_bdp(val);
151 }
152
153 fn mac(&mut self) -> [u8; 6] {
155 [
156 self.read8(0x00),
157 self.read8(0x01),
158 self.read8(0x02),
159 self.read8(0x03),
160 self.read8(0x04),
161 self.read8(0x05),
162 ]
163 }
164}
165
166impl PcnetDevice {
167 pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Self, &'static str> {
169 let io_base = match pci_dev.read_bar(0) {
170 Some(Bar::Io { port }) => port as u16,
171 _ => return Err("Invalid BAR"),
172 };
173
174 let mut ports = Ports::new(io_base);
175 let mac = ports.mac();
176 let name = format!("pcnet_{:02x}{:02x}{:02x}", mac[3], mac[4], mac[5]);
177
178 let mut rx_buffers = [core::ptr::null_mut(); RX_BUFFERS_COUNT];
179 let mut rx_phys = [0u64; RX_BUFFERS_COUNT];
180 for i in 0..RX_BUFFERS_COUNT {
181 let frame = allocate_zeroed_frame().ok_or("Failed to allocate RX buffer")?;
182 rx_phys[i] = frame.start_address.as_u64();
183 rx_buffers[i] = phys_to_virt(rx_phys[i]) as *mut u8;
184 }
185
186 let mut tx_buffers = [core::ptr::null_mut(); TX_BUFFERS_COUNT];
187 let mut tx_phys = [0u64; TX_BUFFERS_COUNT];
188 for i in 0..TX_BUFFERS_COUNT {
189 let frame = allocate_zeroed_frame().ok_or("Failed to allocate TX buffer")?;
190 tx_phys[i] = frame.start_address.as_u64();
191 tx_buffers[i] = phys_to_virt(tx_phys[i]) as *mut u8;
192 }
193
194 let rx_des_frame = allocate_zeroed_frame().ok_or("Failed to allocate RX descriptors")?;
195 let rx_des_phys = rx_des_frame.start_address.as_u64();
196 let rx_des = phys_to_virt(rx_des_phys) as *mut u8;
197 unsafe {
198 core::ptr::write_bytes(rx_des, 0, RX_BUFFERS_COUNT * DESC_LEN);
199 }
200
201 let tx_des_frame = allocate_zeroed_frame().ok_or("Failed to allocate TX descriptors")?;
202 let tx_des_phys = tx_des_frame.start_address.as_u64();
203 let tx_des = phys_to_virt(tx_des_phys) as *mut u8;
204 unsafe {
205 core::ptr::write_bytes(tx_des, 0, TX_BUFFERS_COUNT * DESC_LEN);
206 }
207
208 let mut device = Self {
209 ports: Mutex::new(ports),
210 rx_buffers,
211 rx_phys,
212 tx_buffers,
213 tx_phys,
214 rx_des,
215 rx_des_phys,
216 tx_des,
217 tx_des_phys,
218 rx_id: AtomicUsize::new(0),
219 tx_id: AtomicUsize::new(0),
220 mac,
221 name,
222 };
223
224 device.init();
225 Ok(device)
226 }
227
228 fn init(&mut self) {
230 let mut ports = self.ports.lock();
231
232 ports.read8(0x18);
233 let _ = ports.read32(0x18);
234
235 let mut csr_58 = ports.read_csr(58);
236 csr_58 &= 0xFF00;
237 csr_58 |= 2;
238 ports.write_csr(58, csr_58);
239
240 let mut bcr_2 = ports.read_bcr(2);
241 bcr_2 |= 2;
242 ports.write_bcr(2, bcr_2);
243
244 for i in 0..RX_BUFFERS_COUNT {
245 self.init_rx_descriptor(i);
246 }
247 for i in 0..TX_BUFFERS_COUNT {
248 self.init_tx_descriptor(i);
249 }
250
251 let init_struct_frame = allocate_zeroed_frame().unwrap();
252 let init_phys = init_struct_frame.start_address.as_u64();
253 let init_virt = phys_to_virt(init_phys) as *mut u8;
254 unsafe {
255 core::ptr::write_bytes(init_virt, 0, 28);
256 }
257
258 unsafe {
259 init_virt.write(0);
260 init_virt.add(1).write(0);
261 init_virt
262 .add(2)
263 .write((log2(RX_BUFFERS_COUNT as u8) as u8) << 4);
264 init_virt
265 .add(3)
266 .write((log2(TX_BUFFERS_COUNT as u8) as u8) << 4);
267
268 init_virt.add(4).write(self.mac[0]);
269 init_virt.add(5).write(self.mac[1]);
270 init_virt.add(6).write(self.mac[2]);
271 init_virt.add(7).write(self.mac[3]);
272 init_virt.add(8).write(self.mac[4]);
273 init_virt.add(9).write(self.mac[5]);
274
275 init_virt.add(20).write((self.rx_des_phys & 0xFF) as u8);
276 init_virt
277 .add(21)
278 .write(((self.rx_des_phys >> 8) & 0xFF) as u8);
279 init_virt
280 .add(22)
281 .write(((self.rx_des_phys >> 16) & 0xFF) as u8);
282 init_virt
283 .add(23)
284 .write(((self.rx_des_phys >> 24) & 0xFF) as u8);
285
286 init_virt.add(24).write((self.tx_des_phys & 0xFFFF) as u8);
287 init_virt
288 .add(25)
289 .write(((self.tx_des_phys >> 8) & 0xFF) as u8);
290 init_virt
291 .add(26)
292 .write(((self.tx_des_phys >> 16) & 0xFF) as u8);
293 init_virt
294 .add(27)
295 .write(((self.tx_des_phys >> 24) & 0xFF) as u8);
296 }
297
298 ports.write_csr(1, (init_phys & 0xFFFF) as u32);
299 ports.write_csr(2, ((init_phys >> 16) & 0xFFFF) as u32);
300
301 let mut csr_0 = ports.read_csr(0);
302 csr_0 |= 1 << CSR0_INIT;
303 ports.write_csr(0, csr_0);
304
305 core::hint::spin_loop();
306
307 let mut csr_0 = ports.read_csr(0);
308 csr_0 |= 1 << CSR0_STRT;
309 ports.write_csr(0, csr_0);
310
311 log::info!(
312 "PCnet: MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
313 self.mac[0],
314 self.mac[1],
315 self.mac[2],
316 self.mac[3],
317 self.mac[4],
318 self.mac[5]
319 );
320 }
321
322 fn init_rx_descriptor(&self, i: usize) {
324 unsafe {
325 let desc = self.rx_des.add(i * DESC_LEN);
326 desc.write_bytes(0, DESC_LEN);
327
328 let buf_addr = self.rx_phys[i];
329 desc.add(0).write((buf_addr & 0xFF) as u8);
330 desc.add(1).write(((buf_addr >> 8) & 0xFF) as u8);
331 desc.add(2).write(((buf_addr >> 16) & 0xFF) as u8);
332 desc.add(3).write(((buf_addr >> 24) & 0xFF) as u8);
333 let bcnt = (!(MTU as u16)).wrapping_add(1) & 0x0FFF;
334 desc.add(4).write((bcnt & 0xFF) as u8);
335 desc.add(5).write(((bcnt >> 8) as u8) | 0xF0);
336 desc.add(7).write(0x80);
337 }
338 }
339
340 fn init_tx_descriptor(&self, i: usize) {
342 unsafe {
343 let desc = self.tx_des.add(i * DESC_LEN);
344 desc.write_bytes(0, DESC_LEN);
345
346 let buf_addr = self.tx_phys[i];
347 desc.add(0).write((buf_addr & 0xFF) as u8);
348 desc.add(1).write(((buf_addr >> 8) & 0xFF) as u8);
349 desc.add(2).write(((buf_addr >> 16) & 0xFF) as u8);
350 desc.add(3).write(((buf_addr >> 24) & 0xFF) as u8);
351 }
352 }
353
354 fn receive_inner(&self) -> Option<Vec<u8>> {
356 let rx_id = self.rx_id.load(Ordering::Relaxed);
357
358 unsafe {
359 let desc = self.rx_des.add(rx_id * DESC_LEN + 7);
360 let status = desc.read_volatile();
361
362 if (status & (1 << DE_OWN)) != 0 {
363 return None;
364 }
365
366 let stp = (status & (1 << DE_STP)) != 0;
367 let enp = (status & (1 << DE_ENP)) != 0;
368
369 if stp && enp {
370 let len_offset = rx_id * DESC_LEN + 8;
371 let len_lo = self.rx_des.add(len_offset).read() as usize;
372 let len_hi = self.rx_des.add(len_offset + 1).read() as usize & 0xF;
373 let len = ((len_hi << 8) | len_lo) & 0xFFF;
374
375 if len <= MTU {
376 let mut buf = Vec::with_capacity(len);
377 core::ptr::copy_nonoverlapping(self.rx_buffers[rx_id], buf.as_mut_ptr(), len);
378 buf.set_len(len);
379
380 let desc = self.rx_des.add(rx_id * DESC_LEN + 7);
381 desc.write_volatile(0x80);
382
383 self.rx_id
384 .store((rx_id + 1) % RX_BUFFERS_COUNT, Ordering::Relaxed);
385 return Some(buf);
386 }
387 }
388
389 let desc = self.rx_des.add(rx_id * DESC_LEN + 7);
390 desc.write_volatile(0x80);
391 self.rx_id
392 .store((rx_id + 1) % RX_BUFFERS_COUNT, Ordering::Relaxed);
393 }
394
395 None
396 }
397
398 fn transmit_inner(&self, data: &[u8]) -> Result<(), NetError> {
400 if data.len() > MTU {
401 return Err(NetError::BufferTooSmall);
402 }
403
404 let tx_id = self.tx_id.load(Ordering::Relaxed);
405
406 unsafe {
407 let desc = self.tx_des.add(tx_id * DESC_LEN + 7);
408 let status = desc.read_volatile();
409
410 if (status & (1 << DE_OWN)) != 0 {
411 let mut timeout = 10000;
412 while (self.tx_des.add(tx_id * DESC_LEN + 7).read_volatile() & (1 << DE_OWN)) != 0 {
413 core::hint::spin_loop();
414 timeout -= 1;
415 if timeout == 0 {
416 return Err(NetError::NotReady);
417 }
418 }
419 }
420
421 core::ptr::copy_nonoverlapping(data.as_ptr(), self.tx_buffers[tx_id], data.len());
422
423 let desc = self.tx_des.add(tx_id * DESC_LEN);
424 let bcnt = (!(data.len() as u16)).wrapping_add(1) & 0x0FFF;
425 desc.add(4).write((bcnt & 0xFF) as u8);
426 desc.add(5).write(((bcnt >> 8) as u8) | 0xF0);
427 desc.add(6).write(0);
428 desc.add(7).write(0x83);
429
430 self.tx_id
431 .store((tx_id + 1) % TX_BUFFERS_COUNT, Ordering::Relaxed);
432
433 let mut ports = self.ports.lock();
434 let mut csr_0 = ports.read_csr(0);
435 csr_0 |= 1 << CSR0_TDMD;
436 ports.write_csr(0, csr_0);
437 }
438
439 Ok(())
440 }
441}
442
443impl NetworkDevice for PcnetDevice {
444 fn name(&self) -> &str {
446 &self.name
447 }
448
449 fn mac_address(&self) -> [u8; 6] {
451 self.mac
452 }
453
454 fn link_up(&self) -> bool {
456 let mut ports = self.ports.lock();
457 let csr_4 = ports.read_csr(4);
458 (csr_4 & 0x20) != 0
459 }
460
461 fn receive(&self, buf: &mut [u8]) -> Result<usize, NetError> {
463 if let Some(packet) = self.receive_inner() {
464 let len = core::cmp::min(packet.len(), buf.len());
465 buf[..len].copy_from_slice(&packet[..len]);
466 Ok(len)
467 } else {
468 Err(NetError::NoPacket)
469 }
470 }
471
472 fn transmit(&self, data: &[u8]) -> Result<(), NetError> {
474 self.transmit_inner(data)
475 }
476}
477
478static PCNET_DEVICES: Mutex<Vec<Arc<PcnetDevice>>> = Mutex::new(Vec::new());
479
480pub fn init() {
482 log::info!("[PCnet] Scanning for PCnet devices...");
483
484 let candidates = pci::probe_all(ProbeCriteria {
485 vendor_id: Some(0x1022),
486 device_id: None,
487 class_code: Some(pci::class::NETWORK),
488 subclass: Some(pci::net_subclass::ETHERNET),
489 prog_if: None,
490 });
491
492 for pci_dev in candidates.into_iter() {
493 if pci_dev.device_id != 0x2000 && pci_dev.device_id != 0x2001 {
494 continue;
495 }
496
497 log::info!(
498 "PCnet: Found device at {:?} (VEN:{:04x} DEV:{:04x})",
499 pci_dev.address,
500 pci_dev.vendor_id,
501 pci_dev.device_id
502 );
503
504 pci_dev.enable_bus_master();
505
506 match unsafe { PcnetDevice::new(pci_dev) } {
507 Ok(device) => {
508 let arc = Arc::new(device);
509 PCNET_DEVICES.lock().push(arc.clone());
510 let _iface = crate::hardware::nic::register_device(arc);
511 }
512 Err(e) => {
513 log::warn!("PCnet: Failed to initialize device: {}", e);
514 }
515 }
516 }
517
518 log::info!("[PCnet] Found {} device(s)", PCNET_DEVICES.lock().len());
519}