entropy.rs85.06%
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
use std::fmt::Debug;16
use std::fs::{File, OpenOptions};17
use std::os::unix::prelude::OpenOptionsExt;18
use std::path::Path;19
use std::sync::Arc;20
use std::sync::mpsc::Receiver;21
use std::thread::JoinHandle;22
23
use libc::O_NONBLOCK;24
use mio::Registry;25
use mio::event::Event;26
use serde::Deserialize;27
use serde_aco::Help;28
use snafu::ResultExt;29
30
use crate::hv::IoeventFd;31
use crate::mem::emulated::{Action, Mmio};32
use crate::mem::mapped::RamBus;33
use crate::sync::notifier::Notifier;34
use crate::virtio::dev::{DevParam, DeviceId, Virtio, WakeEvent};35
use crate::virtio::queue::{QueueReg, VirtQueue, copy_from_reader};36
use crate::virtio::worker::mio::{ActiveMio, Mio, VirtioMio};37
use crate::virtio::{FEATURE_BUILT_IN, IrqSender, Result, error};38
use crate::{bitflags, mem};39
40
#[derive(Debug, Clone)]41
pub struct EntropyConfig;42
43
impl Mmio for EntropyConfig {44
fn size(&self) -> u64 {3x45
03x46
}3x47
48
fn read(&self, _offset: u64, _size: u8) -> mem::Result<u64> {3x49
Ok(0)3x50
}3x51
52
fn write(&self, _offset: u64, _size: u8, _val: u64) -> mem::Result<Action> {3x53
Ok(Action::None)3x54
}3x55
}56
57
bitflags! {58
pub struct EntropyFeature(u128) { }59
}60
61
#[derive(Debug)]62
pub struct Entropy {63
name: Arc<str>,64
source: File,65
config: Arc<EntropyConfig>,66
}67
68
impl Entropy {69
pub fn new(param: EntropyParam, name: impl Into<Arc<str>>) -> Result<Self> {3x70
let name = name.into();3x71
let mut options = OpenOptions::new();3x72
options.custom_flags(O_NONBLOCK).read(true);3x73
let path = param.source.as_deref().unwrap_or(Path::new("/dev/urandom"));3x74
let file = options.open(path).context(error::AccessFile { path })?;3x75
Ok(Entropy {3x76
name,3x77
source: file,3x78
config: Arc::new(EntropyConfig),3x79
})3x80
}3x81
}82
83
impl Virtio for Entropy {84
type Config = EntropyConfig;85
type Feature = EntropyFeature;86
87
fn id(&self) -> DeviceId {3x88
DeviceId::ENTROPY3x89
}3x90
91
fn name(&self) -> &str {12x92
&self.name12x93
}12x94
95
fn spawn_worker<S, E>(3x96
self,3x97
event_rx: Receiver<WakeEvent<S, E>>,3x98
memory: Arc<RamBus>,3x99
queue_regs: Arc<[QueueReg]>,3x100
) -> Result<(JoinHandle<()>, Arc<Notifier>)>3x101
where3x102
S: IrqSender,3x103
E: IoeventFd,3x104
{105
Mio::spawn_worker(self, event_rx, memory, queue_regs)3x106
}3x107
108
fn num_queues(&self) -> u16 {3x109
13x110
}3x111
112
fn config(&self) -> Arc<EntropyConfig> {3x113
self.config.clone()3x114
}3x115
116
fn feature(&self) -> u128 {3x117
FEATURE_BUILT_IN3x118
}3x119
}120
121
impl VirtioMio for Entropy {122
fn activate<'m, Q, S, E>(3x123
&mut self,3x124
_feature: u128,3x125
_active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,3x126
) -> Result<()>3x127
where3x128
Q: VirtQueue<'m>,3x129
S: IrqSender,3x130
E: IoeventFd,3x131
{132
Ok(())3x133
}3x134
135
fn handle_queue<'m, Q, S, E>(9x136
&mut self,9x137
index: u16,9x138
active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,9x139
) -> Result<()>9x140
where9x141
Q: VirtQueue<'m>,9x142
S: IrqSender,9x143
E: IoeventFd,9x144
{145
let Some(Some(queue)) = active_mio.queues.get_mut(index as usize) else {9x146
log::error!("{}: invalid queue index {index}", self.name);147
return Ok(());148
};149
queue.handle_desc(index, active_mio.irq_sender, copy_from_reader(&self.source))9x150
}9x151
152
fn handle_event<'a, 'm, Q, S, E>(153
&mut self,154
_event: &Event,155
_active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,156
) -> Result<()>157
where158
Q: VirtQueue<'m>,159
S: IrqSender,160
E: IoeventFd,161
{162
Ok(())163
}164
165
fn reset(&mut self, _registry: &Registry) {}3x166
}167
168
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Help)]169
pub struct EntropyParam {170
/// Source of entropy [default: /dev/urandom]171
pub source: Option<Box<Path>>,172
}173
174
impl DevParam for EntropyParam {175
type Device = Entropy;176
177
fn build(self, name: impl Into<Arc<str>>) -> Result<Self::Device> {3x178
Entropy::new(self, name)3x179
}3x180
}181
182
#[cfg(test)]183
#[path = "entropy_test.rs"]184
mod tests;185