wraith/km/
device.rs

1//! Device object management
2
3use core::ffi::c_void;
4use core::ptr::NonNull;
5
6use super::driver::UnicodeStringRaw;
7use super::error::{status, KmError, KmResult, NtStatus};
8use super::string::UnicodeString;
9
10/// device object raw structure
11#[repr(C)]
12pub struct DeviceObjectRaw {
13    pub type_: i16,
14    pub size: u16,
15    pub reference_count: i32,
16    pub driver_object: *mut c_void,
17    pub next_device: *mut DeviceObjectRaw,
18    pub attached_device: *mut DeviceObjectRaw,
19    pub current_irp: *mut c_void,
20    pub timer: *mut c_void,
21    pub flags: u32,
22    pub characteristics: u32,
23    pub vpb: *mut c_void,
24    pub device_extension: *mut c_void,
25    pub device_type: u32,
26    pub stack_size: i8,
27    // ... more fields
28}
29
30/// device type constants
31#[repr(u32)]
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum DeviceType {
34    Unknown = 0x00000022,
35    Beep = 0x00000001,
36    CdRom = 0x00000002,
37    CdRomFileSystem = 0x00000003,
38    Controller = 0x00000004,
39    Disk = 0x00000007,
40    DiskFileSystem = 0x00000008,
41    FileSystem = 0x00000009,
42    Keyboard = 0x0000000b,
43    Mouse = 0x0000000f,
44    Network = 0x00000012,
45    Null = 0x00000015,
46    Parallel = 0x00000016,
47    Physical = 0x00000017,
48    Printer = 0x00000018,
49    Scanner = 0x00000019,
50    Serial = 0x0000001b,
51    Screen = 0x0000001c,
52    Sound = 0x0000001d,
53    Transport = 0x00000021,
54    Ks = 0x0000002f,
55}
56
57/// device characteristics
58#[repr(u32)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum DeviceCharacteristics {
61    None = 0,
62    RemovableMedia = 0x00000001,
63    ReadOnlyDevice = 0x00000002,
64    FloppyDiskette = 0x00000004,
65    WriteOnceMedia = 0x00000008,
66    RemoteDevice = 0x00000010,
67    DeviceIsMounted = 0x00000020,
68    VirtualVolume = 0x00000040,
69    SecureOpen = 0x00000100,
70}
71
72/// device flags (bitflags)
73pub mod DeviceFlags {
74    pub const NONE: u32 = 0;
75    pub const BUFFERED_IO: u32 = 0x00000004;
76    pub const DIRECT_IO: u32 = 0x00000010;
77    pub const DO_EXCLUSIVE: u32 = 0x00000800;
78    pub const POWER_PAGEABLE: u32 = 0x00001000;
79    pub const DO_DEVICE_INITIALIZING: u32 = 0x00000080;
80
81    // aliases for compatibility
82    pub const DO_BUFFERED_IO: u32 = BUFFERED_IO;
83    pub const DO_DIRECT_IO: u32 = DIRECT_IO;
84}
85
86/// safe device object wrapper
87pub struct Device {
88    raw: NonNull<DeviceObjectRaw>,
89    symbolic_link: Option<UnicodeString>,
90}
91
92impl Device {
93    /// wrap raw device object pointer
94    ///
95    /// # Safety
96    /// ptr must be a valid DEVICE_OBJECT pointer
97    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
98        NonNull::new(ptr as *mut DeviceObjectRaw).map(|raw| Self {
99            raw,
100            symbolic_link: None,
101        })
102    }
103
104    /// get raw pointer
105    pub fn as_raw(&self) -> *mut DeviceObjectRaw {
106        self.raw.as_ptr()
107    }
108
109    /// set device flags
110    pub fn set_flags(&mut self, flags: u32) {
111        // SAFETY: we have exclusive access
112        unsafe {
113            (*self.raw.as_ptr()).flags = flags;
114        }
115    }
116
117    /// add device flag
118    pub fn add_flag(&mut self, flag: u32) {
119        // SAFETY: we have exclusive access
120        unsafe {
121            (*self.raw.as_ptr()).flags |= flag;
122        }
123    }
124
125    /// remove device flag
126    pub fn remove_flag(&mut self, flag: u32) {
127        // SAFETY: we have exclusive access
128        unsafe {
129            (*self.raw.as_ptr()).flags &= !flag;
130        }
131    }
132
133    /// get device flags
134    pub fn flags(&self) -> u32 {
135        // SAFETY: device object is valid
136        unsafe { (*self.raw.as_ptr()).flags }
137    }
138
139    /// get device type
140    pub fn device_type(&self) -> u32 {
141        // SAFETY: device object is valid
142        unsafe { (*self.raw.as_ptr()).device_type }
143    }
144
145    /// get device extension
146    pub fn extension<T>(&self) -> Option<&T> {
147        // SAFETY: device object is valid
148        unsafe {
149            let ext = (*self.raw.as_ptr()).device_extension;
150            if ext.is_null() {
151                None
152            } else {
153                Some(&*(ext as *const T))
154            }
155        }
156    }
157
158    /// get mutable device extension
159    pub fn extension_mut<T>(&mut self) -> Option<&mut T> {
160        // SAFETY: we have exclusive access
161        unsafe {
162            let ext = (*self.raw.as_ptr()).device_extension;
163            if ext.is_null() {
164                None
165            } else {
166                Some(&mut *(ext as *mut T))
167            }
168        }
169    }
170
171    /// create symbolic link for this device
172    pub fn create_symbolic_link(&mut self, link_name: &UnicodeString, device_name: &UnicodeString) -> KmResult<()> {
173        // SAFETY: valid unicode strings
174        let status = unsafe {
175            IoCreateSymbolicLink(
176                link_name.as_ptr() as *const _,
177                device_name.as_ptr() as *const _,
178            )
179        };
180
181        if !status::nt_success(status) {
182            return Err(KmError::SymbolicLinkFailed {
183                reason: "IoCreateSymbolicLink failed",
184            });
185        }
186
187        Ok(())
188    }
189
190    /// delete symbolic link
191    pub fn delete_symbolic_link(link_name: &UnicodeString) -> KmResult<()> {
192        // SAFETY: valid unicode string
193        let status = unsafe {
194            IoDeleteSymbolicLink(link_name.as_ptr() as *const _)
195        };
196
197        if !status::nt_success(status) {
198            return Err(KmError::SymbolicLinkFailed {
199                reason: "IoDeleteSymbolicLink failed",
200            });
201        }
202
203        Ok(())
204    }
205
206    /// set DO_BUFFERED_IO flag (for small data transfers)
207    pub fn set_buffered_io(&mut self) {
208        self.add_flag(DeviceFlags::BUFFERED_IO);
209    }
210
211    /// set DO_DIRECT_IO flag (for large data transfers)
212    pub fn set_direct_io(&mut self) {
213        self.add_flag(DeviceFlags::DIRECT_IO);
214    }
215
216    /// clear the DO_DEVICE_INITIALIZING flag (required after device creation)
217    pub fn initialization_complete(&mut self) {
218        self.remove_flag(DeviceFlags::DO_DEVICE_INITIALIZING);
219    }
220}
221
222impl Drop for Device {
223    fn drop(&mut self) {
224        // Note: IoDeleteDevice should be called explicitly before drop
225        // to properly clean up symbolic links first
226    }
227}
228
229/// delete device object
230pub fn delete_device(device: *mut c_void) {
231    if !device.is_null() {
232        // SAFETY: caller ensures device is valid
233        unsafe {
234            IoDeleteDevice(device);
235        }
236    }
237}
238
239/// device builder for common setup patterns
240pub struct DeviceBuilder<'a> {
241    driver: &'a mut super::driver::Driver,
242    name: Option<UnicodeString>,
243    symbolic_link: Option<UnicodeString>,
244    device_type: u32,
245    characteristics: u32,
246    exclusive: bool,
247    flags: u32,
248}
249
250impl<'a> DeviceBuilder<'a> {
251    /// create new device builder
252    pub fn new(driver: &'a mut super::driver::Driver) -> Self {
253        Self {
254            driver,
255            name: None,
256            symbolic_link: None,
257            device_type: DeviceType::Unknown as u32,
258            characteristics: 0,
259            exclusive: false,
260            flags: 0,
261        }
262    }
263
264    /// set device name (e.g., "\\Device\\MyDevice")
265    pub fn name(mut self, name: UnicodeString) -> Self {
266        self.name = Some(name);
267        self
268    }
269
270    /// set symbolic link name (e.g., "\\DosDevices\\MyDevice")
271    pub fn symbolic_link(mut self, link: UnicodeString) -> Self {
272        self.symbolic_link = Some(link);
273        self
274    }
275
276    /// set device type
277    pub fn device_type(mut self, dtype: DeviceType) -> Self {
278        self.device_type = dtype as u32;
279        self
280    }
281
282    /// set device characteristics
283    pub fn characteristics(mut self, chars: u32) -> Self {
284        self.characteristics = chars;
285        self
286    }
287
288    /// set exclusive access
289    pub fn exclusive(mut self) -> Self {
290        self.exclusive = true;
291        self
292    }
293
294    /// use buffered I/O
295    pub fn buffered_io(mut self) -> Self {
296        self.flags |= DeviceFlags::BUFFERED_IO;
297        self
298    }
299
300    /// use direct I/O
301    pub fn direct_io(mut self) -> Self {
302        self.flags |= DeviceFlags::DIRECT_IO;
303        self
304    }
305
306    /// build the device
307    pub fn build(self) -> KmResult<Device> {
308        let name = self.name.ok_or(KmError::InvalidParameter {
309            context: "device name required",
310        })?;
311
312        let mut device = self.driver.create_device(
313            &name,
314            self.device_type,
315            self.characteristics,
316            self.exclusive,
317        )?;
318
319        if self.flags != 0 {
320            device.add_flag(self.flags);
321        }
322
323        if let Some(ref link) = self.symbolic_link {
324            device.create_symbolic_link(link, &name)?;
325        }
326
327        device.initialization_complete();
328
329        Ok(device)
330    }
331}
332
333// kernel device functions
334extern "system" {
335    fn IoDeleteDevice(DeviceObject: *mut c_void);
336    fn IoCreateSymbolicLink(
337        SymbolicLinkName: *const c_void,
338        DeviceName: *const c_void,
339    ) -> NtStatus;
340    fn IoDeleteSymbolicLink(SymbolicLinkName: *const c_void) -> NtStatus;
341}