Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for registering misc devices #44

Merged
merged 1 commit into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions drivers/char/rust_example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
#![no_std]
#![feature(global_asm)]

extern crate alloc;

use alloc::boxed::Box;
use core::pin::Pin;
use kernel::prelude::*;
use kernel::{cstr, file_operations::FileOperations, miscdev};

module! {
type: RustExample,
Expand All @@ -25,8 +30,18 @@ module! {
},
}

struct RustFile;

impl FileOperations for RustFile {
fn open() -> KernelResult<Self> {
println!("rust file was opened!");
Ok(Self)
}
}

struct RustExample {
message: String,
_dev: Pin<Box<miscdev::Registration>>,
}

impl KernelModule for RustExample {
Expand All @@ -36,8 +51,10 @@ impl KernelModule for RustExample {
println!("Parameters:");
println!(" my_bool: {}", my_bool.read());
println!(" my_i32: {}", my_i32.read());

Ok(RustExample {
message: "on the heap!".to_owned(),
_dev: miscdev::Registration::new_pinned::<RustFile>(cstr!("rust_miscdev"), None)?,
})
}
}
Expand Down
1 change: 1 addition & 0 deletions rust/kernel/src/bindings_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/miscdevice.h>

// bindgen gets confused at certain things
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
1 change: 1 addition & 0 deletions rust/kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod c_types;
pub mod chrdev;
mod error;
pub mod file_operations;
pub mod miscdev;
pub mod prelude;
pub mod printk;
pub mod random;
Expand Down
78 changes: 78 additions & 0 deletions rust/kernel/src/miscdev.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0

use crate::error::{Error, KernelResult};
use crate::file_operations::{FileOperations, FileOperationsVtable};
use crate::{bindings, c_types, CStr};
use alloc::boxed::Box;
use core::marker::PhantomPinned;
use core::pin::Pin;

/// A registration of a misc device.
pub struct Registration {
mdev: Option<bindings::miscdevice>,
_pin: PhantomPinned,
}

impl Registration {
/// Initialises a new registration but does not register it yet. It is allowed to move.
pub fn new() -> Self {
Self {
mdev: None,
_pin: PhantomPinned,
}
}

/// Registers a new misc device. On success, it returns a pinned heap-allocated representation
/// of the registration.
pub fn new_pinned<T: FileOperations>(
name: CStr<'static>,
minor: Option<i32>,
) -> KernelResult<Pin<Box<Self>>> {
let mut r = crate::try_alloc_pinned(Self::new())?;
r.as_mut().register::<T>(name, minor)?;
Ok(r)
}

/// Attempts to actually register the misc device with the rest of the kernel. It must be
/// pinned because the memory block that represents the registration is self-referential. If a
/// minor is not given, the kernel allocates a new one if possible.
pub fn register<T: FileOperations>(
self: Pin<&mut Self>,
name: CStr<'static>,
minor: Option<i32>,
) -> KernelResult<()> {
// SAFETY: we must ensure that we never move out of `this`.
let this = unsafe { self.get_unchecked_mut() };
if this.mdev.is_some() {
// Already registered.
return Err(Error::EINVAL);
}

this.mdev = Some(bindings::miscdevice::default());
let dev = this.mdev.as_mut().unwrap();
dev.fops = &FileOperationsVtable::<T>::VTABLE;
dev.name = name.as_ptr() as *const c_types::c_char;
dev.minor = minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
let ret = unsafe { bindings::misc_register(dev) };
if ret < 0 {
this.mdev = None;
return Err(Error::from_kernel_errno(ret));
}
Ok(())
}
}

// SAFETY: The only method is `register`, which requires a (pinned) mutable `Registration`, so it
// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
unsafe impl Sync for Registration {}

impl Drop for Registration {
/// Removes the registration from the kernel if it has completed successfully before.
fn drop(&mut self) {
if let Some(ref mut dev) = self.mdev {
unsafe {
bindings::misc_deregister(dev);
}
}
}
}