-
Notifications
You must be signed in to change notification settings - Fork 438
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
Simple Rust driver that touches real hardware: PR 4/6 #305
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -30,13 +30,31 @@ pub struct Registration { | |||||||||||||||||||||||||||||||
// (it is fine for multiple threads to have a shared reference to it). | ||||||||||||||||||||||||||||||||
unsafe impl Sync for Registration {} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
extern "C" { | ||||||||||||||||||||||||||||||||
#[allow(improper_ctypes)] | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the improper ctype here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without it, I get the following warning: RUSTC L rust/kernel.o
warning: `extern` block uses type `arch_spinlock_t`, which is not FFI-safe
--> rust/kernel/platdev.rs:36:15
|
36 | pdev: *const bindings::platform_device,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: `#[warn(improper_ctypes)]` on by default
= help: consider adding a member to this struct
= note: this struct has no fields
note: the type is defined here
--> /home/sva/repos/kernel-arcx/rust/bindings_generated.rs:7331:1
|
7331 | pub struct arch_spinlock_t {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: 1 warning emitted There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What type is using Line 10 in d8c6b9c
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi Gary, thanks for the help! I suspect that on arm 32-bit, linux/arch/arm/include/asm/spinlock_types.h Lines 11 to 24 in d8c6b9c
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, when I add
and still the warnings keep coming. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting Do you need to peek into fields of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edited wait a minute... yes, we do need to peek into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But the peeking is just a hack, and will disappear once we proceed. I'll make a mental note to add |
||||||||||||||||||||||||||||||||
fn rust_helper_platform_get_drvdata( | ||||||||||||||||||||||||||||||||
pdev: *const bindings::platform_device, | ||||||||||||||||||||||||||||||||
) -> *mut c_types::c_void; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
#[allow(improper_ctypes)] | ||||||||||||||||||||||||||||||||
fn rust_helper_platform_set_drvdata( | ||||||||||||||||||||||||||||||||
pdev: *mut bindings::platform_device, | ||||||||||||||||||||||||||||||||
data: *mut c_types::c_void, | ||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
extern "C" fn probe_callback<P: PlatformDriver>( | ||||||||||||||||||||||||||||||||
pdev: *mut bindings::platform_device, | ||||||||||||||||||||||||||||||||
) -> c_types::c_int { | ||||||||||||||||||||||||||||||||
from_kernel_result! { | ||||||||||||||||||||||||||||||||
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. | ||||||||||||||||||||||||||||||||
let device_id = unsafe { (*pdev).id }; | ||||||||||||||||||||||||||||||||
P::probe(device_id)?; | ||||||||||||||||||||||||||||||||
let drv_data = P::probe(device_id)?; | ||||||||||||||||||||||||||||||||
let drv_data = drv_data.into_pointer() as *mut c_types::c_void; | ||||||||||||||||||||||||||||||||
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. | ||||||||||||||||||||||||||||||||
unsafe { | ||||||||||||||||||||||||||||||||
rust_helper_platform_set_drvdata(pdev, drv_data); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
Ok(0) | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
@@ -47,7 +65,16 @@ extern "C" fn remove_callback<P: PlatformDriver>( | |||||||||||||||||||||||||||||||
from_kernel_result! { | ||||||||||||||||||||||||||||||||
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. | ||||||||||||||||||||||||||||||||
let device_id = unsafe { (*pdev).id }; | ||||||||||||||||||||||||||||||||
P::remove(device_id)?; | ||||||||||||||||||||||||||||||||
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. | ||||||||||||||||||||||||||||||||
let ptr = unsafe { rust_helper_platform_get_drvdata(pdev) }; | ||||||||||||||||||||||||||||||||
// SAFETY: | ||||||||||||||||||||||||||||||||
// - we allocated this pointer using `P::DrvData::into_pointer`, | ||||||||||||||||||||||||||||||||
// so it is safe to turn back into a `P::DrvData`. | ||||||||||||||||||||||||||||||||
// - the allocation happened in `probe`, no-one freed the memory, | ||||||||||||||||||||||||||||||||
// `remove` is the canonical kernel location to free driver data. so OK | ||||||||||||||||||||||||||||||||
// to convert the pointer back to a Rust structure here. | ||||||||||||||||||||||||||||||||
let drv_data = unsafe { P::DrvData::from_pointer(ptr) }; | ||||||||||||||||||||||||||||||||
P::remove(device_id, drv_data)?; | ||||||||||||||||||||||||||||||||
Ok(0) | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
@@ -124,15 +151,25 @@ impl Drop for Registration { | |||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||
/// Implement this trait whenever you create a platform driver. | ||||||||||||||||||||||||||||||||
pub trait PlatformDriver { | ||||||||||||||||||||||||||||||||
/// Device driver data. | ||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||
/// Corresponds to the data set or retrieved via the kernel's | ||||||||||||||||||||||||||||||||
/// `platform_{set,get}_drvdata()` functions. | ||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||
/// Require that `DrvData` implements `PointerWrapper`. We guarantee to | ||||||||||||||||||||||||||||||||
/// never move the underlying wrapped data structure. This allows | ||||||||||||||||||||||||||||||||
/// driver writers to use pinned or self-referential data structures. | ||||||||||||||||||||||||||||||||
type DrvData: PointerWrapper; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
/// Platform driver probe. | ||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||
/// Called when a new platform device is added or discovered. | ||||||||||||||||||||||||||||||||
/// Implementers should attempt to initialize the device here. | ||||||||||||||||||||||||||||||||
fn probe(device_id: i32) -> Result; | ||||||||||||||||||||||||||||||||
fn probe(device_id: i32) -> Result<Self::DrvData>; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
/// Platform driver remove. | ||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||
/// Called when a platform device is removed. | ||||||||||||||||||||||||||||||||
/// Implementers should prepare the device for complete removal here. | ||||||||||||||||||||||||||||||||
fn remove(device_id: i32) -> Result; | ||||||||||||||||||||||||||||||||
fn remove(device_id: i32, drv_data: Self::DrvData) -> Result; | ||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a FIXME just in case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review! While the PR x/6 effort is ongoing, the driver is a continual WIP. I'm just adding functionality, as it becomes available in the Rust kernel core.
Do you think there is merit in placing a "warning this is a work in progress, not fully functional" comment on top of the driver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable to me. I'll add it.