1pub 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
26pub 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 (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 (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 (0x8086, 0x100e) => "intel e1000",
242 (0x8086, 0x10d3) => "intel e1000e",
243 (0x8086, _) => "intel unknown",
244
245 (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 (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 (0x1234, 0x1111) => "qemu stdvga",
276
277 (_, _) => "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 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 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 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 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}