virtqueue: Add missing fences

These values are either written by the device and read by the guest or
vice versa.  Either way, since these could happen simultaneously on
separate cores we need fences to prevent the CPU from re-ordering loads
and stores.

"get" methods use acquire-load semantics while "set" methods use
release-store semantics.  This also matches what we were already doing
for "get_avail_index" and "set_used_index".

With this it should be possible to re-enable the check for
VIRTIO_AVAIL_F_NO_INTERRUPT but we'll do that in a separate change since
we need these changes no matter what.

BUG=none
TEST=crostini.Basic.buster_stable

Change-Id: I2d52c92fbd7ab0fe6d64693d60f46d0dec4b4cb5
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3026685
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
This commit is contained in:
Chirantan Ekbote 2021-07-08 19:39:50 +09:00 committed by Commit Bot
parent bc55e30b89
commit f95a1df7d2

View file

@ -345,6 +345,9 @@ impl Queue {
//
// This value is only used if the `VIRTIO_F_EVENT_IDX` feature has been negotiated.
fn set_avail_event(&mut self, mem: &GuestMemory, avail_index: Wrapping<u16>) {
// Ensure that all previous writes are available before this one.
fence(Ordering::Release);
let avail_event_addr = self
.used_ring
.unchecked_add(4 + 8 * u64::from(self.actual_size()));
@ -358,6 +361,10 @@ impl Queue {
#[allow(dead_code)]
fn get_avail_flag(&self, mem: &GuestMemory, flag: u16) -> bool {
let avail_flags: u16 = mem.read_obj_from_addr(self.avail_ring).unwrap();
// Don't allow subsequent reads to be ordered before the avail_flags read.
fence(Ordering::Acquire);
avail_flags & flag == flag
}
@ -373,6 +380,10 @@ impl Queue {
.avail_ring
.unchecked_add(4 + 2 * u64::from(self.actual_size()));
let used_event: u16 = mem.read_obj_from_addr(used_event_addr).unwrap();
// Prevent any reads after this from being ordered before the used_event read.
fence(Ordering::Acquire);
Wrapping(used_event)
}
@ -393,6 +404,9 @@ impl Queue {
//
// Changes the bit specified by the mask in `flag` to `value`.
fn set_used_flag(&mut self, mem: &GuestMemory, flag: u16, value: bool) {
// This fence ensures all descriptor writes are visible before the flag update.
fence(Ordering::Release);
let mut used_flags: u16 = mem.read_obj_from_addr(self.used_ring).unwrap();
if value {
used_flags |= flag;