queue.rs100.00%
1
// Copyright 2024 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
pub mod packed;16
pub mod split;17
18
use std::collections::HashMap;19
use std::fmt::Debug;20
use std::io::{ErrorKind, IoSlice, IoSliceMut, Read, Write};21
use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU64, Ordering, fence};22
23
use crate::bitflags;24
use crate::mem::mapped::Ram;25
use crate::virtio::{IrqSender, Result, error};26
27
pub const QUEUE_SIZE_MAX: u16 = 256;28
29
bitflags! {30
pub struct DescFlag(u16) {31
NEXT = 1 << 0;32
WRITE = 1 << 1;33
INDIRECT = 1 << 2;34
AVAIL = 1 << 7;35
USED = 1 << 15;36
}37
}38
39
#[derive(Debug, Default)]40
pub struct QueueReg {41
pub size: AtomicU16,42
pub desc: AtomicU64,43
pub driver: AtomicU64,44
pub device: AtomicU64,45
pub enabled: AtomicBool,46
}47
48
#[derive(Debug)]49
pub struct DescChain<'m> {50
id: u16,51
delta: u16,52
pub readable: Vec<IoSlice<'m>>,53
pub writable: Vec<IoSliceMut<'m>>,54
}55
56
impl DescChain<'_> {57
pub fn id(&self) -> u16 {6x58
self.id6x59
}6x60
}61
62
pub trait VirtQueue<'m> {63
type Index: Clone + Copy;64
const INIT_INDEX: Self::Index;65
fn desc_avail(&self, index: Self::Index) -> bool;66
fn get_avail(&self, index: Self::Index, ram: &'m Ram) -> Result<Option<DescChain<'m>>>;67
fn set_used(&self, index: Self::Index, id: u16, len: u32);68
fn enable_notification(&self, enabled: bool);69
fn interrupt_enabled(&self, index: Self::Index, delta: u16) -> bool;70
fn index_add(&self, index: Self::Index, delta: u16) -> Self::Index;71
}72
73
#[derive(Debug)]74
pub enum Status {75
Done { len: u32 },76
Deferred,77
Break,78
}79
80
pub struct Queue<'r, 'm, Q>81
where82
Q: VirtQueue<'m>,83
{84
q: Q,85
avail: Q::Index,86
used: Q::Index,87
reg: &'r QueueReg,88
ram: &'m Ram,89
deferred: HashMap<u16, DescChain<'m>>,90
}91
92
impl<'r, 'm, Q> Queue<'r, 'm, Q>93
where94
Q: VirtQueue<'m>,95
{96
pub fn new(q: Q, reg: &'r QueueReg, ram: &'m Ram) -> Self {21x97
Self {21x98
q,21x99
avail: Q::INIT_INDEX,21x100
used: Q::INIT_INDEX,21x101
reg,21x102
ram,21x103
deferred: HashMap::new(),21x104
}21x105
}21x106
107
pub fn reg(&self) -> &QueueReg {3x108
self.reg3x109
}3x110
111
fn push_used(&mut self, chain: DescChain, len: u32) {57x112
self.q.set_used(self.used, chain.id, len);57x113
self.used = self.q.index_add(self.used, chain.delta);57x114
}57x115
116
pub fn handle_deferred(9x117
&mut self,9x118
id: u16,9x119
q_index: u16,9x120
irq_sender: &impl IrqSender,9x121
mut op: impl FnMut(&mut DescChain) -> Result<u32>,9x122
) -> Result<()> {9x123
let Some(mut chain) = self.deferred.remove(&id) else {9x124
return error::InvalidDescriptor { id }.fail();3x125
};126
let len = op(&mut chain)?;6x127
let delta = chain.delta;6x128
self.push_used(chain, len);6x129
if self.q.interrupt_enabled(self.used, delta) {6x130
irq_sender.queue_irq(q_index);6x131
}6x132
Ok(())6x133
}9x134
135
pub fn handle_desc(93x136
&mut self,93x137
q_index: u16,93x138
irq_sender: &impl IrqSender,93x139
mut op: impl FnMut(&mut DescChain) -> Result<Status>,93x140
) -> Result<()> {93x141
let mut send_irq = false;93x142
let mut ret = Ok(());93x143
'out: loop {144
if !self.q.desc_avail(self.avail) {147x145
break;75x146
}72x147
self.q.enable_notification(false);72x148
while let Some(mut chain) = self.q.get_avail(self.avail, self.ram)? {129x149
let delta = chain.delta;75x150
match op(&mut chain) {75x151
Err(e) => {6x152
ret = Err(e);6x153
self.q.enable_notification(true);6x154
break 'out;6x155
}156
Ok(Status::Break) => break 'out,12x157
Ok(Status::Done { len }) => {51x158
self.push_used(chain, len);51x159
send_irq = send_irq || self.q.interrupt_enabled(self.used, delta);51x160
}161
Ok(Status::Deferred) => {6x162
self.deferred.insert(chain.id, chain);6x163
}6x164
}165
self.avail = self.q.index_add(self.avail, delta);57x166
}167
self.q.enable_notification(true);54x168
fence(Ordering::SeqCst);54x169
}170
if send_irq {93x171
fence(Ordering::SeqCst);51x172
irq_sender.queue_irq(q_index);51x173
}51x174
ret93x175
}93x176
}177
178
pub fn copy_from_reader(mut reader: impl Read) -> impl FnMut(&mut DescChain) -> Result<Status> {36x179
move |chain| {27x180
let ret = reader.read_vectored(&mut chain.writable);27x181
match ret {6x182
Ok(0) => {183
let size: usize = chain.writable.iter().map(|s| s.len()).sum();6x184
if size == 0 {6x185
Ok(Status::Done { len: 0 })3x186
} else {187
Ok(Status::Break)3x188
}189
}190
Ok(len) => Ok(Status::Done { len: len as u32 }),15x191
Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),6x192
Err(e) => Err(e.into()),3x193
}194
}27x195
}36x196
197
pub fn copy_to_writer(mut writer: impl Write) -> impl FnMut(&mut DescChain) -> Result<Status> {27x198
move |chain| {21x199
let ret = writer.write_vectored(&chain.readable);21x200
match ret {6x201
Ok(0) => {202
let size: usize = chain.readable.iter().map(|s| s.len()).sum();6x203
if size == 0 {6x204
Ok(Status::Done { len: 0 })3x205
} else {206
Ok(Status::Break)3x207
}208
}209
Ok(_) => Ok(Status::Done { len: 0 }),9x210
Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),6x211
Err(e) => Err(e.into()),3x212
}213
}21x214
}27x215
216
#[cfg(test)]217
#[path = "queue_test.rs"]218
pub(in crate::virtio) mod tests;219