Skip to content

Commit

Permalink
Merge pull request #170 from rcore-os/safereg
Browse files Browse the repository at this point in the history
Add macros to read or write config space in a type safe way
  • Loading branch information
qwandor authored Dec 4, 2024
2 parents 4374e81 + f4605c9 commit b2eb08b
Show file tree
Hide file tree
Showing 15 changed files with 417 additions and 283 deletions.
114 changes: 114 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//! Types and macros for VirtIO device configuration space.
use crate::{transport::Transport, Error};
use zerocopy::{FromBytes, Immutable, IntoBytes};

/// A configuration space register from which the driver can only read.
#[derive(Default, FromBytes, Immutable, IntoBytes)]
#[repr(transparent)]
pub struct ReadOnly<T: Copy + FromBytes>(pub T);

impl<T: Copy + FromBytes> ReadOnly<T> {
/// Constructs a new instance for testing.
pub const fn new(value: T) -> Self {
Self(value)
}
}

/// A configuration space register to which the driver can only write.
#[derive(Default, FromBytes, Immutable, IntoBytes)]
#[repr(transparent)]
pub struct WriteOnly<T: Copy + Immutable + IntoBytes>(pub T);

impl<T: Copy + Immutable + IntoBytes> WriteOnly<T> {
/// Constructs a new instance for testing.
pub const fn new(value: T) -> Self {
Self(value)
}
}

/// A configuration space register which the driver may both read and write.
#[derive(Default, FromBytes, Immutable, IntoBytes)]
#[repr(transparent)]
pub struct ReadWrite<T: Copy + FromBytes + Immutable + IntoBytes>(pub T);

impl<T: Copy + FromBytes + Immutable + IntoBytes> ReadWrite<T> {
/// Constructs a new instance for testing.
pub const fn new(value: T) -> Self {
Self(value)
}
}

/// Marker trait for configuration space registers from which the driver may read.
pub trait ConfigReadable<T> {}

/// Marker trait for configuration space registers to which the driver may write.
pub trait ConfigWritable<T> {}

impl<T: Copy + FromBytes> ConfigReadable<T> for ReadOnly<T> {}
impl<T: Copy + FromBytes + Immutable + IntoBytes> ConfigReadable<T> for ReadWrite<T> {}
impl<T: Copy + FromBytes + Immutable + IntoBytes> ConfigWritable<T> for ReadWrite<T> {}
impl<T: Copy + Immutable + IntoBytes> ConfigWritable<T> for WriteOnly<T> {}

/// Wrapper for `Transport::read_config_space`` with an extra dummy parameter to force the correct
/// type to be inferred.
#[inline(always)]
pub(crate) fn read_help<T, V, R>(
transport: &T,
offset: usize,
_dummy_r: Option<R>,
) -> Result<V, Error>
where
T: Transport,
V: FromBytes,
R: ConfigReadable<V>,
{
transport.read_config_space(offset)
}

/// Wrapper for Transport::write_config_space with an extra dummy parameter to force the correct
/// type to be inferred.
#[inline(always)]
pub(crate) fn write_help<T, V, W>(
transport: &mut T,
offset: usize,
value: V,
_dummy_w: Option<W>,
) -> Result<(), Error>
where
T: Transport,
V: Immutable + IntoBytes,
W: ConfigWritable<V>,
{
transport.write_config_space(offset, value)
}

/// Reads the given field of the given struct from the device config space via the given transport.
macro_rules! read_config {
($transport:expr, $struct:ty, $field:ident) => {{
let dummy_struct: Option<$struct> = None;
let dummy_field = dummy_struct.map(|s| s.$field);
crate::config::read_help(
&$transport,
core::mem::offset_of!($struct, $field),
dummy_field,
)
}};
}

/// Writes the given field of the given struct from the device config space via the given transport.
macro_rules! write_config {

Check warning on line 100 in src/config.rs

View workflow job for this annotation

GitHub Actions / build

unused macro definition: `write_config`

Check warning on line 100 in src/config.rs

View workflow job for this annotation

GitHub Actions / build

unused macro definition: `write_config`
($transport:expr, $struct:ty, $field:ident, $value:expr) => {{
let dummy_struct: Option<$struct> = None;
let dummy_field = dummy_struct.map(|s| s.$field);
crate::config::write_help(
&mut $transport,
core::mem::offset_of!($struct, $field),
$value,
dummy_field,
)
}};
}

pub(crate) use read_config;
pub(crate) use write_config;

Check warning on line 114 in src/config.rs

View workflow job for this annotation

GitHub Actions / build

unused import: `write_config`

Check warning on line 114 in src/config.rs

View workflow job for this annotation

GitHub Actions / build

unused import: `write_config`
Loading

0 comments on commit b2eb08b

Please sign in to comment.