pci_x86/
cfg.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2025.
4
5//! Constants and helpers for working with the PCI configuration space.
6
7use x86::registers::io;
8
9use crate::bdf::Bdf;
10
11/// PCI configuration address I/O port
12const CONFIG_ADDRESS: u16 = 0x0CF8;
13
14/// PCI configuration data I/O port
15const CONFIG_DATA: u16 = 0x0CFC;
16
17/// Reads a 32-bit value from the PCI configuration space.
18#[inline]
19pub fn read32(bdf: Bdf, offset: u16) -> u32 {
20    unsafe {
21        io::outl(CONFIG_ADDRESS, bdf.cfg_addr(offset));
22        io::inl(CONFIG_DATA)
23    }
24}
25
26/// Writes a 32-bit value to the PCI configuration space.
27#[inline]
28pub fn write32(bdf: Bdf, offset: u16, value: u32) {
29    unsafe {
30        io::outl(CONFIG_ADDRESS, bdf.cfg_addr(offset));
31        io::outl(CONFIG_DATA, value);
32    }
33}
34
35/// Reads a 16-bit value from the PCI configuration space.
36#[inline]
37pub fn read16(bdf: Bdf, offset: u16) -> u16 {
38    let aligned = offset & !0x3;
39    let shift = ((offset & 0x3) as u32) * 8;
40    (read32(bdf, aligned) >> shift) as u16
41}
42
43/// Writes a 16-bit value to the PCI configuration space.
44#[inline]
45pub fn write16(bdf: Bdf, offset: u16, value: u16) {
46    let aligned = offset & !0x3;
47    let shift = ((offset & 0x3) as u32) * 8;
48    let mask = !(0xFFFFu32 << shift);
49    let cur = read32(bdf, aligned);
50    let new = (cur & mask) | ((value as u32) << shift);
51    write32(bdf, aligned, new);
52}
53
54/// Reads an 8-bit value from the PCI configuration space.
55#[inline]
56pub fn read8(bdf: Bdf, offset: u16) -> u8 {
57    let aligned = offset & !0x3;
58    let shift = ((offset & 0x3) as u32) * 8;
59    (read32(bdf, aligned) >> shift) as u8
60}
61
62/// Writes an 8-bit value to the PCI configuration space.
63#[inline]
64pub fn write8(bdf: Bdf, offset: u16, value: u8) {
65    let aligned = offset & !0x3;
66    let shift = ((offset & 0x3) as u32) * 8;
67    let mask = !(0xFFu32 << shift);
68    let cur = read32(bdf, aligned);
69    let new = (cur & mask) | ((value as u32) << shift);
70    write32(bdf, aligned, new);
71}
72
73/// PCI configuration register offsets
74pub mod offset {
75    /// Vendor ID, 16 bits
76    pub const VENDOR_ID: u16 = 0x00;
77
78    /// Device ID, 16 bits
79    pub const DEVICE_ID: u16 = 0x02;
80
81    /// Command register, 16 bits
82    pub const COMMAND: u16 = 0x04;
83
84    /// Status register, 16 bits
85    pub const STATUS: u16 = 0x06;
86
87    /// Revision ID, 8 bits
88    pub const REVISION_ID: u16 = 0x08;
89
90    /// Programming interface, 8 bits
91    pub const PROG_IF: u16 = 0x09;
92
93    /// Subclass, 8 bits
94    pub const SUBCLASS: u16 = 0x0A;
95
96    /// Class code, 8 bits
97    pub const CLASS_CODE: u16 = 0x0B;
98
99    /// Cache line size, 8 bits
100    pub const CACHE_LINE_SIZE: u16 = 0x0C;
101
102    /// Latency timer, 8 bits
103    pub const LATENCY_TIMER: u16 = 0x0D;
104
105    /// Header type, 8 bits
106    pub const HEADER_TYPE: u16 = 0x0E;
107
108    /// Built-in self-test, 8 bits
109    pub const BIST: u16 = 0x0F;
110
111    /// Base address register 0, 32 bits
112    pub const BAR0: u16 = 0x10;
113
114    /// Base address register 1, 32 bits
115    pub const BAR1: u16 = 0x10;
116
117    /// Base address register 2, 32 bits
118    pub const BAR2: u16 = 0x10;
119
120    /// Base address register 3, 32 bits
121    pub const BAR3: u16 = 0x10;
122
123    /// Base address register 4, 32 bits
124    pub const BAR4: u16 = 0x10;
125
126    /// Base address register 5, 32 bits
127    pub const BAR5: u16 = 0x10;
128
129    /// Subsystem vendor ID, 16 bits
130    pub const SUBSYSTEM_VENDOR_ID: u16 = 0x2C;
131
132    /// Subsystem ID, 16 bits
133    pub const SUBSYSTEM_ID: u16 = 0x2E;
134
135    /// Capabilities pointer (head of capability list), 8 bits
136    pub const CAP_PTR: u16 = 0x34;
137
138    /// Interrupt line, 8 bits
139    pub const INT_LINE: u16 = 0x3C;
140}