Skip to main content

virtfw_libhw/pci/
mod.rs

1//! pci config space data structures and access functions
2pub mod ecam;
3pub mod x86;
4
5#[cfg(feature = "alloc")]
6pub mod setup;
7
8use bitfield_struct::bitfield;
9use core::fmt;
10use core::ops::Deref;
11
12use crate::size::*;
13
14pub const PCI_CFG_VENDOR: u8 = 0x00;
15pub const PCI_CFG_DEVICE: u8 = 0x02;
16pub const PCI_CFG_COMMAND: u8 = 0x04;
17pub const PCI_CFG_STATUS: u8 = 0x06;
18pub const PCI_CFG_REVISION: u8 = 0x08;
19pub const PCI_CFG_CLASS_PROG: u8 = 0x09;
20pub const PCI_CFG_CLASS_DEVICE: u8 = 0x0a;
21pub const PCI_CFG_CACHE_LINE_SIZE: u8 = 0x0c;
22pub const PCI_CFG_LATENCY_TIMER: u8 = 0x0d;
23pub const PCI_CFG_HEADER_TYPE: u8 = 0x0e;
24pub const PCI_CFG_BIST: u8 = 0x0f;
25
26// pci bridge
27pub const PCI_CFG_PRIMARY_BUS: u8 = 0x18;
28pub const PCI_CFG_SECONDARY_BUS: u8 = 0x19;
29pub const PCI_CFG_SUBORDINATE_BUS: u8 = 0x1a;
30pub const PCI_CFG_IO_BASE: u8 = 0x1c;
31pub const PCI_CFG_IO_LIMIT: u8 = 0x1d;
32pub const PCI_CFG_MEM_BASE: u8 = 0x20;
33pub const PCI_CFG_MEM_LIMIT: u8 = 0x22;
34pub const PCI_CFG_PREFMEM_BASE: u8 = 0x24;
35pub const PCI_CFG_PREFMEM_LIMIT: u8 = 0x26;
36pub const PCI_CFG_PREFMEM_BASE_U32: u8 = 0x28;
37pub const PCI_CFG_PREFMEM_LIMIT_U32: u8 = 0x2c;
38pub const PCI_CFG_BRIDGE_CTRL: u8 = 0x3e;
39
40pub const PCI_CFG_SUB_VENDOR: u8 = 0x2c;
41pub const PCI_CFG_SUB_DEVICE: u8 = 0x2e;
42
43#[bitfield(u16)]
44pub struct PciCommand {
45    pub io: bool,
46    pub memory: bool,
47    pub master: bool,
48    pub special: bool,
49    pub invalidate: bool,
50    pub vga_palette: bool,
51    pub parity: bool,
52    pub wait: bool,
53    pub serr: bool,
54    pub fast_back: bool,
55    pub intx_disable: bool,
56    #[bits(5)]
57    _pad: u8,
58}
59
60impl fmt::Display for PciCommand {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        write!(
63            f,
64            "io{} memory{} master{} special{} inval{} vga-snoop{} parity{} wait{} serr{} fast-back{} no-intx{}",
65            if self.io() { "+" } else { "-" },
66            if self.memory() { "+" } else { "-" },
67            if self.master() { "+" } else { "-" },
68            if self.special() { "+" } else { "-" },
69            if self.invalidate() { "+" } else { "-" },
70            if self.vga_palette() { "+" } else { "-" },
71            if self.parity() { "+" } else { "-" },
72            if self.wait() { "+" } else { "-" },
73            if self.serr() { "+" } else { "-" },
74            if self.fast_back() { "+" } else { "-" },
75            if self.intx_disable() { "+" } else { "-" },
76        )
77    }
78}
79
80#[bitfield(u8)]
81pub struct PciHeaderType {
82    #[bits(7)]
83    pub value: u8,
84    pub mfd: bool,
85}
86
87#[bitfield(u8)]
88pub struct PciBridgeCtrl {
89    pub parity: bool,
90    pub serr: bool,
91    pub isa: bool,
92    pub vga: bool,
93    _pad: bool,
94    pub master_abort: bool,
95    pub bus_reset: bool,
96    pub fast_back: bool,
97}
98
99impl fmt::Display for PciBridgeCtrl {
100    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101        write!(
102            f,
103            "parity{} serr{} isa{} vga{} abort{} bus-reset{} fast-back{}",
104            if self.parity() { "+" } else { "-" },
105            if self.serr() { "+" } else { "-" },
106            if self.isa() { "+" } else { "-" },
107            if self.vga() { "+" } else { "-" },
108            if self.master_abort() { "+" } else { "-" },
109            if self.bus_reset() { "+" } else { "-" },
110            if self.fast_back() { "+" } else { "-" },
111        )
112    }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub enum PciAddrKind {
117    Io,
118    Mem32,
119    Mem64,
120}
121
122#[derive(Debug, Clone)]
123pub struct PciAddrRange {
124    pub kind: PciAddrKind,
125    pub prefetchable: bool,
126    pub base: u64,
127    pub size: u64,
128}
129
130impl PciAddrRange {
131    pub fn new_sized(kind: PciAddrKind, size: u64) -> Self {
132        Self {
133            kind,
134            prefetchable: (kind == PciAddrKind::Mem64),
135            base: 0,
136            size,
137        }
138    }
139
140    pub fn new_empty(kind: PciAddrKind) -> Self {
141        Self::new_sized(kind, 0)
142    }
143
144    pub fn name(&self) -> &'static str {
145        match (&self.kind, &self.prefetchable) {
146            (PciAddrKind::Io, _) => "io",
147            (PciAddrKind::Mem32, false) => "mem32",
148            (PciAddrKind::Mem32, true) => "prefmem32",
149            (PciAddrKind::Mem64, false) => "mem64",
150            (PciAddrKind::Mem64, true) => "prefmem64",
151        }
152    }
153
154    pub fn limit(&self) -> u64 {
155        self.base + self.size - 1
156    }
157}
158
159impl fmt::Display for PciAddrRange {
160    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161        let (v, u) = pretty_usize(self.size as usize);
162        if self.base > 0 {
163            write!(
164                f,
165                "{}: {:x}-{:x} [size {v}{u}]",
166                self.name(),
167                self.base,
168                self.limit()
169            )
170        } else {
171            write!(f, "{}: <unmapped> [size {v}{u}]", self.name())
172        }
173    }
174}
175
176#[derive(Debug, Clone)]
177pub struct PciDevAddr {
178    pub bus: u8,
179    pub slot: u8,
180    pub func: u8,
181}
182
183impl fmt::Display for PciDevAddr {
184    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185        write!(f, "{:02x}:{:02x}.{:x}", self.bus, self.slot, self.func)
186    }
187}
188
189pub struct PciDevice {
190    pub addr: PciDevAddr,
191    pub vendor: u16,
192    pub device: u16,
193    pub class: u16,
194}
195
196impl Deref for PciDevice {
197    type Target = PciDevAddr;
198
199    fn deref(&self) -> &Self::Target {
200        &self.addr
201    }
202}
203
204impl fmt::Display for PciDevice {
205    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206        write!(
207            f,
208            "{}  {:04x}:{:04x}  [{:04x} {}]  {}",
209            self.addr,
210            self.vendor,
211            self.device,
212            self.class,
213            self.class_name(),
214            self.device_name(),
215        )
216    }
217}
218
219impl PciDevice {
220    pub fn device_name(&self) -> &str {
221        match (self.vendor, self.device) {
222            // 'pc' machine type
223            (0x8086, 0x1237) => "intel i440fx",
224            (0x8086, 0x7000) => "intel piix4 lpc",
225            (0x8086, 0x7010) => "intel piix4 ide",
226            (0x8086, 0x7020) => "intel piix4 uhci",
227            (0x8086, 0x7113) => "intel piix4 acpi",
228
229            // 'q35' machine type
230            (0x8086, 0x29c0) => "intel q35",
231            (0x8086, 0x2918) => "intel ich9 lpc",
232            (0x8086, 0x2922) => "intel ich9 ahci",
233            (0x8086, 0x2930) => "intel ich9 smbus",
234
235            (0x8086, 0x2934) => "intel ich9 uhci1",
236            (0x8086, 0x2935) => "intel ich9 uhci2",
237            (0x8086, 0x2936) => "intel ich9 uhci3",
238            (0x8086, 0x293a) => "intel ich9 ehci",
239
240            // intel device
241            (0x8086, 0x100e) => "intel e1000",
242            (0x8086, 0x10d3) => "intel e1000e",
243            (0x8086, _) => "intel unknown",
244
245            // virtio devices (vendor 0x1af4)
246            (0x1af4, 0x1000) => "virtio net",
247            (0x1af4, 0x1001) => "virtio blk",
248            (0x1af4, 0x1003) => "virtio console",
249            (0x1af4, 0x1004) => "virtio scsi",
250            (0x1af4, 0x1005) => "virtio rng",
251            (0x1af4, 0x1012) => "virtio vsock",
252
253            (0x1af4, 0x1041) => "virtio net 1.0",
254            (0x1af4, 0x1042) => "virtio blk 1.0",
255            (0x1af4, 0x1043) => "virtio console 1.0",
256            (0x1af4, 0x1044) => "virtio rng 1.0",
257            (0x1af4, 0x1048) => "virtio scsi 1.0",
258            (0x1af4, 0x1050) => "virtio gpu",
259            (0x1af4, 0x1052) => "virtio input",
260            (0x1af4, 0x1053) => "virtio vsock 1.0",
261
262            (0x1af4, _) => "virtio unknown",
263
264            // qemu devices (vendor 0x1b36)
265            (0x1b36, 0x0001) => "qemu pci-pci bridge",
266            (0x1b36, 0x0007) => "qemu sdhci",
267            (0x1b36, 0x0008) => "qemu pcie host bridge",
268            (0x1b36, 0x000c) => "qemu pcie root port",
269            (0x1b36, 0x000d) => "qemu xhci",
270            (0x1b36, 0x000e) => "qemu pcie-pci bridge",
271            (0x1b36, 0x0010) => "qemu nvme",
272            (0x1b36, _) => "qemu unknown",
273
274            // qemu devices (other)
275            (0x1234, 0x1111) => "qemu stdvga",
276
277            // catch all
278            (_, _) => "unknown",
279        }
280    }
281
282    pub fn class_name(&self) -> &str {
283        match self.class {
284            0x0100 => "scsi",
285            0x0101 => "ide",
286            0x0105 => "ata",
287            0x0106 => "sata",
288            0x0180 => "storage",
289
290            0x0200 => "ethernet",
291            0x0280 => "network",
292
293            0x0300 => "vga",
294            0x0380 => "display",
295
296            0x0600 => "host bridge",
297            0x0601 => "isa bridge",
298            0x0604 => "pci bridge",
299
300            0x0c03 => "usb",
301            0x0c05 => "smbus",
302
303            _ => "unknown",
304        }
305    }
306}
307
308pub trait PciHost {
309    fn readl(&self, dev: &PciDevAddr, addr: u8) -> u32;
310    fn readw(&self, dev: &PciDevAddr, addr: u8) -> u16;
311    fn readb(&self, dev: &PciDevAddr, addr: u8) -> u8;
312
313    fn writel(&self, dev: &PciDevAddr, addr: u8, value: u32);
314    fn writew(&self, dev: &PciDevAddr, addr: u8, value: u16);
315    fn writeb(&self, dev: &PciDevAddr, addr: u8, value: u8);
316
317    fn try_device(&self, bus: u8, slot: u8, func: u8) -> Option<PciDevice> {
318        let addr = PciDevAddr { bus, slot, func };
319        let vendor = self.readw(&addr, PCI_CFG_VENDOR);
320        if (vendor == 0x0000) || (vendor == 0xffff) {
321            return None;
322        }
323        let device = self.readw(&addr, PCI_CFG_DEVICE);
324        let class = self.readw(&addr, PCI_CFG_CLASS_DEVICE);
325        let pcidev = PciDevice {
326            addr,
327            vendor,
328            device,
329            class,
330        };
331        Some(pcidev)
332    }
333
334    fn command(&self, addr: &PciDevAddr) -> PciCommand {
335        PciCommand::from(self.readw(addr, PCI_CFG_COMMAND))
336    }
337
338    fn revision(&self, addr: &PciDevAddr) -> u8 {
339        self.readb(addr, PCI_CFG_DEVICE)
340    }
341
342    fn header_type(&self, addr: &PciDevAddr) -> PciHeaderType {
343        PciHeaderType::from(self.readb(addr, PCI_CFG_HEADER_TYPE))
344    }
345
346    fn is_vga(&self, dev: &PciDevice) -> bool {
347        dev.class == 0x0300
348    }
349
350    fn is_mfd(&self, dev: &PciDevice) -> bool {
351        let h = self.header_type(dev);
352        h.mfd()
353    }
354
355    fn is_device(&self, dev: &PciDevice) -> bool {
356        if self.header_type(dev).value() != 0 {
357            return false;
358        }
359        true
360    }
361
362    fn read_bar(&self, addr: &PciDevAddr, nr: u8) -> u32 {
363        let offset = 0x10 + nr * 4;
364        self.readl(addr, offset)
365    }
366
367    fn write_bar(&self, addr: &PciDevAddr, nr: u8, value: u32) {
368        let offset = 0x10 + nr * 4;
369        self.writel(addr, offset, value);
370    }
371
372    fn bar(&self, addr: &PciDevAddr, nr: u8) -> Option<PciAddrRange> {
373        if nr > 5 {
374            return None;
375        }
376        let mut base = self.read_bar(addr, nr) as u64;
377        if nr > 0 {
378            let prevbase = self.read_bar(addr, nr - 1);
379            if (prevbase & 6) == 4 {
380                // previous bar is 64-bit
381                return None;
382            }
383        }
384
385        self.write_bar(addr, nr, !0);
386        let mut size = self.read_bar(addr, nr) as u64;
387        self.write_bar(addr, nr, base as u32);
388
389        if base == 0 && size == 0 {
390            None
391        } else if (base & 1) == 1 {
392            // io
393            base &= !0x03;
394            size &= !0x03;
395            size = !size & 0xffffffff;
396            Some(PciAddrRange {
397                kind: PciAddrKind::Io,
398                prefetchable: false,
399                base,
400                size: size + 1,
401            })
402        } else if (base & 6) == 0 {
403            // 32 bit mem
404            let prefetchable = (base & 0x08) != 0;
405            base &= !0x0f;
406            size &= !0x0f;
407            size = !size & 0xffffffff;
408            Some(PciAddrRange {
409                kind: PciAddrKind::Mem32,
410                prefetchable,
411                base,
412                size: size + 1,
413            })
414        } else if (base & 6) == 4 {
415            // 64 bit mem
416            let prefetchable = (base & 0x08) != 0;
417            base &= !0x0f;
418            size &= !0x0f;
419
420            let nextbase = self.read_bar(addr, nr + 1) as u64;
421            self.write_bar(addr, nr + 1, !0);
422            let nextsize = self.read_bar(addr, nr + 1) as u64;
423            self.write_bar(addr, nr + 1, nextbase as u32);
424
425            base += nextbase << 32;
426            size += nextsize << 32;
427            size = !size;
428
429            Some(PciAddrRange {
430                kind: PciAddrKind::Mem64,
431                prefetchable,
432                base,
433                size: size + 1,
434            })
435        } else {
436            None
437        }
438    }
439
440    fn is_pci_bridge(&self, dev: &PciDevice) -> bool {
441        if dev.class != 0x0604 {
442            return false;
443        }
444        if self.header_type(dev).value() != 1 {
445            return false;
446        }
447        true
448    }
449
450    fn bridge_ctl(&self, addr: &PciDevAddr) -> PciBridgeCtrl {
451        PciBridgeCtrl::from(self.readb(addr, PCI_CFG_BRIDGE_CTRL))
452    }
453
454    fn bridge_primary(&self, addr: &PciDevAddr) -> u8 {
455        self.readb(addr, PCI_CFG_PRIMARY_BUS)
456    }
457
458    fn bridge_secondary(&self, addr: &PciDevAddr) -> u8 {
459        self.readb(addr, PCI_CFG_SECONDARY_BUS)
460    }
461
462    fn bridge_subordinate(&self, addr: &PciDevAddr) -> u8 {
463        self.readb(addr, PCI_CFG_SUBORDINATE_BUS)
464    }
465
466    fn bridge_io(&self, addr: &PciDevAddr) -> Option<PciAddrRange> {
467        let basereg = self.readb(addr, PCI_CFG_IO_BASE) as u64;
468        let limitreg = self.readb(addr, PCI_CFG_IO_LIMIT) as u64;
469        if limitreg != 0 {
470            let base = (basereg & 0xf0) << 8;
471            let limit = ((limitreg & 0xf0) << 8) + 0xfff;
472            Some(PciAddrRange {
473                kind: PciAddrKind::Io,
474                prefetchable: false,
475                base,
476                size: limit - base + 1,
477            })
478        } else {
479            None
480        }
481    }
482
483    fn bridge_mem(&self, addr: &PciDevAddr) -> Option<PciAddrRange> {
484        let basereg = self.readw(addr, PCI_CFG_MEM_BASE) as u64;
485        let limitreg = self.readw(addr, PCI_CFG_MEM_LIMIT) as u64;
486        if limitreg != 0 {
487            let base = (basereg & 0xfff0) << 16;
488            let limit = ((limitreg & 0xfff0) << 16) + 0xfffff;
489            Some(PciAddrRange {
490                kind: PciAddrKind::Mem32,
491                prefetchable: false,
492                base,
493                size: limit - base + 1,
494            })
495        } else {
496            None
497        }
498    }
499
500    fn bridge_prefmem(&self, addr: &PciDevAddr) -> Option<PciAddrRange> {
501        let basereg = self.readw(addr, PCI_CFG_PREFMEM_BASE) as u64;
502        let limitreg = self.readw(addr, PCI_CFG_PREFMEM_LIMIT) as u64;
503        let basereg_u32 = self.readl(addr, PCI_CFG_PREFMEM_BASE_U32) as u64;
504        let limitreg_u32 = self.readl(addr, PCI_CFG_PREFMEM_LIMIT_U32) as u64;
505
506        let mut base = (basereg & 0xfff0) << 16;
507        let mut limit = (limitreg & 0xfff0) << 16;
508        base |= basereg_u32 << 32;
509        limit |= limitreg_u32 << 32;
510
511        if limit != 0 {
512            limit += 0xfffff;
513            Some(PciAddrRange {
514                kind: PciAddrKind::Mem64,
515                prefetchable: true,
516                base,
517                size: limit - base + 1,
518            })
519        } else {
520            None
521        }
522    }
523
524    fn set_bridge_primary(&self, addr: &PciDevAddr, nr: u8) {
525        self.writeb(addr, PCI_CFG_PRIMARY_BUS, nr)
526    }
527
528    fn set_bridge_secondary(&self, addr: &PciDevAddr, nr: u8) {
529        self.writeb(addr, PCI_CFG_SECONDARY_BUS, nr)
530    }
531
532    fn set_bridge_subordinate(&self, addr: &PciDevAddr, nr: u8) {
533        self.writeb(addr, PCI_CFG_SUBORDINATE_BUS, nr)
534    }
535
536    fn set_bridge_io(&self, addr: &PciDevAddr, range: &PciAddrRange) {
537        let basereg = (range.base >> 8) & 0xf0;
538        let limitreg = (range.limit() >> 8) & 0xf0;
539        self.writeb(addr, PCI_CFG_IO_BASE, basereg as u8);
540        self.writeb(addr, PCI_CFG_IO_LIMIT, limitreg as u8);
541    }
542
543    fn set_bridge_mem(&self, addr: &PciDevAddr, range: &PciAddrRange) {
544        let basereg = (range.base >> 16) & 0xfff0;
545        let limitreg = (range.limit() >> 16) & 0xfff0;
546        self.writew(addr, PCI_CFG_MEM_BASE, basereg as u16);
547        self.writew(addr, PCI_CFG_MEM_LIMIT, limitreg as u16);
548    }
549
550    fn set_bridge_prefmem(&self, addr: &PciDevAddr, range: &PciAddrRange) {
551        let base = range.base >> 16;
552        let limit = range.limit() >> 16;
553        self.writew(addr, PCI_CFG_PREFMEM_BASE, (base & 0xffff) as u16);
554        self.writew(addr, PCI_CFG_PREFMEM_LIMIT, (limit & 0xffff) as u16);
555        self.writel(addr, PCI_CFG_PREFMEM_BASE_U32, (base >> 16) as u32);
556        self.writel(addr, PCI_CFG_PREFMEM_LIMIT_U32, (limit >> 16) as u32);
557    }
558
559    fn set_bar(&self, addr: &PciDevAddr, nr: u8, range: &PciAddrRange) {
560        match range.kind {
561            PciAddrKind::Io => {
562                let value = (range.base & 0xfffc) | 1;
563                self.write_bar(addr, nr, value as u32);
564            }
565            PciAddrKind::Mem32 => {
566                let value = range.base & 0xffff_fff0;
567                self.write_bar(addr, nr, value as u32);
568            }
569            PciAddrKind::Mem64 => {
570                let value_lo = (range.base & 0xffff_fff0) | 4;
571                let value_hi = range.base >> 32;
572                self.write_bar(addr, nr, value_lo as u32);
573                self.write_bar(addr, nr + 1, value_hi as u32);
574            }
575        }
576    }
577}
578
579pub fn pci_foreach_device<F>(pcihost: &dyn PciHost, bus: u8, mut function: F)
580where
581    F: FnMut(&PciDevice),
582{
583    for slot in 0..32 {
584        for func in 0..8 {
585            if let Some(dev) = pcihost.try_device(bus, slot, func) {
586                function(&dev);
587                if func == 0 && !pcihost.is_mfd(&dev) {
588                    break;
589                }
590            }
591        }
592    }
593}