1 // Copyright 2019 Intel Corporation. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 use super::Error as DeviceError; 5 use super::{ 6 ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, 7 VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, 8 VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, 9 }; 10 use crate::seccomp_filters::{get_seccomp_filter, Thread}; 11 use crate::GuestMemoryMmap; 12 use crate::VirtioInterrupt; 13 use libc::EFD_NONBLOCK; 14 use seccomp::{SeccompAction, SeccompFilter}; 15 use std::cmp; 16 use std::collections::VecDeque; 17 use std::io; 18 use std::io::Write; 19 use std::ops::DerefMut; 20 use std::os::unix::io::AsRawFd; 21 use std::result; 22 use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; 23 use std::sync::{Arc, Barrier, Mutex}; 24 use std::thread; 25 use versionize::{VersionMap, Versionize, VersionizeResult}; 26 use versionize_derive::Versionize; 27 use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic}; 28 use vm_migration::VersionMapped; 29 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; 30 use vmm_sys_util::eventfd::EventFd; 31 32 const QUEUE_SIZE: u16 = 256; 33 const NUM_QUEUES: usize = 2; 34 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES]; 35 36 // New descriptors are pending on the virtio queue. 37 const INPUT_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1; 38 const OUTPUT_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2; 39 // Some input from the VMM is ready to be injected into the VM. 40 const INPUT_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3; 41 // Console configuration change event is triggered. 42 const CONFIG_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4; 43 44 //Console size feature bit 45 const VIRTIO_CONSOLE_F_SIZE: u64 = 0; 46 47 #[derive(Copy, Clone, Debug, Default, Versionize)] 48 #[repr(C, packed)] 49 pub struct VirtioConsoleConfig { 50 cols: u16, 51 rows: u16, 52 max_nr_ports: u32, 53 emerg_wr: u32, 54 } 55 56 // Safe because it only has data and has no implicit padding. 57 unsafe impl ByteValued for VirtioConsoleConfig {} 58 59 struct ConsoleEpollHandler { 60 queues: Vec<Queue>, 61 mem: GuestMemoryAtomic<GuestMemoryMmap>, 62 interrupt_cb: Arc<dyn VirtioInterrupt>, 63 in_buffer: Arc<Mutex<VecDeque<u8>>>, 64 out: Arc<Mutex<Box<dyn io::Write + Send + Sync + 'static>>>, 65 input_queue_evt: EventFd, 66 output_queue_evt: EventFd, 67 input_evt: EventFd, 68 config_evt: EventFd, 69 kill_evt: EventFd, 70 pause_evt: EventFd, 71 } 72 73 impl ConsoleEpollHandler { 74 /* 75 * Each port of virtio console device has one receive 76 * queue. One or more empty buffers are placed by the 77 * driver in the receive queue for incoming data. Here, 78 * we place the input data to these empty buffers. 79 */ 80 fn process_input_queue(&mut self) -> bool { 81 let mut in_buffer = self.in_buffer.lock().unwrap(); 82 let recv_queue = &mut self.queues[0]; //receiveq 83 let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize]; 84 let mut used_count = 0; 85 86 if in_buffer.is_empty() { 87 return false; 88 } 89 90 let mem = self.mem.memory(); 91 for avail_desc in recv_queue.iter(&mem) { 92 let len = cmp::min(avail_desc.len as u32, in_buffer.len() as u32); 93 let source_slice = in_buffer.drain(..len as usize).collect::<Vec<u8>>(); 94 if let Err(e) = mem.write_slice(&source_slice[..], avail_desc.addr) { 95 error!("Failed to write slice: {:?}", e); 96 recv_queue.go_to_previous_position(); 97 break; 98 } 99 100 used_desc_heads[used_count] = (avail_desc.index, len); 101 used_count += 1; 102 103 if in_buffer.is_empty() { 104 break; 105 } 106 } 107 108 for &(desc_index, len) in &used_desc_heads[..used_count] { 109 recv_queue.add_used(&mem, desc_index, len); 110 } 111 112 used_count > 0 113 } 114 115 /* 116 * Each port of virtio console device has one transmit 117 * queue. For outgoing data, characters are placed in 118 * the transmit queue by the driver. Therefore, here 119 * we read data from the transmit queue and flush them 120 * to the referenced address. 121 */ 122 fn process_output_queue(&mut self) -> bool { 123 let trans_queue = &mut self.queues[1]; //transmitq 124 let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize]; 125 let mut used_count = 0; 126 127 let mem = self.mem.memory(); 128 for avail_desc in trans_queue.iter(&mem) { 129 let len; 130 let mut out = self.out.lock().unwrap(); 131 let _ = mem.write_to( 132 avail_desc.addr, 133 &mut out.deref_mut(), 134 avail_desc.len as usize, 135 ); 136 let _ = out.flush(); 137 138 len = avail_desc.len; 139 used_desc_heads[used_count] = (avail_desc.index, len); 140 used_count += 1; 141 } 142 143 for &(desc_index, len) in &used_desc_heads[..used_count] { 144 trans_queue.add_used(&mem, desc_index, len); 145 } 146 used_count > 0 147 } 148 149 fn signal_used_queue(&self) -> result::Result<(), DeviceError> { 150 self.interrupt_cb 151 .trigger(&VirtioInterruptType::Queue, Some(&self.queues[0])) 152 .map_err(|e| { 153 error!("Failed to signal used queue: {:?}", e); 154 DeviceError::FailedSignalingUsedQueue(e) 155 }) 156 } 157 158 fn run( 159 &mut self, 160 paused: Arc<AtomicBool>, 161 paused_sync: Arc<Barrier>, 162 ) -> result::Result<(), EpollHelperError> { 163 let mut helper = EpollHelper::new(&self.kill_evt, &self.pause_evt)?; 164 helper.add_event(self.input_queue_evt.as_raw_fd(), INPUT_QUEUE_EVENT)?; 165 helper.add_event(self.output_queue_evt.as_raw_fd(), OUTPUT_QUEUE_EVENT)?; 166 helper.add_event(self.input_evt.as_raw_fd(), INPUT_EVENT)?; 167 helper.add_event(self.config_evt.as_raw_fd(), CONFIG_EVENT)?; 168 helper.run(paused, paused_sync, self)?; 169 170 Ok(()) 171 } 172 } 173 174 impl EpollHelperHandler for ConsoleEpollHandler { 175 fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { 176 let ev_type = event.data as u16; 177 match ev_type { 178 INPUT_QUEUE_EVENT => { 179 if let Err(e) = self.input_queue_evt.read() { 180 error!("Failed to get queue event: {:?}", e); 181 return true; 182 } else if self.process_input_queue() { 183 if let Err(e) = self.signal_used_queue() { 184 error!("Failed to signal used queue: {:?}", e); 185 return true; 186 } 187 } 188 } 189 OUTPUT_QUEUE_EVENT => { 190 if let Err(e) = self.output_queue_evt.read() { 191 error!("Failed to get queue event: {:?}", e); 192 return true; 193 } else { 194 self.process_output_queue(); 195 } 196 } 197 INPUT_EVENT => { 198 if let Err(e) = self.input_evt.read() { 199 error!("Failed to get input event: {:?}", e); 200 return true; 201 } else if self.process_input_queue() { 202 if let Err(e) = self.signal_used_queue() { 203 error!("Failed to signal used queue: {:?}", e); 204 return true; 205 } 206 } 207 } 208 CONFIG_EVENT => { 209 if let Err(e) = self.config_evt.read() { 210 error!("Failed to get config event: {:?}", e); 211 return true; 212 } else if let Err(e) = self 213 .interrupt_cb 214 .trigger(&VirtioInterruptType::Config, None) 215 { 216 error!("Failed to signal console driver: {:?}", e); 217 return true; 218 } 219 } 220 _ => { 221 error!("Unknown event for virtio-console"); 222 return true; 223 } 224 } 225 false 226 } 227 } 228 229 /// Input device. 230 pub struct ConsoleInput { 231 input_evt: EventFd, 232 config_evt: EventFd, 233 in_buffer: Arc<Mutex<VecDeque<u8>>>, 234 config: Arc<Mutex<VirtioConsoleConfig>>, 235 acked_features: AtomicU64, 236 } 237 238 impl ConsoleInput { 239 pub fn queue_input_bytes(&self, input: &[u8]) { 240 let mut in_buffer = self.in_buffer.lock().unwrap(); 241 in_buffer.extend(input); 242 let _ = self.input_evt.write(1); 243 } 244 245 pub fn update_console_size(&self, cols: u16, rows: u16) { 246 if self 247 .acked_features 248 .fetch_and(1u64 << VIRTIO_CONSOLE_F_SIZE, Ordering::AcqRel) 249 != 0 250 { 251 self.config.lock().unwrap().update_console_size(cols, rows); 252 //Send the interrupt to the driver 253 let _ = self.config_evt.write(1); 254 } 255 } 256 } 257 258 impl VirtioConsoleConfig { 259 pub fn new(cols: u16, rows: u16) -> Self { 260 VirtioConsoleConfig { 261 cols, 262 rows, 263 max_nr_ports: 1u32, 264 emerg_wr: 0u32, 265 } 266 } 267 268 pub fn update_console_size(&mut self, cols: u16, rows: u16) { 269 self.cols = cols; 270 self.rows = rows; 271 } 272 } 273 274 /// Virtio device for exposing console to the guest OS through virtio. 275 pub struct Console { 276 common: VirtioCommon, 277 id: String, 278 config: Arc<Mutex<VirtioConsoleConfig>>, 279 input: Arc<ConsoleInput>, 280 out: Arc<Mutex<Box<dyn io::Write + Send + Sync + 'static>>>, 281 seccomp_action: SeccompAction, 282 } 283 284 #[derive(Versionize)] 285 pub struct ConsoleState { 286 avail_features: u64, 287 acked_features: u64, 288 config: VirtioConsoleConfig, 289 in_buffer: Vec<u8>, 290 } 291 292 impl VersionMapped for ConsoleState {} 293 294 impl Console { 295 /// Create a new virtio console device that gets random data from /dev/urandom. 296 pub fn new( 297 id: String, 298 out: Box<dyn io::Write + Send + Sync + 'static>, 299 cols: u16, 300 rows: u16, 301 iommu: bool, 302 seccomp_action: SeccompAction, 303 ) -> io::Result<(Console, Arc<ConsoleInput>)> { 304 let mut avail_features = 1u64 << VIRTIO_F_VERSION_1 | 1u64 << VIRTIO_CONSOLE_F_SIZE; 305 306 if iommu { 307 avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM; 308 } 309 310 let input_evt = EventFd::new(EFD_NONBLOCK).unwrap(); 311 let config_evt = EventFd::new(EFD_NONBLOCK).unwrap(); 312 let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::new(cols, rows))); 313 let console_input = Arc::new(ConsoleInput { 314 input_evt, 315 config_evt, 316 in_buffer: Arc::new(Mutex::new(VecDeque::new())), 317 config: console_config.clone(), 318 acked_features: AtomicU64::new(0), 319 }); 320 321 Ok(( 322 Console { 323 common: VirtioCommon { 324 device_type: VirtioDeviceType::Console as u32, 325 queue_sizes: QUEUE_SIZES.to_vec(), 326 avail_features, 327 paused_sync: Some(Arc::new(Barrier::new(2))), 328 min_queues: NUM_QUEUES as u16, 329 ..Default::default() 330 }, 331 id, 332 config: console_config, 333 input: console_input.clone(), 334 out: Arc::new(Mutex::new(out)), 335 seccomp_action, 336 }, 337 console_input, 338 )) 339 } 340 341 fn state(&self) -> ConsoleState { 342 ConsoleState { 343 avail_features: self.common.avail_features, 344 acked_features: self.common.acked_features, 345 config: *(self.config.lock().unwrap()), 346 in_buffer: self.input.in_buffer.lock().unwrap().clone().into(), 347 } 348 } 349 350 fn set_state(&mut self, state: &ConsoleState) { 351 self.common.avail_features = state.avail_features; 352 self.common.acked_features = state.acked_features; 353 *(self.config.lock().unwrap()) = state.config; 354 *(self.input.in_buffer.lock().unwrap()) = state.in_buffer.clone().into(); 355 } 356 } 357 358 impl Drop for Console { 359 fn drop(&mut self) { 360 if let Some(kill_evt) = self.common.kill_evt.take() { 361 // Ignore the result because there is nothing we can do about it. 362 let _ = kill_evt.write(1); 363 } 364 } 365 } 366 367 impl VirtioDevice for Console { 368 fn device_type(&self) -> u32 { 369 self.common.device_type 370 } 371 372 fn queue_max_sizes(&self) -> &[u16] { 373 &self.common.queue_sizes 374 } 375 376 fn features(&self) -> u64 { 377 self.common.avail_features 378 } 379 380 fn ack_features(&mut self, value: u64) { 381 self.common.ack_features(value) 382 } 383 384 fn read_config(&self, offset: u64, data: &mut [u8]) { 385 self.read_config_from_slice(self.config.lock().unwrap().as_slice(), offset, data); 386 } 387 388 fn activate( 389 &mut self, 390 mem: GuestMemoryAtomic<GuestMemoryMmap>, 391 interrupt_cb: Arc<dyn VirtioInterrupt>, 392 queues: Vec<Queue>, 393 mut queue_evts: Vec<EventFd>, 394 ) -> ActivateResult { 395 self.common.activate(&queues, &queue_evts, &interrupt_cb)?; 396 self.input 397 .acked_features 398 .store(self.common.acked_features, Ordering::Relaxed); 399 400 if self.common.feature_acked(VIRTIO_CONSOLE_F_SIZE) { 401 if let Err(e) = interrupt_cb.trigger(&VirtioInterruptType::Config, None) { 402 error!("Failed to signal console driver: {:?}", e); 403 } 404 } 405 406 let (kill_evt, pause_evt) = self.common.dup_eventfds(); 407 408 let mut handler = ConsoleEpollHandler { 409 queues, 410 mem, 411 interrupt_cb, 412 in_buffer: self.input.in_buffer.clone(), 413 out: self.out.clone(), 414 input_queue_evt: queue_evts.remove(0), 415 output_queue_evt: queue_evts.remove(0), 416 input_evt: self.input.input_evt.try_clone().unwrap(), 417 config_evt: self.input.config_evt.try_clone().unwrap(), 418 kill_evt, 419 pause_evt, 420 }; 421 422 let paused = self.common.paused.clone(); 423 let paused_sync = self.common.paused_sync.clone(); 424 let mut epoll_threads = Vec::new(); 425 // Retrieve seccomp filter for virtio_console thread 426 let virtio_console_seccomp_filter = 427 get_seccomp_filter(&self.seccomp_action, Thread::VirtioConsole) 428 .map_err(ActivateError::CreateSeccompFilter)?; 429 thread::Builder::new() 430 .name(self.id.clone()) 431 .spawn(move || { 432 if let Err(e) = SeccompFilter::apply(virtio_console_seccomp_filter) { 433 error!("Error applying seccomp filter: {:?}", e); 434 } else if let Err(e) = handler.run(paused, paused_sync.unwrap()) { 435 error!("Error running worker: {:?}", e); 436 } 437 }) 438 .map(|thread| epoll_threads.push(thread)) 439 .map_err(|e| { 440 error!("failed to clone the virtio-console epoll thread: {}", e); 441 ActivateError::BadActivate 442 })?; 443 444 self.common.epoll_threads = Some(epoll_threads); 445 446 event!("virtio-device", "activated", "id", &self.id); 447 Ok(()) 448 } 449 450 fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> { 451 let result = self.common.reset(); 452 event!("virtio-device", "reset", "id", &self.id); 453 result 454 } 455 } 456 457 impl Pausable for Console { 458 fn pause(&mut self) -> result::Result<(), MigratableError> { 459 self.common.pause() 460 } 461 462 fn resume(&mut self) -> result::Result<(), MigratableError> { 463 self.common.resume() 464 } 465 } 466 467 impl Snapshottable for Console { 468 fn id(&self) -> String { 469 self.id.clone() 470 } 471 472 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 473 Snapshot::new_from_versioned_state(&self.id, &self.state()) 474 } 475 476 fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 477 self.set_state(&snapshot.to_versioned_state(&self.id)?); 478 Ok(()) 479 } 480 } 481 impl Transportable for Console {} 482 impl Migratable for Console {} 483