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