Skip to content

Commit 054867b

Browse files
committed
virtio: provide a rust interface of virtio_driver in rust
Wrap the struct virtio_driver in rust. Signed-off-by: Li Hongyu <[email protected]>
1 parent f42f82c commit 054867b

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed

rust/bindings/bindings_helper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
#include <linux/sysctl.h>
3636
#include <linux/uaccess.h>
3737
#include <linux/uio.h>
38+
#include <linux/virtio.h>
39+
#include <linux/vringh.h>
40+
#include <linux/virtio_config.h>
41+
#include <linux/virtio_ring.h>
3842
#include <uapi/linux/android/binder.h>
3943
#include <linux/fs_parser.h>
4044

rust/kernel/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ pub mod user_ptr;
104104
#[cfg(CONFIG_KUNIT)]
105105
pub mod kunit;
106106

107+
#[cfg(CONFIG_VIRTIO)]
108+
pub mod virtio;
109+
107110
#[doc(hidden)]
108111
pub use build_error::build_error;
109112

rust/kernel/virtio.rs

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Virtio.
4+
//!
5+
//! C header: [`include/linux/virtio.h`](../../../../include/linux/virtio.h)
6+
7+
use crate::{
8+
bindings, device, driver, error::from_kernel_result, str::CStr, to_result,
9+
types::PointerWrapper, Result, ThisModule,
10+
};
11+
12+
/// A registration of a virtio driver.
13+
pub type Registration<T> = driver::Registration<Adapter<T>>;
14+
15+
/// Id of a Virtio device.
16+
#[derive(Clone, Copy)]
17+
pub struct DeviceId {
18+
/// Device id.
19+
pub device: u32,
20+
21+
/// Vendor id of the virtio device.
22+
pub vendor: u32,
23+
}
24+
25+
// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores in `virtio_id::data`.
26+
unsafe impl const driver::RawDeviceId for DeviceId {
27+
type RawType = bindings::virtio_device_id;
28+
const ZERO: Self::RawType = bindings::virtio_device_id {
29+
device: 0,
30+
vendor: 0,
31+
};
32+
33+
fn to_rawid(&self, _offset: isize) -> Self::RawType {
34+
bindings::virtio_device_id {
35+
device: self.device,
36+
vendor: self.vendor,
37+
}
38+
}
39+
}
40+
41+
/// An adapter for the registration of virtio drivers.
42+
pub struct Adapter<T: Driver>(T);
43+
44+
impl<T: Driver> driver::DriverOps for Adapter<T> {
45+
type RegType = bindings::virtio_driver;
46+
47+
unsafe fn register(
48+
reg: *mut bindings::virtio_driver,
49+
name: &'static CStr,
50+
module: &'static ThisModule,
51+
) -> Result {
52+
// SAFETY: By the safety requirements of this function (defined in the trait definition),
53+
// `reg` is non-null and valid.
54+
let vdrv = unsafe { &mut *reg };
55+
56+
vdrv.driver.name = name.as_char_ptr();
57+
vdrv.driver.owner = module.0;
58+
vdrv.probe = Some(Self::probe_callback);
59+
vdrv.remove = Some(Self::remove_callback);
60+
if let Some(t) = T::ID_TABLE {
61+
vdrv.id_table = t.as_ref();
62+
}
63+
// SAFETY:
64+
// - `vdrv` lives at least until the call to `register_virtio_driver()` returns.
65+
// - `name` pointer has static lifetime.
66+
// - `module.0` lives at least as long as the module.
67+
// - `probe()` and `remove()` are static functions.
68+
// - `id_table` is either a raw pointer with static lifetime,
69+
// as guaranteed by the [`driver::IdTable`] type, or null.
70+
to_result(unsafe { bindings::register_virtio_driver(reg) })
71+
}
72+
73+
unsafe fn unregister(reg: *mut bindings::virtio_driver) {
74+
// SAFETY: By the safety requirements of this function (defined in the trait definition),
75+
// `reg` was passed (and updated) by a previous successful call to
76+
// `register_virtio_driver`.
77+
unsafe { bindings::unregister_virtio_driver(reg) };
78+
}
79+
}
80+
81+
impl<T: Driver> Adapter<T> {
82+
extern "C" fn probe_callback(vdev: *mut bindings::virtio_device) -> core::ffi::c_int {
83+
from_kernel_result! {
84+
// SAFETY: `vdev` is valid by the contract with the C code. `dev` is alive only for the
85+
// duration of this call, so it is guaranteed to remain alive for the lifetime of
86+
// `vdev`.
87+
let mut dev = unsafe { Device::from_ptr(vdev) };
88+
let data = T::probe(&mut dev)?;
89+
// SAFETY: `vdev` is guaranteed to be a valid, non-null pointer.
90+
unsafe{(*vdev).priv_ = T::Data::into_pointer(data) as _;}
91+
Ok(0)
92+
}
93+
}
94+
95+
extern "C" fn remove_callback(vdev: *mut bindings::virtio_device) {
96+
// SAFETY: `vdev` is guaranteed to be a valid, non-null pointer.
97+
let ptr = unsafe { *vdev }.priv_;
98+
// SAFETY:
99+
// - we allocated this pointer using `T::Data::into_pointer`,
100+
// so it is safe to turn back into a `T::Data`.
101+
// - the allocation happened in `probe`, no-one freed the memory,
102+
// `remove` is the canonical kernel location to free driver data. so OK
103+
// to convert the pointer back to a Rust structure here.
104+
let data = unsafe { T::Data::from_pointer(ptr) };
105+
T::remove(&data);
106+
<T::Data as driver::DeviceRemoval>::device_remove(&data);
107+
}
108+
}
109+
110+
/// A virtio driver.
111+
pub trait Driver {
112+
/// Data stored on device by driver.
113+
type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = ();
114+
115+
/// The table of device ids supported by the driver.
116+
const ID_TABLE: Option<driver::IdTable<'static, DeviceId, ()>> = None;
117+
118+
/// Probes for the device with the given id.
119+
fn probe(dev: &mut Device) -> Result<Self::Data>;
120+
121+
/// Cleans any resources up that are associated with the device.
122+
///
123+
/// This is called when the driver is detached from the device.
124+
fn remove(_data: &Self::Data) {}
125+
}
126+
127+
/// A Virtio device.
128+
///
129+
/// # Invariants
130+
///
131+
/// The field `ptr` is non-null and valid for the lifetime of the object.
132+
pub struct Device {
133+
ptr: *mut bindings::virtio_device,
134+
}
135+
136+
impl Device {
137+
/// Creates a new device from the given pointer.
138+
///
139+
/// # Safety
140+
///
141+
/// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
142+
/// instance.
143+
unsafe fn from_ptr(ptr: *mut bindings::virtio_device) -> Self {
144+
// INVARIANT: The safety requirements of the function ensure the lifetime invariant.
145+
Self { ptr }
146+
}
147+
}
148+
149+
// SAFETY: The device returned by `raw_device` is the raw virtio device.
150+
unsafe impl device::RawDevice for Device {
151+
fn raw_device(&self) -> *mut bindings::device {
152+
// SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
153+
unsafe { &mut (*self.ptr).dev }
154+
}
155+
}
156+
157+
/// Declares a kernel module that exposes a single virtio driver.
158+
///
159+
/// # Examples
160+
///
161+
/// ```ignore
162+
/// # use kernel::{virtio, define_virtio_id_table, module_virtio_driver};
163+
/// #
164+
/// struct MyDriver;
165+
/// impl virtio::Driver for MyDriver {
166+
/// // [...]
167+
/// # fn probe(_dev: &mut virtio::Device) -> Result {
168+
/// # Ok(())
169+
/// # }
170+
/// # define_virtio_id_table! {(), [
171+
/// # ({ device: 0x00000001, vendor: 0xffffffff }, None),
172+
/// # ]}
173+
/// }
174+
///
175+
/// module_virtio_driver! {
176+
/// type: MyDriver,
177+
/// name: b"module_name",
178+
/// author: b"Author name",
179+
/// license: b"GPL",
180+
/// }
181+
/// ```
182+
#[macro_export]
183+
macro_rules! module_virtio_driver {
184+
($($f:tt)*) => {
185+
$crate::module_driver!(<T>, $crate::virtio::Adapter<T>, { $($f)* });
186+
};
187+
}
188+
189+
/// Defines the id table for virtio devices.
190+
///
191+
/// # Examples
192+
///
193+
/// ```
194+
/// # use kernel::{virtio, define_virtio_id_table};
195+
/// #
196+
/// # struct Sample;
197+
/// # impl kernel::virtio::Driver for Sample {
198+
/// # fn probe(_dev: &mut virtio::Device) -> Result {
199+
/// # Ok(())
200+
/// # }
201+
/// define_virtio_id_table! {(), [
202+
/// ({ device: 0x00000001, vendor: 0xffffffff }, None),
203+
/// ]}
204+
/// # }
205+
/// ```
206+
#[macro_export]
207+
macro_rules! define_virtio_id_table {
208+
($data_type:ty, $($t:tt)*) => {
209+
$crate::define_id_table!(ID_TABLE, $crate::virtio::DeviceId, $data_type, $($t)*);
210+
};
211+
}

0 commit comments

Comments
 (0)