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