Fix RTL8139 driver issues (#483)

* Fix typo in rx buffer size

* Fix issue with small packets tx

* Change tx buffer len

* Fix tx ring overflow

* Use 1024 bytes for max DMA burst size

* Use spin_loop

* Add atomic fence before polling for status change

* Disable interrupts

* Update device capabilities

* Fix http service

* Update /var/www

* Refactor buf len

* Update changelog
This commit is contained in:
Vincent Ollivier 2023-05-05 23:14:42 +02:00 committed by GitHub
parent 1396d7c8d2
commit 7665c11a9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 36 deletions

View File

@ -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)

18
dsk/var/www/index.html Normal file
View File

@ -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>

1
dsk/var/www/moros.css Symbolic link
View File

@ -0,0 +1 @@
../../../www/moros.css

1
dsk/var/www/moros.png Symbolic link
View File

@ -0,0 +1 @@
../../../www/moros.png

View File

@ -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
}

View File

@ -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);
fence(Ordering::SeqCst);
// 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 {}
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] {

View File

@ -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() {

View File

@ -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> {

View File

@ -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