1use devmgr::{DriverSpec, OwnedDevice};
2use pci_types::device_type::DeviceType;
3use twizzler::{
4 collections::vec::VecObject,
5 object::{ObjID, ObjectBuilder},
6};
7use twizzler_abi::kso::{KactionCmd, KactionFlags};
8use twizzler_driver::{
9 bus::pcie::{PcieDeviceInfo, PcieFunctionHeader, PcieKactionSpecific},
10 device::{BusType, Device},
11};
12use twizzler_rt_abi::error::TwzError;
13use volatile::map_field;
14
15fn get_pcie_offset(bus: u8, device: u8, function: u8) -> usize {
16 ((bus as usize * 256) + (device as usize * 8) + function as usize) * 4096
17}
18
19fn start_pcie_device(seg: &Device, bus: u8, device: u8, function: u8) {
20 let kr = seg.kaction(
21 KactionCmd::Specific(PcieKactionSpecific::RegisterDevice.into()),
22 ((bus as u64) << 16) | ((device as u64) << 8) | (function as u64),
23 KactionFlags::empty(),
24 0,
25 );
26 match kr {
27 Ok(_) => {}
28 Err(_) => eprintln!(
29 "failed to register pcie device {:x}.{:x}.{:x}",
30 bus, device, function
31 ),
32 }
33}
34
35fn start_pcie(seg: Device) {
36 tracing::info!("[devmgr] scanning PCIe bus");
37 let mmio = seg.get_mmio(0).unwrap();
38
39 for bus in 0..=255 {
40 for device in 0..32 {
41 let off = get_pcie_offset(bus, device, 0);
42 let cfg = unsafe { mmio.get_mmio_offset::<PcieFunctionHeader>(off) };
43 let cfg = cfg.as_ptr();
44 if map_field!(cfg.vendor_id).read() != 0xffff
45 && map_field!(cfg.device_id).read() != 0xffff
46 && map_field!(cfg.vendor_id).read() != 0
47 {
48 let mf = if map_field!(cfg.header_type).read() & 0x80 != 0 {
49 7
50 } else {
51 0
52 };
53 for function in 0..=mf {
54 let off = get_pcie_offset(bus, device, function);
55 let cfg = unsafe { mmio.get_mmio_offset::<PcieFunctionHeader>(off) };
56 let cfg = cfg.as_ptr();
57 if map_field!(cfg.vendor_id).read() != 0xffff {
58 let dt = DeviceType::from((
59 map_field!(cfg.class).read(),
60 map_field!(cfg.subclass).read(),
61 ));
62 tracing::info!(
63 "pcie device: {:02x}:{:02x}.{:02x} -- {:?} ({:x} {:x})",
64 bus,
65 device,
66 function,
67 dt,
68 map_field!(cfg.class).read(),
69 map_field!(cfg.subclass).read()
70 );
71 start_pcie_device(&seg, bus, device, function)
72 }
73 }
74 }
75 }
76 }
77}
78
79#[secgate::entry(lib = "devmgr")]
80pub fn devmgr_start() -> Result<(), TwzError> {
81 tracing::subscriber::set_global_default(
82 tracing_subscriber::fmt()
83 .with_max_level(tracing::Level::INFO)
84 .without_time()
85 .finish(),
86 )
87 .unwrap();
88
89 let device_root = twizzler_driver::get_bustree_root();
90 for device in device_root.children() {
91 if device.is_bus() && device.bus_type() == BusType::Pcie {
92 start_pcie(device);
93 }
94 }
95 Ok(())
96}
97
98#[secgate::entry(lib = "devmgr")]
99pub fn get_devices(spec: DriverSpec) -> Result<ObjID, TwzError> {
100 match spec.supported {
101 devmgr::Supported::PcieClass(class, subclass, progif) => {
102 let device_root = twizzler_driver::get_bustree_root();
103 let mut ids = Vec::new();
104 for device in device_root.children() {
105 if device.is_bus() && device.bus_type() == BusType::Pcie {
106 for child in device.children() {
107 let info = unsafe { child.get_info::<PcieDeviceInfo>(0).unwrap() };
108 if info.get_data().class == class
109 && info.get_data().subclass == subclass
110 && info.get_data().progif == progif
111 {
112 ids.push(child.id());
113 }
114 }
115 }
116 }
117
118 tracing::debug!("found devices {:?} for spec {:?}", ids, spec);
119 let mut owned_devices_object = VecObject::new(ObjectBuilder::default())?;
120 for id in ids {
121 owned_devices_object.push(OwnedDevice { id })?;
122 }
123 Ok(owned_devices_object.object().id())
125 }
126 devmgr::Supported::Vendor(vendor_code, device_code) => {
127 let device_root = twizzler_driver::get_bustree_root();
128 let mut ids = Vec::new();
129 for device in device_root.children() {
130 if device.is_bus() && device.bus_type() == BusType::Pcie {
131 for child in device.children() {
132 unsafe {
133
134 let Some(info) = child.get_info::<PcieDeviceInfo>(0) else {continue;};
135 if info.get_data().device_id == device_code
136 && info.get_data().vendor_id == vendor_code
137 {
138 ids.push(child.id());
139 }
140 }
141 }
142 }
143 }
144
145 tracing::debug!("found devices {:?} for spec {:?}", ids, spec);
146 let mut owned_devices_object = VecObject::new(ObjectBuilder::default())?;
147 for id in ids {
148 owned_devices_object.push(OwnedDevice { id })?;
149 }
150 Ok(owned_devices_object.object().id())
152 }
153 }
154}