Repository: vinc/moros (language: rust)

Issue:
Fix `RTL8139` network driver on physical hardware



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf067d6b..4cd21b36 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,12 @@
 # Changelog
 
 ## Unreleased
+- Fix RTL8139 driver issues (#483)
+- Improve help system (#481)
+- Refactor lisp functions (#478)
+- Improve asm binaries (#482)
+- Add light palette (#480)
+- Fix invalid bytes from serial (#479)
 - Refactor lisp functions (#478)
 - Improve asm binaries (#482)
 - Add light palette (#480)
diff --git a/dsk/var/www/index.html b/dsk/var/www/index.html
new file mode 100644
index 00000000..b0862bc4
--- /dev/null
+++ b/dsk/var/www/index.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>MOROS: Obscure Rust Operating System</title>
+    <link rel="stylesheet" type="text/css" href="moros.css">
+  </head>
+  <body>
+    <h1>MOROS: Obscure Rust Operating System</h1>
+
+    <p><img src="moros.png" alt="screenshot"></p>
+
+    <p>MOROS is a hobby operating system written in Rust by <a href="https://vinc.cc">Vincent Ollivier</a>.</p>
+
+    <p>It targets computers with a x86-64 architecture and a BIOS, so mostly from 2005
+to 2020, but it also runs well on most emulators (Bochs, QEMU, and VirtualBox).</p>
+  </body>
+</html>
diff --git a/dsk/var/www/moros.css b/dsk/var/www/moros.css
new file mode 120000
index 00000000..50c6c28c
--- /dev/null
+++ b/dsk/var/www/moros.css
@@ -0,0 +1,1 @@
+../../../www/moros.css
\ No newline at end of file
diff --git a/dsk/var/www/moros.png b/dsk/var/www/moros.png
new file mode 120000
index 00000000..2dc35f00
--- /dev/null
+++ b/dsk/var/www/moros.png
@@ -0,0 +1,1 @@
+../../../www/moros.png
\ No newline at end of file
diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs
index 4fff322d..78d0369c 100644
--- a/src/sys/net/mod.rs
+++ b/src/sys/net/mod.rs
@@ -79,7 +79,7 @@ impl<'a> smoltcp::phy::Device<'a> for EthernetDevice {
     fn capabilities(&self) -> DeviceCapabilities {
         let mut caps = DeviceCapabilities::default();
         caps.max_transmission_unit = 1500;
-        caps.max_burst_size = Some(1);
+        caps.max_burst_size = Some(64);
         caps
     }
 
diff --git a/src/sys/net/rtl8139.rs b/src/sys/net/rtl8139.rs
index 1fcfb72e..a71a0772 100644
--- a/src/sys/net/rtl8139.rs
+++ b/src/sys/net/rtl8139.rs
@@ -4,7 +4,8 @@ use crate::sys::net::{EthernetDeviceIO, Config, Stats};
 use alloc::sync::Arc;
 use alloc::vec::Vec;
 use core::convert::TryInto;
-use core::sync::atomic::{AtomicUsize, Ordering};
+use core::hint::spin_loop;
+use core::sync::atomic::{fence, AtomicUsize, Ordering};
 use smoltcp::wire::EthernetAddress;
 use x86_64::instructions::port::Port;
 
@@ -14,18 +15,18 @@ use x86_64::instructions::port::Port;
 // 11 = 64K + 16 bytes
 const RX_BUFFER_IDX: usize = 0;
 
-const MTU: usize = 1500;
+const MTU: usize = 1536;
 
 const RX_BUFFER_PAD: usize = 16;
-const RX_BUFFER_LEN: usize = (8129 << RX_BUFFER_IDX) + RX_BUFFER_PAD;
+const RX_BUFFER_LEN: usize = 8192 << RX_BUFFER_IDX;
 
-const TX_BUFFER_LEN: usize = 4096;
+const TX_BUFFER_LEN: usize = 2048;
 const TX_BUFFERS_COUNT: usize = 4;
 const ROK: u16 = 0x01;
 
-const CR_RST: u8 = 1 << 4; // Reset
-const CR_RE: u8 = 1 << 3; // Receiver Enable
-const CR_TE: u8 = 1 << 2; // Transmitter Enable
+const CR_RST:  u8 = 1 << 4; // Reset
+const CR_RE:   u8 = 1 << 3; // Receiver Enable
+const CR_TE:   u8 = 1 << 2; // Transmitter Enable
 const CR_BUFE: u8 = 1 << 0; // Buffer Empty
 
 // Rx Buffer Length
@@ -37,10 +38,10 @@ const RCR_RBLEN: u32 = (RX_BUFFER_IDX << 11) as u32;
 // of the buffer. So the buffer must have an additionnal 1500 bytes.
 const RCR_WRAP: u32 = 1 << 7;
 
-const RCR_AB: u32 = 1 << 3; // Accept Broadcast packets
-const RCR_AM: u32 = 1 << 2; // Accept Multicast packets
-const RCR_APM: u32 = 1 << 1; // Accept Physical Match packets
-const RCR_AAP: u32 = 1 << 0; // Accept All Packets
+const RCR_AB:   u32 = 1 << 3; // Accept Broadcast packets
+const RCR_AM:   u32 = 1 << 2; // Accept Multicast packets
+const RCR_APM:  u32 = 1 << 1; // Accept Physical Match packets
+const RCR_AAP:  u32 = 1 << 0; // Accept All Packets
 
 // Interframe Gap Time
 const TCR_IFG: u32 = 3 << 24;
@@ -78,7 +79,7 @@ pub struct Ports {
     pub config1: Port<u8>,                       // Configuration Register 1 (CONFIG1)
     pub rx_addr: Port<u32>,                      // Receive (Rx) Buffer Start Address (RBSTART)
     pub capr: Port<u16>,                         // Current Address of Packet Read (CAPR)
-    pub cbr: Port<u16>,                          // Current Buffer Address (CBR)
+    pub cba: Port<u16>,                          // Current Buffer Address (CBA)
     pub cmd: Port<u8>,                           // Command Register (CR)
     pub imr: Port<u16>,                          // Interrupt Mask Register (IMR)
     pub isr: Port<u16>,                          // Interrupt Status Register (ISR)
@@ -112,7 +113,7 @@ impl Ports {
             config1: Port::new(io_base + 0x52),
             rx_addr: Port::new(io_base + 0x30),
             capr: Port::new(io_base + 0x38),
-            cbr: Port::new(io_base + 0x3A),
+            cba: Port::new(io_base + 0x3A),
             cmd: Port::new(io_base + 0x37),
             imr: Port::new(io_base + 0x3C),
             isr: Port::new(io_base + 0x3E),
@@ -155,7 +156,7 @@ impl Device {
             ports: Ports::new(io_base),
 
             // Add MTU to RX_BUFFER_LEN if RCR_WRAP is set
-            rx_buffer: PhysBuf::new(RX_BUFFER_LEN + MTU),
+            rx_buffer: PhysBuf::new(RX_BUFFER_LEN + RX_BUFFER_PAD + MTU),
 
             rx_offset: 0,
             tx_buffers: [(); TX_BUFFERS_COUNT].map(|_| PhysBuf::new(TX_BUFFER_LEN)),
@@ -175,9 +176,15 @@ impl Device {
         // Software reset
         unsafe {
             self.ports.cmd.write(CR_RST);
-            while self.ports.cmd.read() & CR_RST != 0 {}
+            fence(Ordering::SeqCst);
+            while self.ports.cmd.read() & CR_RST != 0 {
+                spin_loop();
+            }
         }
 
+        // Set interrupts
+        //unsafe { self.ports.imr.write(IMR_TOK | IMR_ROK) }
+
         // Enable Receive and Transmitter
         unsafe { self.ports.cmd.write(CR_RE | CR_TE) }
 
@@ -198,14 +205,11 @@ impl Device {
             unsafe { self.ports.tx_addrs[i].write(tx_addr as u32) }
         }
 
-        // Set interrupts
-        unsafe { self.ports.imr.write(IMR_TOK | IMR_ROK) }
-
         // Configure receive buffer (RCR)
         unsafe { self.ports.rx_config.write(RCR_RBLEN | RCR_WRAP | RCR_AB | RCR_AM | RCR_APM | RCR_AAP) }
 
         // Configure transmit buffer (TCR)
-        unsafe { self.ports.tx_config.write(TCR_IFG | TCR_MXDMA0 | TCR_MXDMA1 | TCR_MXDMA2); }
+        unsafe { self.ports.tx_config.write(TCR_IFG | TCR_MXDMA1 | TCR_MXDMA2); }
     }
 }
 
@@ -230,14 +234,13 @@ impl EthernetDeviceIO for Device {
         }
 
         //let isr = unsafe { self.ports.isr.read() };
-        let capr = unsafe { self.ports.capr.read() };
-        let cbr = unsafe { self.ports.cbr.read() };
+        let cba = unsafe { self.ports.cba.read() };
         // CAPR starts at 65520 and with the pad it overflows to 0
+        let capr = unsafe { self.ports.capr.read() };
         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 header & ROK != ROK {
-            unsafe { self.ports.capr.write(cbr) };
+            unsafe { self.ports.capr.write((((cba as usize) % RX_BUFFER_LEN) - RX_BUFFER_PAD) as u16) };
             return None;
         }
 
@@ -247,9 +250,10 @@ impl EthernetDeviceIO for Device {
         // Update buffer read pointer
         self.rx_offset = (offset + n + 4 + 3) & !3;
         unsafe {
-            self.ports.capr.write((self.rx_offset - RX_BUFFER_PAD) as u16);
+            self.ports.capr.write(((self.rx_offset % RX_BUFFER_LEN) - RX_BUFFER_PAD) as u16);
         }
 
+        //unsafe { self.ports.isr.write(0x1); }
         Some(self.rx_buffer[(offset + 4)..(offset + n)].to_vec())
     }
 
@@ -257,6 +261,9 @@ impl EthernetDeviceIO for Device {
         let tx_id = self.tx_id.load(Ordering::SeqCst);
         let mut cmd_port = self.ports.tx_cmds[tx_id].clone();
         unsafe {
+            // RTL8139 will not transmit packets smaller than 64 bits
+            let len = len.max(60); // 60 + 4 bits of CRC
+
             // Fill in Transmit Status: the size of this packet, the early
             // transmit threshold, and clear OWN bit in TSD (this starts the
             // PCI operation).
@@ -265,12 +272,16 @@ impl EthernetDeviceIO for Device {
             // transmit threshold means 8 bytes. So we just write the size of
             // the packet.
             cmd_port.write(0x1FFF & len as u32);
-
-            // 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 {}
+            fence(Ordering::SeqCst);
+
+            while cmd_port.read() & OWN != OWN {
+                spin_loop();
+            }
+            while cmd_port.read() & TOK != TOK {
+                spin_loop();
+            }
         }
+        //unsafe { self.ports.isr.write(0x4); }
     }
 
     fn next_tx_buffer(&mut self, len: usize) -> &mut [u8] {
diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs
index 4e03c721..75c00a16 100644
--- a/src/usr/httpd.rs
+++ b/src/usr/httpd.rs
@@ -210,10 +210,11 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
         println!("{}HTTP Server listening on 0.0.0.0:{}{}", csi_color, port, csi_reset);
 
         let mtu = iface.device().capabilities().max_transmission_unit;
+        let buf_len = mtu - 14 - 20 - 20; // ETH+TCP+IP headers
         let mut connections = Vec::new();
         for _ in 0..MAX_CONNECTIONS {
-            let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; mtu]);
-            let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; mtu]);
+            let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; buf_len]);
+            let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; buf_len]);
             let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
             let tcp_handle = iface.add_socket(tcp_socket);
             let send_queue: VecDeque<Vec<u8>> = VecDeque::new();
@@ -339,12 +340,13 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
                         }
                         (buffer.len(), res)
                     }).unwrap();
-                    for chunk in res.buf.chunks(mtu) {
+                    for chunk in res.buf.chunks(buf_len) {
                         send_queue.push_back(chunk.to_vec());
                     }
                     if socket.can_send() {
                         if let Some(chunk) = send_queue.pop_front() {
-                            socket.send_slice(&chunk).unwrap();
+                            let sent = socket.send_slice(&chunk).expect("Could not send chunk");
+                            debug_assert!(sent == chunk.len());
                         }
                     }
                     if send_queue.is_empty() && !res.is_persistent() {
diff --git a/src/usr/install.rs b/src/usr/install.rs
index fa1adeb7..6d445453 100644
--- a/src/usr/install.rs
+++ b/src/usr/install.rs
@@ -82,8 +82,9 @@ pub fn copy_files(verbose: bool) {
     copy_file("/tmp/beep/mario.sh", include_bytes!("../../dsk/tmp/beep/mario.sh"), verbose);
 
     create_dir("/var/www", verbose);
-    copy_file("/var/www/index.html", include_bytes!("../../www/index.html"), verbose);
-    copy_file("/var/www/moros.png", include_bytes!("../../www/moros.png"), verbose);
+    copy_file("/var/www/index.html", include_bytes!("../../dsk/var/www/index.html"), verbose);
+    copy_file("/var/www/moros.png", include_bytes!("../../dsk/var/www/moros.png"), verbose);
+    copy_file("/var/www/moros.css", include_bytes!("../../dsk/var/www/moros.css"), verbose);
 }
 
 pub fn main(args: &[&str]) -> Result<(), ExitCode> {
diff --git a/www/build.sh b/www/build.sh
index e67d2127..e8f3ca81 100644
--- a/www/build.sh
+++ b/www/build.sh
@@ -14,7 +14,7 @@ for md in ../doc/*.md; do
   <head>
     <meta charset="utf-8">
     <title>$title</title>
-    <link rel="stylesheet" type="text/css" href="/moros.css">
+    <link rel="stylesheet" type="text/css" href="moros.css">
   </head>
   <body>
 EOF


Test patch: