Skip to content

Commit d90db1e

Browse files
committed
Factor out PCI configuration struct
1 parent 7425ddd commit d90db1e

File tree

2 files changed

+115
-60
lines changed

2 files changed

+115
-60
lines changed

rust/src/e1000.rs

+28-15
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::kernel::{ioapicenable, kalloc};
77
use crate::mm::{PhysicalAddress, VirtualAddress, PAGE_SIZE};
88
use crate::net::NetworkDevice;
99
use crate::packet_buffer::PacketBuffer;
10-
use crate::pci;
10+
use crate::pci::PciConfig;
1111

1212
const IRQ_PIC0: u32 = 0xB;
1313

@@ -150,26 +150,38 @@ impl E1000 {
150150

151151
// Enumerate the first four devices on the first PCI bus.
152152
// TODO: Move this out to a more generic PCI `probe` routine.
153-
let mut target_device: Option<u32> = None;
153+
let mut target_device: Option<PciConfig> = None;
154154
for device in 0..4 {
155-
let device_addr: u32 = 0x80000000 | (device << 11);
156-
157-
// Read the vendor and device id of the current device.
158-
let vendor_id = pci::read_vendor_id(device_addr);
159-
let device_id = pci::read_device_id(device_addr);
160-
if vendor_id == VENDOR_ID && device_id == DEVICE_ID {
161-
target_device = Some(device);
162-
break;
163-
}
155+
// Calculate the base address of the current device and load the
156+
// PCI configuration struct for the device at the address.
157+
let base_addr: u32 = 0x80000000 | (device << 11);
158+
let pci_config = match PciConfig::new(base_addr) {
159+
Ok(x) => {
160+
// Check if the device and vendor id match those of an
161+
// E1000 device.
162+
if x.vendor_id() != VENDOR_ID {
163+
continue;
164+
}
165+
if x.device_id() != DEVICE_ID {
166+
continue;
167+
}
168+
169+
// Device is an E1000, stop searching.
170+
target_device = Some(x);
171+
break;
172+
}
173+
Err(_) => continue,
174+
};
164175
}
165176

166177
if target_device.is_none() {
167178
panic!("no network device\n\x00");
168179
}
169180

170-
// Configure the device command register and read the MMIO base register.
171-
pci::set_bus_master(target_device.unwrap());
172-
e1000.mmio_base = pci::read_bar(target_device.unwrap(), 0);
181+
// Configure the device command register and read the first BAR
182+
// register as the MMIO base register.
183+
target_device.as_ref().unwrap().set_bus_master();
184+
e1000.mmio_base = target_device.unwrap().bar(0);
173185

174186
// Read the MAC address.
175187
// TODO: Lock EEPROM.
@@ -356,7 +368,8 @@ impl NetworkDevice for E1000 {
356368
} else if mask & InterruptMask::TXQE as u32 != 0 {
357369
// cprint(b"e1000: tx queue empty\n\x00".as_ptr());
358370
} else if mask & InterruptMask::LSC as u32 != 0 {
359-
// cprint(b"e1000: link status change seq error\n\x00".as_ptr());
371+
// cprint(b"e1000: link status change seq
372+
// error\n\x00".as_ptr());
360373
} else if mask & InterruptMask::RXSEQ as u32 != 0 {
361374
// cprint(b"e1000: rx seq error\n\x00".as_ptr());
362375
} else if mask & InterruptMask::RXDMTO as u32 != 0 {

rust/src/pci.rs

+87-45
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use crate::asm::{in_dw, out_dw};
44
const PCI_CONFIG_ADDR: u16 = 0xCF8;
55
const PCI_CONFIG_DATA: u16 = 0xCFC;
66

7-
/// PCI configuration space header.
7+
/// Represents a PCI configuration space header.
88
pub struct PciConfig {
9+
base_addr: u32,
910
vendor_id: u16,
1011
device_id: u16,
1112
command: u16,
@@ -19,56 +20,97 @@ pub struct PciConfig {
1920
bar: [u32; 6],
2021
}
2122

22-
/// Read a PCI vendor identifier.
23-
pub unsafe fn read_vendor_id(base_addr: u32) -> u16 {
24-
let mut result: u16 = 0x0;
25-
for i in (0..=1).rev() {
26-
out_dw(PCI_CONFIG_ADDR, base_addr | i);
27-
let data = in_dw(PCI_CONFIG_DATA);
28-
result |= (data as u16) << (i * 8);
23+
impl PciConfig {
24+
/// Read a new PciConfig struct from a memory mapped I/O address.
25+
pub fn new(base_addr: u32) -> Result<PciConfig, ()> {
26+
unsafe {
27+
let vendor_id = Self::read_vendor_id(base_addr);
28+
let device_id = Self::read_device_id(base_addr);
29+
let bar_0 = Self::read_bar(base_addr, 0);
30+
31+
Ok(PciConfig {
32+
base_addr: base_addr,
33+
vendor_id: vendor_id,
34+
device_id: device_id,
35+
command: 0,
36+
status: 0,
37+
revision_id: 0,
38+
class_code: [0u8; 3],
39+
cache_line_size: 0,
40+
lat_timer: 0,
41+
header_type: 0,
42+
bist: 0,
43+
bar: [bar_0, 0, 0, 0, 0, 0],
44+
})
45+
}
2946
}
30-
result
31-
}
3247

33-
/// Read a PCI device identifier.
34-
pub unsafe fn read_device_id(base_addr: u32) -> u16 {
35-
let mut result: u16 = 0x0;
36-
let mut j = 1;
37-
for i in (2..=3).rev() {
38-
out_dw(PCI_CONFIG_ADDR, base_addr | i);
39-
let data = in_dw(PCI_CONFIG_DATA);
40-
result |= (data as u16) << (j * 8);
41-
j -= 1;
48+
/// Return the vendor id associated with the device.
49+
pub fn vendor_id(&self) -> u16 {
50+
self.vendor_id
4251
}
43-
result
44-
}
4552

46-
/// Read the `n`th BAR register.
47-
pub unsafe fn read_bar(device: u32, _n: u8) -> u32 {
48-
let mut result: u32 = 0x0;
49-
let mut j = 3;
50-
for i in (16..=19).rev() {
51-
out_dw(PCI_CONFIG_ADDR, (0x80000000 | device << 11) | i);
52-
let data = in_dw(PCI_CONFIG_DATA);
53-
result |= data << (j * 8);
54-
j -= 1;
53+
/// Return the device id associated with the device.
54+
pub fn device_id(&self) -> u16 {
55+
self.device_id
56+
}
57+
58+
/// Return the value of the ith base address register.
59+
pub fn bar(&self, i: u8) -> u32 {
60+
self.bar[i as usize]
5561
}
56-
result
57-
}
5862

59-
/// Setup the device as a bus master.
60-
pub unsafe fn set_bus_master(device: u32) {
61-
let mut command: u32 = 0x0;
62-
let mut j = 1;
63-
for i in (4..=5).rev() {
64-
out_dw(PCI_CONFIG_ADDR, (0x80000000 | device << 11) | i);
65-
let data = in_dw(PCI_CONFIG_DATA);
66-
command |= data << (j * 8);
67-
j -= 1;
63+
/// Set the device as a bus master.
64+
pub unsafe fn set_bus_master(&self) {
65+
let mut command: u32 = 0x0;
66+
let mut j = 1;
67+
for i in (4..=5).rev() {
68+
out_dw(PCI_CONFIG_ADDR, self.base_addr | i);
69+
let data = in_dw(PCI_CONFIG_DATA);
70+
command |= data << (j * 8);
71+
j -= 1;
72+
}
73+
74+
// Set the bus master flag and write back the command register.
75+
command |= 1 << 2;
76+
out_dw(PCI_CONFIG_ADDR, self.base_addr | 4);
77+
out_dw(PCI_CONFIG_DATA, command);
78+
}
79+
80+
/// Read a PCI vendor identifier.
81+
unsafe fn read_vendor_id(base_addr: u32) -> u16 {
82+
let mut result: u16 = 0x0;
83+
for i in (0..=1).rev() {
84+
out_dw(PCI_CONFIG_ADDR, base_addr | i);
85+
let data = in_dw(PCI_CONFIG_DATA);
86+
result |= (data as u16) << (i * 8);
87+
}
88+
result
6889
}
6990

70-
// Set the bus master flag and write back the command register.
71-
command |= 1 << 2;
72-
out_dw(PCI_CONFIG_ADDR, (0x80000000 | device << 11) | 4);
73-
out_dw(PCI_CONFIG_DATA, command);
91+
/// Read a PCI device identifier.
92+
unsafe fn read_device_id(base_addr: u32) -> u16 {
93+
let mut result: u16 = 0x0;
94+
let mut j = 1;
95+
for i in (2..=3).rev() {
96+
out_dw(PCI_CONFIG_ADDR, base_addr | i);
97+
let data = in_dw(PCI_CONFIG_DATA);
98+
result |= (data as u16) << (j * 8);
99+
j -= 1;
100+
}
101+
result
102+
}
103+
104+
/// Read the nth BAR register.
105+
unsafe fn read_bar(base_addr: u32, _n: u32) -> u32 {
106+
let mut result: u32 = 0x0;
107+
let mut j = 3;
108+
for i in (16..=19).rev() {
109+
out_dw(PCI_CONFIG_ADDR, base_addr | i);
110+
let data = in_dw(PCI_CONFIG_DATA);
111+
result |= data << (j * 8);
112+
j -= 1;
113+
}
114+
result
115+
}
74116
}

0 commit comments

Comments
 (0)