Skip to main content

starnix_core/device/
registry.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::device::kobject::{Class, Device, DeviceMetadata, UEventAction, UEventContext};
6use crate::device::kobject_store::KObjectStore;
7use crate::fs::devtmpfs::{devtmpfs_create_device, devtmpfs_remove_path};
8use crate::fs::sysfs::build_device_directory;
9use crate::task::{
10    CurrentTask, CurrentTaskAndLocked, Kernel, KernelOrTask, SimpleWaiter, register_delayed_release,
11};
12use crate::vfs::pseudo::simple_directory::SimpleDirectoryMutator;
13use crate::vfs::{FileOps, FsStr, FsString, NamespaceNode};
14use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
15use starnix_logging::log_error;
16use starnix_sync::{InterruptibleEvent, LockBefore, LockEqualOrBefore, OrderedMutex};
17use starnix_types::ownership::{Releasable, ReleaseGuard};
18use starnix_uapi::as_any::AsAny;
19use starnix_uapi::device_type::{
20    DYN_MAJOR_RANGE, DeviceType, MISC_DYNANIC_MINOR_RANGE, MISC_MAJOR,
21};
22use starnix_uapi::error;
23use starnix_uapi::errors::Errno;
24use starnix_uapi::open_flags::OpenFlags;
25
26use starnix_sync::{FileOpsCore, Locked, MappedMutexGuard, MutexGuard};
27use std::collections::btree_map::{BTreeMap, Entry};
28use std::ops::{Deref, Range};
29use std::sync::Arc;
30
31use dyn_clone::{DynClone, clone_trait_object};
32
33const CHRDEV_MINOR_MAX: u32 = 256;
34const BLKDEV_MINOR_MAX: u32 = 2u32.pow(20);
35
36/// The mode or category of the device driver.
37#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
38pub enum DeviceMode {
39    /// This device is a character device.
40    Char,
41
42    /// This device is a block device.
43    Block,
44}
45
46impl DeviceMode {
47    /// The number of minor device numbers available for this device mode.
48    fn minor_count(&self) -> u32 {
49        match self {
50            Self::Char => CHRDEV_MINOR_MAX,
51            Self::Block => BLKDEV_MINOR_MAX,
52        }
53    }
54
55    /// The range of minor device numbers available for this device mode.
56    pub fn minor_range(&self) -> Range<u32> {
57        0..self.minor_count()
58    }
59}
60
61pub trait DeviceOps: DynClone + Send + Sync + AsAny + 'static {
62    /// Instantiate a FileOps for this device.
63    ///
64    /// This function is called when userspace opens a file with a `DeviceType`
65    /// assigned to this device.
66    fn open(
67        &self,
68        locked: &mut Locked<FileOpsCore>,
69        current_task: &CurrentTask,
70        device_type: DeviceType,
71        node: &NamespaceNode,
72        flags: OpenFlags,
73    ) -> Result<Box<dyn FileOps>, Errno>;
74}
75
76clone_trait_object!(DeviceOps);
77
78/// Allows directly using a function or closure as an implementation of DeviceOps, avoiding having
79/// to write a zero-size struct and an impl for it.
80impl<F> DeviceOps for F
81where
82    F: Clone
83        + Send
84        + Sync
85        + Clone
86        + Fn(
87            &mut Locked<FileOpsCore>,
88            &CurrentTask,
89            DeviceType,
90            &NamespaceNode,
91            OpenFlags,
92        ) -> Result<Box<dyn FileOps>, Errno>
93        + 'static,
94{
95    fn open(
96        &self,
97        locked: &mut Locked<FileOpsCore>,
98        current_task: &CurrentTask,
99        id: DeviceType,
100        node: &NamespaceNode,
101        flags: OpenFlags,
102    ) -> Result<Box<dyn FileOps>, Errno> {
103        self(locked, current_task, id, node, flags)
104    }
105}
106
107/// A simple `DeviceOps` function for any device that implements `FileOps + Default`.
108pub fn simple_device_ops<T: Default + FileOps + 'static>(
109    _locked: &mut Locked<FileOpsCore>,
110    _current_task: &CurrentTask,
111    _id: DeviceType,
112    _node: &NamespaceNode,
113    _flags: OpenFlags,
114) -> Result<Box<dyn FileOps>, Errno> {
115    Ok(Box::new(T::default()))
116}
117
118/// Keys returned by the registration method for `DeviceListener`s that allows to unregister a
119/// listener.
120pub type DeviceListenerKey = u64;
121
122/// A listener for uevents on devices.
123pub trait DeviceListener: Send + Sync {
124    fn on_device_event(&self, action: UEventAction, device: Device, context: UEventContext);
125}
126
127pub struct DeviceOpsWrapper(Box<dyn DeviceOps>);
128impl ReleaserAction<DeviceOpsWrapper> for DeviceOpsWrapper {
129    fn release(device_ops: ReleaseGuard<DeviceOpsWrapper>) {
130        register_delayed_release(device_ops);
131    }
132}
133impl Deref for DeviceOpsWrapper {
134    type Target = dyn DeviceOps;
135    fn deref(&self) -> &Self::Target {
136        self.0.deref()
137    }
138}
139pub type DeviceReleaser = ObjectReleaser<DeviceOpsWrapper, DeviceOpsWrapper>;
140pub type DeviceHandle = Arc<DeviceReleaser>;
141impl Releasable for DeviceOpsWrapper {
142    type Context<'a> = CurrentTaskAndLocked<'a>;
143
144    fn release<'a>(self, _context: CurrentTaskAndLocked<'a>) {}
145}
146
147/// An entry in the `DeviceRegistry`.
148struct DeviceEntry {
149    /// The name of the device.
150    ///
151    /// This name is the same as the name of the KObject for the device.
152    name: FsString,
153
154    /// The ops used to open the device.
155    ops: DeviceHandle,
156}
157
158impl DeviceEntry {
159    fn new(name: FsString, ops: impl DeviceOps) -> Self {
160        Self { name, ops: Arc::new(DeviceOpsWrapper(Box::new(ops)).into()) }
161    }
162}
163
164/// The devices registered for a given `DeviceMode`.
165///
166/// Each `DeviceMode` has its own namespace of registered devices.
167#[derive(Default)]
168struct RegisteredDevices {
169    /// The major devices registered for this device mode.
170    ///
171    /// Typically the devices registered here will add and remove individual devices using the
172    /// `add_device` and `remove_device` functions on `DeviceRegistry`.
173    ///
174    /// A major device registration shadows any minor device registrations for the same major
175    /// device number. We might need to reconsider this choice in the future in order to make
176    /// the /proc/devices file correctly list major devices such as `misc`.
177    majors: BTreeMap<u32, DeviceEntry>,
178
179    /// Individually registered minor devices.
180    ///
181    /// These devices are registered using the `register_device` function on `DeviceRegistry`.
182    minors: BTreeMap<DeviceType, DeviceEntry>,
183}
184
185impl RegisteredDevices {
186    /// Register a major device.
187    ///
188    /// Returns `EINVAL` if the major device is already registered.
189    fn register_major(&mut self, major: u32, entry: DeviceEntry) -> Result<(), Errno> {
190        if let Entry::Vacant(slot) = self.majors.entry(major) {
191            slot.insert(entry);
192            Ok(())
193        } else {
194            error!(EINVAL)
195        }
196    }
197
198    /// Register a minor device.
199    ///
200    /// Overwrites any existing minor device registered with the given `DeviceType`.
201    fn register_minor(&mut self, device_type: DeviceType, entry: DeviceEntry) {
202        self.minors.insert(device_type, entry);
203    }
204
205    /// Get the ops for a given `DeviceType`.
206    ///
207    /// If there is a major device registered with the major device number of the
208    /// `DeviceType`, the ops for that major device will be returned. Otherwise,
209    /// if there is a minor device registered, the ops for that minor device will be
210    /// returned. Otherwise, returns `ENODEV`.
211    fn get(&self, device_type: DeviceType) -> Result<DeviceHandle, Errno> {
212        if let Some(major_device) = self.majors.get(&device_type.major()) {
213            Ok(Arc::clone(&major_device.ops))
214        } else if let Some(minor_device) = self.minors.get(&device_type) {
215            Ok(Arc::clone(&minor_device.ops))
216        } else {
217            error!(ENODEV)
218        }
219    }
220
221    /// Returns a list of the registered major device numbers and their names.
222    fn list_major_devices(&self) -> Vec<(u32, FsString)> {
223        self.majors.iter().map(|(major, entry)| (*major, entry.name.clone())).collect()
224    }
225
226    /// Returns a list of the registered minor devices and their names.
227    fn list_minor_devices(&self, range: Range<DeviceType>) -> Vec<(DeviceType, FsString)> {
228        self.minors
229            .range(range)
230            .map(|(device_type, entry)| (device_type.clone(), entry.name.clone()))
231            .collect()
232    }
233}
234
235/// The registry for devices.
236///
237/// Devices are specified in file systems with major and minor device numbers, together referred to
238/// as a `DeviceType`. When userspace opens one of those files, we look up the `DeviceType` in the
239/// device registry to instantiate a file for that device.
240///
241/// The `DeviceRegistry` also manages the `KObjectStore`, which provides metadata for devices via
242/// the sysfs file system, typically mounted at /sys.
243pub struct DeviceRegistry {
244    /// The KObjects for registered devices.
245    pub objects: KObjectStore,
246
247    /// Mutable state for the device registry.
248    state: OrderedMutex<DeviceRegistryState, starnix_sync::DeviceRegistryState>,
249}
250struct DeviceRegistryState {
251    /// The registered character devices.
252    char_devices: RegisteredDevices,
253
254    /// The registered block devices.
255    block_devices: RegisteredDevices,
256
257    /// Some of the misc devices (devices with the `MISC_MAJOR` major number) are dynamically
258    /// allocated. This allocator keeps track of which device numbers have been allocated to
259    /// such devices.
260    misc_chardev_allocator: DeviceTypeAllocator,
261
262    /// A range of large major device numbers are reserved for other dynamically allocated
263    /// devices. This allocator keeps track of which device numbers have been allocated to
264    /// such devices.
265    dyn_chardev_allocator: DeviceTypeAllocator,
266
267    /// The next anonymous device number to assign to a file system.
268    next_anon_minor: u32,
269
270    /// Listeners registered to learn about new devices being added to the registry.
271    ///
272    /// These listeners generate uevents for those devices, which populates /dev on some
273    /// systems.
274    listeners: BTreeMap<u64, Box<dyn DeviceListener>>,
275
276    /// The next identifier to use for a listener.
277    next_listener_id: u64,
278
279    /// The next event identifier to use when notifying listeners.
280    next_event_id: u64,
281}
282
283impl DeviceRegistry {
284    /// Notify devfs and listeners that a device has been added to the registry.
285    fn notify_device<L>(
286        &self,
287        locked: &mut Locked<L>,
288        kernel: &Kernel,
289        device: Device,
290        event: Option<Arc<InterruptibleEvent>>,
291    ) where
292        L: LockEqualOrBefore<FileOpsCore>,
293    {
294        if let Some(metadata) = &device.metadata {
295            devtmpfs_create_device(kernel, metadata.clone(), event);
296            self.dispatch_uevent(locked, UEventAction::Add, device);
297        }
298    }
299
300    /// Register a device with the `DeviceRegistry`.
301    ///
302    /// If you are registering a device that exists in other systems, please check the metadata
303    /// for that device in /sys and make sure you use the same properties when calling this
304    /// function because these value are visible to userspace.
305    ///
306    /// For example, a typical device will appear in sysfs at a path like:
307    ///
308    ///   `/sys/devices/{bus}/{class}/{name}`
309    ///
310    /// Many common classes have convenient accessors on `DeviceRegistry::objects`.
311    ///
312    /// To fill out the `DeviceMetadata`, look at the `uevent` file:
313    ///
314    ///   `/sys/devices/{bus}/{class}/{name}/uevent`
315    ///
316    /// which as the following format:
317    ///
318    /// ```
319    ///   MAJOR={major-number}
320    ///   MINOR={minor-number}
321    ///   DEVNAME={devname}
322    ///   DEVMODE={devmode}
323    /// ```
324    ///
325    /// Often, the `{name}` and the `{devname}` are the same, but if they are not the same,
326    /// please take care to use the correct string in the correct field.
327    ///
328    /// If the `{major-number}` is 10 and the `{minor-number}` is in the range 52..128, please use
329    /// `register_misc_device` instead because these device numbers are dynamically allocated.
330    ///
331    /// If the `{major-number}` is in the range 234..255, please use `register_dyn_device` instead
332    /// because these device are also dynamically allocated.
333    ///
334    /// If you are unsure which device numbers to use, consult devices.txt:
335    ///
336    ///   https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
337    ///
338    /// If you are still unsure, please ask an experienced Starnix contributor rather than make up
339    /// a device number.
340    ///
341    /// For most devices, the `create_device_sysfs_ops` parameter should be
342    /// `DeviceDirectory::new`, but some devices have custom directories in sysfs.
343    ///
344    /// Finally, the `dev_ops` parameter is where you provide the callback for instantiating
345    /// your device.
346    pub fn register_device<'a, L>(
347        &self,
348        locked: &mut Locked<L>,
349        kernel_or_task: impl KernelOrTask<'a>,
350        name: &FsStr,
351        metadata: DeviceMetadata,
352        class: Class,
353        dev_ops: impl DeviceOps,
354    ) -> Result<Device, Errno>
355    where
356        L: LockEqualOrBefore<FileOpsCore>,
357    {
358        self.register_device_with_dir(
359            locked,
360            kernel_or_task,
361            name,
362            metadata,
363            class,
364            build_device_directory,
365            dev_ops,
366        )
367    }
368
369    /// Register a device with a custom directory.
370    ///
371    /// See `register_device` for an explanation of the parameters.
372    pub fn register_device_with_dir<'a, L>(
373        &self,
374        locked: &mut Locked<L>,
375        kernel_or_task: impl KernelOrTask<'a>,
376        name: &FsStr,
377        metadata: DeviceMetadata,
378        class: Class,
379        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
380        dev_ops: impl DeviceOps,
381    ) -> Result<Device, Errno>
382    where
383        L: LockEqualOrBefore<FileOpsCore>,
384    {
385        let locked = locked.cast_locked::<FileOpsCore>();
386        let entry = DeviceEntry::new(name.into(), dev_ops);
387        self.devices(locked, metadata.mode).register_minor(metadata.device_type, entry);
388        self.add_device(locked, kernel_or_task, name, metadata, class, build_directory)
389    }
390
391    /// Register a dynamic device in the `MISC_MAJOR` major device number.
392    ///
393    /// MISC devices (major number 10) with minor numbers in the range 52..128 are dynamically
394    /// assigned. Rather than hardcoding registrations with these device numbers, use this
395    /// function instead to register the device.
396    ///
397    /// See `register_device` for an explanation of the parameters.
398    pub fn register_misc_device<'a, L>(
399        &self,
400        locked: &mut Locked<L>,
401        kernel_or_task: impl KernelOrTask<'a>,
402        name: &FsStr,
403        dev_ops: impl DeviceOps,
404    ) -> Result<Device, Errno>
405    where
406        L: LockEqualOrBefore<FileOpsCore>,
407    {
408        let device_type =
409            self.state.lock(locked.cast_locked()).misc_chardev_allocator.allocate()?;
410        let metadata = DeviceMetadata::new(name.into(), device_type, DeviceMode::Char);
411        Ok(self.register_device(
412            locked,
413            kernel_or_task,
414            name,
415            metadata,
416            self.objects.misc_class(),
417            dev_ops,
418        )?)
419    }
420
421    /// Register a dynamic device with major numbers 234..255.
422    ///
423    /// Majors device numbers 234..255 are dynamically assigned. Rather than hardcoding
424    /// registrations with these device numbers, use this function instead to register the device.
425    ///
426    /// Note: We do not currently allocate from this entire range because we have mistakenly
427    /// hardcoded some device registrations from the dynamic range. Once we fix these registrations
428    /// to be dynamic, we should expand to using the full dynamic range.
429    ///
430    /// See `register_device` for an explanation of the parameters.
431    pub fn register_dyn_device<'a, L>(
432        &self,
433        locked: &mut Locked<L>,
434        kernel_or_task: impl KernelOrTask<'a>,
435        name: &FsStr,
436        class: Class,
437        dev_ops: impl DeviceOps,
438    ) -> Result<Device, Errno>
439    where
440        L: LockEqualOrBefore<FileOpsCore>,
441    {
442        self.register_dyn_device_with_dir(
443            locked,
444            kernel_or_task,
445            name,
446            class,
447            build_device_directory,
448            dev_ops,
449        )
450    }
451
452    /// Register a dynamic device with a custom directory.
453    ///
454    /// See `register_device` for an explanation of the parameters.
455    pub fn register_dyn_device_with_dir<'a, L>(
456        &self,
457        locked: &mut Locked<L>,
458        kernel_or_task: impl KernelOrTask<'a>,
459        name: &FsStr,
460        class: Class,
461        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
462        dev_ops: impl DeviceOps,
463    ) -> Result<Device, Errno>
464    where
465        L: LockEqualOrBefore<FileOpsCore>,
466    {
467        self.register_dyn_device_with_devname(
468            locked,
469            kernel_or_task,
470            name,
471            name,
472            class,
473            build_directory,
474            dev_ops,
475        )
476    }
477
478    /// Register a dynamic device with major numbers 234..255.
479    ///
480    /// Majors device numbers 234..255 are dynamically assigned. Rather than hardcoding
481    /// registrations with these device numbers, use this function instead to register the device.
482    ///
483    /// Note: We do not currently allocate from this entire range because we have mistakenly
484    /// hardcoded some device registrations from the dynamic range. Once we fix these registrations
485    /// to be dynamic, we should expand to using the full dynamic range.
486    ///
487    /// See `register_device` for an explanation of the parameters.
488    pub fn register_dyn_device_with_devname<'a, L>(
489        &self,
490        locked: &mut Locked<L>,
491        kernel_or_task: impl KernelOrTask<'a>,
492        name: &FsStr,
493        devname: &FsStr,
494        class: Class,
495        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
496        dev_ops: impl DeviceOps,
497    ) -> Result<Device, Errno>
498    where
499        L: LockEqualOrBefore<FileOpsCore>,
500    {
501        let device_type = self.state.lock(locked.cast_locked()).dyn_chardev_allocator.allocate()?;
502        let metadata = DeviceMetadata::new(devname.into(), device_type, DeviceMode::Char);
503        Ok(self.register_device_with_dir(
504            locked,
505            kernel_or_task,
506            name,
507            metadata,
508            class,
509            build_directory,
510            dev_ops,
511        )?)
512    }
513
514    /// Register a "silent" dynamic device with major numbers 234..255.
515    ///
516    /// Only use for devices that should not be registered with the KObjectStore/appear in sysfs.
517    /// This is a rare occurrence.
518    ///
519    /// See `register_dyn_device` for an explanation of dyn devices and of the parameters.
520    pub fn register_silent_dyn_device<'a, L>(
521        &self,
522        locked: &mut Locked<L>,
523        name: &FsStr,
524        dev_ops: impl DeviceOps,
525    ) -> Result<DeviceMetadata, Errno>
526    where
527        L: LockEqualOrBefore<FileOpsCore>,
528    {
529        let locked = locked.cast_locked::<FileOpsCore>();
530        let device_type = self.state.lock(locked).dyn_chardev_allocator.allocate()?;
531        let metadata = DeviceMetadata::new(name.into(), device_type, DeviceMode::Char);
532        let entry = DeviceEntry::new(name.into(), dev_ops);
533        self.devices(locked, metadata.mode).register_minor(metadata.device_type, entry);
534        Ok(metadata)
535    }
536
537    /// Directly add a device to the KObjectStore.
538    ///
539    /// This function should be used only by device that have registered an entire major device
540    /// number. If you want to add a single minor device, use the `register_device` function
541    /// instead.
542    ///
543    /// See `register_device` for an explanation of the parameters.
544    pub fn add_device<'a, L>(
545        &self,
546        locked: &mut Locked<L>,
547        kernel_or_task: impl KernelOrTask<'a>,
548        name: &FsStr,
549        metadata: DeviceMetadata,
550        class: Class,
551        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
552    ) -> Result<Device, Errno>
553    where
554        L: LockEqualOrBefore<FileOpsCore>,
555    {
556        self.devices(locked.cast_locked(), metadata.mode)
557            .get(metadata.device_type)
558            .expect("device is registered");
559        let device = self.objects.create_device(name, Some(metadata), class, build_directory);
560
561        block_task_until(kernel_or_task, |kernel, event| {
562            Ok(self.notify_device(locked, kernel, device.clone(), event))
563        })?;
564        Ok(device)
565    }
566
567    /// Add a net device to the device registry.
568    ///
569    /// Net devices are different from other devices because they do not have a device number.
570    /// Instead, their `uevent` files have the following format:
571    ///
572    /// ```
573    /// INTERFACE={name}
574    /// IFINDEX={index}
575    /// ```
576    ///
577    /// Currently, we only register the net devices by name and use an empty `uevent` file.
578    pub fn add_net_device(&self, name: &FsStr) -> Device {
579        self.objects.create_device(name, None, self.objects.net_class(), build_device_directory)
580    }
581
582    /// Remove a net device from the device registry.
583    ///
584    /// See `add_net_device` for more details.
585    pub fn remove_net_device(&self, device: Device) {
586        assert!(device.metadata.is_none());
587        self.objects.remove(&device);
588    }
589
590    /// Directly add a device to the KObjectStore that lacks a device number.
591    ///
592    /// This function should be used only by device do not have a major or a minor number. You can
593    /// identify these devices because they appear in sysfs and have an empty `uevent` file.
594    ///
595    /// See `register_device` for an explanation of the parameters.
596    pub fn add_numberless_device<L>(
597        &self,
598        _locked: &mut Locked<L>,
599        name: &FsStr,
600        class: Class,
601        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
602    ) -> Device
603    where
604        L: LockEqualOrBefore<FileOpsCore>,
605    {
606        self.objects.create_device(name, None, class, build_directory)
607    }
608
609    /// Remove a device directly added with `add_device`.
610    ///
611    /// This function should be used only by device that have registered an entire major device
612    /// number. Individually registered minor device cannot be removed at this time.
613    pub fn remove_device<L>(
614        &self,
615        locked: &mut Locked<L>,
616        current_task: &CurrentTask,
617        device: Device,
618    ) where
619        L: LockEqualOrBefore<FileOpsCore>,
620    {
621        if let Some(metadata) = &device.metadata {
622            self.dispatch_uevent(locked, UEventAction::Remove, device.clone());
623
624            if let Err(err) = devtmpfs_remove_path(locked, current_task, metadata.devname.as_ref())
625            {
626                log_error!("Cannot remove device {:?} ({:?})", device, err);
627            }
628        }
629
630        self.objects.remove(&device);
631    }
632
633    /// Returns a list of the registered major device numbers for the given `DeviceMode` and their
634    /// names.
635    pub fn list_major_devices<L>(
636        &self,
637        locked: &mut Locked<L>,
638        mode: DeviceMode,
639    ) -> Vec<(u32, FsString)>
640    where
641        L: LockBefore<starnix_sync::DeviceRegistryState>,
642    {
643        self.devices(locked, mode).list_major_devices()
644    }
645
646    /// Returns a list of the registered minor devices for the given `DeviceMode` and their names.
647    pub fn list_minor_devices<L>(
648        &self,
649        locked: &mut Locked<L>,
650        mode: DeviceMode,
651        range: Range<DeviceType>,
652    ) -> Vec<(DeviceType, FsString)>
653    where
654        L: LockBefore<starnix_sync::DeviceRegistryState>,
655    {
656        self.devices(locked, mode).list_minor_devices(range)
657    }
658
659    /// The `RegisteredDevice` object for the given `DeviceMode`.
660    fn devices<'a, L>(
661        &'a self,
662        locked: &'a mut Locked<L>,
663        mode: DeviceMode,
664    ) -> MappedMutexGuard<'a, RegisteredDevices>
665    where
666        L: LockBefore<starnix_sync::DeviceRegistryState>,
667    {
668        MutexGuard::map(self.state.lock(locked), |state| match mode {
669            DeviceMode::Char => &mut state.char_devices,
670            DeviceMode::Block => &mut state.block_devices,
671        })
672    }
673
674    /// Register an entire major device number.
675    ///
676    /// If you register an entire major device, use `add_device` and `remove_device` to manage the
677    /// sysfs entiries for your device rather than trying to register and unregister individual
678    /// minor devices.
679    pub fn register_major<'a, L>(
680        &self,
681        locked: &mut Locked<L>,
682        name: FsString,
683        mode: DeviceMode,
684        major: u32,
685        dev_ops: impl DeviceOps,
686    ) -> Result<(), Errno>
687    where
688        L: LockEqualOrBefore<FileOpsCore>,
689    {
690        let locked = locked.cast_locked::<FileOpsCore>();
691        let entry = DeviceEntry::new(name, dev_ops);
692        self.devices(locked, mode).register_major(major, entry)
693    }
694
695    /// Allocate an anonymous device identifier.
696    pub fn next_anonymous_dev_id<'a, L>(&self, locked: &mut Locked<L>) -> DeviceType
697    where
698        L: LockEqualOrBefore<FileOpsCore>,
699    {
700        let locked = locked.cast_locked::<FileOpsCore>();
701        let mut state = self.state.lock(locked);
702        let id = DeviceType::new(0, state.next_anon_minor);
703        state.next_anon_minor += 1;
704        id
705    }
706
707    /// Register a new listener for uevents on devices.
708    ///
709    /// Returns a key used to unregister the listener.
710    pub fn register_listener<'a, L>(
711        &self,
712        locked: &mut Locked<L>,
713        listener: impl DeviceListener + 'static,
714    ) -> DeviceListenerKey
715    where
716        L: LockEqualOrBefore<FileOpsCore>,
717    {
718        let mut state = self.state.lock(locked.cast_locked());
719        let key = state.next_listener_id;
720        state.next_listener_id += 1;
721        state.listeners.insert(key, Box::new(listener));
722        key
723    }
724
725    /// Unregister a listener previously registered through `register_listener`.
726    pub fn unregister_listener<'a, L>(&self, locked: &mut Locked<L>, key: &DeviceListenerKey)
727    where
728        L: LockEqualOrBefore<FileOpsCore>,
729    {
730        self.state.lock(locked.cast_locked()).listeners.remove(key);
731    }
732
733    /// Dispatch an uevent for the given `device`.
734    pub fn dispatch_uevent<'a, L>(
735        &self,
736        locked: &mut Locked<L>,
737        action: UEventAction,
738        device: Device,
739    ) where
740        L: LockEqualOrBefore<FileOpsCore>,
741    {
742        let mut state = self.state.lock(locked.cast_locked());
743        let event_id = state.next_event_id;
744        state.next_event_id += 1;
745        let context = UEventContext { seqnum: event_id };
746        for listener in state.listeners.values() {
747            listener.on_device_event(action, device.clone(), context);
748        }
749    }
750
751    /// Instantiate a file for the specified device.
752    ///
753    /// The device will be looked up in the device registry by `DeviceMode` and `DeviceType`.
754    pub fn open_device<L>(
755        &self,
756        locked: &mut Locked<L>,
757        current_task: &CurrentTask,
758        node: &NamespaceNode,
759        flags: OpenFlags,
760        device_type: DeviceType,
761        mode: DeviceMode,
762    ) -> Result<Box<dyn FileOps>, Errno>
763    where
764        L: LockEqualOrBefore<FileOpsCore>,
765    {
766        let locked = locked.cast_locked::<FileOpsCore>();
767        let dev_ops = self.devices(locked, mode).get(device_type)?;
768        dev_ops.open(locked, current_task, device_type, node, flags)
769    }
770
771    pub fn get_device<L>(
772        &self,
773        locked: &mut Locked<L>,
774        device_type: DeviceType,
775        mode: DeviceMode,
776    ) -> Result<DeviceHandle, Errno>
777    where
778        L: LockBefore<starnix_sync::DeviceRegistryState>,
779    {
780        self.devices(locked, mode).get(device_type)
781    }
782}
783
784impl Default for DeviceRegistry {
785    fn default() -> Self {
786        let misc_available = vec![DeviceType::new_range(MISC_MAJOR, MISC_DYNANIC_MINOR_RANGE)];
787        let dyn_available = DYN_MAJOR_RANGE
788            .map(|major| DeviceType::new_range(major, DeviceMode::Char.minor_range()))
789            .rev()
790            .collect();
791        let state = DeviceRegistryState {
792            char_devices: Default::default(),
793            block_devices: Default::default(),
794            misc_chardev_allocator: DeviceTypeAllocator::new(misc_available),
795            dyn_chardev_allocator: DeviceTypeAllocator::new(dyn_available),
796            next_anon_minor: 1,
797            listeners: Default::default(),
798            next_listener_id: 0,
799            next_event_id: 0,
800        };
801        Self { objects: Default::default(), state: OrderedMutex::new(state) }
802    }
803}
804
805/// An allocator for `DeviceType`
806struct DeviceTypeAllocator {
807    /// The available ranges of device types to allocate.
808    ///
809    /// Devices will be allocated from the back of the vector first.
810    freelist: Vec<Range<DeviceType>>,
811}
812
813impl DeviceTypeAllocator {
814    /// Create an allocator for the given ranges of device types.
815    ///
816    /// The devices will be allocated from the front of the vector first.
817    fn new(mut available: Vec<Range<DeviceType>>) -> Self {
818        available.reverse();
819        Self { freelist: available }
820    }
821
822    /// Allocate a `DeviceType`.
823    ///
824    /// Once allocated, there is no mechanism for freeing a `DeviceType`.
825    fn allocate(&mut self) -> Result<DeviceType, Errno> {
826        let Some(range) = self.freelist.pop() else {
827            return error!(ENOMEM);
828        };
829        let allocated = range.start;
830        if let Some(next) = allocated.next_minor() {
831            if next < range.end {
832                self.freelist.push(next..range.end);
833            }
834        }
835        Ok(allocated)
836    }
837}
838
839/// Run the given closure and blocks the thread until the passed event is signaled, if this is
840/// built from a `CurrentTask`, otherwise does not block.
841fn block_task_until<'a, T, F>(kernel_or_task: impl KernelOrTask<'a>, f: F) -> Result<T, Errno>
842where
843    F: FnOnce(&Kernel, Option<Arc<InterruptibleEvent>>) -> Result<T, Errno>,
844{
845    let kernel = kernel_or_task.kernel();
846    match kernel_or_task.maybe_task() {
847        None => f(kernel, None),
848        Some(task) => {
849            let event = InterruptibleEvent::new();
850            let (_waiter, guard) = SimpleWaiter::new(&event);
851            let result = f(kernel, Some(event.clone()))?;
852            task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
853            Ok(result)
854        }
855    }
856}
857
858#[cfg(test)]
859mod tests {
860    use super::*;
861    use crate::device::mem::DevNull;
862    use crate::testing::*;
863    use crate::vfs::*;
864    use starnix_uapi::device_type::{INPUT_MAJOR, MEM_MAJOR};
865
866    #[::fuchsia::test]
867    async fn registry_fails_to_add_duplicate_device() {
868        spawn_kernel_and_run(async |locked, _current_task| {
869            let registry = DeviceRegistry::default();
870            registry
871                .register_major(
872                    locked,
873                    "mem".into(),
874                    DeviceMode::Char,
875                    MEM_MAJOR,
876                    simple_device_ops::<DevNull>,
877                )
878                .expect("registers once");
879            registry
880                .register_major(
881                    locked,
882                    "random".into(),
883                    DeviceMode::Char,
884                    123,
885                    simple_device_ops::<DevNull>,
886                )
887                .expect("registers unique");
888            registry
889                .register_major(
890                    locked,
891                    "mem".into(),
892                    DeviceMode::Char,
893                    MEM_MAJOR,
894                    simple_device_ops::<DevNull>,
895                )
896                .expect_err("fail to register duplicate");
897        })
898        .await;
899    }
900
901    #[::fuchsia::test]
902    async fn registry_opens_device() {
903        spawn_kernel_and_run(async |locked, current_task| {
904            let kernel = current_task.kernel();
905            let registry = DeviceRegistry::default();
906            registry
907                .register_major(
908                    locked,
909                    "mem".into(),
910                    DeviceMode::Char,
911                    MEM_MAJOR,
912                    simple_device_ops::<DevNull>,
913                )
914                .expect("registers unique");
915
916            let fs = create_testfs(locked, &kernel);
917            let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
918
919            // Fail to open non-existent device.
920            assert!(
921                registry
922                    .open_device(
923                        locked,
924                        &current_task,
925                        &node,
926                        OpenFlags::RDONLY,
927                        DeviceType::NONE,
928                        DeviceMode::Char
929                    )
930                    .is_err()
931            );
932
933            // Fail to open in wrong mode.
934            assert!(
935                registry
936                    .open_device(
937                        locked,
938                        &current_task,
939                        &node,
940                        OpenFlags::RDONLY,
941                        DeviceType::NULL,
942                        DeviceMode::Block
943                    )
944                    .is_err()
945            );
946
947            // Open in correct mode.
948            let _ = registry
949                .open_device(
950                    locked,
951                    &current_task,
952                    &node,
953                    OpenFlags::RDONLY,
954                    DeviceType::NULL,
955                    DeviceMode::Char,
956                )
957                .expect("opens device");
958        })
959        .await;
960    }
961
962    #[::fuchsia::test]
963    async fn registry_dynamic_misc() {
964        spawn_kernel_and_run(async |locked, current_task| {
965            let kernel = current_task.kernel();
966            fn create_test_device(
967                _locked: &mut Locked<FileOpsCore>,
968                _current_task: &CurrentTask,
969                _id: DeviceType,
970                _node: &NamespaceNode,
971                _flags: OpenFlags,
972            ) -> Result<Box<dyn FileOps>, Errno> {
973                Ok(Box::new(PanickingFile))
974            }
975
976            let registry = &kernel.device_registry;
977            let device = registry
978                .register_dyn_device(
979                    locked,
980                    &*current_task,
981                    "test-device".into(),
982                    registry.objects.virtual_block_class(),
983                    create_test_device,
984                )
985                .unwrap();
986            let device_type = device.metadata.expect("has metadata").device_type;
987            assert!(DYN_MAJOR_RANGE.contains(&device_type.major()));
988
989            let fs = create_testfs(locked, &kernel);
990            let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
991            let _ = registry
992                .open_device(
993                    locked,
994                    &current_task,
995                    &node,
996                    OpenFlags::RDONLY,
997                    device_type,
998                    DeviceMode::Char,
999                )
1000                .expect("opens device");
1001        })
1002        .await;
1003    }
1004
1005    #[::fuchsia::test]
1006    async fn registery_add_class() {
1007        spawn_kernel_and_run(async |locked, current_task| {
1008            let kernel = current_task.kernel();
1009            let registry = &kernel.device_registry;
1010            registry
1011                .register_major(
1012                    locked,
1013                    "input".into(),
1014                    DeviceMode::Char,
1015                    INPUT_MAJOR,
1016                    simple_device_ops::<DevNull>,
1017                )
1018                .expect("can register input");
1019
1020            let input_class = registry
1021                .objects
1022                .get_or_create_class("input".into(), registry.objects.virtual_bus());
1023            registry
1024                .add_device(
1025                    locked,
1026                    &*current_task,
1027                    "mouse".into(),
1028                    DeviceMetadata::new(
1029                        "mouse".into(),
1030                        DeviceType::new(INPUT_MAJOR, 0),
1031                        DeviceMode::Char,
1032                    ),
1033                    input_class,
1034                    build_device_directory,
1035                )
1036                .expect("add_device");
1037
1038            assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
1039        })
1040        .await;
1041    }
1042
1043    #[::fuchsia::test]
1044    async fn registry_add_bus() {
1045        spawn_kernel_and_run(async |locked, current_task| {
1046            let kernel = current_task.kernel();
1047            let registry = &kernel.device_registry;
1048            registry
1049                .register_major(
1050                    locked,
1051                    "input".into(),
1052                    DeviceMode::Char,
1053                    INPUT_MAJOR,
1054                    simple_device_ops::<DevNull>,
1055                )
1056                .expect("can register input");
1057
1058            let bus = registry.objects.get_or_create_bus("my-bus".into());
1059            let class = registry.objects.get_or_create_class("my-class".into(), bus);
1060            registry
1061                .add_device(
1062                    locked,
1063                    &*current_task,
1064                    "my-device".into(),
1065                    DeviceMetadata::new(
1066                        "my-device".into(),
1067                        DeviceType::new(INPUT_MAJOR, 0),
1068                        DeviceMode::Char,
1069                    ),
1070                    class,
1071                    build_device_directory,
1072                )
1073                .expect("add_device");
1074            assert!(registry.objects.root.lookup("bus/my-bus".into()).is_some());
1075            assert!(registry.objects.root.lookup("devices/my-bus/my-class".into()).is_some());
1076            assert!(
1077                registry.objects.root.lookup("devices/my-bus/my-class/my-device".into()).is_some()
1078            );
1079        })
1080        .await;
1081    }
1082
1083    #[::fuchsia::test]
1084    async fn registry_remove_device() {
1085        spawn_kernel_and_run(async |locked, current_task| {
1086            let kernel = current_task.kernel();
1087            let registry = &kernel.device_registry;
1088            registry
1089                .register_major(
1090                    locked,
1091                    "input".into(),
1092                    DeviceMode::Char,
1093                    INPUT_MAJOR,
1094                    simple_device_ops::<DevNull>,
1095                )
1096                .expect("can register input");
1097
1098            let pci_bus = registry.objects.get_or_create_bus("pci".into());
1099            let input_class = registry.objects.get_or_create_class("input".into(), pci_bus);
1100            let mouse_dev = registry
1101                .add_device(
1102                    locked,
1103                    &*current_task,
1104                    "mouse".into(),
1105                    DeviceMetadata::new(
1106                        "mouse".into(),
1107                        DeviceType::new(INPUT_MAJOR, 0),
1108                        DeviceMode::Char,
1109                    ),
1110                    input_class.clone(),
1111                    build_device_directory,
1112                )
1113                .expect("add_device");
1114
1115            assert!(registry.objects.root.lookup("bus/pci/devices/mouse".into()).is_some());
1116            assert!(registry.objects.root.lookup("devices/pci/input/mouse".into()).is_some());
1117            assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
1118
1119            registry.remove_device(locked, &current_task, mouse_dev);
1120
1121            assert!(registry.objects.root.lookup("bus/pci/devices/mouse".into()).is_none());
1122            assert!(registry.objects.root.lookup("devices/pci/input/mouse".into()).is_none());
1123            assert!(registry.objects.root.lookup("class/input/mouse".into()).is_none());
1124        })
1125        .await;
1126    }
1127
1128    #[::fuchsia::test]
1129    async fn registry_add_and_remove_numberless_device() {
1130        spawn_kernel_and_run(async |locked, current_task| {
1131            let kernel = current_task.kernel();
1132            let registry = &kernel.device_registry;
1133
1134            let cooling_device = registry.add_numberless_device(
1135                locked,
1136                "cooling_device0".into(),
1137                registry.objects.virtual_thermal_class(),
1138                build_device_directory,
1139            );
1140
1141            assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_some());
1142            assert!(
1143                registry
1144                    .objects
1145                    .root
1146                    .lookup("devices/virtual/thermal/cooling_device0".into())
1147                    .is_some()
1148            );
1149
1150            registry.remove_device(locked, &current_task, cooling_device);
1151
1152            assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_none());
1153            assert!(
1154                registry
1155                    .objects
1156                    .root
1157                    .lookup("devices/virtual/thermal/cooling_device0".into())
1158                    .is_none()
1159            );
1160        })
1161        .await;
1162    }
1163}