Red Bear OS base baseline from 0.1.0 pre-patched archive
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "rtl8139d"
|
||||
description = "Realtek 8139 ethernet driver"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bitflags.workspace = true
|
||||
libredox.workspace = true
|
||||
log.workspace = true
|
||||
redox_event.workspace = true
|
||||
redox_syscall.workspace = true
|
||||
|
||||
common = { path = "../../common" }
|
||||
daemon = { path = "../../../daemon" }
|
||||
driver-network = { path = "../driver-network" }
|
||||
pcid = { path = "../../pcid" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,5 @@
|
||||
[[drivers]]
|
||||
name = "RTL8139 NIC"
|
||||
class = 0x02
|
||||
ids = { 0x10ec = [0x8139] }
|
||||
command = ["rtl8139d"]
|
||||
@@ -0,0 +1,309 @@
|
||||
use std::convert::TryInto;
|
||||
use std::mem;
|
||||
|
||||
use driver_network::NetworkAdapter;
|
||||
use syscall::error::{Error, Result, EIO, EMSGSIZE};
|
||||
|
||||
use common::dma::Dma;
|
||||
use common::io::{Io, Mmio, ReadOnly};
|
||||
use common::timeout::Timeout;
|
||||
|
||||
const RX_BUFFER_SIZE: usize = 64 * 1024;
|
||||
|
||||
const RXSTS_ROK: u16 = 1 << 0;
|
||||
|
||||
const TSD_TOK: u32 = 1 << 15;
|
||||
const TSD_OWN: u32 = 1 << 13;
|
||||
const TSD_SIZE_MASK: u32 = 0x1FFF;
|
||||
|
||||
const CR_RST: u8 = 1 << 4;
|
||||
const CR_RE: u8 = 1 << 3;
|
||||
const CR_TE: u8 = 1 << 2;
|
||||
const CR_BUFE: u8 = 1 << 0;
|
||||
|
||||
const IMR_TOK: u16 = 1 << 2;
|
||||
const IMR_ROK: u16 = 1 << 0;
|
||||
|
||||
const RCR_RBLEN_8K: u32 = 0b00 << 11;
|
||||
const RCR_RBLEN_16K: u32 = 0b01 << 11;
|
||||
const RCR_RBLEN_32K: u32 = 0b10 << 11;
|
||||
const RCR_RBLEN_64K: u32 = 0b11 << 11;
|
||||
const RCR_RBLEN_MASK: u32 = 0b11 << 11;
|
||||
const RCR_AER: u32 = 1 << 5;
|
||||
const RCR_AR: u32 = 1 << 4;
|
||||
const RCR_AB: u32 = 1 << 3;
|
||||
const RCR_AM: u32 = 1 << 2;
|
||||
const RCR_APM: u32 = 1 << 1;
|
||||
const RCR_AAP: u32 = 1 << 0;
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct Regs {
|
||||
mac: [Mmio<u32>; 2],
|
||||
mar: [Mmio<u32>; 2],
|
||||
tsd: [Mmio<u32>; 4],
|
||||
tsad: [Mmio<u32>; 4],
|
||||
rbstart: Mmio<u32>,
|
||||
erbcr: ReadOnly<Mmio<u16>>,
|
||||
ersr: ReadOnly<Mmio<u8>>,
|
||||
cr: Mmio<u8>,
|
||||
capr: Mmio<u16>,
|
||||
cbr: ReadOnly<Mmio<u16>>,
|
||||
imr: Mmio<u16>,
|
||||
isr: Mmio<u16>,
|
||||
tcr: Mmio<u32>,
|
||||
rcr: Mmio<u32>,
|
||||
tctr: Mmio<u32>,
|
||||
mpc: Mmio<u32>,
|
||||
cr_9346: Mmio<u8>,
|
||||
config0: Mmio<u8>,
|
||||
config1: Mmio<u8>,
|
||||
rsvd_53: ReadOnly<Mmio<u8>>,
|
||||
timer_int: Mmio<u32>,
|
||||
msr: Mmio<u8>,
|
||||
config2: Mmio<u8>,
|
||||
config3: Mmio<u8>,
|
||||
rsvd_5b: ReadOnly<Mmio<u8>>,
|
||||
mulint: Mmio<u16>,
|
||||
rerid: ReadOnly<Mmio<u8>>,
|
||||
rsvd_5f: ReadOnly<Mmio<u8>>,
|
||||
tsts: ReadOnly<Mmio<u16>>,
|
||||
_todo: [ReadOnly<Mmio<u8>>; 158],
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
unsafe fn from_base(base: usize) -> &'static mut Self {
|
||||
assert_eq!(mem::size_of::<Regs>(), 256);
|
||||
|
||||
let regs = &mut *(base as *mut Regs);
|
||||
|
||||
assert_eq!(®s.mac[0] as *const _ as usize - base, 0x00);
|
||||
assert_eq!(®s.mac[1] as *const _ as usize - base, 0x04);
|
||||
assert_eq!(®s.mar[0] as *const _ as usize - base, 0x08);
|
||||
assert_eq!(®s.mar[1] as *const _ as usize - base, 0x0C);
|
||||
assert_eq!(®s.tsd[0] as *const _ as usize - base, 0x10);
|
||||
assert_eq!(®s.tsd[1] as *const _ as usize - base, 0x14);
|
||||
assert_eq!(®s.tsd[2] as *const _ as usize - base, 0x18);
|
||||
assert_eq!(®s.tsd[3] as *const _ as usize - base, 0x1C);
|
||||
assert_eq!(®s.tsad[0] as *const _ as usize - base, 0x20);
|
||||
assert_eq!(®s.tsad[1] as *const _ as usize - base, 0x24);
|
||||
assert_eq!(®s.tsad[2] as *const _ as usize - base, 0x28);
|
||||
assert_eq!(®s.tsad[3] as *const _ as usize - base, 0x2C);
|
||||
assert_eq!(®s.rbstart as *const _ as usize - base, 0x30);
|
||||
assert_eq!(®s.erbcr as *const _ as usize - base, 0x34);
|
||||
assert_eq!(®s.ersr as *const _ as usize - base, 0x36);
|
||||
assert_eq!(®s.cr as *const _ as usize - base, 0x37);
|
||||
assert_eq!(®s.capr as *const _ as usize - base, 0x38);
|
||||
assert_eq!(®s.cbr as *const _ as usize - base, 0x3A);
|
||||
assert_eq!(®s.imr as *const _ as usize - base, 0x3C);
|
||||
assert_eq!(®s.isr as *const _ as usize - base, 0x3E);
|
||||
assert_eq!(®s.tcr as *const _ as usize - base, 0x40);
|
||||
assert_eq!(®s.rcr as *const _ as usize - base, 0x44);
|
||||
assert_eq!(®s.tctr as *const _ as usize - base, 0x48);
|
||||
assert_eq!(®s.mpc as *const _ as usize - base, 0x4C);
|
||||
assert_eq!(®s.cr_9346 as *const _ as usize - base, 0x50);
|
||||
assert_eq!(®s.config0 as *const _ as usize - base, 0x51);
|
||||
assert_eq!(®s.config1 as *const _ as usize - base, 0x52);
|
||||
assert_eq!(®s.rsvd_53 as *const _ as usize - base, 0x53);
|
||||
assert_eq!(®s.timer_int as *const _ as usize - base, 0x54);
|
||||
assert_eq!(®s.msr as *const _ as usize - base, 0x58);
|
||||
assert_eq!(®s.config2 as *const _ as usize - base, 0x59);
|
||||
assert_eq!(®s.config3 as *const _ as usize - base, 0x5A);
|
||||
assert_eq!(®s.rsvd_5b as *const _ as usize - base, 0x5B);
|
||||
assert_eq!(®s.mulint as *const _ as usize - base, 0x5C);
|
||||
assert_eq!(®s.rerid as *const _ as usize - base, 0x5E);
|
||||
assert_eq!(®s.rsvd_5f as *const _ as usize - base, 0x5F);
|
||||
assert_eq!(®s.tsts as *const _ as usize - base, 0x60);
|
||||
|
||||
regs
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Rtl8139 {
|
||||
regs: &'static mut Regs,
|
||||
receive_buffer: Dma<[Mmio<u8>; RX_BUFFER_SIZE + 16]>,
|
||||
receive_i: usize,
|
||||
transmit_buffer: [Dma<[Mmio<u8>; 1792]>; 4],
|
||||
transmit_i: usize,
|
||||
mac_address: [u8; 6],
|
||||
}
|
||||
|
||||
impl NetworkAdapter for Rtl8139 {
|
||||
fn mac_address(&mut self) -> [u8; 6] {
|
||||
self.mac_address
|
||||
}
|
||||
|
||||
fn available_for_read(&mut self) -> usize {
|
||||
self.next_read()
|
||||
}
|
||||
|
||||
fn read_packet(&mut self, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
if !self.regs.cr.readf(CR_BUFE) {
|
||||
let rxsts = (self.rx(0) as u16) | (self.rx(1) as u16) << 8;
|
||||
|
||||
let size_with_crc = (self.rx(2) as usize) | (self.rx(3) as usize) << 8;
|
||||
|
||||
let res = if (rxsts & RXSTS_ROK) == RXSTS_ROK {
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < size_with_crc.saturating_sub(4) {
|
||||
buf[i] = self.rx(4 + i as u16);
|
||||
i += 1;
|
||||
}
|
||||
Ok(Some(i))
|
||||
} else {
|
||||
//TODO: better error types
|
||||
log::error!("invalid receive status 0x{:X}", rxsts);
|
||||
Err(Error::new(EIO))
|
||||
};
|
||||
|
||||
self.receive_i =
|
||||
(self.receive_i + 4 + size_with_crc).next_multiple_of(4) % RX_BUFFER_SIZE;
|
||||
let capr = self.receive_i.wrapping_sub(16) as u16;
|
||||
self.regs.capr.write(capr);
|
||||
|
||||
res
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_packet(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
loop {
|
||||
if self.transmit_i >= 4 {
|
||||
self.transmit_i = 0;
|
||||
}
|
||||
|
||||
if self.regs.tsd[self.transmit_i].readf(TSD_OWN) {
|
||||
let data = &mut self.transmit_buffer[self.transmit_i];
|
||||
|
||||
if buf.len() > data.len() {
|
||||
return Err(Error::new(EMSGSIZE));
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < data.len() {
|
||||
data[i].write(buf[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
self.regs.tsad[self.transmit_i].write(data.physical() as u32);
|
||||
assert_eq!(i as u32, i as u32 & TSD_SIZE_MASK);
|
||||
self.regs.tsd[self.transmit_i].write(i as u32 & TSD_SIZE_MASK);
|
||||
|
||||
//TODO: wait for TSD_TOK or error
|
||||
|
||||
self.transmit_i += 1;
|
||||
|
||||
return Ok(i);
|
||||
}
|
||||
|
||||
std::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rtl8139 {
|
||||
pub unsafe fn new(base: usize) -> Result<Self> {
|
||||
let regs = Regs::from_base(base);
|
||||
|
||||
let mut module = Rtl8139 {
|
||||
regs,
|
||||
//TODO: limit to 32-bit
|
||||
receive_buffer: Dma::zeroed().map(|dma| dma.assume_init())?,
|
||||
receive_i: 0,
|
||||
//TODO: limit to 32-bit
|
||||
transmit_buffer: (0..4)
|
||||
.map(|_| Ok(Dma::zeroed()?.assume_init()))
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| unreachable!()),
|
||||
transmit_i: 0,
|
||||
mac_address: [0; 6],
|
||||
};
|
||||
|
||||
module.init()?;
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
pub unsafe fn irq(&mut self) -> bool {
|
||||
// Read and then clear the ISR
|
||||
let isr = self.regs.isr.read();
|
||||
self.regs.isr.write(isr);
|
||||
let imr = self.regs.imr.read();
|
||||
(isr & imr) != 0
|
||||
}
|
||||
|
||||
fn rx(&self, offset: u16) -> u8 {
|
||||
let index = (self.receive_i + offset as usize) % RX_BUFFER_SIZE;
|
||||
self.receive_buffer[index].read()
|
||||
}
|
||||
|
||||
pub fn next_read(&self) -> usize {
|
||||
if !self.regs.cr.readf(CR_BUFE) {
|
||||
let rxsts = (self.rx(0) as u16) | (self.rx(1) as u16) << 8;
|
||||
|
||||
let size_with_crc = (self.rx(2) as usize) | (self.rx(3) as usize) << 8;
|
||||
|
||||
if (rxsts & RXSTS_ROK) == RXSTS_ROK {
|
||||
size_with_crc.saturating_sub(4)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init(&mut self) -> Result<()> {
|
||||
let mac_low = self.regs.mac[0].read();
|
||||
let mac_high = self.regs.mac[1].read();
|
||||
let mac = [
|
||||
mac_low as u8,
|
||||
(mac_low >> 8) as u8,
|
||||
(mac_low >> 16) as u8,
|
||||
(mac_low >> 24) as u8,
|
||||
mac_high as u8,
|
||||
(mac_high >> 8) as u8,
|
||||
];
|
||||
log::debug!(
|
||||
"MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}",
|
||||
mac[0],
|
||||
mac[1],
|
||||
mac[2],
|
||||
mac[3],
|
||||
mac[4],
|
||||
mac[5]
|
||||
);
|
||||
self.mac_address = mac;
|
||||
|
||||
// Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value
|
||||
{
|
||||
log::debug!("Reset");
|
||||
let timeout = Timeout::from_secs(1);
|
||||
self.regs.cr.writef(CR_RST, true);
|
||||
while self.regs.cr.readf(CR_RST) {
|
||||
timeout.run().map_err(|()| Error::new(EIO))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up rx buffer
|
||||
log::debug!("Receive buffer");
|
||||
self.regs
|
||||
.rbstart
|
||||
.write(self.receive_buffer.physical() as u32);
|
||||
|
||||
log::debug!("Interrupt mask");
|
||||
self.regs.imr.write(IMR_TOK | IMR_ROK);
|
||||
|
||||
log::debug!("Receive configuration");
|
||||
self.regs
|
||||
.rcr
|
||||
.write(RCR_RBLEN_64K | RCR_AB | RCR_AM | RCR_APM | RCR_AAP);
|
||||
|
||||
log::debug!("Enable RX and TX");
|
||||
self.regs.cr.writef(CR_RE | CR_TE, true);
|
||||
|
||||
log::debug!("Complete!");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use driver_network::NetworkScheme;
|
||||
use event::{user_data, EventQueue};
|
||||
use pcid_interface::irq_helpers::pci_allocate_interrupt_vector;
|
||||
use pcid_interface::PciFunctionHandle;
|
||||
|
||||
pub mod device;
|
||||
|
||||
use std::ops::{Add, Div, Rem};
|
||||
pub fn div_round_up<T>(a: T, b: T) -> T
|
||||
where
|
||||
T: Add<Output = T> + Div<Output = T> + Rem<Output = T> + PartialEq + From<u8> + Copy,
|
||||
{
|
||||
if a % b != T::from(0u8) {
|
||||
a / b + T::from(1u8)
|
||||
} else {
|
||||
a / b
|
||||
}
|
||||
}
|
||||
|
||||
fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 {
|
||||
let config = pcid_handle.config();
|
||||
|
||||
// RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order
|
||||
for &barnum in &[2, 1] {
|
||||
match config.func.bars[usize::from(barnum)] {
|
||||
pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe {
|
||||
return pcid_handle.map_bar(barnum).ptr.as_ptr();
|
||||
},
|
||||
other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other),
|
||||
}
|
||||
}
|
||||
panic!("rtl8139d: failed to find BAR");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
|
||||
let pci_config = pcid_handle.config();
|
||||
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_rtl8139");
|
||||
|
||||
common::setup_logging(
|
||||
"net",
|
||||
"pci",
|
||||
&name,
|
||||
common::output_level(),
|
||||
common::file_level(),
|
||||
);
|
||||
|
||||
log::info!(" + RTL8139 {}", pci_config.func.display());
|
||||
|
||||
let bar = map_bar(&mut pcid_handle);
|
||||
|
||||
let irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8139d");
|
||||
|
||||
let mut scheme = NetworkScheme::new(
|
||||
move || unsafe {
|
||||
device::Rtl8139::new(bar as usize).expect("rtl8139d: failed to allocate device")
|
||||
},
|
||||
daemon,
|
||||
format!("network.{name}"),
|
||||
);
|
||||
|
||||
user_data! {
|
||||
enum Source {
|
||||
Irq,
|
||||
Scheme,
|
||||
}
|
||||
}
|
||||
|
||||
let event_queue = EventQueue::<Source>::new().expect("rtl8139d: Could not create event queue.");
|
||||
event_queue
|
||||
.subscribe(
|
||||
irq_file.irq_handle().as_raw_fd() as usize,
|
||||
Source::Irq,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
event_queue
|
||||
.subscribe(
|
||||
scheme.event_handle().raw(),
|
||||
Source::Scheme,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace");
|
||||
|
||||
scheme.tick().unwrap();
|
||||
|
||||
for event in event_queue.map(|e| e.expect("rtl8139d: failed to get next event")) {
|
||||
match event.user_data {
|
||||
Source::Irq => {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.irq_handle().read(&mut irq).unwrap();
|
||||
//TODO: This may be causing spurious interrupts
|
||||
if unsafe { scheme.adapter_mut().irq() } {
|
||||
irq_file.irq_handle().write(&mut irq).unwrap();
|
||||
|
||||
scheme.tick().unwrap();
|
||||
}
|
||||
}
|
||||
Source::Scheme => {
|
||||
scheme.tick().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
Reference in New Issue
Block a user