xref: /cloud-hypervisor/devices/src/pvmemcontrol.rs (revision eeae63b4595fbf0cc69f62b6e9d9a79c543c4ac7)
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     ) -> Option<Arc<Barrier>> {
702         self.configuration
703             .write_config_register(reg_idx, offset, data);
704         None
705     }
706 
707     fn read_config_register(&mut self, reg_idx: usize) -> u32 {
708         self.configuration.read_config_register(reg_idx)
709     }
710 
711     fn as_any(&mut self) -> &mut dyn std::any::Any {
712         self
713     }
714 
715     fn id(&self) -> Option<String> {
716         Some(self.id.clone())
717     }
718 
719     fn detect_bar_reprogramming(
720         &mut self,
721         reg_idx: usize,
722         data: &[u8],
723     ) -> Option<BarReprogrammingParams> {
724         self.configuration.detect_bar_reprogramming(reg_idx, data)
725     }
726 
727     fn allocate_bars(
728         &mut self,
729         _allocator: &Arc<Mutex<SystemAllocator>>,
730         mmio32_allocator: &mut AddressAllocator,
731         _mmio64_allocator: &mut AddressAllocator,
732         resources: Option<Vec<Resource>>,
733     ) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
734         let mut bars = Vec::new();
735         let region_type = PciBarRegionType::Memory32BitRegion;
736         let bar_id = 0;
737         let region_size = PVMEMCONTROL_DEVICE_MMIO_SIZE;
738         let restoring = resources.is_some();
739         let bar_addr = mmio32_allocator
740             .allocate(None, region_size, Some(PVMEMCONTROL_DEVICE_MMIO_ALIGN))
741             .ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
742 
743         let bar = PciBarConfiguration::default()
744             .set_index(bar_id as usize)
745             .set_address(bar_addr.raw_value())
746             .set_size(region_size)
747             .set_region_type(region_type)
748             .set_prefetchable(PciBarPrefetchable::NotPrefetchable);
749 
750         if !restoring {
751             self.configuration
752                 .add_pci_bar(&bar)
753                 .map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?;
754         }
755 
756         bars.push(bar);
757         self.bar_regions.clone_from(&bars);
758         Ok(bars)
759     }
760 
761     fn free_bars(
762         &mut self,
763         _allocator: &mut SystemAllocator,
764         mmio32_allocator: &mut AddressAllocator,
765         _mmio64_allocator: &mut AddressAllocator,
766     ) -> Result<(), PciDeviceError> {
767         for bar in self.bar_regions.drain(..) {
768             mmio32_allocator.free(GuestAddress(bar.addr()), bar.size())
769         }
770         Ok(())
771     }
772 
773     fn move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), io::Error> {
774         for bar in self.bar_regions.iter_mut() {
775             if bar.addr() == old_base {
776                 *bar = bar.set_address(new_base);
777             }
778         }
779         Ok(())
780     }
781 }
782 
783 impl Pausable for PvmemcontrolPciDevice {
784     fn pause(&mut self) -> std::result::Result<(), MigratableError> {
785         Ok(())
786     }
787 
788     fn resume(&mut self) -> std::result::Result<(), MigratableError> {
789         Ok(())
790     }
791 }
792 
793 impl Snapshottable for PvmemcontrolPciDevice {
794     fn id(&self) -> String {
795         self.id.clone()
796     }
797 
798     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
799         let mut snapshot = Snapshot::new_from_state(&())?;
800 
801         // Snapshot PciConfiguration
802         snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
803 
804         Ok(snapshot)
805     }
806 }
807 
808 impl Transportable for PvmemcontrolPciDevice {}
809 impl Migratable for PvmemcontrolPciDevice {}
810 
811 impl BusDeviceSync for PvmemcontrolBusDevice {
812     fn read(&self, _base: u64, offset: u64, data: &mut [u8]) {
813         self.handle_guest_read(offset, data)
814     }
815 
816     fn write(&self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
817         self.handle_guest_write(offset, data);
818         None
819     }
820 }
821