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