Skip to content

Commit 19406b2

Browse files
committed
Add packed descriptor
Signed-off-by: Wenyu Huang <[email protected]>
1 parent d059319 commit 19406b2

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

virtio-queue/src/desc/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use vm_memory::{ByteValued, Le16, Le32, Le64};
44

5+
pub mod packed;
56
pub mod split;
67

78
/// A virtio descriptor's layout constraints with C representation.
@@ -32,3 +33,9 @@ impl From<Descriptor> for split::Descriptor {
3233
split::Descriptor::new(desc.0.into(), desc.1.into(), desc.2.into(), desc.3.into())
3334
}
3435
}
36+
37+
impl From<Descriptor> for packed::Descriptor {
38+
fn from(desc: Descriptor) -> packed::Descriptor {
39+
packed::Descriptor::new(desc.0.into(), desc.1.into(), desc.2.into(), desc.3.into())
40+
}
41+
}

virtio-queue/src/desc/packed.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//! packed descriptor
2+
use virtio_bindings::bindings::virtio_ring::{
3+
VRING_DESC_F_INDIRECT, VRING_DESC_F_NEXT, VRING_DESC_F_WRITE,
4+
};
5+
use vm_memory::{ByteValued, GuestAddress, Le16, Le32, Le64};
6+
7+
/// A virtio packed descriptor constraints with C representation.
8+
#[repr(C)]
9+
#[derive(Default, Clone, Copy, Debug)]
10+
pub struct Descriptor {
11+
/// Guest physical address of device specific data.
12+
addr: Le64,
13+
/// Length of device specific data.
14+
len: Le32,
15+
/// Index of descriptor in the descriptor table.
16+
id: Le16,
17+
/// Includes next, write, and indirect bits.
18+
flags: Le16,
19+
}
20+
21+
impl Descriptor {
22+
/// Return the guest physical address of the descriptor buffer.
23+
pub fn addr(&self) -> GuestAddress {
24+
GuestAddress(self.addr.into())
25+
}
26+
/// Return the length of the descriptor buffer.
27+
pub fn len(&self) -> u32 {
28+
self.len.into()
29+
}
30+
/// Return the flags for this descriptor, including next, write and indirect bits.
31+
pub fn flags(&self) -> u16 {
32+
println!("packed flags");
33+
self.flags.into()
34+
}
35+
/// Return the index of the descriptor in the descriptor table.
36+
pub fn id(&self) -> u16 {
37+
self.id.into()
38+
}
39+
/// Check whether this descriptor refers to a buffer containing an indirect descriptor table.
40+
pub fn refers_to_indirect_table(&self) -> bool {
41+
self.flags() & VRING_DESC_F_INDIRECT as u16 != 0
42+
}
43+
/// Check whether the `VIRTQ_DESC_F_NEXT` is set for the descriptor.
44+
pub fn has_next(&self) -> bool {
45+
self.flags() & VRING_DESC_F_NEXT as u16 != 0
46+
}
47+
/// Check if the driver designated this as a write only descriptor.
48+
///
49+
/// If this is false, this descriptor is read only.
50+
/// Write only means the the emulated device can write and the driver can read.
51+
pub fn is_write_only(&self) -> bool {
52+
self.flags() & VRING_DESC_F_WRITE as u16 != 0
53+
}
54+
}
55+
56+
impl Descriptor {
57+
/// Create a new descriptor.
58+
///
59+
/// # Arguments
60+
/// * `addr` - the guest physical address of the descriptor buffer.
61+
/// * `len` - the length of the descriptor buffer.
62+
/// * `flags` - the `flags` for the descriptor.
63+
/// * `next` - the `next` field of the descriptor.
64+
pub fn new(addr: u64, len: u32, id: u16, flags: u16) -> Self {
65+
Descriptor {
66+
addr: addr.into(),
67+
len: len.into(),
68+
id: id.into(),
69+
flags: flags.into(),
70+
}
71+
}
72+
/// Set the guest physical address of the descriptor buffer.
73+
pub fn set_addr(&mut self, addr: u64) {
74+
self.addr = addr.into();
75+
}
76+
/// Set the length of the descriptor buffer.
77+
pub fn set_len(&mut self, len: u32) {
78+
self.len = len.into();
79+
}
80+
/// Set the flags for this descriptor.
81+
pub fn set_flags(&mut self, flags: u16) {
82+
self.flags = flags.into();
83+
}
84+
/// Set the value stored in the `next` field of the descriptor.
85+
pub fn set_id(&mut self, id: u16) {
86+
self.id = id.into();
87+
}
88+
}
89+
90+
// SAFETY: This is safe because `Descriptor` contains only wrappers over POD types and
91+
// all accesses through safe `vm-memory` API will validate any garbage that could be
92+
// included in there.
93+
unsafe impl ByteValued for Descriptor {}
94+
95+
/// A packed descriptor event constraints with C representation.
96+
#[repr(C)]
97+
#[derive(Clone, Copy, Debug)]
98+
pub struct PackedDescEvent {
99+
off_wrap: Le16,
100+
flags: Le16,
101+
}
102+
103+
impl PackedDescEvent {
104+
/// Set the value stored in the `off_wrap` field.
105+
pub fn set_off_wrap(&mut self, off_wrap: u16) {
106+
self.off_wrap = off_wrap.into();
107+
}
108+
109+
/// Set the value stored in the `flags` field.
110+
pub fn set_flags(&mut self, flags: u16) {
111+
self.flags = flags.into();
112+
}
113+
114+
/// Get the value stored in the `off_wrap` field
115+
pub fn get_off_wrap(&self) -> u16 {
116+
self.off_wrap.into()
117+
}
118+
119+
/// Get the value stored in the `flags` field.
120+
pub fn get_flags(&self) -> u16 {
121+
self.flags.into()
122+
}
123+
}
124+
125+
// SAFETY: This is safe because `PackedDescEvent` contains only wrappers over POD types and
126+
// all accesses through safe `vm-memory` API will validate any garbage that could be
127+
// included in there.
128+
unsafe impl ByteValued for PackedDescEvent {}
129+
130+
#[cfg(test)]
131+
mod tests {
132+
use super::*;
133+
use memoffset::offset_of;
134+
use std::mem::{align_of, size_of};
135+
#[test]
136+
fn test_descriptor_offset() {
137+
assert_eq!(size_of::<Descriptor>(), 16);
138+
assert_eq!(offset_of!(Descriptor, addr), 0);
139+
assert_eq!(offset_of!(Descriptor, len), 8);
140+
assert_eq!(offset_of!(Descriptor, id), 12);
141+
assert_eq!(offset_of!(Descriptor, flags), 14);
142+
assert!(align_of::<Descriptor>() <= 16);
143+
}
144+
#[test]
145+
fn test_descriptor_getter_setter() {
146+
let mut desc = Descriptor::new(0, 0, 0, 0);
147+
desc.set_addr(0x1000);
148+
assert_eq!(desc.addr(), GuestAddress(0x1000));
149+
desc.set_len(0x2000);
150+
assert_eq!(desc.len(), 0x2000);
151+
desc.set_flags(VRING_DESC_F_NEXT as u16);
152+
assert_eq!(desc.flags(), VRING_DESC_F_NEXT as u16);
153+
assert!(desc.has_next());
154+
assert!(!desc.is_write_only());
155+
assert!(!desc.refers_to_indirect_table());
156+
desc.set_flags(VRING_DESC_F_WRITE as u16);
157+
assert_eq!(desc.flags(), VRING_DESC_F_WRITE as u16);
158+
assert!(!desc.has_next());
159+
assert!(desc.is_write_only());
160+
assert!(!desc.refers_to_indirect_table());
161+
desc.set_flags(VRING_DESC_F_INDIRECT as u16);
162+
assert_eq!(desc.flags(), VRING_DESC_F_INDIRECT as u16);
163+
assert!(!desc.is_write_only());
164+
assert!(desc.refers_to_indirect_table());
165+
}
166+
#[test]
167+
fn test_descriptor_copy() {
168+
let e1 = Descriptor::new(1, 2, 0, 3);
169+
let mut e2 = Descriptor::default();
170+
e2.as_mut_slice().copy_from_slice(e1.as_slice());
171+
assert_eq!(e1.addr(), e2.addr());
172+
assert_eq!(e1.len(), e2.len());
173+
assert_eq!(e1.id(), e2.id());
174+
assert_eq!(e1.flags(), e2.flags());
175+
}
176+
}

0 commit comments

Comments
 (0)