1 // Copyright © 2024 Google LLC 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 use std::collections::HashMap; 7 use std::ffi::CString; 8 use std::sync::{Arc, Barrier, Mutex, RwLock}; 9 use std::{io, result}; 10 11 use num_enum::TryFromPrimitive; 12 use pci::{ 13 BarReprogrammingParams, PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, 14 PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass, 15 }; 16 use thiserror::Error; 17 use vm_allocator::page_size::get_page_size; 18 use vm_allocator::{AddressAllocator, SystemAllocator}; 19 use vm_device::{BusDeviceSync, Resource}; 20 use vm_memory::bitmap::AtomicBitmap; 21 use vm_memory::{ 22 Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, 23 GuestMemoryError, GuestMemoryMmap, Le32, Le64, 24 }; 25 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; 26 27 const PVMEMCONTROL_VENDOR_ID: u16 = 0x1ae0; 28 const PVMEMCONTROL_DEVICE_ID: u16 = 0x0087; 29 30 const PVMEMCONTROL_SUBSYSTEM_VENDOR_ID: u16 = 0x1ae0; 31 const PVMEMCONTROL_SUBSYSTEM_ID: u16 = 0x011F; 32 33 const MAJOR_VERSION: u64 = 1; 34 const MINOR_VERSION: u64 = 0; 35 36 #[derive(Error, Debug)] 37 pub enum Error { 38 // device errors 39 #[error("Guest gave us bad memory addresses: {0}")] 40 GuestMemory(#[source] GuestMemoryError), 41 #[error("Guest sent us invalid request")] 42 InvalidRequest, 43 44 #[error("Guest sent us invalid command: {0}")] 45 InvalidCommand(u32), 46 #[error("Guest sent us invalid connection: {0}")] 47 InvalidConnection(u32), 48 49 // pvmemcontrol errors 50 #[error("Request contains invalid arguments: {0}")] 51 InvalidArgument(u64), 52 #[error("Unknown function code: {0}")] 53 UnknownFunctionCode(u64), 54 #[error("Libc call fail: {0}")] 55 LibcFail(#[source] std::io::Error), 56 } 57 58 #[derive(Copy, Clone)] 59 enum PvmemcontrolSubclass { 60 Other = 0x80, 61 } 62 63 impl PciSubclass for PvmemcontrolSubclass { 64 fn get_register_value(&self) -> u8 { 65 *self as u8 66 } 67 } 68 69 /// commands have 0 as the most significant byte 70 #[repr(u32)] 71 #[derive(PartialEq, Eq, Copy, Clone, TryFromPrimitive)] 72 enum PvmemcontrolTransportCommand { 73 Reset = 0x060f_e6d2, 74 Register = 0x0e35_9539, 75 Ready = 0x0ca8_d227, 76 Disconnect = 0x030f_5da0, 77 Ack = 0x03cf_5196, 78 Error = 0x01fb_a249, 79 } 80 81 #[repr(C)] 82 #[derive(Copy, Clone)] 83 struct PvmemcontrolTransportRegister { 84 buf_phys_addr: Le64, 85 } 86 87 #[repr(C)] 88 #[derive(Copy, Clone)] 89 struct PvmemcontrolTransportRegisterResponse { 90 command: Le32, 91 _padding: u32, 92 } 93 94 #[repr(C)] 95 #[derive(Copy, Clone)] 96 union PvmemcontrolTransportUnion { 97 register: PvmemcontrolTransportRegister, 98 register_response: PvmemcontrolTransportRegisterResponse, 99 unit: (), 100 } 101 102 #[repr(C)] 103 #[derive(Copy, Clone)] 104 struct PvmemcontrolTransport { 105 payload: PvmemcontrolTransportUnion, 106 command: PvmemcontrolTransportCommand, 107 } 108 109 const PVMEMCONTROL_DEVICE_MMIO_SIZE: u64 = std::mem::size_of::<PvmemcontrolTransport>() as u64; 110 const PVMEMCONTROL_DEVICE_MMIO_ALIGN: u64 = std::mem::align_of::<PvmemcontrolTransport>() as u64; 111 112 impl PvmemcontrolTransport { 113 fn ack() -> Self { 114 PvmemcontrolTransport { 115 payload: PvmemcontrolTransportUnion { unit: () }, 116 command: PvmemcontrolTransportCommand::Ack, 117 } 118 } 119 120 fn error() -> Self { 121 PvmemcontrolTransport { 122 payload: PvmemcontrolTransportUnion { unit: () }, 123 command: PvmemcontrolTransportCommand::Error, 124 } 125 } 126 127 fn register_response(command: u32) -> Self { 128 PvmemcontrolTransport { 129 payload: PvmemcontrolTransportUnion { 130 register_response: PvmemcontrolTransportRegisterResponse { 131 command: command.into(), 132 _padding: 0, 133 }, 134 }, 135 command: PvmemcontrolTransportCommand::Ack, 136 } 137 } 138 139 unsafe fn as_register(self) -> PvmemcontrolTransportRegister { 140 self.payload.register 141 } 142 } 143 144 // SAFETY: Contains no references and does not have compiler-inserted padding 145 unsafe impl ByteValued for PvmemcontrolTransportUnion {} 146 // SAFETY: Contains no references and does not have compiler-inserted padding 147 unsafe impl ByteValued for PvmemcontrolTransport {} 148 149 #[repr(u64)] 150 #[derive(Copy, Clone, TryFromPrimitive, Debug)] 151 enum FunctionCode { 152 Info = 0, 153 Dontneed = 1, 154 Remove = 2, 155 Free = 3, 156 Pageout = 4, 157 Dontdump = 5, 158 SetVMAAnonName = 6, 159 Mlock = 7, 160 Munlock = 8, 161 MprotectNone = 9, 162 MprotectR = 10, 163 MprotectW = 11, 164 MprotectRW = 12, 165 Mergeable = 13, 166 Unmergeable = 14, 167 } 168 169 #[repr(C)] 170 #[derive(Copy, Clone, Debug, Default)] 171 struct PvmemcontrolReq { 172 func_code: Le64, 173 addr: Le64, 174 length: Le64, 175 arg: Le64, 176 } 177 178 // SAFETY: it only has data and has no implicit padding. 179 unsafe impl ByteValued for PvmemcontrolReq {} 180 181 #[repr(C)] 182 #[derive(Copy, Clone, Default)] 183 struct PvmemcontrolResp { 184 ret_errno: Le32, 185 ret_code: Le32, 186 ret_value: Le64, 187 arg0: Le64, 188 arg1: Le64, 189 } 190 191 impl std::fmt::Debug for PvmemcontrolResp { 192 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 193 let PvmemcontrolResp { 194 ret_errno, 195 ret_code, 196 .. 197 } = self; 198 write!( 199 f, 200 "PvmemcontrolResp {{ ret_errno: {}, ret_code: {}, .. }}", 201 ret_errno.to_native(), 202 ret_code.to_native() 203 ) 204 } 205 } 206 207 // SAFETY: it only has data and has no implicit padding. 208 unsafe impl ByteValued for PvmemcontrolResp {} 209 210 /// The guest connections start at 0x8000_0000, which has a leading 1 in 211 /// the most significant byte, this ensures it does not conflict with 212 /// any of the transport commands 213 #[derive(Hash, Clone, Copy, PartialEq, Eq, Debug)] 214 pub struct GuestConnection { 215 command: u32, 216 } 217 218 impl Default for GuestConnection { 219 fn default() -> Self { 220 GuestConnection::new(0x8000_0000) 221 } 222 } 223 224 impl GuestConnection { 225 fn new(command: u32) -> Self { 226 Self { command } 227 } 228 229 fn next(&self) -> Self { 230 let GuestConnection { command } = *self; 231 232 if command == u32::MAX { 233 GuestConnection::default() 234 } else { 235 GuestConnection::new(command + 1) 236 } 237 } 238 } 239 240 impl TryFrom<u32> for GuestConnection { 241 type Error = Error; 242 243 fn try_from(value: u32) -> Result<Self, Self::Error> { 244 if (value & 0x8000_0000) != 0 { 245 Ok(GuestConnection::new(value)) 246 } else { 247 Err(Error::InvalidConnection(value)) 248 } 249 } 250 } 251 252 struct PercpuInitState { 253 port_buf_map: HashMap<GuestConnection, GuestAddress>, 254 next_conn: GuestConnection, 255 } 256 257 impl PercpuInitState { 258 fn new() -> Self { 259 PercpuInitState { 260 port_buf_map: HashMap::new(), 261 next_conn: GuestConnection::default(), 262 } 263 } 264 } 265 266 enum PvmemcontrolState { 267 PercpuInit(PercpuInitState), 268 Ready(HashMap<GuestConnection, GuestAddress>), 269 Broken, 270 } 271 272 pub struct PvmemcontrolDevice { 273 transport: PvmemcontrolTransport, 274 state: PvmemcontrolState, 275 } 276 277 impl PvmemcontrolDevice { 278 fn new(transport: PvmemcontrolTransport, state: PvmemcontrolState) -> Self { 279 PvmemcontrolDevice { transport, state } 280 } 281 } 282 283 impl PvmemcontrolDevice { 284 fn register_percpu_buf( 285 guest_memory: &GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>, 286 mut state: PercpuInitState, 287 PvmemcontrolTransportRegister { buf_phys_addr }: PvmemcontrolTransportRegister, 288 ) -> Self { 289 // access to this address is checked 290 let buf_phys_addr = GuestAddress(buf_phys_addr.into()); 291 if !guest_memory.memory().check_range( 292 buf_phys_addr, 293 std::mem::size_of::<PvmemcontrolResp>().max(std::mem::size_of::<PvmemcontrolReq>()), 294 ) { 295 warn!("guest sent invalid phys addr {:#x}", buf_phys_addr.0); 296 return PvmemcontrolDevice::new( 297 PvmemcontrolTransport::error(), 298 PvmemcontrolState::Broken, 299 ); 300 } 301 302 let conn = { 303 // find an available port+byte combination, and fail if full 304 let mut next_conn = state.next_conn; 305 while state.port_buf_map.contains_key(&next_conn) { 306 next_conn = next_conn.next(); 307 if next_conn == state.next_conn { 308 warn!("connections exhausted"); 309 return PvmemcontrolDevice::new( 310 PvmemcontrolTransport::error(), 311 PvmemcontrolState::Broken, 312 ); 313 } 314 } 315 next_conn 316 }; 317 state.next_conn = conn.next(); 318 state.port_buf_map.insert(conn, buf_phys_addr); 319 320 // inform guest of the connection 321 let response = PvmemcontrolTransport::register_response(conn.command); 322 323 PvmemcontrolDevice::new(response, PvmemcontrolState::PercpuInit(state)) 324 } 325 326 fn reset() -> Self { 327 PvmemcontrolDevice::new( 328 PvmemcontrolTransport::ack(), 329 PvmemcontrolState::PercpuInit(PercpuInitState::new()), 330 ) 331 } 332 333 fn error() -> Self { 334 PvmemcontrolDevice::new(PvmemcontrolTransport::error(), PvmemcontrolState::Broken) 335 } 336 337 fn ready(PercpuInitState { port_buf_map, .. }: PercpuInitState) -> Self { 338 PvmemcontrolDevice::new( 339 PvmemcontrolTransport::ack(), 340 PvmemcontrolState::Ready(port_buf_map), 341 ) 342 } 343 344 fn run_command( 345 &mut self, 346 guest_memory: &GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>, 347 command: PvmemcontrolTransportCommand, 348 ) { 349 let state = std::mem::replace(&mut self.state, PvmemcontrolState::Broken); 350 351 *self = match command { 352 PvmemcontrolTransportCommand::Reset => Self::reset(), 353 PvmemcontrolTransportCommand::Register => { 354 if let PvmemcontrolState::PercpuInit(state) = state { 355 // SAFETY: By device protocol. If driver is wrong the device 356 // can enter a Broken state, but the behavior is still sound. 357 Self::register_percpu_buf(guest_memory, state, unsafe { 358 self.transport.as_register() 359 }) 360 } else { 361 debug!("received register without reset"); 362 Self::error() 363 } 364 } 365 PvmemcontrolTransportCommand::Ready => { 366 if let PvmemcontrolState::PercpuInit(state) = state { 367 Self::ready(state) 368 } else { 369 debug!("received ready without reset"); 370 Self::error() 371 } 372 } 373 PvmemcontrolTransportCommand::Disconnect => Self::error(), 374 PvmemcontrolTransportCommand::Ack => { 375 debug!("received ack as command"); 376 Self::error() 377 } 378 PvmemcontrolTransportCommand::Error => { 379 debug!("received error as command"); 380 Self::error() 381 } 382 } 383 } 384 385 /// read from the transport 386 fn read_transport(&self, offset: u64, data: &mut [u8]) { 387 self.transport 388 .as_slice() 389 .iter() 390 .skip(offset as usize) 391 .zip(data.iter_mut()) 392 .for_each(|(src, dest)| *dest = *src) 393 } 394 395 /// can only write to transport payload 396 /// command is a special register that needs separate dispatching 397 fn write_transport(&mut self, offset: u64, data: &[u8]) { 398 self.transport 399 .payload 400 .as_mut_slice() 401 .iter_mut() 402 .skip(offset as usize) 403 .zip(data.iter()) 404 .for_each(|(dest, src)| *dest = *src) 405 } 406 407 fn find_connection(&self, conn: GuestConnection) -> Option<GuestAddress> { 408 match &self.state { 409 PvmemcontrolState::Ready(map) => map.get(&conn).copied(), 410 _ => None, 411 } 412 } 413 } 414 415 pub struct PvmemcontrolBusDevice { 416 mem: GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>, 417 dev: RwLock<PvmemcontrolDevice>, 418 } 419 420 pub struct PvmemcontrolPciDevice { 421 id: String, 422 configuration: PciConfiguration, 423 bar_regions: Vec<PciBarConfiguration>, 424 } 425 426 impl PvmemcontrolBusDevice { 427 /// f is called with the host address of `range_base` and only when 428 /// [`range_base`, `range_base` + `range_len`) is present in the guest 429 fn operate_on_memory_range<F>(&self, addr: u64, length: u64, f: F) -> result::Result<(), Error> 430 where 431 F: FnOnce(*mut libc::c_void, libc::size_t) -> libc::c_int, 432 { 433 let memory = self.mem.memory(); 434 let range_base = GuestAddress(addr); 435 let range_len = usize::try_from(length).map_err(|_| Error::InvalidRequest)?; 436 437 // assume guest memory is not interleaved with vmm memory on the host. 438 if !memory.check_range(range_base, range_len) { 439 return Err(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress( 440 range_base, 441 ))); 442 } 443 let hva = memory 444 .get_host_address(range_base) 445 .map_err(Error::GuestMemory)?; 446 let res = f(hva as *mut libc::c_void, range_len as libc::size_t); 447 if res != 0 { 448 return Err(Error::LibcFail(io::Error::last_os_error())); 449 } 450 Ok(()) 451 } 452 453 fn madvise(&self, addr: u64, length: u64, advice: libc::c_int) -> result::Result<(), Error> { 454 // SAFETY: [`base`, `base` + `len`) is guest memory 455 self.operate_on_memory_range(addr, length, |base, len| unsafe { 456 libc::madvise(base, len, advice) 457 }) 458 } 459 460 fn mlock(&self, addr: u64, length: u64, on_default: bool) -> result::Result<(), Error> { 461 // SAFETY: [`base`, `base` + `len`) is guest memory 462 self.operate_on_memory_range(addr, length, |base, len| unsafe { 463 libc::mlock2(base, len, if on_default { libc::MLOCK_ONFAULT } else { 0 }) 464 }) 465 } 466 467 fn munlock(&self, addr: u64, length: u64) -> result::Result<(), Error> { 468 // SAFETY: [`base`, `base` + `len`) is guest memory 469 self.operate_on_memory_range(addr, length, |base, len| unsafe { 470 libc::munlock(base, len) 471 }) 472 } 473 474 fn mprotect( 475 &self, 476 addr: u64, 477 length: u64, 478 protection: libc::c_int, 479 ) -> result::Result<(), Error> { 480 // SAFETY: [`base`, `base` + `len`) is guest memory 481 self.operate_on_memory_range(addr, length, |base, len| unsafe { 482 libc::mprotect(base, len, protection) 483 }) 484 } 485 486 fn set_vma_anon_name(&self, addr: u64, length: u64, name: u64) -> result::Result<(), Error> { 487 let name = (name != 0).then(|| CString::new(format!("pvmemcontrol-{name}")).unwrap()); 488 let name_ptr = if let Some(name) = &name { 489 name.as_ptr() 490 } else { 491 std::ptr::null() 492 }; 493 debug!("addr {:X} length {} name {:?}", addr, length, name); 494 495 // SAFETY: [`base`, `base` + `len`) is guest memory 496 self.operate_on_memory_range(addr, length, |base, len| unsafe { 497 libc::prctl( 498 libc::PR_SET_VMA, 499 libc::PR_SET_VMA_ANON_NAME, 500 base, 501 len, 502 name_ptr, 503 ) 504 }) 505 } 506 507 fn process_request( 508 &self, 509 func_code: FunctionCode, 510 addr: u64, 511 length: u64, 512 arg: u64, 513 ) -> Result<PvmemcontrolResp, Error> { 514 let result = match func_code { 515 FunctionCode::Info => { 516 return Ok(PvmemcontrolResp { 517 ret_errno: 0.into(), 518 ret_code: 0.into(), 519 ret_value: get_page_size().into(), 520 arg0: MAJOR_VERSION.into(), 521 arg1: MINOR_VERSION.into(), 522 }) 523 } 524 FunctionCode::Dontneed => self.madvise(addr, length, libc::MADV_DONTNEED), 525 FunctionCode::Remove => self.madvise(addr, length, libc::MADV_REMOVE), 526 FunctionCode::Free => self.madvise(addr, length, libc::MADV_FREE), 527 FunctionCode::Pageout => self.madvise(addr, length, libc::MADV_PAGEOUT), 528 FunctionCode::Dontdump => self.madvise(addr, length, libc::MADV_DONTDUMP), 529 FunctionCode::SetVMAAnonName => self.set_vma_anon_name(addr, length, arg), 530 FunctionCode::Mlock => self.mlock(addr, length, false), 531 FunctionCode::Munlock => self.munlock(addr, length), 532 FunctionCode::MprotectNone => self.mprotect(addr, length, libc::PROT_NONE), 533 FunctionCode::MprotectR => self.mprotect(addr, length, libc::PROT_READ), 534 FunctionCode::MprotectW => self.mprotect(addr, length, libc::PROT_WRITE), 535 FunctionCode::MprotectRW => { 536 self.mprotect(addr, length, libc::PROT_READ | libc::PROT_WRITE) 537 } 538 FunctionCode::Mergeable => self.madvise(addr, length, libc::MADV_MERGEABLE), 539 FunctionCode::Unmergeable => self.madvise(addr, length, libc::MADV_UNMERGEABLE), 540 }; 541 result.map(|_| PvmemcontrolResp::default()) 542 } 543 544 fn handle_request( 545 &self, 546 PvmemcontrolReq { 547 func_code, 548 addr, 549 length, 550 arg, 551 }: PvmemcontrolReq, 552 ) -> Result<PvmemcontrolResp, Error> { 553 let (func_code, addr, length, arg) = ( 554 func_code.to_native(), 555 addr.to_native(), 556 length.to_native(), 557 arg.to_native(), 558 ); 559 560 let resp_or_err = FunctionCode::try_from(func_code) 561 .map_err(|_| Error::UnknownFunctionCode(func_code)) 562 .and_then(|func_code| self.process_request(func_code, addr, length, arg)); 563 564 let resp = match resp_or_err { 565 Ok(resp) => resp, 566 Err(e) => match e { 567 Error::InvalidArgument(arg) => PvmemcontrolResp { 568 ret_errno: (libc::EINVAL as u32).into(), 569 ret_code: (arg as u32).into(), 570 ..Default::default() 571 }, 572 Error::LibcFail(err) => PvmemcontrolResp { 573 ret_errno: (err.raw_os_error().unwrap_or(libc::EFAULT) as u32).into(), 574 ret_code: 0u32.into(), 575 ..Default::default() 576 }, 577 Error::UnknownFunctionCode(func_code) => PvmemcontrolResp { 578 ret_errno: (libc::EOPNOTSUPP as u32).into(), 579 ret_code: (func_code as u32).into(), 580 ..Default::default() 581 }, 582 Error::GuestMemory(err) => { 583 warn!("{}", err); 584 PvmemcontrolResp { 585 ret_errno: (libc::EINVAL as u32).into(), 586 ret_code: (func_code as u32).into(), 587 ..Default::default() 588 } 589 } 590 // device error, stop responding 591 other => return Err(other), 592 }, 593 }; 594 Ok(resp) 595 } 596 597 fn handle_pvmemcontrol_request(&self, guest_addr: GuestAddress) { 598 let request: PvmemcontrolReq = if let Ok(x) = self.mem.memory().read_obj(guest_addr) { 599 x 600 } else { 601 warn!("cannot read from guest address {:#x}", guest_addr.0); 602 return; 603 }; 604 605 let response: PvmemcontrolResp = match self.handle_request(request) { 606 Ok(x) => x, 607 Err(e) => { 608 warn!("cannot process request {:?} with error {}", request, e); 609 return; 610 } 611 }; 612 613 if self.mem.memory().write_obj(response, guest_addr).is_err() { 614 warn!("cannot write to guest address {:#x}", guest_addr.0); 615 } 616 } 617 618 fn handle_guest_write(&self, offset: u64, data: &[u8]) { 619 if offset as usize != std::mem::offset_of!(PvmemcontrolTransport, command) { 620 if data.len() != 4 && data.len() != 8 { 621 warn!("guest write is not 4 or 8 bytes long"); 622 return; 623 } 624 self.dev.write().unwrap().write_transport(offset, data); 625 return; 626 } 627 let data = if data.len() == 4 { 628 let mut d = [0u8; 4]; 629 d.iter_mut() 630 .zip(data.iter()) 631 .for_each(|(d, data)| *d = *data); 632 d 633 } else { 634 warn!("guest write with non u32 at command register"); 635 return; 636 }; 637 let data_cmd = u32::from_le_bytes(data); 638 let command = PvmemcontrolTransportCommand::try_from(data_cmd); 639 640 match command { 641 Ok(command) => self.dev.write().unwrap().run_command(&self.mem, command), 642 Err(_) => { 643 GuestConnection::try_from(data_cmd) 644 .and_then(|conn| { 645 self.dev 646 .read() 647 .unwrap() 648 .find_connection(conn) 649 .ok_or(Error::InvalidConnection(conn.command)) 650 }) 651 .map(|gpa| self.handle_pvmemcontrol_request(gpa)) 652 .unwrap_or_else(|err| warn!("{:?}", err)); 653 } 654 } 655 } 656 657 fn handle_guest_read(&self, offset: u64, data: &mut [u8]) { 658 self.dev.read().unwrap().read_transport(offset, data) 659 } 660 } 661 662 impl PvmemcontrolDevice { 663 pub fn make_device( 664 id: String, 665 mem: GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>, 666 ) -> (PvmemcontrolPciDevice, PvmemcontrolBusDevice) { 667 let dev = RwLock::new(PvmemcontrolDevice::error()); 668 let mut configuration = PciConfiguration::new( 669 PVMEMCONTROL_VENDOR_ID, 670 PVMEMCONTROL_DEVICE_ID, 671 0x1, 672 PciClassCode::BaseSystemPeripheral, 673 &PvmemcontrolSubclass::Other, 674 None, 675 PciHeaderType::Device, 676 PVMEMCONTROL_SUBSYSTEM_VENDOR_ID, 677 PVMEMCONTROL_SUBSYSTEM_ID, 678 None, 679 None, 680 ); 681 let command: [u8; 2] = [0x03, 0x01]; // memory, io, SERR# 682 683 configuration.write_config_register(1, 0, &command); 684 ( 685 PvmemcontrolPciDevice { 686 id, 687 configuration, 688 bar_regions: Vec::new(), 689 }, 690 PvmemcontrolBusDevice { mem, dev }, 691 ) 692 } 693 } 694 695 impl PciDevice for PvmemcontrolPciDevice { 696 fn write_config_register( 697 &mut self, 698 reg_idx: usize, 699 offset: u64, 700 data: &[u8], 701 ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) { 702 ( 703 self.configuration 704 .write_config_register(reg_idx, offset, data), 705 None, 706 ) 707 } 708 709 fn read_config_register(&mut self, reg_idx: usize) -> u32 { 710 self.configuration.read_config_register(reg_idx) 711 } 712 713 fn as_any_mut(&mut self) -> &mut dyn std::any::Any { 714 self 715 } 716 717 fn id(&self) -> Option<String> { 718 Some(self.id.clone()) 719 } 720 721 fn allocate_bars( 722 &mut self, 723 _allocator: &Arc<Mutex<SystemAllocator>>, 724 mmio32_allocator: &mut AddressAllocator, 725 _mmio64_allocator: &mut AddressAllocator, 726 resources: Option<Vec<Resource>>, 727 ) -> Result<Vec<PciBarConfiguration>, PciDeviceError> { 728 let mut bars = Vec::new(); 729 let region_type = PciBarRegionType::Memory32BitRegion; 730 let bar_id = 0; 731 let region_size = PVMEMCONTROL_DEVICE_MMIO_SIZE; 732 let restoring = resources.is_some(); 733 let bar_addr = mmio32_allocator 734 .allocate(None, region_size, Some(PVMEMCONTROL_DEVICE_MMIO_ALIGN)) 735 .ok_or(PciDeviceError::IoAllocationFailed(region_size))?; 736 737 let bar = PciBarConfiguration::default() 738 .set_index(bar_id as usize) 739 .set_address(bar_addr.raw_value()) 740 .set_size(region_size) 741 .set_region_type(region_type) 742 .set_prefetchable(PciBarPrefetchable::NotPrefetchable); 743 744 if !restoring { 745 self.configuration 746 .add_pci_bar(&bar) 747 .map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?; 748 } 749 750 bars.push(bar); 751 self.bar_regions.clone_from(&bars); 752 Ok(bars) 753 } 754 755 fn free_bars( 756 &mut self, 757 _allocator: &mut SystemAllocator, 758 mmio32_allocator: &mut AddressAllocator, 759 _mmio64_allocator: &mut AddressAllocator, 760 ) -> Result<(), PciDeviceError> { 761 for bar in self.bar_regions.drain(..) { 762 mmio32_allocator.free(GuestAddress(bar.addr()), bar.size()) 763 } 764 Ok(()) 765 } 766 767 fn move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), io::Error> { 768 for bar in self.bar_regions.iter_mut() { 769 if bar.addr() == old_base { 770 *bar = bar.set_address(new_base); 771 } 772 } 773 Ok(()) 774 } 775 } 776 777 impl Pausable for PvmemcontrolPciDevice { 778 fn pause(&mut self) -> std::result::Result<(), MigratableError> { 779 Ok(()) 780 } 781 782 fn resume(&mut self) -> std::result::Result<(), MigratableError> { 783 Ok(()) 784 } 785 } 786 787 impl Snapshottable for PvmemcontrolPciDevice { 788 fn id(&self) -> String { 789 self.id.clone() 790 } 791 792 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 793 let mut snapshot = Snapshot::new_from_state(&())?; 794 795 // Snapshot PciConfiguration 796 snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?); 797 798 Ok(snapshot) 799 } 800 } 801 802 impl Transportable for PvmemcontrolPciDevice {} 803 impl Migratable for PvmemcontrolPciDevice {} 804 805 impl BusDeviceSync for PvmemcontrolBusDevice { 806 fn read(&self, _base: u64, offset: u64, data: &mut [u8]) { 807 self.handle_guest_read(offset, data) 808 } 809 810 fn write(&self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> { 811 self.handle_guest_write(offset, data); 812 None 813 } 814 } 815