1use core::fmt;
2
3use crate::cpu::{self, IoPortInt};
4
5fn read_pci_config<T: IoPortInt>(bus: u8, dev: u8, func: u8, offset: u8) -> T {
6 let address = 0x80000000
7 | ((bus as u32) << 16)
8 | ((dev as u32) << 11)
9 | ((func as u32) << 8)
10 | (offset as u32);
11 unsafe {
12 cpu::io_out(0xCF8, address);
13 cpu::io_in(0xCFC)
14 }
15}
16
17fn write_pci_config<T: IoPortInt>(bus: u8, dev: u8, func: u8, offset: u8, value: T) {
18 let address = 0x80000000
19 | ((bus as u32) << 16)
20 | ((dev as u32) << 11)
21 | ((func as u32) << 8)
22 | (offset as u32);
23 unsafe {
24 cpu::io_out(0xCF8, address);
25 cpu::io_out(0xCFC, value);
26 }
27}
28
29#[allow(dead_code)]
30pub mod reg {
31 pub const VENDOR_ID: u8 = 0x00;
32 pub const DEVICE_ID: u8 = 0x02;
33 pub const COMMAND: u8 = 0x04;
34 pub const STATUS: u8 = 0x06;
35 pub const CLASS_DWORD: u8 = 0x08;
36 pub const HEADER_TYPE: u8 = 0x0E;
37 pub const BAR0: u8 = 0x10;
38 pub const BAR1: u8 = 0x14;
39 pub const BAR2: u8 = 0x18;
40 pub const BAR3: u8 = 0x1C;
41 pub const BAR4: u8 = 0x20;
42 pub const BAR5: u8 = 0x24;
43 pub const SUBSYSTEM_VENDOR_ID: u8 = 0x2C;
44 pub const SUBSYSTEM_ID: u8 = 0x2E;
45 pub const CAPABILITIES_PTR: u8 = 0x34;
46 pub const INTERRUPT_LINE: u8 = 0x3C;
47 pub const INTERRUPT_PIN: u8 = 0x3D;
48}
49
50pub struct PciDeviceProbeIterator {
51 bus: u8,
52 dev: u8,
53 func: u8,
54}
55
56impl PciDeviceProbeIterator {
57 pub fn new() -> PciDeviceProbeIterator {
58 PciDeviceProbeIterator {
59 bus: 0,
60 dev: 0,
61 func: 0,
62 }
63 }
64}
65
66impl Iterator for PciDeviceProbeIterator {
67 type Item = PciDeviceConfig;
68
69 fn next(&mut self) -> Option<Self::Item> {
70 loop {
72 while self.dev < 32 {
73 while self.func < 8 {
74 let config = PciDeviceConfig::probe(self.bus, self.dev, self.func);
75 self.func += 1;
76 if config.is_some() {
77 return config;
78 }
79 }
80 self.func = 0;
81 self.dev += 1;
82 }
83 self.dev = 0;
84 let (bus, overflow) = self.bus.overflowing_add(1);
85 if overflow {
86 break;
87 }
88 self.bus = bus;
89 }
90
91 None
92 }
93}
94
95#[repr(u8)]
96#[derive(Debug, Clone)]
97pub enum PciDeviceType {
98 Unclassified(u8, u8, u8),
99 MassStorageController(u8, u8, u8),
100 NetworkController(u8, u8, u8),
101 DisplayController(u8, u8, u8),
102 MultimediaController(u8, u8, u8),
103 MemoryController(u8, u8, u8),
104 BridgeDevice(u8, u8, u8),
105 SimpleCommunicationController(u8, u8, u8),
106 BaseSystemPeripheral(u8, u8, u8),
107 InputDeviceController(u8, u8, u8),
108 DockingStation(u8, u8, u8),
109 Processor(u8, u8, u8),
110 SerialBusController(u8, u8, u8),
111 WirelessController(u8, u8, u8),
112 IntelligentController(u8, u8, u8),
113 SatelliteCommunicationController(u8, u8, u8),
114 EncryptionController(u8, u8, u8),
115 SignalProcessingController(u8, u8, u8),
116 ProcessingAccelerator(u8, u8, u8),
117 NonEssentialInstrumentation(u8, u8, u8),
118 CoProcessor(u8, u8, u8),
119 Reserved(u8, u8, u8, u8),
120 Unassigned(u8, u8, u8),
121}
122
123impl PciDeviceType {
124 pub fn new(class_dword: u32) -> Self {
125 let class_id = (class_dword >> 24) as u8;
126 let subclass_id = ((class_dword >> 16) & 0xFF) as u8;
127 let prog_if = ((class_dword >> 8) & 0xFF) as u8;
128 let revision_id = (class_dword & 0xFF) as u8;
129
130 match class_id {
131 0x00 => Self::Unclassified(subclass_id, prog_if, revision_id),
132 0x01 => Self::MassStorageController(subclass_id, prog_if, revision_id),
133 0x02 => Self::NetworkController(subclass_id, prog_if, revision_id),
134 0x03 => Self::DisplayController(subclass_id, prog_if, revision_id),
135 0x04 => Self::MultimediaController(subclass_id, prog_if, revision_id),
136 0x05 => Self::MemoryController(subclass_id, prog_if, revision_id),
137 0x06 => Self::BridgeDevice(subclass_id, prog_if, revision_id),
138 0x07 => Self::SimpleCommunicationController(subclass_id, prog_if, revision_id),
139 0x08 => Self::BaseSystemPeripheral(subclass_id, prog_if, revision_id),
140 0x09 => Self::InputDeviceController(subclass_id, prog_if, revision_id),
141 0x0A => Self::DockingStation(subclass_id, prog_if, revision_id),
142 0x0B => Self::Processor(subclass_id, prog_if, revision_id),
143 0x0C => Self::SerialBusController(subclass_id, prog_if, revision_id),
144 0x0D => Self::WirelessController(subclass_id, prog_if, revision_id),
145 0x0E => Self::IntelligentController(subclass_id, prog_if, revision_id),
146 0x0F => Self::SatelliteCommunicationController(subclass_id, prog_if, revision_id),
147 0x10 => Self::EncryptionController(subclass_id, prog_if, revision_id),
148 0x11 => Self::SignalProcessingController(subclass_id, prog_if, revision_id),
149 0x12 => Self::ProcessingAccelerator(subclass_id, prog_if, revision_id),
150 0x13 => Self::NonEssentialInstrumentation(subclass_id, prog_if, revision_id),
151 0x14..=0x3F => Self::Reserved(class_id, subclass_id, prog_if, revision_id),
152 0x40 => Self::CoProcessor(subclass_id, prog_if, revision_id),
153 0x41..=0xFE => Self::Reserved(class_id, subclass_id, prog_if, revision_id),
154 0xFF => Self::Unassigned(subclass_id, prog_if, revision_id),
155 }
156 }
157}
158
159impl fmt::Display for PciDeviceType {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
161 match self {
162 Self::Reserved(class, subclass, prog, rev) => {
163 write!(
164 f,
165 "Reserved({class:02X}.{subclass:02X}.{prog:02X}.{rev:02X})"
166 )
167 }
168 Self::Unassigned(subclass, prog, rev) => {
169 write!(f, "Unassigned({subclass:02X}.{prog:02X}.{rev:02X})")
170 }
171 Self::Unclassified(subclass, prog, rev) => {
172 write!(f, "Unclassified({subclass:02X}.{prog:02X}.{rev:02X})")
173 }
174 Self::MassStorageController(subclass, prog, rev) => {
175 write!(
176 f,
177 "MassStorageController({subclass:02X}.{prog:02X}.{rev:02X})"
178 )
179 }
180 Self::NetworkController(subclass, prog, rev) => {
181 write!(f, "NetworkController({subclass:02X}.{prog:02X}.{rev:02X})")
182 }
183 Self::DisplayController(subclass, prog, rev) => {
184 write!(f, "DisplayController({subclass:02X}.{prog:02X}.{rev:02X})")
185 }
186 Self::MultimediaController(subclass, prog, rev) => {
187 write!(
188 f,
189 "MultimediaController({subclass:02X}.{prog:02X}.{rev:02X})"
190 )
191 }
192 Self::MemoryController(subclass, prog, rev) => {
193 write!(f, "MemoryController({subclass:02X}.{prog:02X}.{rev:02X})")
194 }
195 Self::BridgeDevice(subclass, prog, rev) => {
196 write!(f, "BridgeDevice({subclass:02X}.{prog:02X}.{rev:02X})")
197 }
198 Self::SimpleCommunicationController(subclass, prog, rev) => {
199 write!(
200 f,
201 "SimpleCommunicationController({subclass:02X}.{prog:02X}.{rev:02X})"
202 )
203 }
204 Self::BaseSystemPeripheral(subclass, prog, rev) => {
205 write!(
206 f,
207 "BaseSystemPeripheral({subclass:02X}.{prog:02X}.{rev:02X})"
208 )
209 }
210 Self::InputDeviceController(subclass, prog, rev) => {
211 write!(
212 f,
213 "InputDeviceController({subclass:02X}.{prog:02X}.{rev:02X})"
214 )
215 }
216 Self::DockingStation(subclass, prog, rev) => {
217 write!(f, "DockingStation({subclass:02X}.{prog:02X}.{rev:02X})")
218 }
219 Self::Processor(subclass, prog, rev) => {
220 write!(f, "Processor({subclass:02X}.{prog:02X}.{rev:02X})")
221 }
222 Self::SerialBusController(subclass, prog, rev) => {
223 write!(
224 f,
225 "SerialBusController({subclass:02X}.{prog:02X}.{rev:02X})"
226 )
227 }
228
229 Self::WirelessController(subclass, prog, rev) => {
230 write!(f, "WirelessController({subclass:02X}.{prog:02X}.{rev:02X})")
231 }
232 Self::IntelligentController(subclass, prog, rev) => {
233 write!(
234 f,
235 "IntelligentController({subclass:02X}.{prog:02X}.{rev:02X})"
236 )
237 }
238 Self::SatelliteCommunicationController(subclass, prog, rev) => {
239 write!(
240 f,
241 "SatelliteCommunicationController({subclass:02X}.{prog:02X}.{rev:02X})"
242 )
243 }
244 Self::EncryptionController(subclass, prog, rev) => {
245 write!(
246 f,
247 "EncryptionController({subclass:02X}.{prog:02X}.{rev:02X})"
248 )
249 }
250 Self::SignalProcessingController(subclass, prog, rev) => {
251 write!(
252 f,
253 "SignalProcessingController({subclass:02X}.{prog:02X}.{rev:02X})"
254 )
255 }
256 Self::ProcessingAccelerator(subclass, prog, rev) => {
257 write!(
258 f,
259 "ProcessingAccelerator({subclass:02X}.{prog:02X}.{rev:02X})"
260 )
261 }
262 Self::NonEssentialInstrumentation(subclass, prog, rev) => {
263 write!(
264 f,
265 "NonEssentialInstrumentation({subclass:02X}.{prog:02X}.{rev:02X})"
266 )
267 }
268 Self::CoProcessor(subclass, prog, rev) => {
269 write!(f, "CoProcessor({subclass:02X}.{prog:02X}.{rev:02X})")
270 }
271 }
272 }
273}
274
275#[allow(dead_code)]
276#[derive(Debug, Clone, Copy)]
277pub enum PciBar {
278 Memory {
279 addr: usize,
280 size: usize,
281 prefetchable: bool,
282 },
283 Io {
284 addr: u16,
285 size: usize,
286 },
287 None,
288}
289
290#[allow(dead_code)]
291impl PciBar {
292 pub fn get_io(&self) -> Option<(u16, usize)> {
293 match self {
294 Self::Io { addr, size } => Some((*addr, *size)),
295 _ => None,
296 }
297 }
298
299 pub fn get_memory(&self) -> Option<(usize, usize, bool)> {
300 match self {
301 Self::Memory {
302 addr,
303 size,
304 prefetchable,
305 } => Some((*addr, *size, *prefetchable)),
306 _ => None,
307 }
308 }
309}
310
311#[allow(dead_code)]
312#[derive(Debug, Clone)]
313pub struct PciDeviceConfig {
314 pub(super) bus: u8,
315 pub(super) dev: u8,
316 pub(super) func: u8,
317 pub(super) vendor_id: u16,
318 pub(super) device_id: u16,
319 pub(super) device_type: PciDeviceType,
320 pub(super) header_type: u8,
321 pub(super) base_address: [PciBar; 6],
322 pub(super) interrupt_line: u8,
323 pub(super) interrupt_pin: u8,
324 pub(super) capabilities_ptr: Option<u8>,
325}
326
327impl PciDeviceConfig {
328 pub fn probe(bus: u8, dev: u8, func: u8) -> Option<PciDeviceConfig> {
329 let vendor_id = read_pci_config(bus, dev, func, reg::VENDOR_ID);
330 if vendor_id == 0xFFFF {
331 return None;
332 }
333 let device_id = read_pci_config(bus, dev, func, reg::DEVICE_ID);
334
335 let class_dword = read_pci_config(bus, dev, func, reg::CLASS_DWORD);
336 let device_type = PciDeviceType::new(class_dword);
337
338 let header_type = read_pci_config(bus, dev, func, reg::HEADER_TYPE);
339 if header_type & 0x7F != 0x00 {
341 return None;
342 }
343 let mut base_address = [PciBar::None; 6];
345 let mut i = 0;
346 while i < 6 {
347 let bar_v = read_pci_config::<u32>(bus, dev, func, reg::BAR0 + i * 4);
348 if bar_v == 0 {
349 i += 1;
350 continue;
351 }
352
353 if bar_v & 1 == 1 {
354 let old_bar = bar_v & 0xFFFF_FFFC;
356
357 write_pci_config(bus, dev, func, reg::BAR0 + i * 4, 0xFFFF_FFFCu32);
358 let bar = read_pci_config::<u32>(bus, dev, func, reg::BAR0 + i * 4);
359 write_pci_config(bus, dev, func, reg::BAR0 + i * 4, old_bar);
360 let size = (!(bar & 0xFFFF_FFFC) + 1) as usize;
361
362 base_address[i as usize] = PciBar::Io {
363 addr: old_bar as u16,
364 size,
365 };
366 } else {
367 let old_bar = bar_v & 0xFFFF_FFF0;
369
370 write_pci_config(bus, dev, func, reg::BAR0 + i * 4, 0xFFFF_FFF0u32);
371 let bar = read_pci_config::<u32>(bus, dev, func, reg::BAR0 + i * 4);
372 write_pci_config(bus, dev, func, reg::BAR0 + i * 4, old_bar);
373 let size = (!(bar & 0xFFFF_FFF0) + 1) as usize;
374
375 let prefetchable = (bar_v & 0x8) == 0x8;
376 let ty = (bar_v & 0x6) >> 1;
377 match ty {
378 0x0 => {
379 base_address[i as usize] = PciBar::Memory {
381 addr: old_bar as usize,
382 size,
383 prefetchable,
384 }
385 }
386 0x2 => {
387 if cfg!(target_pointer_width = "32") {
388 panic!("64-bit bar on 32-bit system");
389 }
390
391 assert!(i < 5);
393 let bar_2 = read_pci_config::<u32>(bus, dev, func, reg::BAR0 + (i + 1) * 4);
394 i += 1;
395
396 let whole_bar = (bar_2 as usize) << 32 | (old_bar as usize);
397 base_address[i as usize] = PciBar::Memory {
398 addr: whole_bar,
399 size,
400 prefetchable,
401 };
402 base_address[(i - 1) as usize] = base_address[i as usize];
404 }
405 _ => panic!("Reserved bar memory type {ty}, BAR{i}=0x{bar_v:08X}"),
406 };
407 }
408 i += 1;
409 }
410 let interrupt_info = read_pci_config::<u16>(bus, dev, func, reg::INTERRUPT_LINE);
411 let interrupt_line = interrupt_info as u8;
412 let interrupt_pin = (interrupt_info >> 8) as u8;
413
414 let capabilities_ptr = read_pci_config(bus, dev, func, reg::CAPABILITIES_PTR);
415 let capabilities_ptr = if capabilities_ptr == 0 {
416 None
417 } else {
418 Some(capabilities_ptr)
419 };
420
421 Some(PciDeviceConfig {
422 bus,
423 dev,
424 func,
425 vendor_id,
426 device_id,
427 device_type,
428 header_type,
429 base_address,
430 interrupt_line,
431 interrupt_pin,
432 capabilities_ptr,
433 })
434 }
435
436 pub fn read_config<T: IoPortInt>(&self, offset: u8) -> T {
437 read_pci_config(self.bus, self.dev, self.func, offset)
438 }
439
440 pub fn write_config<T: IoPortInt>(&self, offset: u8, value: T) {
441 write_pci_config(self.bus, self.dev, self.func, offset, value);
442 }
443
444 #[allow(dead_code)]
445 pub fn write_command(&self, value: u16) {
446 self.write_config(reg::COMMAND, value);
447 }
448
449 #[allow(dead_code)]
450 pub fn read_command(&self) -> u16 {
451 self.read_config(reg::COMMAND)
452 }
453
454 #[allow(dead_code)]
455 pub fn write_status(&self, value: u16) {
456 self.write_config(reg::STATUS, value);
457 }
458
459 #[allow(dead_code)]
460 pub fn read_status(&self) -> u16 {
461 self.read_config(reg::STATUS)
462 }
463}
464
465pub struct ProbeExtra {
470 pub args: [u64; 4],
471}
472
473pub trait PciDevice {
474 fn probe_init(config: &PciDeviceConfig, extra: ProbeExtra) -> Option<Self>
475 where
476 Self: Sized;
477 #[allow(dead_code)]
478 fn device_name(&self) -> &'static str;
479}