Skip to content

Commit

Permalink
Directly implement AsBytes trait for Generic structs [experiemntal].
Browse files Browse the repository at this point in the history
Attempts to completely remove the AsSliceU8 trait by directly
implementing AsBytes for generic structs because of lack of support for
generics using derive.

Fixes #692.

Signed-off-by: Joanne Chen <[email protected]>
  • Loading branch information
Joanne Chen committed Apr 21, 2023
1 parent 5934f22 commit eb56619
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 97 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ lock_api = "0.4"
num = { version = "0.4", default-features = false }
num-traits = { version = "0.2", default-features = false }
num-derive = "0.3"
zerocopy = "0.6"
zerocopy = "0.7.0-alpha.3"

[dependencies.smoltcp]
version = "0.9"
Expand Down
5 changes: 3 additions & 2 deletions src/drivers/fs/virtio_fs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use zerocopy::AsBytes;

use self::constants::{FeatureSet, Features};
use crate::config::VIRTIO_MAX_QUEUE_SIZE;
Expand All @@ -12,7 +13,7 @@ use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg};
#[cfg(feature = "pci")]
use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg};
use crate::drivers::virtio::virtqueue::{
AsSliceU8, BuffSpec, BufferToken, Bytes, Virtq, VqIndex, VqSize, VqType,
BuffSpec, BufferToken, Bytes, Virtq, VqIndex, VqSize, VqType,
};
use crate::fs::fuse::{self, FuseInterface};

Expand Down Expand Up @@ -168,7 +169,7 @@ impl FuseInterface for VirtioFsDriver {
self.ready_queue.push(tkn);

if let Some(response) = response {
rsp.as_slice_u8_mut()[..response.len()].copy_from_slice(response.as_ref());
rsp.as_bytes_mut()[..response.len()].copy_from_slice(response.as_ref());
}
}
}
Expand Down
56 changes: 7 additions & 49 deletions src/drivers/virtio/virtqueue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ impl Virtq {
///
/// Structures provided to the Queue must pass this test, otherwise the queue
/// currently panics.
pub fn check_bounds<T: AsSliceU8>(data: &T) -> bool {
let slice = data.as_slice_u8();
pub fn check_bounds<T: AsBytes>(data: &T) -> bool {
let slice = data.as_bytes();

let start_virt = (&slice[0] as *const u8) as usize;
let end_virt = (&slice[slice.len() - 1] as *const u8) as usize;
Expand Down Expand Up @@ -443,7 +443,7 @@ impl Virtq {
/// ```
/// Then he must split the structure after the send part and provide the respective part via the send argument and the respective other
/// part via the recv argument.
pub fn prep_transfer_from_raw<T: AsSliceU8 + 'static, K: AsSliceU8 + 'static>(
pub fn prep_transfer_from_raw<T: AsBytes + 'static, K: AsBytes + 'static>(
&self,
rc_self: Rc<Virtq>,
send: Option<(*mut T, BuffSpec<'_>)>,
Expand Down Expand Up @@ -519,48 +519,6 @@ impl Virtq {
}
}

/// The trait needs to be implemented on structures which are to be used via the `prep_transfer()` function of virtqueues and for
/// structures which are to be used to write data into buffers of a [BufferToken](BufferToken) via `BufferToken.write()` or
/// `BufferToken.write_seq()`.
///
/// **INFO:*
/// The trait provides a decent default implementation. Please look at the code for details.
/// The provided default implementation computes the size of the given structure via `core::mem::size_of_val(&self)`
/// and then casts the given `*const Self` pointer of the structure into an `*const u8`.
///
/// Users must be really careful, and check, whether the memory representation of the given structure equals
/// the representation the device expects. It is advised to only use `#[repr(C)]` and to check the output
/// of `as_slice_u8` and `as_slice_u8_mut`.
pub trait AsSliceU8 {
/// Retruns the size of the structure
///
/// In case of an unsized structure, the function should returns
/// the exact value of the structure.
fn len(&self) -> usize {
core::mem::size_of_val(self)
}

/// Returns a slice of the given structure.
///
/// ** WARN:**
/// * The slice must be little endian coded in order to be understood by the device
/// * The slice must serialize the actual structure the device expects, as the queue will use
/// the addresses of the slice in order to refer to the structure.
fn as_slice_u8(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts((self as *const _) as *const u8, self.len()) }
}

/// Returns a mutable slice of the given structure.
///
/// ** WARN:**
/// * The slice must be little endian coded in order to be understood by the device
/// * The slice must serialize the actual structure the device expects, as the queue will use
/// the addresses of the slice in order to refer to the structure.
fn as_slice_u8_mut(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut((self as *const _) as *mut u8, self.len()) }
}
}

/// The [Transfer](Transfer) will be received when a [TransferToken](TransferToken) is dispatched via `TransferToken.dispatch()` or
/// via `TransferToken.dispatch_blocking()`.
///
Expand Down Expand Up @@ -1605,18 +1563,18 @@ impl BufferToken {
/// descriptors.
/// The `write()` function does NOT take into account the distinct descriptors of a buffer but treats the buffer as a single continuous
/// memory element and as a result writes `T` or `H` as a slice of bytes into this memory.
pub fn write<K: AsSliceU8 + ?Sized, H: AsSliceU8 + ?Sized>(
pub fn write<K: AsBytes + ?Sized, H: AsBytes + ?Sized>(
mut self,
send: Option<&K>,
recv: Option<&H>,
) -> Result<TransferToken, VirtqError> {
if let Some(data) = send {
match self.send_buff.as_mut() {
Some(buff) => {
if buff.len() < data.as_slice_u8().len() {
if buff.len() < data.as_bytes().len() {
return Err(VirtqError::WriteToLarge(self));
} else {
let data_slc = data.as_slice_u8();
let data_slc = data.as_bytes();
let mut from = 0usize;

for i in 0..buff.num_descr() {
Expand All @@ -1640,7 +1598,7 @@ impl BufferToken {
if let Some(data) = recv {
match self.recv_buff.as_mut() {
Some(buff) => {
let data_slc = data.as_slice_u8();
let data_slc = data.as_bytes();

if buff.len() < data_slc.len() {
return Err(VirtqError::WriteToLarge(self));
Expand Down
37 changes: 19 additions & 18 deletions src/drivers/virtio/virtqueue/packed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use alloc::vec::Vec;
use core::cell::RefCell;
use core::ptr;
use core::sync::atomic::{fence, Ordering};
use zerocopy::AsBytes;

use align_address::Align;

Expand All @@ -20,7 +21,7 @@ use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl};
use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl};
use super::error::VirtqError;
use super::{
AsSliceU8, BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Pinned,
BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Pinned,
Transfer, TransferState, TransferToken, Virtq, VqIndex, VqSize,
};
use crate::arch::mm::paging::{BasePageSize, PageSize};
Expand Down Expand Up @@ -1314,7 +1315,7 @@ impl PackedVq {
}

/// See `Virtq.prep_transfer_from_raw()` documentation.
pub fn prep_transfer_from_raw<T: AsSliceU8 + 'static, K: AsSliceU8 + 'static>(
pub fn prep_transfer_from_raw<T: AsBytes + 'static, K: AsBytes + 'static>(
&self,
master: Rc<Virtq>,
send: Option<(*mut T, BuffSpec<'_>)>,
Expand All @@ -1325,7 +1326,7 @@ impl PackedVq {
(Some((send_data, send_spec)), None) => {
match send_spec {
BuffSpec::Single(size) => {
let data_slice = unsafe { (*send_data).as_slice_u8() };
let data_slice = unsafe { (*send_data).as_bytes() };

// Buffer must have the right size
if data_slice.len() != size.into() {
Expand Down Expand Up @@ -1358,7 +1359,7 @@ impl PackedVq {
})
}
BuffSpec::Multiple(size_lst) => {
let data_slice = unsafe { (*send_data).as_slice_u8() };
let data_slice = unsafe { (*send_data).as_bytes() };
let mut desc_lst: Vec<MemDescr> = Vec::with_capacity(size_lst.len());
let mut index = 0usize;

Expand Down Expand Up @@ -1399,7 +1400,7 @@ impl PackedVq {
})
}
BuffSpec::Indirect(size_lst) => {
let data_slice = unsafe { (*send_data).as_slice_u8() };
let data_slice = unsafe { (*send_data).as_bytes() };
let mut desc_lst: Vec<MemDescr> = Vec::with_capacity(size_lst.len());
let mut index = 0usize;

Expand Down Expand Up @@ -1447,7 +1448,7 @@ impl PackedVq {
(None, Some((recv_data, recv_spec))) => {
match recv_spec {
BuffSpec::Single(size) => {
let data_slice = unsafe { (*recv_data).as_slice_u8() };
let data_slice = unsafe { (*recv_data).as_bytes() };

// Buffer must have the right size
if data_slice.len() != size.into() {
Expand Down Expand Up @@ -1480,7 +1481,7 @@ impl PackedVq {
})
}
BuffSpec::Multiple(size_lst) => {
let data_slice = unsafe { (*recv_data).as_slice_u8() };
let data_slice = unsafe { (*recv_data).as_bytes() };
let mut desc_lst: Vec<MemDescr> = Vec::with_capacity(size_lst.len());
let mut index = 0usize;

Expand Down Expand Up @@ -1521,7 +1522,7 @@ impl PackedVq {
})
}
BuffSpec::Indirect(size_lst) => {
let data_slice = unsafe { (*recv_data).as_slice_u8() };
let data_slice = unsafe { (*recv_data).as_bytes() };
let mut desc_lst: Vec<MemDescr> = Vec::with_capacity(size_lst.len());
let mut index = 0usize;

Expand Down Expand Up @@ -1569,7 +1570,7 @@ impl PackedVq {
(Some((send_data, send_spec)), Some((recv_data, recv_spec))) => {
match (send_spec, recv_spec) {
(BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => {
let send_data_slice = unsafe { (*send_data).as_slice_u8() };
let send_data_slice = unsafe { (*send_data).as_bytes() };

// Buffer must have the right size
if send_data_slice.len() != send_size.into() {
Expand All @@ -1584,7 +1585,7 @@ impl PackedVq {
Err(vq_err) => return Err(vq_err),
};

let recv_data_slice = unsafe { (*recv_data).as_slice_u8() };
let recv_data_slice = unsafe { (*recv_data).as_bytes() };

// Buffer must have the right size
if recv_data_slice.len() != recv_size.into() {
Expand Down Expand Up @@ -1621,7 +1622,7 @@ impl PackedVq {
})
}
(BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => {
let send_data_slice = unsafe { (*send_data).as_slice_u8() };
let send_data_slice = unsafe { (*send_data).as_bytes() };

// Buffer must have the right size
if send_data_slice.len() != send_size.into() {
Expand All @@ -1636,7 +1637,7 @@ impl PackedVq {
Err(vq_err) => return Err(vq_err),
};

let recv_data_slice = unsafe { (*recv_data).as_slice_u8() };
let recv_data_slice = unsafe { (*recv_data).as_bytes() };
let mut recv_desc_lst: Vec<MemDescr> =
Vec::with_capacity(recv_size_lst.len());
let mut index = 0usize;
Expand Down Expand Up @@ -1684,7 +1685,7 @@ impl PackedVq {
})
}
(BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => {
let send_data_slice = unsafe { (*send_data).as_slice_u8() };
let send_data_slice = unsafe { (*send_data).as_bytes() };
let mut send_desc_lst: Vec<MemDescr> =
Vec::with_capacity(send_size_lst.len());
let mut index = 0usize;
Expand All @@ -1710,7 +1711,7 @@ impl PackedVq {
index += usize::from(*byte);
}

let recv_data_slice = unsafe { (*recv_data).as_slice_u8() };
let recv_data_slice = unsafe { (*recv_data).as_bytes() };
let mut recv_desc_lst: Vec<MemDescr> =
Vec::with_capacity(recv_size_lst.len());
let mut index = 0usize;
Expand Down Expand Up @@ -1758,7 +1759,7 @@ impl PackedVq {
})
}
(BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => {
let send_data_slice = unsafe { (*send_data).as_slice_u8() };
let send_data_slice = unsafe { (*send_data).as_bytes() };
let mut send_desc_lst: Vec<MemDescr> =
Vec::with_capacity(send_size_lst.len());
let mut index = 0usize;
Expand All @@ -1784,7 +1785,7 @@ impl PackedVq {
index += usize::from(*byte);
}

let recv_data_slice = unsafe { (*recv_data).as_slice_u8() };
let recv_data_slice = unsafe { (*recv_data).as_bytes() };

// Buffer must have the right size
if recv_data_slice.len() != recv_size.into() {
Expand Down Expand Up @@ -1821,7 +1822,7 @@ impl PackedVq {
})
}
(BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => {
let send_data_slice = unsafe { (*send_data).as_slice_u8() };
let send_data_slice = unsafe { (*send_data).as_bytes() };
let mut send_desc_lst: Vec<MemDescr> =
Vec::with_capacity(send_size_lst.len());
let mut index = 0usize;
Expand All @@ -1844,7 +1845,7 @@ impl PackedVq {
index += usize::from(*byte);
}

let recv_data_slice = unsafe { (*recv_data).as_slice_u8() };
let recv_data_slice = unsafe { (*recv_data).as_bytes() };
let mut recv_desc_lst: Vec<MemDescr> =
Vec::with_capacity(recv_size_lst.len());
let mut index = 0usize;
Expand Down
Loading

0 comments on commit eb56619

Please sign in to comment.