Skip to main content

nvme/
queue.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! NVMe submission and completion queue types.
5
6use crate::DOORBELL_STRIDE_BITS;
7use crate::spec;
8use guestmem::GuestMemory;
9use guestmem::GuestMemoryError;
10use inspect::Inspect;
11use parking_lot::RwLock;
12use std::sync::Arc;
13use std::sync::atomic::Ordering;
14use std::task::Context;
15use std::task::Poll;
16use std::task::Waker;
17use std::task::ready;
18use thiserror::Error;
19use vmcore::interrupt::Interrupt;
20
21pub struct DoorbellMemory {
22    mem: GuestMemory,
23    private_mem: GuestMemory,
24    offset: u64,
25    event_idx_offset: Option<u64>,
26    wakers: Vec<Option<Waker>>,
27}
28
29pub struct InvalidDoorbell;
30
31impl DoorbellMemory {
32    pub fn new(num_qids: u16) -> Self {
33        let private_mem = GuestMemory::allocate((num_qids as usize) << DOORBELL_STRIDE_BITS);
34        Self {
35            mem: private_mem.clone(),
36            private_mem,
37            offset: 0,
38            event_idx_offset: None,
39            wakers: (0..num_qids).map(|_| None).collect(),
40        }
41    }
42
43    pub fn reset(&mut self) {
44        let Self {
45            mem,
46            private_mem,
47            offset,
48            event_idx_offset,
49            wakers,
50        } = self;
51        private_mem
52            .fill_at(0, 0, wakers.len() << DOORBELL_STRIDE_BITS)
53            .expect("private doorbell memory must be writable");
54        *mem = private_mem.clone();
55        *offset = 0;
56        *event_idx_offset = None;
57        wakers.fill(None);
58    }
59
60    /// Update the memory used to store the doorbell values. This is used to
61    /// support shadow doorbells, where the values are directly in guest memory.
62    pub fn replace_mem(
63        &mut self,
64        mem: GuestMemory,
65        offset: u64,
66        event_idx_offset: Option<u64>,
67    ) -> Result<(), GuestMemoryError> {
68        // Copy the current doorbell values into the new memory.
69        let len = self.wakers.len() << DOORBELL_STRIDE_BITS;
70        let mut current = vec![0; len];
71        self.mem.read_at(self.offset, &mut current)?;
72        mem.write_at(offset, &current)?;
73        if let Some(event_idx_offset) = event_idx_offset {
74            // Catch eventidx up to the current doorbell value.
75            mem.write_at(event_idx_offset, &current)?;
76        }
77        self.mem = mem;
78        self.offset = offset;
79        self.event_idx_offset = event_idx_offset;
80        Ok(())
81    }
82
83    pub fn try_write(&self, db_id: u16, value: u32) -> Result<(), InvalidDoorbell> {
84        if (db_id as usize) >= self.wakers.len() {
85            return Err(InvalidDoorbell);
86        }
87        self.write(db_id, value);
88        Ok(())
89    }
90
91    fn write(&self, db_id: u16, value: u32) {
92        assert!((db_id as usize) < self.wakers.len());
93        let addr = self
94            .offset
95            .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS);
96        if let Err(err) = self.mem.write_plain(addr, &value) {
97            tracelimit::error_ratelimited!(
98                error = &err as &dyn std::error::Error,
99                "failed to write doorbell memory"
100            );
101        }
102        if let Some(waker) = &self.wakers[db_id as usize] {
103            waker.wake_by_ref();
104        }
105    }
106
107    fn read(&self, db_id: u16) -> Option<u32> {
108        assert!((db_id as usize) < self.wakers.len());
109        self.mem
110            .read_plain(
111                self.offset
112                    .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS),
113            )
114            .inspect_err(|err| {
115                tracelimit::error_ratelimited!(
116                    error = err as &dyn std::error::Error,
117                    "failed to read doorbell memory"
118                );
119            })
120            .ok()
121    }
122
123    fn has_event_idx(&self) -> bool {
124        self.event_idx_offset.is_some()
125    }
126
127    fn write_event_idx(&self, db_id: u16, val: u32) {
128        assert!((db_id as usize) < self.wakers.len());
129        if let Err(err) = self.mem.write_plain(
130            self.event_idx_offset
131                .unwrap()
132                .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS),
133            &val,
134        ) {
135            tracelimit::error_ratelimited!(
136                error = &err as &dyn std::error::Error,
137                "failed to read event_idx memory"
138            )
139        }
140    }
141
142    fn read_event_idx(&self, db_id: u16) -> Option<u32> {
143        assert!((db_id as usize) < self.wakers.len());
144        self.mem
145            .read_plain(
146                self.event_idx_offset?
147                    .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS),
148            )
149            .inspect_err(|err| {
150                tracelimit::error_ratelimited!(
151                    error = err as &dyn std::error::Error,
152                    "failed to read doorbell memory"
153                );
154            })
155            .ok()
156    }
157}
158
159#[derive(Inspect)]
160#[inspect(extra = "Self::inspect_shadow")]
161struct DoorbellState {
162    #[inspect(hex)]
163    current: u32,
164    #[inspect(hex)]
165    event_idx: u32,
166    db_id: u16,
167    db_offset: u64,
168    #[inspect(hex)]
169    len: u32,
170    #[inspect(skip)]
171    doorbells: Arc<RwLock<DoorbellMemory>>,
172    #[inspect(skip)]
173    registered_waker: Option<Waker>,
174}
175
176impl DoorbellState {
177    fn inspect_shadow(&self, resp: &mut inspect::Response<'_>) {
178        resp.field_with("doorbell", || {
179            self.doorbells.read().read(self.db_id).map(inspect::AsHex)
180        })
181        .field_with("shadow_event_idx", || {
182            self.doorbells
183                .read()
184                .read_event_idx(self.db_id)
185                .map(inspect::AsHex)
186        });
187    }
188
189    fn new(doorbells: Arc<RwLock<DoorbellMemory>>, db_id: u16, len: u32) -> Self {
190        Self {
191            current: 0,
192            event_idx: 0,
193            len,
194            doorbells,
195            registered_waker: None,
196            db_id,
197            db_offset: (db_id as u64) << DOORBELL_STRIDE_BITS,
198        }
199    }
200
201    fn probe_inner(&mut self, update_event_idx: bool) -> Option<u32> {
202        // Try to read forward.
203        let doorbell = self.doorbells.read();
204        let val = doorbell.read(self.db_id)?;
205        if val != self.current {
206            return Some(val);
207        }
208
209        if self.event_idx == val || !update_event_idx || !doorbell.has_event_idx() {
210            return None;
211        }
212
213        // Update the event index so that the guest will write the real doorbell
214        // on the next update.
215        doorbell.write_event_idx(self.db_id, val);
216        self.event_idx = val;
217
218        // Double check after a memory barrier.
219        std::sync::atomic::fence(Ordering::SeqCst);
220        let val = doorbell.read(self.db_id)?;
221        if val != self.current { Some(val) } else { None }
222    }
223
224    fn probe(&mut self, update_event_idx: bool) -> Result<bool, QueueError> {
225        // If shadow doorbells are in use, use that instead of what was written to the doorbell
226        // register, as it may be more current.
227        if let Some(val) = self.probe_inner(update_event_idx) {
228            if val >= self.len {
229                return Err(QueueError::InvalidDoorbell { val, len: self.len });
230            }
231            self.current = val;
232            Ok(true)
233        } else {
234            Ok(false)
235        }
236    }
237
238    fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), QueueError>> {
239        // Ensure we get woken up whenever the doorbell is written to.
240        if self
241            .registered_waker
242            .as_ref()
243            .is_none_or(|w| !cx.waker().will_wake(w))
244        {
245            let _old_waker =
246                self.doorbells.write().wakers[self.db_id as usize].replace(cx.waker().clone());
247            self.registered_waker = Some(cx.waker().clone());
248        }
249        if !self.probe(true)? {
250            return Poll::Pending;
251        }
252        Poll::Ready(Ok(()))
253    }
254}
255
256#[derive(Inspect)]
257pub struct SubmissionQueue {
258    tail: DoorbellState,
259    mem: GuestMemory,
260    #[inspect(hex)]
261    head: u32,
262    #[inspect(hex)]
263    gpa: u64,
264}
265
266#[derive(Debug, Error)]
267pub enum QueueError {
268    #[error("invalid doorbell value {val:#x}, len {len:#x}")]
269    InvalidDoorbell { val: u32, len: u32 },
270    #[error("queue access error")]
271    Memory(#[source] GuestMemoryError),
272}
273
274impl SubmissionQueue {
275    pub fn new(cq: &CompletionQueue, db_id: u16, gpa: u64, len: u16) -> Self {
276        let doorbells = cq.head.doorbells.clone();
277        let mem = cq.mem.clone();
278        doorbells.read().write(db_id, 0);
279        Self {
280            tail: DoorbellState::new(doorbells, db_id, len.into()),
281            head: 0,
282            gpa,
283            mem,
284        }
285    }
286
287    /// This function returns a future for the next entry in the submission queue.  It also
288    /// has a side effect of updating the tail.
289    pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Result<spec::Command, QueueError>> {
290        let tail = self.tail.current;
291        if tail == self.head {
292            ready!(self.tail.poll(cx))?;
293        }
294        let command: spec::Command = self
295            .mem
296            .read_plain(
297                self.gpa
298                    .wrapping_add(self.head as u64 * size_of::<spec::Command>() as u64),
299            )
300            .map_err(QueueError::Memory)?;
301
302        self.head = advance(self.head, self.tail.len);
303        Poll::Ready(Ok(command))
304    }
305
306    pub fn sqhd(&self) -> u16 {
307        self.head as u16
308    }
309}
310
311#[derive(Inspect)]
312pub struct CompletionQueue {
313    #[inspect(hex)]
314    tail: u32,
315    head: DoorbellState,
316    phase: bool,
317    #[inspect(hex)]
318    gpa: u64,
319    #[inspect(with = "Option::is_some")]
320    interrupt: Option<Interrupt>,
321    mem: GuestMemory,
322}
323
324impl CompletionQueue {
325    pub fn new(
326        doorbells: Arc<RwLock<DoorbellMemory>>,
327        db_id: u16,
328        mem: GuestMemory,
329        interrupt: Option<Interrupt>,
330        gpa: u64,
331        len: u16,
332    ) -> Self {
333        doorbells.read().write(db_id, 0);
334        Self {
335            tail: 0,
336            head: DoorbellState::new(doorbells, db_id, len.into()),
337            phase: true,
338            gpa,
339            interrupt,
340            mem,
341        }
342    }
343
344    /// Wait for free completions.
345    pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), QueueError>> {
346        let next_tail = advance(self.tail, self.head.len);
347        if self.head.current == next_tail {
348            ready!(self.head.poll(cx))?;
349        }
350        Poll::Ready(Ok(()))
351    }
352
353    pub fn write(&mut self, mut data: spec::Completion) -> Result<bool, QueueError> {
354        let next = advance(self.tail, self.head.len);
355        // Check the doorbell register instead of requiring the caller to
356        // go around the slow path and call `poll_ready`.
357        if self.head.current == next && !self.head.probe(false)? {
358            return Ok(false);
359        }
360        data.status.set_phase(self.phase);
361
362        // Atomically write the low part of the completion entry first, then the
363        // high part, using release fences to ensure ordering.
364        //
365        // This is necessary to ensure the guest can observe the full completion
366        // once it observes the phase bit change (which is in the high part).
367        let [low, high]: [u64; 2] = zerocopy::transmute!(data);
368        let gpa = self
369            .gpa
370            .wrapping_add(self.tail as u64 * size_of::<spec::Completion>() as u64);
371        self.mem
372            .write_plain(gpa, &low)
373            .map_err(QueueError::Memory)?;
374        std::sync::atomic::fence(Ordering::Release);
375        self.mem
376            .write_plain(gpa + 8, &high)
377            .map_err(QueueError::Memory)?;
378        std::sync::atomic::fence(Ordering::Release);
379
380        if let Some(interrupt) = &self.interrupt {
381            interrupt.deliver();
382        }
383        self.tail = next;
384        if self.tail == 0 {
385            self.phase = !self.phase;
386        }
387        Ok(true)
388    }
389}
390
391fn advance(n: u32, l: u32) -> u32 {
392    if n + 1 < l { n + 1 } else { 0 }
393}