vmbus_relay_intercept_device/
ring_buffer.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! This module implements a vmbus ring buffer backed by a MemoryBlock,
5//! allocated memory that has been locked to physical pages and whose pfns are
6//! known.
7
8use safeatomic::AtomicSliceOps;
9use std::sync::atomic::AtomicU32;
10use user_driver::memory::MemoryBlock;
11use vmbus_ring::CONTROL_WORD_COUNT;
12use vmbus_ring::PAGE_SIZE;
13use vmbus_ring::RingMem;
14
15pub struct MemoryBlockRingBuffer(MemoryBlock);
16
17impl MemoryBlockRingBuffer {
18    pub fn new(mem: MemoryBlock) -> Self {
19        assert!(mem.len() >= 2 * PAGE_SIZE);
20        Self(mem)
21    }
22}
23
24impl From<MemoryBlock> for MemoryBlockRingBuffer {
25    fn from(mem: MemoryBlock) -> Self {
26        Self::new(mem)
27    }
28}
29
30impl RingMem for MemoryBlockRingBuffer {
31    fn len(&self) -> usize {
32        self.0.len() - PAGE_SIZE
33    }
34
35    fn read_at(&self, addr: usize, data: &mut [u8]) {
36        let addr = addr % self.len();
37        let initial_size = usize::min(data.len(), self.len() - addr);
38        self.0.read_at(addr + PAGE_SIZE, &mut data[..initial_size]);
39        if initial_size < data.len() {
40            self.0.read_at(PAGE_SIZE, &mut data[initial_size..]);
41        }
42    }
43
44    fn write_at(&self, addr: usize, data: &[u8]) {
45        let addr = addr % self.len();
46        let initial_size = usize::min(data.len(), self.len() - addr);
47        self.0.write_at(addr + PAGE_SIZE, &data[..initial_size]);
48        if initial_size < data.len() {
49            self.0.write_at(PAGE_SIZE, &data[initial_size..]);
50        }
51    }
52
53    fn control(&self) -> &[AtomicU32; CONTROL_WORD_COUNT] {
54        self.0.as_slice().as_atomic_slice().unwrap()[..CONTROL_WORD_COUNT]
55            .try_into()
56            .unwrap()
57    }
58}