Skip to content

Commit ad14a44

Browse files
e1000: init
Signed-off-by: Andy-Python-Programmer <[email protected]>
1 parent 893b4bc commit ad14a44

File tree

2 files changed

+309
-0
lines changed

2 files changed

+309
-0
lines changed

src/aero_kernel/src/drivers/e1000.rs

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
/*
2+
* Copyright (C) 2021-2023 The Aero Project Developers.
3+
*
4+
* This file is part of The Aero Project.
5+
*
6+
* Aero is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Aero is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
use alloc::sync::Arc;
21+
22+
use crate::drivers::pci::*;
23+
use crate::mem::paging::*;
24+
25+
const TX_DESC_NUM: usize = 32;
26+
const TX_DESC_SIZE: usize = TX_DESC_NUM * core::mem::size_of::<TxDescriptor>();
27+
28+
const RX_QUEUE_SIZE: usize = 32;
29+
30+
#[derive(Copy, Clone, Debug)]
31+
enum Error {
32+
UnknownBar,
33+
NoEeprom,
34+
OutOfMemory,
35+
NotSupported,
36+
}
37+
38+
#[derive(Copy, Clone)]
39+
#[repr(usize)]
40+
enum Register {
41+
Control = 0x00,
42+
Eeprom = 0x14,
43+
44+
TCtrl = 0x400,
45+
/// Lower bits of the 64 bit descriptor base address.
46+
TxDesLo = 0x3800,
47+
/// Upper 32 bits of the 64 bit descriptor base address.
48+
TxDesHi = 0x3804,
49+
/// Descriptor length and must be 128B aligned.
50+
TxDescLen = 0x3808,
51+
/// Head pointer for the transmit descriptor ring.
52+
TxDescHead = 0x3810,
53+
/// Tail pointer for the transmit descriptor ring.
54+
TxDescTail = 0x3818,
55+
/// Controls the IPG (Inter Packet Gap) timer.
56+
Tipg = 0x410,
57+
}
58+
59+
bitflags::bitflags! {
60+
struct ControlFlags: u32 {
61+
const LRST = 1 << 3;
62+
const ASDE = 1 << 5;
63+
const SLU = 1 << 6;
64+
const ILOS = 1 << 7;
65+
const RST = 1 << 26;
66+
const VME = 1 << 30;
67+
const PHY_RST = 1 << 31;
68+
}
69+
}
70+
71+
bitflags::bitflags! {
72+
pub struct TStatus: u8 {
73+
const DD = 1 << 0; // Descriptor Done
74+
const EC = 1 << 1; // Excess Collisions
75+
const LC = 1 << 2; // Late Collision
76+
const TU = 1 << 3; // Transmit Underrun
77+
}
78+
}
79+
80+
bitflags::bitflags! {
81+
pub struct TCtl: u32 {
82+
const EN = 1 << 1; // Transmit Enable
83+
const PSP = 1 << 3; // Pad Short Packets
84+
const SWXOFF = 1 << 22; // Software XOFF Transmission
85+
const RTLC = 1 << 24; // Re-transmit on Late Collision
86+
}
87+
}
88+
89+
impl TCtl {
90+
/// Sets the number of attempts at retransmission prior to giving
91+
/// up on the packet (not including the first transmission attempt).
92+
pub fn set_collision_threshold(&mut self, value: u8) {
93+
self.bits |= (value as u32) << 4;
94+
}
95+
96+
/// Sets the minimum number of byte times which must elapse for
97+
/// proper CSMA/CD operation.
98+
pub fn set_collision_distance(&mut self, value: u8) {
99+
self.bits |= (value as u32) << 12;
100+
}
101+
}
102+
103+
#[repr(C, packed)]
104+
pub struct TxDescriptor {
105+
pub addr: u64,
106+
pub length: u16,
107+
pub cso: u8,
108+
pub cmd: u8,
109+
pub status: TStatus,
110+
pub css: u8,
111+
pub special: u16,
112+
}
113+
114+
struct Eeprom<'a> {
115+
e1000: &'a E1000,
116+
}
117+
118+
impl<'a> Eeprom<'a> {
119+
fn new(e1000: &'a E1000) -> Self {
120+
Self { e1000 }
121+
}
122+
123+
fn read(&self, addr: u8) -> u32 {
124+
self.e1000.write(Register::Eeprom, 1 | ((addr as u32) << 8));
125+
126+
loop {
127+
let res = self.e1000.read(Register::Eeprom);
128+
129+
if res & (1 << 4) > 0 {
130+
return (res >> 16) & 0xffff;
131+
}
132+
}
133+
}
134+
}
135+
136+
struct E1000 {
137+
base: VirtAddr,
138+
}
139+
140+
impl E1000 {
141+
fn new(header: &PciHeader) -> Result<(), Error> {
142+
header.enable_bus_mastering();
143+
header.enable_mmio();
144+
145+
let bar0 = header.get_bar(0).ok_or(Error::UnknownBar)?;
146+
147+
let registers_addr = match bar0 {
148+
Bar::Memory64 { address, .. } => PhysAddr::new(address),
149+
Bar::Memory32 { address, .. } => PhysAddr::new(address as u64),
150+
_ => return Err(Error::UnknownBar),
151+
};
152+
153+
let this = Self {
154+
base: registers_addr.as_hhdm_virt(),
155+
};
156+
157+
this.reset();
158+
159+
if !this.detect_eeprom() {
160+
return Err(Error::NoEeprom);
161+
}
162+
163+
let eeprom = Eeprom::new(&this);
164+
165+
let mut mac = [0u8; 6];
166+
167+
// Get the MAC address
168+
for i in 0..3 {
169+
let x = eeprom.read(i) as u16;
170+
mac[i as usize * 2] = (x & 0xff) as u8;
171+
mac[i as usize * 2 + 1] = (x >> 8) as u8;
172+
}
173+
174+
log::trace!(
175+
"e1000: MAC address {:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
176+
mac[0],
177+
mac[1],
178+
mac[2],
179+
mac[3],
180+
mac[4],
181+
mac[5]
182+
);
183+
184+
this.init_tx()?;
185+
this.init_rx()?;
186+
187+
log::trace!("e1000: successfully initialized");
188+
Ok(())
189+
}
190+
191+
fn init_tx(&self) -> Result<(), Error> {
192+
assert!(core::mem::size_of::<TxDescriptor>() * TX_DESC_NUM < Size4KiB::SIZE as usize);
193+
194+
let frame: PhysFrame<Size4KiB> =
195+
FRAME_ALLOCATOR.allocate_frame().ok_or(Error::OutOfMemory)?;
196+
197+
let addr = frame.start_address().as_hhdm_virt();
198+
let descriptors = addr
199+
.read_mut::<[TxDescriptor; TX_DESC_NUM]>()
200+
.ok_or(Error::NotSupported)?;
201+
202+
for desc in descriptors {
203+
desc.status = TStatus::DD;
204+
}
205+
206+
let phys = frame.start_address();
207+
208+
self.write(Register::TxDesLo, phys.as_u64() as _);
209+
self.write(Register::TxDesHi, (phys.as_u64() >> 32) as _);
210+
self.write(Register::TxDescLen, TX_DESC_SIZE as _);
211+
self.write(Register::TxDescHead, 0);
212+
self.write(Register::TxDescTail, 0);
213+
214+
let mut flags = TCtl::EN | TCtl::PSP | TCtl::RTLC;
215+
flags.set_collision_distance(64);
216+
flags.set_collision_threshold(15);
217+
218+
self.write(Register::TCtrl, flags.bits());
219+
220+
// TODO: Set the default values for the Tx Inter Packet
221+
// Gap Timer.
222+
// self.write(Register::Tipg, 0x??????)
223+
224+
Ok(())
225+
}
226+
227+
fn init_rx(&self) -> Result<(), Error> {
228+
Ok(())
229+
}
230+
231+
fn detect_eeprom(&self) -> bool {
232+
self.write(Register::Eeprom, 1);
233+
234+
for _ in 0..1000 {
235+
let value = self.read(Register::Eeprom);
236+
237+
if value & (1 << 4) > 0 {
238+
return true;
239+
}
240+
}
241+
242+
false
243+
}
244+
245+
fn reset(&self) {
246+
self.insert_flags(Register::Control, ControlFlags::RST.bits());
247+
248+
while ControlFlags::from_bits_truncate(self.read(Register::Control))
249+
.contains(ControlFlags::RST)
250+
{
251+
core::hint::spin_loop();
252+
}
253+
254+
// Do not use VLANs, clear reset and do not invert loss-of-signal.
255+
self.remove_flags(
256+
Register::Control,
257+
(ControlFlags::LRST | ControlFlags::PHY_RST | ControlFlags::VME).bits(),
258+
);
259+
}
260+
261+
fn remove_flags(&self, register: Register, flag: u32) {
262+
self.write(register, self.read(register) & !flag);
263+
}
264+
265+
fn insert_flags(&self, register: Register, flag: u32) {
266+
self.write(register, self.read(register) | flag);
267+
}
268+
269+
fn write(&self, register: Register, value: u32) {
270+
unsafe {
271+
let register = self.base.as_mut_ptr::<u8>().add(register as usize);
272+
core::ptr::write_volatile(register as *mut u32, value);
273+
}
274+
}
275+
276+
fn read(&self, register: Register) -> u32 {
277+
unsafe { self.read_raw(register as u32) }
278+
}
279+
280+
unsafe fn read_raw(&self, register: u32) -> u32 {
281+
let register = self.base.as_ptr::<u8>().add(register as usize);
282+
core::ptr::read_volatile(register as *const u32)
283+
}
284+
}
285+
286+
struct Handler;
287+
288+
impl Handler {
289+
fn new() -> Arc<Self> {
290+
Arc::new(Self {})
291+
}
292+
}
293+
294+
impl PciDeviceHandle for Handler {
295+
fn handles(&self, vendor_id: Vendor, device_id: DeviceType) -> bool {
296+
vendor_id == Vendor::Intel && device_id == DeviceType::EthernetController
297+
}
298+
299+
fn start(&self, header: &PciHeader, _offset_table: &mut OffsetPageTable) {
300+
E1000::new(header).unwrap()
301+
}
302+
}
303+
304+
fn init() {
305+
register_device_driver(Handler::new())
306+
}
307+
308+
crate::module_init!(init, ModuleType::Block);

src/aero_kernel/src/drivers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub mod keyboard;
2828
#[cfg(target_arch = "x86_64")]
2929
pub mod lai;
3030
// FIXME: aarch64 port
31+
pub mod e1000;
3132
pub mod mouse;
3233
#[cfg(target_arch = "x86_64")]
3334
pub mod pci;

0 commit comments

Comments
 (0)