1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
use alloc::vec::Vec;
use x86_64::instructions::port::Port;
const CONFIG_ADDRESS: u16 = 0xCF8;
const CONFIG_DATA: u16 = 0xCFC;
#[derive(Debug, Clone, Copy)]
pub struct PciDevice {
pub bus: u8,
pub device: u8,
pub function: u8,
pub vendor_id: u16,
pub device_id: u16,
pub class: u8,
pub subclass: u8,
}
pub fn read_config(bus: u8, device: u8, function: u8, offset: u8) -> u32 {
let address = 1u32 << 31 | (bus as u32) << 16
| (device as u32) << 11
| (function as u32) << 8
| (offset as u32 & 0xfc);
unsafe {
Port::<u32>::new(CONFIG_ADDRESS).write(address);
Port::<u32>::new(CONFIG_DATA).read()
}
}
pub fn write_config(bus: u8, device: u8, function: u8, offset: u8, value: u32) {
let address = 1u32 << 31 | (bus as u32) << 16 | (device as u32) << 11 | (function as u32) << 8 | (offset as u32 & 0xfc);
unsafe {
Port::<u32>::new(CONFIG_ADDRESS).write(address);
Port::<u32>::new(CONFIG_DATA).write(value);
}
}
impl PciDevice {
fn read(&self, offset: u8) -> u32 {
read_config(self.bus, self.device, self.function, offset)
}
pub fn bar(&self, n: u8) -> u32 {
self.read(0x10 + 4 * n)
}
pub fn interrupt_line(&self) -> u8 {
read_config(self.bus, self.device, self.function, 0x3c) as u8
}
pub fn enable_io_and_bus_master(&self) {
let command = self.read(0x04);
write_config(self.bus, self.device, self.function, 0x04, command | 0b101);
}
pub fn class_name(&self) -> &'static str {
match (self.class, self.subclass) {
(0x01, 0x01) => "IDE controller",
(0x01, 0x00) => "SCSI storage (virtio-blk)",
(0x01, 0x06) => "SATA controller",
(0x01, _) => "storage controller",
(0x02, _) => "network controller",
(0x03, _) => "display controller",
(0x06, 0x00) => "host bridge",
(0x06, 0x01) => "ISA bridge",
(0x06, 0x80) => "bridge (other)",
(0x06, _) => "bridge",
(0x0c, 0x03) => "USB controller",
_ => "other",
}
}
}
fn probe(bus: u8, device: u8, function: u8) -> Option<PciDevice> {
let id = read_config(bus, device, function, 0x00);
let vendor_id = id as u16;
if vendor_id == 0xffff {
return None; }
let class = read_config(bus, device, function, 0x08);
Some(PciDevice {
bus,
device,
function,
vendor_id,
device_id: (id >> 16) as u16,
class: (class >> 24) as u8,
subclass: (class >> 16) as u8,
})
}
pub fn scan() -> Vec<PciDevice> {
let mut found = Vec::new();
for bus in 0..=255u8 {
for device in 0..32u8 {
let Some(first) = probe(bus, device, 0) else { continue };
found.push(first);
let header_type = (read_config(bus, device, 0, 0x0c) >> 16) as u8;
if header_type & 0x80 != 0 {
found.extend((1..8).filter_map(|f| probe(bus, device, f)));
}
}
}
found
}
|