kernel/devices/
pci.rs

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 until we find a valid device
71        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        // make sure first we are reading the intended header type
340        if header_type & 0x7F != 0x00 {
341            return None;
342        }
343        // standard header
344        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                // IO
355                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                // Memory
368                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                        // 32-bit
380                        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                        // 64-bit
392                        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                        // store it in the two bars
403                        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
465// Some extra args for probing
466// this is used since some PCI devices might produce multiple devices
467// so we use this to select which one to probe and store them individually
468// so that its easier to interact with them
469pub 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}