devmgr_srv/
lib.rs

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            // TODO: on-drop for this object.
126            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            // TODO: on-drop for this object.
150            Ok(owned_devices_object.object().id())
151        }
152    }
153}