parent
85ae4b1ba1
commit
7a3c66a923
@ -0,0 +1,381 @@
|
|||||||
|
use alloc::alloc::{GlobalAlloc, Layout};
|
||||||
|
use alloc::format;
|
||||||
|
use alloc::prelude::*;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use core::mem::size_of;
|
||||||
|
use core::slice;
|
||||||
|
use core::sync::atomic::{fence, Ordering};
|
||||||
|
|
||||||
|
use crate::arch::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
|
||||||
|
use bitflags::*;
|
||||||
|
use device_tree::util::SliceRead;
|
||||||
|
use device_tree::Node;
|
||||||
|
use log::*;
|
||||||
|
use rcore_memory::paging::PageTable;
|
||||||
|
use rcore_memory::PAGE_SIZE;
|
||||||
|
use smoltcp::phy::{self, DeviceCapabilities};
|
||||||
|
use smoltcp::time::Instant;
|
||||||
|
use smoltcp::wire::EthernetAddress;
|
||||||
|
use smoltcp::Result;
|
||||||
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
|
use crate::arch::cpu;
|
||||||
|
use crate::memory::active_table;
|
||||||
|
use crate::sync::SpinNoIrqLock as Mutex;
|
||||||
|
use crate::HEAP_ALLOCATOR;
|
||||||
|
|
||||||
|
use super::super::{DeviceType, Driver, NetDriver, DRIVERS, NET_DRIVERS};
|
||||||
|
|
||||||
|
pub struct E1000 {
|
||||||
|
header: usize,
|
||||||
|
size: usize,
|
||||||
|
mac: EthernetAddress,
|
||||||
|
send_page: usize,
|
||||||
|
send_buffers: Vec<usize>,
|
||||||
|
recv_page: usize,
|
||||||
|
recv_buffers: Vec<usize>,
|
||||||
|
first_trans: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct E1000Driver(Arc<Mutex<E1000>>);
|
||||||
|
|
||||||
|
impl Driver for E1000Driver {
|
||||||
|
fn try_handle_interrupt(&mut self) -> bool {
|
||||||
|
let driver = self.0.lock();
|
||||||
|
|
||||||
|
// ensure header page is mapped
|
||||||
|
active_table().map_if_not_exists(driver.header, driver.size);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_type(&self) -> DeviceType {
|
||||||
|
DeviceType::Net
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl E1000 {
|
||||||
|
fn transmit_available(&self) -> bool {
|
||||||
|
// TODO map it in all cpu
|
||||||
|
let mut current_addr = self.header;
|
||||||
|
while current_addr < self.header + self.size {
|
||||||
|
active_table().map_if_not_exists(current_addr, current_addr);
|
||||||
|
current_addr = current_addr + PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e1000 = unsafe { slice::from_raw_parts_mut(self.header as *mut Volatile<u32>, self.size / 4) };
|
||||||
|
let send_queue_size = PAGE_SIZE / size_of::<E1000SendDesc>();
|
||||||
|
let mut send_queue =
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.send_page as *mut E1000RecvDesc, send_queue_size) };
|
||||||
|
let mut tdt = e1000[0x3818 / 4].read();
|
||||||
|
let index = (tdt as usize + 1) % send_queue_size;
|
||||||
|
let send_desc = &mut send_queue[index];
|
||||||
|
|
||||||
|
// TODO: fix it
|
||||||
|
return self.first_trans || (*send_desc).status & 1 != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive_available(&self) -> bool {
|
||||||
|
// TODO map it in all cpu
|
||||||
|
let mut current_addr = self.header;
|
||||||
|
while current_addr < self.header + self.size {
|
||||||
|
active_table().map_if_not_exists(current_addr, current_addr);
|
||||||
|
current_addr = current_addr + PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e1000 = unsafe { slice::from_raw_parts_mut(self.header as *mut Volatile<u32>, self.size / 4) };
|
||||||
|
let recv_queue_size = PAGE_SIZE / size_of::<E1000RecvDesc>();
|
||||||
|
let mut recv_queue =
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.recv_page as *mut E1000RecvDesc, recv_queue_size) };
|
||||||
|
let mut rdt = e1000[0x2818 / 4].read();
|
||||||
|
let index = (rdt as usize + 1) % recv_queue_size;
|
||||||
|
let recv_desc = &mut recv_queue[index];
|
||||||
|
return (*recv_desc).status & 1 != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetDriver for E1000Driver {
|
||||||
|
fn get_mac(&self) -> EthernetAddress {
|
||||||
|
self.0.lock().mac
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ifname(&self) -> String {
|
||||||
|
format!("e1000")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
struct E1000SendDesc {
|
||||||
|
addr: u64,
|
||||||
|
len: u16,
|
||||||
|
cso: u8,
|
||||||
|
cmd: u8,
|
||||||
|
status: u8,
|
||||||
|
css: u8,
|
||||||
|
special: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
struct E1000RecvDesc {
|
||||||
|
addr: u64,
|
||||||
|
len: u16,
|
||||||
|
chksum: u16,
|
||||||
|
status: u16,
|
||||||
|
error: u8,
|
||||||
|
special: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct E1000RxToken(E1000Driver);
|
||||||
|
pub struct E1000TxToken(E1000Driver);
|
||||||
|
|
||||||
|
impl<'a> phy::Device<'a> for E1000Driver {
|
||||||
|
type RxToken = E1000RxToken;
|
||||||
|
type TxToken = E1000TxToken;
|
||||||
|
|
||||||
|
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||||
|
let driver = self.0.lock();
|
||||||
|
if driver.transmit_available() && driver.receive_available() {
|
||||||
|
// potential racing
|
||||||
|
Some((E1000RxToken(self.clone()), E1000TxToken(self.clone())))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
||||||
|
let driver = self.0.lock();
|
||||||
|
if driver.transmit_available() {
|
||||||
|
Some(E1000TxToken(self.clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capabilities(&self) -> DeviceCapabilities {
|
||||||
|
let mut caps = DeviceCapabilities::default();
|
||||||
|
caps.max_transmission_unit = 1536;
|
||||||
|
caps.max_burst_size = Some(1);
|
||||||
|
caps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl phy::RxToken for E1000RxToken {
|
||||||
|
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&[u8]) -> Result<R>,
|
||||||
|
{
|
||||||
|
let data = {
|
||||||
|
let mut driver = (self.0).0.lock();
|
||||||
|
let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4) };
|
||||||
|
let recv_queue_size = PAGE_SIZE / size_of::<E1000RecvDesc>();
|
||||||
|
let mut recv_queue =
|
||||||
|
unsafe { slice::from_raw_parts_mut(driver.recv_page as *mut E1000RecvDesc, recv_queue_size) };
|
||||||
|
let mut rdt = e1000[0x2818 / 4].read();
|
||||||
|
let index = (rdt as usize + 1) % recv_queue_size;
|
||||||
|
let recv_desc = &mut recv_queue[index];
|
||||||
|
assert!(recv_desc.status & 1 != 0);
|
||||||
|
let buffer = unsafe { slice::from_raw_parts(driver.recv_buffers[index] as *const u8, recv_desc.len as usize) };
|
||||||
|
|
||||||
|
println!("{:?}", recv_desc);
|
||||||
|
for i in 0..recv_desc.len {
|
||||||
|
print!("{:#X} ", buffer[i as usize]);
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
|
||||||
|
recv_desc.status = recv_desc.status & !1;
|
||||||
|
|
||||||
|
rdt = (rdt + 1) % recv_queue_size as u32;
|
||||||
|
e1000[0x2818 / 4].write(rdt);
|
||||||
|
|
||||||
|
buffer
|
||||||
|
};
|
||||||
|
let result = f(&data);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl phy::TxToken for E1000TxToken {
|
||||||
|
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||||
|
{
|
||||||
|
let mut buffer = [0u8; 2048];
|
||||||
|
let result = f(&mut buffer[..len]);
|
||||||
|
|
||||||
|
let mut driver = (self.0).0.lock();
|
||||||
|
|
||||||
|
let e1000 = unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4) };
|
||||||
|
let send_queue_size = PAGE_SIZE / size_of::<E1000SendDesc>();
|
||||||
|
let mut send_queue =
|
||||||
|
unsafe { slice::from_raw_parts_mut(driver.send_page as *mut E1000SendDesc, send_queue_size) };
|
||||||
|
let mut tdt = e1000[0x3818 / 4].read();
|
||||||
|
|
||||||
|
let index_next = (tdt as usize + 1) % send_queue_size;
|
||||||
|
let send_desc = &mut send_queue[index_next];
|
||||||
|
assert!(driver.first_trans || send_desc.status & 1 != 0);
|
||||||
|
|
||||||
|
let index = (tdt as usize) % send_queue_size;
|
||||||
|
let send_desc = &mut send_queue[index];
|
||||||
|
let target = unsafe { slice::from_raw_parts_mut(driver.send_buffers[index] as *mut u8, len) };
|
||||||
|
target.copy_from_slice(&buffer[..len]);
|
||||||
|
|
||||||
|
println!("len {:?}", len);
|
||||||
|
let buffer_page_pa = active_table().get_entry(driver.send_buffers[index]).unwrap().target();
|
||||||
|
assert_eq!(buffer_page_pa, send_desc.addr as usize);
|
||||||
|
send_desc.len = len as u16 + 4;
|
||||||
|
send_desc.cmd = (1 << 3) | (1 << 0);
|
||||||
|
send_desc.status = 0;
|
||||||
|
|
||||||
|
println!("{:?}", &send_queue[index]);
|
||||||
|
for i in 0..len {
|
||||||
|
print!("{:#X} ", target[i]);
|
||||||
|
}
|
||||||
|
println!("tdh {} tdt {}", e1000[0x3810 / 4].read(), e1000[0x3818 / 4].read());
|
||||||
|
|
||||||
|
fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
tdt = (tdt + 2) % send_queue_size as u32;
|
||||||
|
e1000[0x3818 / 4].write(tdt);
|
||||||
|
|
||||||
|
fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
// round
|
||||||
|
if tdt == 0 {
|
||||||
|
driver.first_trans = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
struct E1000Status : u32 {
|
||||||
|
const FD = 1 << 0;
|
||||||
|
const LU = 1 << 1;
|
||||||
|
const TXOFF = 1 << 4;
|
||||||
|
const TBIMODE = 1 << 5;
|
||||||
|
const SPEED_100M = 1 << 6;
|
||||||
|
const SPEED_1000M = 1 << 7;
|
||||||
|
const ASDV_100M = 1 << 8;
|
||||||
|
const ASDV_1000M = 1 << 9;
|
||||||
|
const MTXCKOK = 1 << 10;
|
||||||
|
const PCI66 = 1 << 11;
|
||||||
|
const BUS64 = 1 << 12;
|
||||||
|
const PCIX_MODE = 1 << 13;
|
||||||
|
const GIO_MASTER_ENABLE = 1 << 19;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JudgeDuck-OS/kern/e1000.c
|
||||||
|
pub fn e1000_init(header: usize, size: usize) {
|
||||||
|
info!("Probing e1000");
|
||||||
|
assert_eq!(size_of::<E1000SendDesc>(), 16);
|
||||||
|
assert_eq!(size_of::<E1000RecvDesc>(), 16);
|
||||||
|
|
||||||
|
let send_page = unsafe {
|
||||||
|
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap())
|
||||||
|
} as usize;
|
||||||
|
let recv_page = unsafe {
|
||||||
|
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap())
|
||||||
|
} as usize;
|
||||||
|
let send_page_pa = active_table().get_entry(send_page).unwrap().target();
|
||||||
|
let recv_page_pa = active_table().get_entry(recv_page).unwrap().target();
|
||||||
|
let send_queue_size = PAGE_SIZE / size_of::<E1000SendDesc>();
|
||||||
|
let recv_queue_size = PAGE_SIZE / size_of::<E1000RecvDesc>();
|
||||||
|
let mut send_queue =
|
||||||
|
unsafe { slice::from_raw_parts_mut(send_page as *mut E1000SendDesc, send_queue_size) };
|
||||||
|
let mut recv_queue =
|
||||||
|
unsafe { slice::from_raw_parts_mut(recv_page as *mut E1000RecvDesc, recv_queue_size) };
|
||||||
|
// randomly generated
|
||||||
|
let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, 0x3C];
|
||||||
|
|
||||||
|
let mut driver = E1000 {
|
||||||
|
header,
|
||||||
|
size,
|
||||||
|
mac: EthernetAddress::from_bytes(&mac),
|
||||||
|
send_page,
|
||||||
|
send_buffers: Vec::with_capacity(send_queue_size),
|
||||||
|
recv_page,
|
||||||
|
recv_buffers: Vec::with_capacity(recv_queue_size),
|
||||||
|
first_trans: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut current_addr = header;
|
||||||
|
while current_addr < header + size {
|
||||||
|
active_table().map_if_not_exists(current_addr, current_addr);
|
||||||
|
current_addr = current_addr + PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e1000 = unsafe { slice::from_raw_parts_mut(header as *mut Volatile<u32>, size / 4) };
|
||||||
|
debug!(
|
||||||
|
"status before setup: {:#?}",
|
||||||
|
E1000Status::from_bits_truncate(e1000[0x8 / 4].read())
|
||||||
|
);
|
||||||
|
|
||||||
|
e1000[0x3800 / 4].write(send_page_pa as u32); // TDBAL
|
||||||
|
e1000[0x3804 / 4].write((send_page_pa >> 32) as u32); // TDBAH
|
||||||
|
e1000[0x3808 / 8].write(PAGE_SIZE as u32); // TDLEN
|
||||||
|
e1000[0x3810 / 4].write(0); // TDH
|
||||||
|
e1000[0x3818 / 4].write(0); // TDT
|
||||||
|
|
||||||
|
for i in 0..send_queue_size {
|
||||||
|
let buffer_page = unsafe {
|
||||||
|
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap())
|
||||||
|
} as usize;
|
||||||
|
let buffer_page_pa = active_table().get_entry(buffer_page).unwrap().target();
|
||||||
|
send_queue[i].addr = buffer_page_pa as u64;
|
||||||
|
driver.send_buffers.push(buffer_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
e1000[0x400 / 4].write((1 << 1) | (1 << 3) | (0x10 << 4) | (0x40 << 12)); // TCTL
|
||||||
|
e1000[0x410 / 4].write(0xa | (0x8 << 10) | (0xc << 20)); // TIPG
|
||||||
|
|
||||||
|
let mut RAL: u32 = 0;
|
||||||
|
let mut RAH: u32 = 0;
|
||||||
|
for i in 0..4 {
|
||||||
|
RAL = RAL | (mac[i] as u32) << (i * 8);
|
||||||
|
}
|
||||||
|
for i in 0..2 {
|
||||||
|
RAH = RAH | (mac[i + 4] as u32) << (i * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
e1000[0x5400 / 4].write(RAL); // RAL
|
||||||
|
e1000[0x5404 / 4].write(RAH | (1 << 31)); // RAH
|
||||||
|
|
||||||
|
// MTA
|
||||||
|
for i in (0x5200 / 4)..(0x5400 / 4) {
|
||||||
|
e1000[i].write(0);
|
||||||
|
}
|
||||||
|
e1000[0xd0 / 4].write(0); // IMS
|
||||||
|
|
||||||
|
e1000[0x2800 / 4].write(recv_page_pa as u32); // RDBAL
|
||||||
|
e1000[0x2804 / 4].write((recv_page_pa >> 32) as u32); // RDBAH
|
||||||
|
e1000[0x2808 / 4].write(PAGE_SIZE as u32); // RDLEN
|
||||||
|
e1000[0x2810 / 4].write(0); // RDH
|
||||||
|
e1000[0x2818 / 4].write((recv_queue_size - 1) as u32); // RDT
|
||||||
|
|
||||||
|
for i in 0..recv_queue_size {
|
||||||
|
let buffer_page = unsafe {
|
||||||
|
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap())
|
||||||
|
} as usize;
|
||||||
|
let buffer_page_pa = active_table().get_entry(buffer_page).unwrap().target();
|
||||||
|
recv_queue[i].addr = buffer_page_pa as u64;
|
||||||
|
driver.recv_buffers.push(buffer_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
e1000[0x100 / 4].write((1 << 1) | (1 << 15) | (3 << 16) | (1 << 25) | (1 << 26)); // RCTL
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"status after setup: {:#?}",
|
||||||
|
E1000Status::from_bits_truncate(e1000[0x8 / 4].read())
|
||||||
|
);
|
||||||
|
|
||||||
|
let net_driver = E1000Driver(Arc::new(Mutex::new(driver)));
|
||||||
|
|
||||||
|
DRIVERS.lock().push(Box::new(net_driver.clone()));
|
||||||
|
NET_DRIVERS.lock().push(Box::new(net_driver));
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub mod virtio_net;
|
pub mod virtio_net;
|
||||||
|
pub mod e1000;
|
Loading…
Reference in new issue