1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap; 6*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Write; 7*bb4ee6a4SAndroid Build Coastguard Worker 8*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow; 9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context; 10*bb4ee6a4SAndroid Build Coastguard Worker use base::error; 11*bb4ee6a4SAndroid Build Coastguard Worker use base::warn; 12*bb4ee6a4SAndroid Build Coastguard Worker use base::Event; 13*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken; 14*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor; 15*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext; 16*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread; 17*bb4ee6a4SAndroid Build Coastguard Worker use rand::rngs::OsRng; 18*bb4ee6a4SAndroid Build Coastguard Worker use rand::RngCore; 19*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory; 20*bb4ee6a4SAndroid Build Coastguard Worker 21*bb4ee6a4SAndroid Build Coastguard Worker use super::DeviceType; 22*bb4ee6a4SAndroid Build Coastguard Worker use super::Interrupt; 23*bb4ee6a4SAndroid Build Coastguard Worker use super::Queue; 24*bb4ee6a4SAndroid Build Coastguard Worker use super::VirtioDevice; 25*bb4ee6a4SAndroid Build Coastguard Worker 26*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZE: u16 = 256; 27*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE]; 28*bb4ee6a4SAndroid Build Coastguard Worker 29*bb4ee6a4SAndroid Build Coastguard Worker // Chosen to match the Linux guest driver RNG buffer refill size. 30*bb4ee6a4SAndroid Build Coastguard Worker const CHUNK_SIZE: usize = 64; 31*bb4ee6a4SAndroid Build Coastguard Worker 32*bb4ee6a4SAndroid Build Coastguard Worker struct Worker { 33*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt, 34*bb4ee6a4SAndroid Build Coastguard Worker queue: Queue, 35*bb4ee6a4SAndroid Build Coastguard Worker } 36*bb4ee6a4SAndroid Build Coastguard Worker 37*bb4ee6a4SAndroid Build Coastguard Worker impl Worker { process_queue(&mut self)38*bb4ee6a4SAndroid Build Coastguard Worker fn process_queue(&mut self) { 39*bb4ee6a4SAndroid Build Coastguard Worker let mut rand_bytes = [0u8; CHUNK_SIZE]; 40*bb4ee6a4SAndroid Build Coastguard Worker let mut needs_interrupt = false; 41*bb4ee6a4SAndroid Build Coastguard Worker 42*bb4ee6a4SAndroid Build Coastguard Worker while let Some(mut avail_desc) = self.queue.pop() { 43*bb4ee6a4SAndroid Build Coastguard Worker let writer = &mut avail_desc.writer; 44*bb4ee6a4SAndroid Build Coastguard Worker while writer.available_bytes() > 0 { 45*bb4ee6a4SAndroid Build Coastguard Worker let chunk_size = writer.available_bytes().min(CHUNK_SIZE); 46*bb4ee6a4SAndroid Build Coastguard Worker let chunk = &mut rand_bytes[..chunk_size]; 47*bb4ee6a4SAndroid Build Coastguard Worker OsRng.fill_bytes(chunk); 48*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = writer.write_all(chunk) { 49*bb4ee6a4SAndroid Build Coastguard Worker warn!("Failed to write random data to the guest: {}", e); 50*bb4ee6a4SAndroid Build Coastguard Worker break; 51*bb4ee6a4SAndroid Build Coastguard Worker } 52*bb4ee6a4SAndroid Build Coastguard Worker } 53*bb4ee6a4SAndroid Build Coastguard Worker 54*bb4ee6a4SAndroid Build Coastguard Worker let written_size = writer.bytes_written(); 55*bb4ee6a4SAndroid Build Coastguard Worker self.queue.add_used(avail_desc, written_size as u32); 56*bb4ee6a4SAndroid Build Coastguard Worker needs_interrupt = true; 57*bb4ee6a4SAndroid Build Coastguard Worker } 58*bb4ee6a4SAndroid Build Coastguard Worker 59*bb4ee6a4SAndroid Build Coastguard Worker if needs_interrupt { 60*bb4ee6a4SAndroid Build Coastguard Worker self.queue.trigger_interrupt(); 61*bb4ee6a4SAndroid Build Coastguard Worker } 62*bb4ee6a4SAndroid Build Coastguard Worker } 63*bb4ee6a4SAndroid Build Coastguard Worker run(&mut self, kill_evt: Event) -> anyhow::Result<()>64*bb4ee6a4SAndroid Build Coastguard Worker fn run(&mut self, kill_evt: Event) -> anyhow::Result<()> { 65*bb4ee6a4SAndroid Build Coastguard Worker #[derive(EventToken)] 66*bb4ee6a4SAndroid Build Coastguard Worker enum Token { 67*bb4ee6a4SAndroid Build Coastguard Worker QueueAvailable, 68*bb4ee6a4SAndroid Build Coastguard Worker InterruptResample, 69*bb4ee6a4SAndroid Build Coastguard Worker Kill, 70*bb4ee6a4SAndroid Build Coastguard Worker } 71*bb4ee6a4SAndroid Build Coastguard Worker 72*bb4ee6a4SAndroid Build Coastguard Worker let wait_ctx = WaitContext::build_with(&[ 73*bb4ee6a4SAndroid Build Coastguard Worker (self.queue.event(), Token::QueueAvailable), 74*bb4ee6a4SAndroid Build Coastguard Worker (&kill_evt, Token::Kill), 75*bb4ee6a4SAndroid Build Coastguard Worker ]) 76*bb4ee6a4SAndroid Build Coastguard Worker .context("failed creating WaitContext")?; 77*bb4ee6a4SAndroid Build Coastguard Worker 78*bb4ee6a4SAndroid Build Coastguard Worker if let Some(resample_evt) = self.interrupt.get_resample_evt() { 79*bb4ee6a4SAndroid Build Coastguard Worker wait_ctx 80*bb4ee6a4SAndroid Build Coastguard Worker .add(resample_evt, Token::InterruptResample) 81*bb4ee6a4SAndroid Build Coastguard Worker .context("failed adding resample event to WaitContext.")?; 82*bb4ee6a4SAndroid Build Coastguard Worker } 83*bb4ee6a4SAndroid Build Coastguard Worker 84*bb4ee6a4SAndroid Build Coastguard Worker let mut exiting = false; 85*bb4ee6a4SAndroid Build Coastguard Worker while !exiting { 86*bb4ee6a4SAndroid Build Coastguard Worker let events = wait_ctx.wait().context("failed polling for events")?; 87*bb4ee6a4SAndroid Build Coastguard Worker for event in events.iter().filter(|e| e.is_readable) { 88*bb4ee6a4SAndroid Build Coastguard Worker match event.token { 89*bb4ee6a4SAndroid Build Coastguard Worker Token::QueueAvailable => { 90*bb4ee6a4SAndroid Build Coastguard Worker self.queue 91*bb4ee6a4SAndroid Build Coastguard Worker .event() 92*bb4ee6a4SAndroid Build Coastguard Worker .wait() 93*bb4ee6a4SAndroid Build Coastguard Worker .context("failed reading queue Event")?; 94*bb4ee6a4SAndroid Build Coastguard Worker self.process_queue(); 95*bb4ee6a4SAndroid Build Coastguard Worker } 96*bb4ee6a4SAndroid Build Coastguard Worker Token::InterruptResample => { 97*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt.interrupt_resample(); 98*bb4ee6a4SAndroid Build Coastguard Worker } 99*bb4ee6a4SAndroid Build Coastguard Worker Token::Kill => exiting = true, 100*bb4ee6a4SAndroid Build Coastguard Worker } 101*bb4ee6a4SAndroid Build Coastguard Worker } 102*bb4ee6a4SAndroid Build Coastguard Worker } 103*bb4ee6a4SAndroid Build Coastguard Worker 104*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 105*bb4ee6a4SAndroid Build Coastguard Worker } 106*bb4ee6a4SAndroid Build Coastguard Worker } 107*bb4ee6a4SAndroid Build Coastguard Worker 108*bb4ee6a4SAndroid Build Coastguard Worker /// Virtio device for exposing entropy to the guest OS through virtio. 109*bb4ee6a4SAndroid Build Coastguard Worker pub struct Rng { 110*bb4ee6a4SAndroid Build Coastguard Worker worker_thread: Option<WorkerThread<Worker>>, 111*bb4ee6a4SAndroid Build Coastguard Worker virtio_features: u64, 112*bb4ee6a4SAndroid Build Coastguard Worker } 113*bb4ee6a4SAndroid Build Coastguard Worker 114*bb4ee6a4SAndroid Build Coastguard Worker impl Rng { 115*bb4ee6a4SAndroid Build Coastguard Worker /// Create a new virtio rng device that gets random data from /dev/urandom. new(virtio_features: u64) -> anyhow::Result<Rng>116*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(virtio_features: u64) -> anyhow::Result<Rng> { 117*bb4ee6a4SAndroid Build Coastguard Worker Ok(Rng { 118*bb4ee6a4SAndroid Build Coastguard Worker worker_thread: None, 119*bb4ee6a4SAndroid Build Coastguard Worker virtio_features, 120*bb4ee6a4SAndroid Build Coastguard Worker }) 121*bb4ee6a4SAndroid Build Coastguard Worker } 122*bb4ee6a4SAndroid Build Coastguard Worker } 123*bb4ee6a4SAndroid Build Coastguard Worker 124*bb4ee6a4SAndroid Build Coastguard Worker impl VirtioDevice for Rng { keep_rds(&self) -> Vec<RawDescriptor>125*bb4ee6a4SAndroid Build Coastguard Worker fn keep_rds(&self) -> Vec<RawDescriptor> { 126*bb4ee6a4SAndroid Build Coastguard Worker Vec::new() 127*bb4ee6a4SAndroid Build Coastguard Worker } 128*bb4ee6a4SAndroid Build Coastguard Worker device_type(&self) -> DeviceType129*bb4ee6a4SAndroid Build Coastguard Worker fn device_type(&self) -> DeviceType { 130*bb4ee6a4SAndroid Build Coastguard Worker DeviceType::Rng 131*bb4ee6a4SAndroid Build Coastguard Worker } 132*bb4ee6a4SAndroid Build Coastguard Worker queue_max_sizes(&self) -> &[u16]133*bb4ee6a4SAndroid Build Coastguard Worker fn queue_max_sizes(&self) -> &[u16] { 134*bb4ee6a4SAndroid Build Coastguard Worker QUEUE_SIZES 135*bb4ee6a4SAndroid Build Coastguard Worker } 136*bb4ee6a4SAndroid Build Coastguard Worker features(&self) -> u64137*bb4ee6a4SAndroid Build Coastguard Worker fn features(&self) -> u64 { 138*bb4ee6a4SAndroid Build Coastguard Worker self.virtio_features 139*bb4ee6a4SAndroid Build Coastguard Worker } 140*bb4ee6a4SAndroid Build Coastguard Worker activate( &mut self, _mem: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>141*bb4ee6a4SAndroid Build Coastguard Worker fn activate( 142*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 143*bb4ee6a4SAndroid Build Coastguard Worker _mem: GuestMemory, 144*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt, 145*bb4ee6a4SAndroid Build Coastguard Worker mut queues: BTreeMap<usize, Queue>, 146*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> { 147*bb4ee6a4SAndroid Build Coastguard Worker if queues.len() != 1 { 148*bb4ee6a4SAndroid Build Coastguard Worker return Err(anyhow!("expected 1 queue, got {}", queues.len())); 149*bb4ee6a4SAndroid Build Coastguard Worker } 150*bb4ee6a4SAndroid Build Coastguard Worker 151*bb4ee6a4SAndroid Build Coastguard Worker let queue = queues.remove(&0).unwrap(); 152*bb4ee6a4SAndroid Build Coastguard Worker 153*bb4ee6a4SAndroid Build Coastguard Worker self.worker_thread = Some(WorkerThread::start("v_rng", move |kill_evt| { 154*bb4ee6a4SAndroid Build Coastguard Worker let mut worker = Worker { interrupt, queue }; 155*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = worker.run(kill_evt) { 156*bb4ee6a4SAndroid Build Coastguard Worker error!("rng worker thread failed: {:#}", e); 157*bb4ee6a4SAndroid Build Coastguard Worker } 158*bb4ee6a4SAndroid Build Coastguard Worker worker 159*bb4ee6a4SAndroid Build Coastguard Worker })); 160*bb4ee6a4SAndroid Build Coastguard Worker 161*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 162*bb4ee6a4SAndroid Build Coastguard Worker } 163*bb4ee6a4SAndroid Build Coastguard Worker reset(&mut self) -> anyhow::Result<()>164*bb4ee6a4SAndroid Build Coastguard Worker fn reset(&mut self) -> anyhow::Result<()> { 165*bb4ee6a4SAndroid Build Coastguard Worker if let Some(worker_thread) = self.worker_thread.take() { 166*bb4ee6a4SAndroid Build Coastguard Worker let _worker = worker_thread.stop(); 167*bb4ee6a4SAndroid Build Coastguard Worker } 168*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 169*bb4ee6a4SAndroid Build Coastguard Worker } 170*bb4ee6a4SAndroid Build Coastguard Worker virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>171*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> { 172*bb4ee6a4SAndroid Build Coastguard Worker if let Some(worker_thread) = self.worker_thread.take() { 173*bb4ee6a4SAndroid Build Coastguard Worker let worker = worker_thread.stop(); 174*bb4ee6a4SAndroid Build Coastguard Worker return Ok(Some(BTreeMap::from([(0, worker.queue)]))); 175*bb4ee6a4SAndroid Build Coastguard Worker } 176*bb4ee6a4SAndroid Build Coastguard Worker Ok(None) 177*bb4ee6a4SAndroid Build Coastguard Worker } 178*bb4ee6a4SAndroid Build Coastguard Worker virtio_wake( &mut self, queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>179*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_wake( 180*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 181*bb4ee6a4SAndroid Build Coastguard Worker queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, 182*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> { 183*bb4ee6a4SAndroid Build Coastguard Worker if let Some((mem, interrupt, queues)) = queues_state { 184*bb4ee6a4SAndroid Build Coastguard Worker self.activate(mem, interrupt, queues)?; 185*bb4ee6a4SAndroid Build Coastguard Worker } 186*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 187*bb4ee6a4SAndroid Build Coastguard Worker } 188*bb4ee6a4SAndroid Build Coastguard Worker virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value>189*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value> { 190*bb4ee6a4SAndroid Build Coastguard Worker // `virtio_sleep` ensures there is no pending state, except for the `Queue`s, which are 191*bb4ee6a4SAndroid Build Coastguard Worker // handled at a higher layer. 192*bb4ee6a4SAndroid Build Coastguard Worker Ok(serde_json::Value::Null) 193*bb4ee6a4SAndroid Build Coastguard Worker } 194*bb4ee6a4SAndroid Build Coastguard Worker virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>195*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> { 196*bb4ee6a4SAndroid Build Coastguard Worker anyhow::ensure!( 197*bb4ee6a4SAndroid Build Coastguard Worker data == serde_json::Value::Null, 198*bb4ee6a4SAndroid Build Coastguard Worker "unexpected snapshot data: should be null, got {}", 199*bb4ee6a4SAndroid Build Coastguard Worker data, 200*bb4ee6a4SAndroid Build Coastguard Worker ); 201*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 202*bb4ee6a4SAndroid Build Coastguard Worker } 203*bb4ee6a4SAndroid Build Coastguard Worker } 204