Bläddra i källkod

Use zerocopy rather than our AsBuf trait.

The derive macros in zerocopy check that the structs are actually valid
to convert to and from bytes. This required converting some enums to
structs, as there's no guarantee that the value we get is actually a
valid enum variant.
Andrew Walbran 2 år sedan
förälder
incheckning
8048887954
5 ändrade filer med 47 tillägg och 51 borttagningar
  1. 1 0
      Cargo.toml
  2. 26 22
      src/blk.rs
  3. 4 5
      src/input.rs
  4. 0 11
      src/lib.rs
  5. 16 13
      src/net.rs

+ 1 - 0
Cargo.toml

@@ -17,6 +17,7 @@ categories = ["hardware-support", "no-std"]
 [dependencies]
 log = "0.4"
 bitflags = "1.3"
+zerocopy = "0.6.1"
 
 [features]
 default = ["alloc"]

+ 26 - 22
src/blk.rs

@@ -4,6 +4,7 @@ use crate::transport::Transport;
 use crate::volatile::{volread, Volatile};
 use bitflags::*;
 use log::*;
+use zerocopy::{AsBytes, FromBytes};
 
 const QUEUE: u16 = 0;
 
@@ -77,12 +78,12 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
         };
         let mut resp = BlkResp::default();
         self.queue.add_notify_wait_pop(
-            &[req.as_buf()],
-            &[buf, resp.as_buf_mut()],
+            &[req.as_bytes()],
+            &[buf, resp.as_bytes_mut()],
             &mut self.transport,
         )?;
         match resp.status {
-            RespStatus::Ok => Ok(()),
+            RespStatus::OK => Ok(()),
             _ => Err(Error::IoError),
         }
     }
@@ -127,7 +128,9 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
             reserved: 0,
             sector: block_id as u64,
         };
-        let token = self.queue.add(&[req.as_buf()], &[buf, resp.as_buf_mut()])?;
+        let token = self
+            .queue
+            .add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()])?;
         self.transport.notify(QUEUE);
         Ok(token)
     }
@@ -142,12 +145,12 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
         };
         let mut resp = BlkResp::default();
         self.queue.add_notify_wait_pop(
-            &[req.as_buf(), buf],
-            &[resp.as_buf_mut()],
+            &[req.as_bytes(), buf],
+            &[resp.as_bytes_mut()],
             &mut self.transport,
         )?;
         match resp.status {
-            RespStatus::Ok => Ok(()),
+            RespStatus::OK => Ok(()),
             _ => Err(Error::IoError),
         }
     }
@@ -181,7 +184,9 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
             reserved: 0,
             sector: block_id as u64,
         };
-        let token = self.queue.add(&[req.as_buf(), buf], &[resp.as_buf_mut()])?;
+        let token = self
+            .queue
+            .add(&[req.as_bytes(), buf], &[resp.as_bytes_mut()])?;
         self.transport.notify(QUEUE);
         Ok(token)
     }
@@ -227,7 +232,7 @@ struct BlkConfig {
 }
 
 #[repr(C)]
-#[derive(Debug)]
+#[derive(AsBytes, Debug)]
 struct BlkReq {
     type_: ReqType,
     reserved: u32,
@@ -236,7 +241,7 @@ struct BlkReq {
 
 /// Response of a VirtIOBlk request.
 #[repr(C)]
-#[derive(Debug)]
+#[derive(AsBytes, Debug, FromBytes)]
 pub struct BlkResp {
     status: RespStatus,
 }
@@ -249,7 +254,7 @@ impl BlkResp {
 }
 
 #[repr(u32)]
-#[derive(Debug)]
+#[derive(AsBytes, Debug)]
 enum ReqType {
     In = 0,
     Out = 1,
@@ -259,23 +264,25 @@ enum ReqType {
 }
 
 /// Status of a VirtIOBlk request.
-#[repr(u8)]
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum RespStatus {
+#[repr(transparent)]
+#[derive(AsBytes, Copy, Clone, Debug, Eq, FromBytes, PartialEq)]
+pub struct RespStatus(u8);
+
+impl RespStatus {
     /// Ok.
-    Ok = 0,
+    pub const OK: RespStatus = RespStatus(0);
     /// IoErr.
-    IoErr = 1,
+    pub const IO_ERR: RespStatus = RespStatus(1);
     /// Unsupported yet.
-    Unsupported = 2,
+    pub const UNSUPPORTED: RespStatus = RespStatus(2);
     /// Not ready.
-    _NotReady = 3,
+    pub const NOT_READY: RespStatus = RespStatus(3);
 }
 
 impl Default for BlkResp {
     fn default() -> Self {
         BlkResp {
-            status: RespStatus::_NotReady,
+            status: RespStatus::NOT_READY,
         }
     }
 }
@@ -332,6 +339,3 @@ bitflags! {
         const NOTIFICATION_DATA     = 1 << 38;
     }
 }
-
-unsafe impl AsBuf for BlkReq {}
-unsafe impl AsBuf for BlkResp {}

+ 4 - 5
src/input.rs

@@ -5,6 +5,7 @@ use alloc::boxed::Box;
 use bitflags::*;
 use core::ptr::NonNull;
 use log::*;
+use zerocopy::{AsBytes, FromBytes};
 
 /// Virtual human interface devices such as keyboards, mice and tablets.
 ///
@@ -37,7 +38,7 @@ impl<H: Hal, T: Transport> VirtIOInput<H, T> {
         let status_queue = VirtQueue::new(&mut transport, QUEUE_STATUS, QUEUE_SIZE as u16)?;
         for (i, event) in event_buf.as_mut().iter_mut().enumerate() {
             // Safe because the buffer lasts as long as the queue.
-            let token = unsafe { event_queue.add(&[], &[event.as_buf_mut()])? };
+            let token = unsafe { event_queue.add(&[], &[event.as_bytes_mut()])? };
             assert_eq!(token, i as u16);
         }
 
@@ -63,7 +64,7 @@ impl<H: Hal, T: Transport> VirtIOInput<H, T> {
             let event = &mut self.event_buf[token as usize];
             // requeue
             // Safe because buffer lasts as long as the queue.
-            if let Ok(new_token) = unsafe { self.event_queue.add(&[], &[event.as_buf_mut()]) } {
+            if let Ok(new_token) = unsafe { self.event_queue.add(&[], &[event.as_bytes_mut()]) } {
                 // This only works because nothing happen between `pop_used` and `add` that affects
                 // the list of free descriptors in the queue, so `add` reuses the descriptor which
                 // was just freed by `pop_used`.
@@ -161,7 +162,7 @@ struct DevIDs {
 /// Both queues use the same `virtio_input_event` struct. `type`, `code` and `value`
 /// are filled according to the Linux input layer (evdev) interface.
 #[repr(C)]
-#[derive(Clone, Copy, Debug, Default)]
+#[derive(AsBytes, Clone, Copy, Debug, Default, FromBytes)]
 pub struct InputEvent {
     /// Event type.
     pub event_type: u16,
@@ -171,8 +172,6 @@ pub struct InputEvent {
     pub value: u32,
 }
 
-unsafe impl AsBuf for InputEvent {}
-
 bitflags! {
     struct Feature: u64 {
         // device independent

+ 0 - 11
src/lib.rs

@@ -30,7 +30,6 @@ use self::queue::VirtQueue;
 pub use self::transport::mmio::{MmioError, MmioTransport, MmioVersion, VirtIOHeader};
 pub use self::transport::pci;
 pub use self::transport::{DeviceStatus, DeviceType, Transport};
-use core::mem::size_of;
 use hal::*;
 
 /// The page size in bytes supported by the library (4 KiB).
@@ -69,13 +68,3 @@ fn align_up(size: usize) -> usize {
 fn pages(size: usize) -> usize {
     (size + PAGE_SIZE - 1) / PAGE_SIZE
 }
-
-/// Convert a struct into a byte buffer.
-unsafe trait AsBuf: Sized {
-    fn as_buf(&self) -> &[u8] {
-        unsafe { core::slice::from_raw_parts(self as *const _ as _, size_of::<Self>()) }
-    }
-    fn as_buf_mut(&mut self) -> &mut [u8] {
-        unsafe { core::slice::from_raw_parts_mut(self as *mut _ as _, size_of::<Self>()) }
-    }
-}

+ 16 - 13
src/net.rs

@@ -5,6 +5,7 @@ use crate::transport::Transport;
 use crate::volatile::{volread, ReadOnly};
 use bitflags::*;
 use log::*;
+use zerocopy::{AsBytes, FromBytes};
 
 /// The virtio network device is a virtual ethernet card.
 ///
@@ -75,7 +76,7 @@ impl<H: Hal, T: Transport> VirtIONet<H, T> {
     /// Receive a packet.
     pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize> {
         let mut header = MaybeUninit::<Header>::uninit();
-        let header_buf = unsafe { (*header.as_mut_ptr()).as_buf_mut() };
+        let header_buf = unsafe { (*header.as_mut_ptr()).as_bytes_mut() };
         let len =
             self.recv_queue
                 .add_notify_wait_pop(&[], &[header_buf, buf], &mut self.transport)?;
@@ -87,7 +88,7 @@ impl<H: Hal, T: Transport> VirtIONet<H, T> {
     pub fn send(&mut self, buf: &[u8]) -> Result {
         let header = unsafe { MaybeUninit::<Header>::zeroed().assume_init() };
         self.send_queue
-            .add_notify_wait_pop(&[header.as_buf(), buf], &[], &mut self.transport)?;
+            .add_notify_wait_pop(&[header.as_bytes(), buf], &[], &mut self.transport)?;
         Ok(())
     }
 }
@@ -186,7 +187,7 @@ type EthernetAddress = [u8; 6];
 
 // virtio 5.1.6 Device Operation
 #[repr(C)]
-#[derive(Debug)]
+#[derive(AsBytes, Debug, FromBytes)]
 struct Header {
     flags: Flags,
     gso_type: GsoType,
@@ -197,9 +198,9 @@ struct Header {
     // payload starts from here
 }
 
-unsafe impl AsBuf for Header {}
-
 bitflags! {
+    #[repr(transparent)]
+    #[derive(AsBytes, FromBytes)]
     struct Flags: u8 {
         const NEEDS_CSUM = 1;
         const DATA_VALID = 2;
@@ -207,14 +208,16 @@ bitflags! {
     }
 }
 
-#[repr(u8)]
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-enum GsoType {
-    None = 0,
-    TcpV4 = 1,
-    Udp = 3,
-    TcpV6 = 4,
-    Ecn = 0x80,
+#[repr(transparent)]
+#[derive(AsBytes, Debug, Copy, Clone, Eq, FromBytes, PartialEq)]
+struct GsoType(u8);
+
+impl GsoType {
+    const NONE: GsoType = GsoType(0);
+    const TCPV4: GsoType = GsoType(1);
+    const UDP: GsoType = GsoType(3);
+    const TCPV6: GsoType = GsoType(4);
+    const ECN: GsoType = GsoType(0x80);
 }
 
 const QUEUE_RECEIVE: u16 = 0;