Switch to pci_types for header parsing

This commit is contained in:
pjht 2025-03-04 08:33:35 -06:00
parent 465a46f294
commit d18ead3093
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
3 changed files with 415 additions and 357 deletions

194
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "atomic-polyfill"
@ -47,9 +47,9 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bitflags"
version = "2.6.0"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "byteorder"
@ -71,9 +71,9 @@ checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
[[package]]
name = "critical-section"
version = "1.1.3"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "derive-try-from-primitive"
@ -88,9 +88,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.13.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d"
[[package]]
name = "embedded-io"
@ -106,9 +106,9 @@ checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
name = "equivalent"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "hash32"
@ -121,9 +121,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.0"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heapless"
@ -141,9 +141,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.6.0"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown",
@ -151,9 +151,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.159"
version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "lock_api"
@ -171,6 +171,22 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "parking_lot"
version = "0.12.3"
@ -200,7 +216,9 @@ version = "0.1.0"
dependencies = [
"binread",
"derive-try-from-primitive",
"pci-ids",
"pci_rpc",
"pci_types",
"serde",
"spin",
"syslog_rpc",
@ -208,6 +226,19 @@ dependencies = [
"x86_64",
]
[[package]]
name = "pci-ids"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d88ae3281b415d856e9c2ddbcdd5961e71c1a3e90138512c04d720241853a6af"
dependencies = [
"nom",
"phf",
"phf_codegen",
"proc-macro2",
"quote",
]
[[package]]
name = "pci_rpc"
version = "0.1.0"
@ -217,10 +248,58 @@ dependencies = [
]
[[package]]
name = "postcard"
version = "1.0.10"
name = "pci_types"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e"
checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0"
dependencies = [
"bit_field",
"bitflags",
]
[[package]]
name = "phf"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
"siphasher",
]
[[package]]
name = "postcard"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8"
dependencies = [
"cobs",
"embedded-io 0.4.0",
@ -231,27 +310,42 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.86"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.7"
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "redox_syscall"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f"
dependencies = [
"bitflags",
]
@ -267,9 +361,9 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.17"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]]
name = "scopeguard"
@ -279,24 +373,24 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.23"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
[[package]]
name = "serde"
version = "1.0.210"
version = "1.0.218"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.210"
version = "1.0.218"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.98",
]
[[package]]
@ -309,10 +403,16 @@ dependencies = [
]
[[package]]
name = "smallvec"
version = "1.13.2"
name = "siphasher"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "smallvec"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]]
name = "spin"
@ -342,9 +442,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.79"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [
"proc-macro2",
"quote",
@ -369,9 +469,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.19"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
dependencies = [
"serde",
"serde_spanned",
@ -390,9 +490,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.22"
version = "0.22.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
dependencies = [
"indexmap",
"serde",
@ -403,9 +503,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.13"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[package]]
name = "volatile"
@ -479,18 +579,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.6.20"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
dependencies = [
"memchr",
]
[[package]]
name = "x86_64"
version = "0.15.1"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df"
checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae"
dependencies = [
"bit_field",
"bitflags",

View File

@ -6,7 +6,9 @@ edition = "2021"
[dependencies]
binread = "2.2.0"
derive-try-from-primitive = "1.0.0"
pci-ids = "0.2.5"
pci_rpc = { version = "0.1.0", path = "pci_rpc" }
pci_types = "0.10.0"
serde = { path = "../serde/serde", features = ["derive"] }
spin = "0.9.8"
syslog_rpc = { version = "0.1.0", path = "../syslog/syslog_rpc" }

View File

@ -1,11 +1,18 @@
#![allow(clippy::verbose_bit_mask)]
use std::{
collections::HashMap, fs, io::Cursor, os::mikros::{ipc, syscalls}, path::{Path, PathBuf}
collections::HashMap,
fs,
os::mikros::{ipc, syscalls},
path::{Path, PathBuf},
};
use binread::prelude::*;
use device_types::{Class, InvalidClass};
use device_types::Class;
use pci_ids::Device;
use pci_rpc::Server;
use pci_types::{
capability::PciCapability,
Bar, ConfigRegionAccess, EndpointHeader, PciAddress, PciHeader, MAX_BARS,
};
use serde::{Deserialize, Serialize};
use spin::Mutex;
use x86_64::instructions::port::{Port, PortWriteOnly};
@ -15,217 +22,36 @@ pub mod device_types;
static CONFIG_PORT: Mutex<PortWriteOnly<u32>> = Mutex::new(PortWriteOnly::new(0xCF8));
static DATA_PORT: Mutex<Port<u32>> = Mutex::new(Port::new(0xCFC));
#[derive(Debug, Copy, Clone)]
struct ConfigAccessor(u32);
struct PortAccessor;
impl ConfigAccessor {
pub fn new(bus: u8, device: u8, function: u8) -> Self {
assert!(device < 32);
assert!(function < 8);
Self(
(u32::from(bus) << 16)
| (u32::from(device) << 11)
| (u32::from(function) << 8)
| 0x8000_0000,
)
}
fn read(self, index: u8) -> u32 {
assert!(index < 64);
let register = index * 4;
unsafe { CONFIG_PORT.lock().write(self.0 | u32::from(register)) }
impl ConfigRegionAccess for PortAccessor {
unsafe fn read(&self, address: pci_types::PciAddress, offset: u16) -> u32 {
unsafe {
CONFIG_PORT.lock().write(
0x8000_0000
| (u32::from(address.bus()) << 16)
| (u32::from(address.device()) << 11)
| (u32::from(address.function()) << 8)
| u32::from(offset),
)
}
unsafe { DATA_PORT.lock().read() }
}
fn write(self, index: u8, data: u32) {
assert!(index < 64);
let register = index * 4;
unsafe { CONFIG_PORT.lock().write(self.0 | u32::from(register)) }
unsafe { DATA_PORT.lock().write(data) }
}
}
#[derive(Debug, Copy, Clone)]
pub struct InvalidHeaderType;
#[derive(Debug)]
pub struct ConfigRaw {
pub data: [u8; 256],
}
impl ConfigRaw {
pub fn new(bus: u8, device: u8, function: u8) -> Self {
let accessor = ConfigAccessor::new(bus, device, function);
let mut data = [0; 256];
for reg_num in 0..32 {
let reg = accessor.read(reg_num);
for (i, &byte) in reg.to_le_bytes().iter().enumerate() {
data[usize::from(reg_num) * 4 + i] = byte;
}
unsafe fn write(&self, address: pci_types::PciAddress, offset: u16, value: u32) {
unsafe {
CONFIG_PORT.lock().write(
0x8000_0000
| (u32::from(address.bus()) << 16)
| (u32::from(address.device()) << 11)
| (u32::from(address.function()) << 8)
| u32::from(offset),
)
}
ConfigRaw { data }
unsafe { DATA_PORT.lock().write(value) }
}
pub fn common(&self) -> ConfigCommon {
Cursor::new(&self.data)
.read_le()
.expect("Unable to parse PCI device common config")
}
pub fn config(&self) -> Result<ConfigTypeSpecific, InvalidHeaderType> {
match Cursor::new(&self.data).read_le() {
Ok(cfg) => Ok(cfg),
Err(binread::Error::NoVariantMatch { pos: _ }) => Err(InvalidHeaderType),
Err(err) => panic!("Only NoVariantMatch should be possible: {:?}", err),
}
}
}
#[derive(Debug, Copy, Clone, BinRead)]
#[repr(C)]
pub struct ConfigCommon {
pub vendor_id: u16,
pub device_id: u16,
pub command: u16,
pub status: u16,
pub rev_id: u8,
pub prog_if: u8,
pub subclass: u8,
pub class_code: u8,
pub cache_line_size: u8,
pub lat_timer: u8,
pub header_type: u8,
pub bist: u8,
}
impl ConfigCommon {
fn class(&self) -> Result<Class, InvalidClass> {
Class::new(self.class_code, self.subclass, self.prog_if)
}
}
#[derive(Debug, Copy, Clone, BinRead)]
pub enum ConfigTypeSpecific {
Type0(ConfigType0),
Type1(ConfigType1),
Type2(ConfigType2),
}
#[derive(Debug, Copy, Clone, BinRead)]
#[repr(C)]
pub struct ConfigType0 {
pub vendor_id: u16,
pub device_id: u16,
pub command: u16,
pub status: u16,
pub rev_id: u8,
pub prog_if: u8,
pub subclass: u8,
pub class_code: u8,
pub cache_line_size: u8,
pub lat_timer: u8,
#[br(assert(header_type & 0x7F == 0))]
pub header_type: u8,
pub bist: u8,
pub bars: [u32; 6],
pub cardbus_cis: u32,
pub sub_sys_vendor_id: u16,
pub sub_sys_id: u16,
pub exp_rom_base: u32,
pub cap_ptr: u8,
reserved: [u8; 7],
pub int_line: u8,
pub int_pin: u8,
pub min_grant: u8,
pub max_latency: u8,
}
#[derive(Debug, Copy, Clone, BinRead)]
#[repr(C)]
pub struct ConfigType1 {
pub vendor_id: u16,
pub device_id: u16,
pub command: u16,
pub status: u16,
pub rev_id: u8,
pub prog_if: u8,
pub subclass: u8,
pub class_code: u8,
pub cache_line_size: u8,
pub lat_timer: u8,
#[br(assert(header_type & 0x7F == 1))]
pub header_type: u8,
pub bist: u8,
pub bars: [u32; 2],
pub prim_bus_num: u8,
pub sec_bus_num: u8,
pub sub_bus_num: u8,
pub sec_latency_timer: u8,
pub io_base: u8,
pub io_limit: u8,
pub sec_status: u16,
pub mem_base: u16,
pub mem_limit: u16,
pub prefetch_mem_base: u16,
pub prefetch_mem_limit: u16,
pub prefetch_mem_base_upper32: u32,
pub prefetch_mem_limit_upper32: u32,
pub io_base_upper16: u16,
pub io_limit_upper16: u16,
pub cap_ptr: u8,
reserved: [u8; 3],
pub exp_rom_base: u32,
pub int_line: u8,
pub int_pin: u8,
pub bridge_control: u16,
}
#[derive(Debug, Copy, Clone, BinRead)]
#[repr(C)]
#[repr(packed)]
pub struct ConfigType2 {
pub vendor_id: u16,
pub device_id: u16,
pub command: u16,
pub status: u16,
pub rev_id: u8,
pub prog_if: u8,
pub subclass: u8,
pub class_code: u8,
pub cache_line_size: u8,
pub lat_timer: u8,
#[br(assert(header_type & 0x7F == 2))]
pub header_type: u8,
pub bist: u8,
pub cap_ptr: u8,
reserved: u8,
pub sec_status: u16,
pub mem_base_0: u32,
pub mem_limit_0: u32,
pub mem_base_1: u32,
pub mem_limit_1: u32,
pub io_base_0: u32,
pub io_limit_0: u32,
pub io_base_1: u32,
pub io_limit_1: u32,
pub int_line: u8,
pub int_pin: u8,
pub bridge_control: u16,
pub sub_sys_vendor_id: u16,
pub sub_sys_id: u16,
pub legacy_card_base: u32,
}
#[derive(Debug, Clone)]
pub struct Device {
pub bus: u8,
pub device: u8,
pub function: u8,
pub common: ConfigCommon,
pub type_specific: ConfigTypeSpecific,
pub class: Class,
}
#[derive(Serialize, Deserialize, Debug)]
@ -257,91 +83,73 @@ impl DriverMapping {
}
}
fn scan_bus(bus: u8, device_vec: &mut Vec<Device>) {
fn scan_bus(bus: u8, device_vec: &mut Vec<PciAddress>) {
for device in 0..32 {
scan_device(bus, device, device_vec);
}
}
fn scan_device(bus: u8, device: u8, device_vec: &mut Vec<Device>) {
let func0cfg = ConfigRaw::new(bus, device, 0);
if func0cfg.common().vendor_id == 0xFFFF {
fn scan_device(bus: u8, device: u8, device_vec: &mut Vec<PciAddress>) {
//let func0cfg = ConfigRaw::new(bus, device, 0);
let func0cfg = PciHeader::new(PciAddress::new(0, bus, device, 0));
if func0cfg.id(PortAccessor).0 == 0xFFFF {
return;
}
let header_type = func0cfg.common().header_type;
found_function(bus, device, 0, &func0cfg, device_vec);
if (header_type & 0x80) != 0 {
device_vec.push(PciAddress::new(0, bus, device, 0));
if func0cfg.has_multiple_functions(PortAccessor) {
for func in 1..8 {
let cfg = ConfigRaw::new(bus, device, func);
if cfg.common().vendor_id != 0xFFFF {
found_function(bus, device, func, &cfg, device_vec);
let adresss = PciAddress::new(0, bus, device, func);
let cfg = PciHeader::new(adresss);
if cfg.id(PortAccessor).0 != 0xFFFF {
device_vec.push(adresss)
}
}
}
}
fn found_function(
bus: u8,
device: u8,
function: u8,
cfg: &ConfigRaw,
device_vec: &mut Vec<Device>,
) {
let type_specific = if let Ok(type_specific) = cfg.config() {
type_specific
} else {
return;
};
let class = if let Ok(class) = cfg.common().class() {
class
} else {
return;
};
let device = Device {
bus,
device,
function,
common: cfg.common(),
type_specific,
class,
};
device_vec.push(device);
}
struct PCIServer(Vec<Device>);
struct PCIServer(Vec<PciAddress>);
impl Server for PCIServer {
fn get_bars(&self, bus: u8, dev_no: u8, func: u8) -> Result<[(bool, u32, u32); 6], ()> {
let device = self
let address = *self
.0
.iter()
.find(|dev| dev.bus == bus && dev.device == dev_no && dev.function == func)
.find(|addr| addr.bus() == bus && addr.device() == dev_no && addr.function() == func)
.ok_or(())?;
match device.type_specific {
ConfigTypeSpecific::Type0(hdr) => {
let accessor = ConfigAccessor::new(bus, dev_no, func);
let mut res: [(bool, u32, u32); 6] = [(false, 0, 0); 6];
for (i, bar) in hdr.bars.iter().copied().enumerate() {
let bar_idx = (i + 0x4) as u8;
accessor.write(bar_idx, 0xFFFF_FFFF);
let bar_tmp = accessor.read(bar_idx);
let info_bits = if bar & 0x1 == 1 {
bar_tmp & !0x3
} else {
bar_tmp & !0xF
};
let size = !(info_bits) + 1;
accessor.write(bar_idx, bar);
if bar & 0x1 == 1 {
res[i] = (true, bar & !0x3, size);
} else {
res[i] = (false, bar & !0xF, size);
};
let common_hdr = PciHeader::new(address);
if let Some(hdr) = EndpointHeader::from_header(common_hdr, PortAccessor) {
let mut res: [(bool, u32, u32); 6] = [(false, 0, 0); 6];
let mut i = 0;
while i < MAX_BARS as u8 {
let Some(bar) = hdr.bar(i, PortAccessor) else {
i += 1;
continue;
};
match bar {
Bar::Memory32 {
address,
size,
prefetchable: _,
} => {
res[i as usize] = (false, address, size);
}
Bar::Memory64 {
address: _,
size: _,
prefetchable: _,
} => {
i += 1;
// TODO
}
Bar::Io { port } => {
res[i as usize] = (true, port, 0);
}
}
Ok(res)
i += 1;
}
ConfigTypeSpecific::Type1(_) => Err(()),
ConfigTypeSpecific::Type2(_) => Err(()),
Ok(res)
} else {
Err(())
}
}
}
@ -355,65 +163,209 @@ fn main() {
}
};
let syslog_client = syslog_rpc::Client::new(syslog_pid);
let mut device_vec = Vec::new();
scan_bus(0, &mut device_vec);
let srv = PCIServer(device_vec.clone());
let mut device_addresses = Vec::new();
scan_bus(0, &mut device_addresses);
let srv = PCIServer(device_addresses.clone());
pci_rpc::register_server(Box::new(srv));
let mut driver_map: HashMap<PathBuf, Vec<(u8, u8, u8)>> = HashMap::new();
for device in &device_vec {
for &address in &device_addresses {
let common_hdr = PciHeader::new(address);
let (vid, pid) = common_hdr.id(PortAccessor);
let device_id = Device::from_vid_pid(vid, pid);
let (_, class, subclass, progif) = common_hdr.revision_and_class(PortAccessor);
let Ok(class) = Class::new(class, subclass, progif) else {
continue;
};
syslog_client.send_text_message(
"pci",
format!(
"Bus {}, device {}, function {}: Type {:?}, Vendor ID {:#x}, Device ID {:#x}, Header type {}",
device.bus,
device.device,
device.function,
device.class,
device.common.vendor_id,
device.common.device_id,
device.common.header_type,
"Bus {}, device {}, function {}: Type {:?}, Vendor ID {:#x} ({}), Device ID {:#x} ({}), Header type {:?}",
address.bus(),
address.device(),
address.function(),
class,
vid,
device_id.map_or("Unknown", |x| x.vendor().name()),
pid,
device_id.map_or("Unknown", |x| x.name()),
common_hdr.header_type(PortAccessor),
)
).unwrap();
if let &ConfigTypeSpecific::Type0(cfg_type0) = &device.type_specific {
let accessor = ConfigAccessor::new(device.bus, device.device, device.function);
for (i, &bar) in cfg_type0.bars.iter().enumerate() {
if bar == 0x0 {
if let Some(hdr) = EndpointHeader::from_header(common_hdr, PortAccessor) {
let mut i = 0;
while i < MAX_BARS as u8 {
let Some(bar) = hdr.bar(i, PortAccessor) else {
i += 1;
continue;
}
let bar_idx = (i + 0x4) as u8;
accessor.write(bar_idx, 0xFFFF_FFFF);
let bar_tmp = accessor.read(bar_idx);
let info_bits = if bar & 0x1 == 1 {
bar_tmp & !0x3
} else {
bar_tmp & !0xF
};
let size = !(info_bits) + 1;
accessor.write(bar_idx, bar);
if bar & 0x1 == 1 {
syslog_client.send_text_message("pci", format!("BAR {}: IO {:#x}, size {:#x}", i, bar & (!0x3), size)).unwrap();
} else {
syslog_client.send_text_message("pci", format!("BAR {}: MEM {:#x}, size {:#x}", i, bar & (!0xF), size)).unwrap();
match bar {
Bar::Memory32 {
address,
size,
prefetchable: _,
} => {
syslog_client
.send_text_message(
"pci",
format!("BAR {i}: MEM 32 {address:#x}, size {size:#x}"),
)
.unwrap();
}
Bar::Memory64 {
address,
size,
prefetchable: _,
} => {
syslog_client
.send_text_message(
"pci",
format!("BAR {i}: MEM 64 {address:#x}, size {size:#x}"),
)
.unwrap();
i += 1;
}
Bar::Io { port } => {
syslog_client
.send_text_message("pci", format!("BAR {i}: IO {port:#x}"))
.unwrap();
}
}
i += 1;
}
if hdr.status(PortAccessor).has_capability_list() {
syslog_client
.send_text_message("pci", "Capabilities supported")
.unwrap();
for capability in hdr.capabilities(PortAccessor) {
match capability {
PciCapability::PowerManagement(_) => syslog_client
.send_text_message("pci", "Power management capability")
.unwrap(),
PciCapability::AcceleratedGraphicsPort(_) => syslog_client
.send_text_message("pci", "AGP capability")
.unwrap(),
PciCapability::VitalProductData(_) => syslog_client
.send_text_message("pci", "Vital product data capability")
.unwrap(),
PciCapability::SlotIdentification(_) => syslog_client
.send_text_message("pci", "External expansion capability")
.unwrap(),
PciCapability::Msi(_) => syslog_client
.send_text_message("pci", "MSI capability")
.unwrap(),
PciCapability::CompactPCIHotswap(_) => syslog_client
.send_text_message("pci", "CompactPCI Hotswap capability")
.unwrap(),
PciCapability::PciX(_) => syslog_client
.send_text_message("pci", "PCI-X capability")
.unwrap(),
PciCapability::HyperTransport(_) => syslog_client
.send_text_message("pci", "HyperTransport capability")
.unwrap(),
PciCapability::Vendor(_) => syslog_client
.send_text_message("pci", "Vendor specific capability")
.unwrap(),
PciCapability::DebugPort(_) => syslog_client
.send_text_message("pci", "Debug port capability")
.unwrap(),
PciCapability::CompactPCICentralResourceControl(_) => syslog_client
.send_text_message("pci", "CompactPCI central resource control capability")
.unwrap(),
PciCapability::PciHotPlugControl(_) => syslog_client
.send_text_message("pci", "Hotplug capability")
.unwrap(),
PciCapability::BridgeSubsystemVendorId(_) => syslog_client
.send_text_message("pci", "Bridge Subsystem Vendor ID capability")
.unwrap(),
PciCapability::AGP3(_) => syslog_client
.send_text_message("pci", "AGP3 capability")
.unwrap(),
PciCapability::PciExpress(_) => syslog_client
.send_text_message("pci", "PCI-Express capability")
.unwrap(),
PciCapability::MsiX(_) => syslog_client
.send_text_message("pci", "MSI-X capability")
.unwrap(),
PciCapability::Unknown { address: _, id } => syslog_client
.send_text_message("pci", format!("Other capability (type {id:#x})")).unwrap(),
}
}
}
}
//if cfg_type0.status & 0x10 > 0 {
// syslog_client
// .send_text_message("pci", "Capabilities supported")
// .unwrap();
// let mut cap_ptr = cfg_type0.cap_ptr & 0xFC;
// while cap_ptr > 0 {
// let cap_reg0 = accessor.read(cap_ptr / 4);
// let typ = (cap_reg0 & 0xFF) as u8;
// if typ == 0x9 && device.common.vendor_id == 0x1AF4 {
// let cfg_typ = ((cap_reg0 >> 24) & 0xFF) as u8;
// let bar = accessor.read((cap_ptr / 4) + 1) as u8;
// let offfset = accessor.read((cap_ptr / 4) + 2);
// let length = accessor.read((cap_ptr / 4) + 3);
// syslog_client.send_text_message("pci", format!("Virtio capability type {}, BAR {}, offfset {:#x}, length {:#x} found", cfg_typ, bar, offfset, length)).unwrap();
// } else if typ == 0x5 {
// let control = ((cap_reg0 >> 16) & 0xFFFF) as u16;
// let en = (control & 0x1) > 0;
// let mmc = (control & 0xE) as u8;
// let mme = ((control & 0x70) >> 4) as u8;
// let address = if (control & 0x80) > 0 {
// let address_low = accessor.read((cap_ptr / 4) + 1);
// let address_high = accessor.read((cap_ptr / 4) + 2);
// ((address_high as u64) << 32) | (address_low as u64)
// } else {
// let address = accessor.read((cap_ptr / 4) + 1);
// address as u64
// };
// let data = if (control & 0x80) > 0 {
// accessor.read((cap_ptr / 4) + 3) as u16
// } else {
// accessor.read((cap_ptr / 4) + 2) as u16
// };
// if (control & 0x100) > 0 {
// let mask = accessor.read((cap_ptr / 4) + 4);
// syslog_client.send_text_message("pci", format!("MSI capability: en = {en:?}, mmc = {mmc}, mme = {mme}, addr = {address:#x}, data = {data:#x}, mask = {mask:#x}")).unwrap();
// } else {
// syslog_client.send_text_message("pci", format!("MSI capability: en = {en:?}, mmc = {mmc}, mme = {mme}, addr = {address:#x}, data = {data:#x}, no masking")).unwrap();
// }
// } else if typ == 0x11 {
// let control = ((cap_reg0 >> 16) & 0xFFFF) as u16;
// let en = (control & 0x8000) > 0;
// let mask_all = (control & 0x4000) > 0;
// let size = (control & 0x7FF) + 1;
// let cap_reg1 = accessor.read((cap_ptr / 4) + 1);
// let table_bar = (cap_reg1 & 0x7) as u8;
// let table_offset = cap_reg1 & 0xFFFF_FFF8;
// let cap_reg2 = accessor.read((cap_ptr / 4) + 1);
// let pending_bar = (cap_reg2 & 0x7) as u8;
// let pending_offset = cap_reg2 & 0xFFFF_FFF8;
// syslog_client.send_text_message("pci", format!("MSI-X capability: en = {en:?}, mask_all = {mask_all:?}, size = {size}, table_bar = {table_bar}, table_offset = {table_offset:#x}, pending_bar = {pending_bar}, pending_offset = {pending_offset:#x}")).unwrap();
// } else {
// syslog_client
// .send_text_message("pci", format!("Capability {:#x} found", typ))
// .unwrap();
// }
// cap_ptr = ((cap_reg0 >> 8) & 0xFF) as u8;
// }
// }
//}
let driver = config
.mappings
.iter()
.find(|mapping| match mapping {
DriverMapping::GenericClass {
class,
class: drv_class,
vend_dev_exclude,
..
} => {
&device.class == class
&& !vend_dev_exclude.as_ref().map_or(false, |x| {
x.contains(&(device.common.vendor_id, device.common.device_id))
})
}
DriverMapping::VendDev { list, .. } => {
list.contains(&(device.common.vendor_id, device.common.device_id))
&class == drv_class
&& !vend_dev_exclude
.as_ref()
.map_or(false, |x| x.contains(&(vid, pid)))
}
DriverMapping::VendDev { list, .. } => list.contains(&(vid, pid)),
})
.map(|mapping| mapping.path());
if let Some(driver) = driver {
@ -421,7 +373,11 @@ fn main() {
.send_text_message("pci", format!(" Driver {}", driver.display()))
.unwrap();
driver_map.entry(driver.to_owned()).or_default().push((device.bus, device.device, device.function));
driver_map.entry(driver.to_owned()).or_default().push((
address.bus(),
address.device(),
address.function(),
));
} else {
syslog_client
.send_text_message("pci", " WARN: No driver")