xref: /cloud-hypervisor/devices/src/pvmemcontrol.rs (revision 4ad44caa5217cf55eed512fc10fd68416a37d31c)
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