Skip to content

Commit 990777c

Browse files
committed
queue: Add support for big-endian arches
According to the virtio specification, on non-legacy devices the values in the virtqueue are represented in little-endian, no matter the host nor the guest actual endianess. If needed, fix the endianess of values that have been read from memory or will be written to it. The methods "from_le" and "to_le" are a no-op on little-endian machines, so this shouldn't have a performance impact on those. Fixes #117 Signed-off-by: Sergio Lopez <slp@redhat.com>
1 parent 3827020 commit 990777c

File tree

3 files changed

+32
-28
lines changed

3 files changed

+32
-28
lines changed

crates/virtio-queue/src/descriptor.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//
1111
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
1212

13-
use vm_memory::{ByteValued, GuestAddress};
13+
use vm_memory::{ByteValued, GuestAddress, Le16, Le32, Le64};
1414

1515
use crate::defs::{VIRTQ_DESC_F_INDIRECT, VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
1616

@@ -19,38 +19,38 @@ use crate::defs::{VIRTQ_DESC_F_INDIRECT, VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
1919
#[derive(Default, Clone, Copy, Debug)]
2020
pub struct Descriptor {
2121
/// Guest physical address of device specific data
22-
addr: u64,
22+
addr: Le64,
2323

2424
/// Length of device specific data
25-
len: u32,
25+
len: Le32,
2626

2727
/// Includes next, write, and indirect bits
28-
flags: u16,
28+
flags: Le16,
2929

3030
/// Index into the descriptor table of the next descriptor if flags has the next bit set
31-
next: u16,
31+
next: Le16,
3232
}
3333

3434
#[allow(clippy::len_without_is_empty)]
3535
impl Descriptor {
3636
/// Return the guest physical address of descriptor buffer.
3737
pub fn addr(&self) -> GuestAddress {
38-
GuestAddress(self.addr)
38+
GuestAddress(self.addr.into())
3939
}
4040

4141
/// Return the length of descriptor buffer.
4242
pub fn len(&self) -> u32 {
43-
self.len
43+
self.len.into()
4444
}
4545

4646
/// Return the flags for this descriptor, including next, write and indirect bits.
4747
pub fn flags(&self) -> u16 {
48-
self.flags
48+
self.flags.into()
4949
}
5050

5151
/// Return the value stored in the `next` field of the descriptor.
5252
pub fn next(&self) -> u16 {
53-
self.next
53+
self.next.into()
5454
}
5555

5656
/// Check whether this descriptor refers to a buffer containing an indirect descriptor table.
@@ -77,31 +77,31 @@ impl Descriptor {
7777
/// Creates a new descriptor
7878
pub fn new(addr: u64, len: u32, flags: u16, next: u16) -> Self {
7979
Descriptor {
80-
addr: addr.to_le(),
81-
len: len.to_le(),
82-
flags: flags.to_le(),
83-
next: next.to_le(),
80+
addr: addr.into(),
81+
len: len.into(),
82+
flags: flags.into(),
83+
next: next.into(),
8484
}
8585
}
8686

8787
/// Set the guest physical address of descriptor buffer
8888
pub fn set_addr(&mut self, addr: u64) {
89-
self.addr = addr.to_le();
89+
self.addr = addr.into();
9090
}
9191

9292
/// Set the length of descriptor buffer.
9393
pub fn set_len(&mut self, len: u32) {
94-
self.len = len.to_le();
94+
self.len = len.into();
9595
}
9696

9797
/// Set the flags for this descriptor.
9898
pub fn set_flags(&mut self, flags: u16) {
99-
self.flags = flags.to_le();
99+
self.flags = flags.into();
100100
}
101101

102102
/// Set the value stored in the `next` field of the descriptor.
103103
pub fn set_next(&mut self, next: u16) {
104-
self.next = next.to_le();
104+
self.next = next.into();
105105
}
106106
}
107107

@@ -111,16 +111,16 @@ unsafe impl ByteValued for Descriptor {}
111111
#[repr(C)]
112112
#[derive(Clone, Copy, Default, Debug)]
113113
pub struct VirtqUsedElem {
114-
id: u32,
115-
len: u32,
114+
id: Le32,
115+
len: Le32,
116116
}
117117

118118
impl VirtqUsedElem {
119119
/// Create a new `VirtqUsedElem` instance.
120-
pub fn new(id: u16, len: u32) -> Self {
120+
pub fn new(id: u32, len: u32) -> Self {
121121
VirtqUsedElem {
122-
id: u32::from_le(id as u32),
123-
len: len.to_le(),
122+
id: id.into(),
123+
len: len.into(),
124124
}
125125
}
126126
}
@@ -130,12 +130,12 @@ impl VirtqUsedElem {
130130
impl VirtqUsedElem {
131131
/// Get id field of the used descriptor.
132132
pub fn id(&self) -> u32 {
133-
u32::from_le(self.id)
133+
self.id.into()
134134
}
135135

136136
/// Get length field of the used descriptor.
137137
pub fn len(&self) -> u32 {
138-
u32::from_le(self.len)
138+
self.len.into()
139139
}
140140
}
141141

crates/virtio-queue/src/iterator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ where
8686
let head_index: u16 = self
8787
.mem
8888
.load(addr, Ordering::Acquire)
89+
.map(u16::from_le)
8990
.map_err(|_| error!("Failed to read from memory {:x}", addr.raw_value()))
9091
.ok()?;
9192

crates/virtio-queue/src/state.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ impl QueueState {
7878
let offset = VIRTQ_USED_RING_HEADER_SIZE + elem_sz;
7979
let addr = self.used_ring.unchecked_add(offset);
8080

81-
mem.store(val, addr, order).map_err(Error::GuestMemory)
81+
mem.store(u16::to_le(val), addr, order)
82+
.map_err(Error::GuestMemory)
8283
}
8384

8485
// Set the value of the `flags` field of the used ring, applying the specified ordering.
@@ -88,7 +89,7 @@ impl QueueState {
8889
val: u16,
8990
order: Ordering,
9091
) -> Result<(), Error> {
91-
mem.store(val, self.used_ring, order)
92+
mem.store(u16::to_le(val), self.used_ring, order)
9293
.map_err(Error::GuestMemory)
9394
}
9495

@@ -133,6 +134,7 @@ impl QueueState {
133134
let used_event_addr = self.avail_ring.unchecked_add(offset);
134135

135136
mem.load(used_event_addr, order)
137+
.map(u16::from_le)
136138
.map(Wrapping)
137139
.map_err(Error::GuestMemory)
138140
}
@@ -281,6 +283,7 @@ impl QueueStateT for QueueState {
281283
let addr = self.avail_ring.unchecked_add(2);
282284

283285
mem.load(addr, order)
286+
.map(u16::from_le)
284287
.map(Wrapping)
285288
.map_err(Error::GuestMemory)
286289
}
@@ -303,13 +306,13 @@ impl QueueStateT for QueueState {
303306
let elem_sz = next_used_index * VIRTQ_USED_ELEMENT_SIZE;
304307
let offset = VIRTQ_USED_RING_HEADER_SIZE + elem_sz;
305308
let addr = self.used_ring.unchecked_add(offset);
306-
mem.write_obj(VirtqUsedElem::new(head_index, len), addr)
309+
mem.write_obj(VirtqUsedElem::new(head_index.into(), len), addr)
307310
.map_err(Error::GuestMemory)?;
308311

309312
self.next_used += Wrapping(1);
310313

311314
mem.store(
312-
self.next_used.0,
315+
u16::to_le(self.next_used.0),
313316
self.used_ring.unchecked_add(2),
314317
Ordering::Release,
315318
)

0 commit comments

Comments
 (0)