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