xref: /cloud-hypervisor/devices/src/pvmemcontrol.rs (revision 1b91aa8ef3ba490a12853d41783ed558cf7b7060)
15f18ac3bSYuanchu Xie // Copyright © 2024 Google LLC
25f18ac3bSYuanchu Xie //
35f18ac3bSYuanchu Xie // SPDX-License-Identifier: Apache-2.0
45f18ac3bSYuanchu Xie //
55f18ac3bSYuanchu Xie 
661e57e1cSRuoqing He use std::collections::HashMap;
761e57e1cSRuoqing He use std::ffi::CString;
861e57e1cSRuoqing He use std::sync::{Arc, Barrier, Mutex, RwLock};
961e57e1cSRuoqing He use std::{io, result};
1088a9f799SRob Bradford 
1188a9f799SRob Bradford use num_enum::TryFromPrimitive;
1288a9f799SRob Bradford use pci::{
1388a9f799SRob Bradford     BarReprogrammingParams, PciBarConfiguration, PciBarPrefetchable, PciBarRegionType,
1488a9f799SRob Bradford     PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
1588a9f799SRob Bradford };
165f18ac3bSYuanchu Xie use thiserror::Error;
1761e57e1cSRuoqing He use vm_allocator::page_size::get_page_size;
1861e57e1cSRuoqing He use vm_allocator::{AddressAllocator, SystemAllocator};
195f18ac3bSYuanchu Xie use vm_device::{BusDeviceSync, Resource};
2061e57e1cSRuoqing He use vm_memory::bitmap::AtomicBitmap;
215f18ac3bSYuanchu Xie use vm_memory::{
2261e57e1cSRuoqing He     Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
2361e57e1cSRuoqing He     GuestMemoryError, GuestMemoryMmap, Le32, Le64,
245f18ac3bSYuanchu Xie };
255f18ac3bSYuanchu Xie use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
265f18ac3bSYuanchu Xie 
275f18ac3bSYuanchu Xie const PVMEMCONTROL_VENDOR_ID: u16 = 0x1ae0;
285f18ac3bSYuanchu Xie const PVMEMCONTROL_DEVICE_ID: u16 = 0x0087;
295f18ac3bSYuanchu Xie 
305f18ac3bSYuanchu Xie const PVMEMCONTROL_SUBSYSTEM_VENDOR_ID: u16 = 0x1ae0;
315f18ac3bSYuanchu Xie const PVMEMCONTROL_SUBSYSTEM_ID: u16 = 0x011F;
325f18ac3bSYuanchu Xie 
335f18ac3bSYuanchu Xie const MAJOR_VERSION: u64 = 1;
345f18ac3bSYuanchu Xie const MINOR_VERSION: u64 = 0;
355f18ac3bSYuanchu Xie 
365f18ac3bSYuanchu Xie #[derive(Error, Debug)]
375f18ac3bSYuanchu Xie pub enum Error {
385f18ac3bSYuanchu Xie     // device errors
39*1b91aa8eSPhilipp Schuster     #[error("Guest gave us bad memory addresses")]
405f18ac3bSYuanchu Xie     GuestMemory(#[source] GuestMemoryError),
415f18ac3bSYuanchu Xie     #[error("Guest sent us invalid request")]
425f18ac3bSYuanchu Xie     InvalidRequest,
435f18ac3bSYuanchu Xie 
445f18ac3bSYuanchu Xie     #[error("Guest sent us invalid command: {0}")]
455f18ac3bSYuanchu Xie     InvalidCommand(u32),
465f18ac3bSYuanchu Xie     #[error("Guest sent us invalid connection: {0}")]
475f18ac3bSYuanchu Xie     InvalidConnection(u32),
485f18ac3bSYuanchu Xie 
495f18ac3bSYuanchu Xie     // pvmemcontrol errors
505f18ac3bSYuanchu Xie     #[error("Request contains invalid arguments: {0}")]
515f18ac3bSYuanchu Xie     InvalidArgument(u64),
525f18ac3bSYuanchu Xie     #[error("Unknown function code: {0}")]
535f18ac3bSYuanchu Xie     UnknownFunctionCode(u64),
54*1b91aa8eSPhilipp Schuster     #[error("Libc call fail")]
555f18ac3bSYuanchu Xie     LibcFail(#[source] std::io::Error),
565f18ac3bSYuanchu Xie }
575f18ac3bSYuanchu Xie 
585f18ac3bSYuanchu Xie #[derive(Copy, Clone)]
595f18ac3bSYuanchu Xie enum PvmemcontrolSubclass {
605f18ac3bSYuanchu Xie     Other = 0x80,
615f18ac3bSYuanchu Xie }
625f18ac3bSYuanchu Xie 
635f18ac3bSYuanchu Xie impl PciSubclass for PvmemcontrolSubclass {
get_register_value(&self) -> u8645f18ac3bSYuanchu Xie     fn get_register_value(&self) -> u8 {
655f18ac3bSYuanchu Xie         *self as u8
665f18ac3bSYuanchu Xie     }
675f18ac3bSYuanchu Xie }
685f18ac3bSYuanchu Xie 
695f18ac3bSYuanchu Xie /// commands have 0 as the most significant byte
705f18ac3bSYuanchu Xie #[repr(u32)]
715f18ac3bSYuanchu Xie #[derive(PartialEq, Eq, Copy, Clone, TryFromPrimitive)]
725f18ac3bSYuanchu Xie enum PvmemcontrolTransportCommand {
735f18ac3bSYuanchu Xie     Reset = 0x060f_e6d2,
745f18ac3bSYuanchu Xie     Register = 0x0e35_9539,
755f18ac3bSYuanchu Xie     Ready = 0x0ca8_d227,
765f18ac3bSYuanchu Xie     Disconnect = 0x030f_5da0,
775f18ac3bSYuanchu Xie     Ack = 0x03cf_5196,
785f18ac3bSYuanchu Xie     Error = 0x01fb_a249,
795f18ac3bSYuanchu Xie }
805f18ac3bSYuanchu Xie 
815f18ac3bSYuanchu Xie #[repr(C)]
825f18ac3bSYuanchu Xie #[derive(Copy, Clone)]
835f18ac3bSYuanchu Xie struct PvmemcontrolTransportRegister {
845f18ac3bSYuanchu Xie     buf_phys_addr: Le64,
855f18ac3bSYuanchu Xie }
865f18ac3bSYuanchu Xie 
875f18ac3bSYuanchu Xie #[repr(C)]
885f18ac3bSYuanchu Xie #[derive(Copy, Clone)]
895f18ac3bSYuanchu Xie struct PvmemcontrolTransportRegisterResponse {
905f18ac3bSYuanchu Xie     command: Le32,
915f18ac3bSYuanchu Xie     _padding: u32,
925f18ac3bSYuanchu Xie }
935f18ac3bSYuanchu Xie 
945f18ac3bSYuanchu Xie #[repr(C)]
955f18ac3bSYuanchu Xie #[derive(Copy, Clone)]
965f18ac3bSYuanchu Xie union PvmemcontrolTransportUnion {
975f18ac3bSYuanchu Xie     register: PvmemcontrolTransportRegister,
985f18ac3bSYuanchu Xie     register_response: PvmemcontrolTransportRegisterResponse,
995f18ac3bSYuanchu Xie     unit: (),
1005f18ac3bSYuanchu Xie }
1015f18ac3bSYuanchu Xie 
1025f18ac3bSYuanchu Xie #[repr(C)]
1035f18ac3bSYuanchu Xie #[derive(Copy, Clone)]
1045f18ac3bSYuanchu Xie struct PvmemcontrolTransport {
1055f18ac3bSYuanchu Xie     payload: PvmemcontrolTransportUnion,
1065f18ac3bSYuanchu Xie     command: PvmemcontrolTransportCommand,
1075f18ac3bSYuanchu Xie }
1085f18ac3bSYuanchu Xie 
1095f18ac3bSYuanchu Xie const PVMEMCONTROL_DEVICE_MMIO_SIZE: u64 = std::mem::size_of::<PvmemcontrolTransport>() as u64;
1105f18ac3bSYuanchu Xie const PVMEMCONTROL_DEVICE_MMIO_ALIGN: u64 = std::mem::align_of::<PvmemcontrolTransport>() as u64;
1115f18ac3bSYuanchu Xie 
1125f18ac3bSYuanchu Xie impl PvmemcontrolTransport {
ack() -> Self1135f18ac3bSYuanchu Xie     fn ack() -> Self {
1145f18ac3bSYuanchu Xie         PvmemcontrolTransport {
1155f18ac3bSYuanchu Xie             payload: PvmemcontrolTransportUnion { unit: () },
1165f18ac3bSYuanchu Xie             command: PvmemcontrolTransportCommand::Ack,
1175f18ac3bSYuanchu Xie         }
1185f18ac3bSYuanchu Xie     }
1195f18ac3bSYuanchu Xie 
error() -> Self1205f18ac3bSYuanchu Xie     fn error() -> Self {
1215f18ac3bSYuanchu Xie         PvmemcontrolTransport {
1225f18ac3bSYuanchu Xie             payload: PvmemcontrolTransportUnion { unit: () },
1235f18ac3bSYuanchu Xie             command: PvmemcontrolTransportCommand::Error,
1245f18ac3bSYuanchu Xie         }
1255f18ac3bSYuanchu Xie     }
1265f18ac3bSYuanchu Xie 
register_response(command: u32) -> Self1275f18ac3bSYuanchu Xie     fn register_response(command: u32) -> Self {
1285f18ac3bSYuanchu Xie         PvmemcontrolTransport {
1295f18ac3bSYuanchu Xie             payload: PvmemcontrolTransportUnion {
1305f18ac3bSYuanchu Xie                 register_response: PvmemcontrolTransportRegisterResponse {
1315f18ac3bSYuanchu Xie                     command: command.into(),
1325f18ac3bSYuanchu Xie                     _padding: 0,
1335f18ac3bSYuanchu Xie                 },
1345f18ac3bSYuanchu Xie             },
1355f18ac3bSYuanchu Xie             command: PvmemcontrolTransportCommand::Ack,
1365f18ac3bSYuanchu Xie         }
1375f18ac3bSYuanchu Xie     }
1385f18ac3bSYuanchu Xie 
as_register(self) -> PvmemcontrolTransportRegister1395f18ac3bSYuanchu Xie     unsafe fn as_register(self) -> PvmemcontrolTransportRegister {
1405f18ac3bSYuanchu Xie         self.payload.register
1415f18ac3bSYuanchu Xie     }
1425f18ac3bSYuanchu Xie }
1435f18ac3bSYuanchu Xie 
1445f18ac3bSYuanchu Xie // SAFETY: Contains no references and does not have compiler-inserted padding
1455f18ac3bSYuanchu Xie unsafe impl ByteValued for PvmemcontrolTransportUnion {}
1465f18ac3bSYuanchu Xie // SAFETY: Contains no references and does not have compiler-inserted padding
1475f18ac3bSYuanchu Xie unsafe impl ByteValued for PvmemcontrolTransport {}
1485f18ac3bSYuanchu Xie 
1495f18ac3bSYuanchu Xie #[repr(u64)]
1505f18ac3bSYuanchu Xie #[derive(Copy, Clone, TryFromPrimitive, Debug)]
1515f18ac3bSYuanchu Xie enum FunctionCode {
1525f18ac3bSYuanchu Xie     Info = 0,
1535f18ac3bSYuanchu Xie     Dontneed = 1,
1545f18ac3bSYuanchu Xie     Remove = 2,
1555f18ac3bSYuanchu Xie     Free = 3,
1565f18ac3bSYuanchu Xie     Pageout = 4,
1575f18ac3bSYuanchu Xie     Dontdump = 5,
1585f18ac3bSYuanchu Xie     SetVMAAnonName = 6,
1595f18ac3bSYuanchu Xie     Mlock = 7,
1605f18ac3bSYuanchu Xie     Munlock = 8,
1615f18ac3bSYuanchu Xie     MprotectNone = 9,
1625f18ac3bSYuanchu Xie     MprotectR = 10,
1635f18ac3bSYuanchu Xie     MprotectW = 11,
1645f18ac3bSYuanchu Xie     MprotectRW = 12,
1655f18ac3bSYuanchu Xie     Mergeable = 13,
1665f18ac3bSYuanchu Xie     Unmergeable = 14,
1675f18ac3bSYuanchu Xie }
1685f18ac3bSYuanchu Xie 
1695f18ac3bSYuanchu Xie #[repr(C)]
1705f18ac3bSYuanchu Xie #[derive(Copy, Clone, Debug, Default)]
1715f18ac3bSYuanchu Xie struct PvmemcontrolReq {
1725f18ac3bSYuanchu Xie     func_code: Le64,
1735f18ac3bSYuanchu Xie     addr: Le64,
1745f18ac3bSYuanchu Xie     length: Le64,
1755f18ac3bSYuanchu Xie     arg: Le64,
1765f18ac3bSYuanchu Xie }
1775f18ac3bSYuanchu Xie 
1785f18ac3bSYuanchu Xie // SAFETY: it only has data and has no implicit padding.
1795f18ac3bSYuanchu Xie unsafe impl ByteValued for PvmemcontrolReq {}
1805f18ac3bSYuanchu Xie 
1815f18ac3bSYuanchu Xie #[repr(C)]
1825f18ac3bSYuanchu Xie #[derive(Copy, Clone, Default)]
1835f18ac3bSYuanchu Xie struct PvmemcontrolResp {
1845f18ac3bSYuanchu Xie     ret_errno: Le32,
1855f18ac3bSYuanchu Xie     ret_code: Le32,
1865f18ac3bSYuanchu Xie     ret_value: Le64,
1875f18ac3bSYuanchu Xie     arg0: Le64,
1885f18ac3bSYuanchu Xie     arg1: Le64,
1895f18ac3bSYuanchu Xie }
1905f18ac3bSYuanchu Xie 
1915f18ac3bSYuanchu Xie impl std::fmt::Debug for PvmemcontrolResp {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result1925f18ac3bSYuanchu Xie     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1935f18ac3bSYuanchu Xie         let PvmemcontrolResp {
1945f18ac3bSYuanchu Xie             ret_errno,
1955f18ac3bSYuanchu Xie             ret_code,
1965f18ac3bSYuanchu Xie             ..
1975f18ac3bSYuanchu Xie         } = self;
1985f18ac3bSYuanchu Xie         write!(
1995f18ac3bSYuanchu Xie             f,
2005f18ac3bSYuanchu Xie             "PvmemcontrolResp {{ ret_errno: {}, ret_code: {}, .. }}",
2015f18ac3bSYuanchu Xie             ret_errno.to_native(),
2025f18ac3bSYuanchu Xie             ret_code.to_native()
2035f18ac3bSYuanchu Xie         )
2045f18ac3bSYuanchu Xie     }
2055f18ac3bSYuanchu Xie }
2065f18ac3bSYuanchu Xie 
2075f18ac3bSYuanchu Xie // SAFETY: it only has data and has no implicit padding.
2085f18ac3bSYuanchu Xie unsafe impl ByteValued for PvmemcontrolResp {}
2095f18ac3bSYuanchu Xie 
2105f18ac3bSYuanchu Xie /// The guest connections start at 0x8000_0000, which has a leading 1 in
2115f18ac3bSYuanchu Xie /// the most significant byte, this ensures it does not conflict with
2125f18ac3bSYuanchu Xie /// any of the transport commands
2135f18ac3bSYuanchu Xie #[derive(Hash, Clone, Copy, PartialEq, Eq, Debug)]
2145f18ac3bSYuanchu Xie pub struct GuestConnection {
2155f18ac3bSYuanchu Xie     command: u32,
2165f18ac3bSYuanchu Xie }
2175f18ac3bSYuanchu Xie 
2185f18ac3bSYuanchu Xie impl Default for GuestConnection {
default() -> Self2195f18ac3bSYuanchu Xie     fn default() -> Self {
2205f18ac3bSYuanchu Xie         GuestConnection::new(0x8000_0000)
2215f18ac3bSYuanchu Xie     }
2225f18ac3bSYuanchu Xie }
2235f18ac3bSYuanchu Xie 
2245f18ac3bSYuanchu Xie impl GuestConnection {
new(command: u32) -> Self2255f18ac3bSYuanchu Xie     fn new(command: u32) -> Self {
2265f18ac3bSYuanchu Xie         Self { command }
2275f18ac3bSYuanchu Xie     }
2285f18ac3bSYuanchu Xie 
next(&self) -> Self2295f18ac3bSYuanchu Xie     fn next(&self) -> Self {
2305f18ac3bSYuanchu Xie         let GuestConnection { command } = *self;
2315f18ac3bSYuanchu Xie 
2325f18ac3bSYuanchu Xie         if command == u32::MAX {
2335f18ac3bSYuanchu Xie             GuestConnection::default()
2345f18ac3bSYuanchu Xie         } else {
2355f18ac3bSYuanchu Xie             GuestConnection::new(command + 1)
2365f18ac3bSYuanchu Xie         }
2375f18ac3bSYuanchu Xie     }
2385f18ac3bSYuanchu Xie }
2395f18ac3bSYuanchu Xie 
2405f18ac3bSYuanchu Xie impl TryFrom<u32> for GuestConnection {
2415f18ac3bSYuanchu Xie     type Error = Error;
2425f18ac3bSYuanchu Xie 
try_from(value: u32) -> Result<Self, Self::Error>2435f18ac3bSYuanchu Xie     fn try_from(value: u32) -> Result<Self, Self::Error> {
2445f18ac3bSYuanchu Xie         if (value & 0x8000_0000) != 0 {
2455f18ac3bSYuanchu Xie             Ok(GuestConnection::new(value))
2465f18ac3bSYuanchu Xie         } else {
2475f18ac3bSYuanchu Xie             Err(Error::InvalidConnection(value))
2485f18ac3bSYuanchu Xie         }
2495f18ac3bSYuanchu Xie     }
2505f18ac3bSYuanchu Xie }
2515f18ac3bSYuanchu Xie 
2525f18ac3bSYuanchu Xie struct PercpuInitState {
2535f18ac3bSYuanchu Xie     port_buf_map: HashMap<GuestConnection, GuestAddress>,
2545f18ac3bSYuanchu Xie     next_conn: GuestConnection,
2555f18ac3bSYuanchu Xie }
2565f18ac3bSYuanchu Xie 
2575f18ac3bSYuanchu Xie impl PercpuInitState {
new() -> Self2585f18ac3bSYuanchu Xie     fn new() -> Self {
2595f18ac3bSYuanchu Xie         PercpuInitState {
2605f18ac3bSYuanchu Xie             port_buf_map: HashMap::new(),
2615f18ac3bSYuanchu Xie             next_conn: GuestConnection::default(),
2625f18ac3bSYuanchu Xie         }
2635f18ac3bSYuanchu Xie     }
2645f18ac3bSYuanchu Xie }
2655f18ac3bSYuanchu Xie 
2665f18ac3bSYuanchu Xie enum PvmemcontrolState {
2675f18ac3bSYuanchu Xie     PercpuInit(PercpuInitState),
2685f18ac3bSYuanchu Xie     Ready(HashMap<GuestConnection, GuestAddress>),
2695f18ac3bSYuanchu Xie     Broken,
2705f18ac3bSYuanchu Xie }
2715f18ac3bSYuanchu Xie 
2725f18ac3bSYuanchu Xie pub struct PvmemcontrolDevice {
2735f18ac3bSYuanchu Xie     transport: PvmemcontrolTransport,
2745f18ac3bSYuanchu Xie     state: PvmemcontrolState,
2755f18ac3bSYuanchu Xie }
2765f18ac3bSYuanchu Xie 
2775f18ac3bSYuanchu Xie impl PvmemcontrolDevice {
new(transport: PvmemcontrolTransport, state: PvmemcontrolState) -> Self2785f18ac3bSYuanchu Xie     fn new(transport: PvmemcontrolTransport, state: PvmemcontrolState) -> Self {
2795f18ac3bSYuanchu Xie         PvmemcontrolDevice { transport, state }
2805f18ac3bSYuanchu Xie     }
2815f18ac3bSYuanchu Xie }
2825f18ac3bSYuanchu Xie 
2835f18ac3bSYuanchu Xie impl PvmemcontrolDevice {
2845f18ac3bSYuanchu Xie     fn register_percpu_buf(
2855f18ac3bSYuanchu Xie         guest_memory: &GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>,
2865f18ac3bSYuanchu Xie         mut state: PercpuInitState,
2875f18ac3bSYuanchu Xie         PvmemcontrolTransportRegister { buf_phys_addr }: PvmemcontrolTransportRegister,
2885f18ac3bSYuanchu Xie     ) -> Self {
2895f18ac3bSYuanchu Xie         // access to this address is checked
2905f18ac3bSYuanchu Xie         let buf_phys_addr = GuestAddress(buf_phys_addr.into());
2915f18ac3bSYuanchu Xie         if !guest_memory.memory().check_range(
2925f18ac3bSYuanchu Xie             buf_phys_addr,
2935f18ac3bSYuanchu Xie             std::mem::size_of::<PvmemcontrolResp>().max(std::mem::size_of::<PvmemcontrolReq>()),
2945f18ac3bSYuanchu Xie         ) {
2955f18ac3bSYuanchu Xie             warn!("guest sent invalid phys addr {:#x}", buf_phys_addr.0);
2965f18ac3bSYuanchu Xie             return PvmemcontrolDevice::new(
2975f18ac3bSYuanchu Xie                 PvmemcontrolTransport::error(),
2985f18ac3bSYuanchu Xie                 PvmemcontrolState::Broken,
2995f18ac3bSYuanchu Xie             );
3005f18ac3bSYuanchu Xie         }
3015f18ac3bSYuanchu Xie 
3025f18ac3bSYuanchu Xie         let conn = {
3035f18ac3bSYuanchu Xie             // find an available port+byte combination, and fail if full
3045f18ac3bSYuanchu Xie             let mut next_conn = state.next_conn;
3055f18ac3bSYuanchu Xie             while state.port_buf_map.contains_key(&next_conn) {
3065f18ac3bSYuanchu Xie                 next_conn = next_conn.next();
3075f18ac3bSYuanchu Xie                 if next_conn == state.next_conn {
3085f18ac3bSYuanchu Xie                     warn!("connections exhausted");
3095f18ac3bSYuanchu Xie                     return PvmemcontrolDevice::new(
3105f18ac3bSYuanchu Xie                         PvmemcontrolTransport::error(),
3115f18ac3bSYuanchu Xie                         PvmemcontrolState::Broken,
3125f18ac3bSYuanchu Xie                     );
3135f18ac3bSYuanchu Xie                 }
3145f18ac3bSYuanchu Xie             }
3155f18ac3bSYuanchu Xie             next_conn
3165f18ac3bSYuanchu Xie         };
3175f18ac3bSYuanchu Xie         state.next_conn = conn.next();
3185f18ac3bSYuanchu Xie         state.port_buf_map.insert(conn, buf_phys_addr);
3195f18ac3bSYuanchu Xie 
3205f18ac3bSYuanchu Xie         // inform guest of the connection
3215f18ac3bSYuanchu Xie         let response = PvmemcontrolTransport::register_response(conn.command);
3225f18ac3bSYuanchu Xie 
3235f18ac3bSYuanchu Xie         PvmemcontrolDevice::new(response, PvmemcontrolState::PercpuInit(state))
3245f18ac3bSYuanchu Xie     }
3255f18ac3bSYuanchu Xie 
reset() -> Self3265f18ac3bSYuanchu Xie     fn reset() -> Self {
3275f18ac3bSYuanchu Xie         PvmemcontrolDevice::new(
3285f18ac3bSYuanchu Xie             PvmemcontrolTransport::ack(),
3295f18ac3bSYuanchu Xie             PvmemcontrolState::PercpuInit(PercpuInitState::new()),
3305f18ac3bSYuanchu Xie         )
3315f18ac3bSYuanchu Xie     }
3325f18ac3bSYuanchu Xie 
error() -> Self3335f18ac3bSYuanchu Xie     fn error() -> Self {
3345f18ac3bSYuanchu Xie         PvmemcontrolDevice::new(PvmemcontrolTransport::error(), PvmemcontrolState::Broken)
3355f18ac3bSYuanchu Xie     }
3365f18ac3bSYuanchu Xie 
3375f18ac3bSYuanchu Xie     fn ready(PercpuInitState { port_buf_map, .. }: PercpuInitState) -> Self {
3385f18ac3bSYuanchu Xie         PvmemcontrolDevice::new(
3395f18ac3bSYuanchu Xie             PvmemcontrolTransport::ack(),
3405f18ac3bSYuanchu Xie             PvmemcontrolState::Ready(port_buf_map),
3415f18ac3bSYuanchu Xie         )
3425f18ac3bSYuanchu Xie     }
3435f18ac3bSYuanchu Xie 
run_command( &mut self, guest_memory: &GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>, command: PvmemcontrolTransportCommand, )3445f18ac3bSYuanchu Xie     fn run_command(
3455f18ac3bSYuanchu Xie         &mut self,
3465f18ac3bSYuanchu Xie         guest_memory: &GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>,
3475f18ac3bSYuanchu Xie         command: PvmemcontrolTransportCommand,
3485f18ac3bSYuanchu Xie     ) {
3495f18ac3bSYuanchu Xie         let state = std::mem::replace(&mut self.state, PvmemcontrolState::Broken);
3505f18ac3bSYuanchu Xie 
3515f18ac3bSYuanchu Xie         *self = match command {
3525f18ac3bSYuanchu Xie             PvmemcontrolTransportCommand::Reset => Self::reset(),
3535f18ac3bSYuanchu Xie             PvmemcontrolTransportCommand::Register => {
3545f18ac3bSYuanchu Xie                 if let PvmemcontrolState::PercpuInit(state) = state {
3555f18ac3bSYuanchu Xie                     // SAFETY: By device protocol. If driver is wrong the device
3565f18ac3bSYuanchu Xie                     // can enter a Broken state, but the behavior is still sound.
3575f18ac3bSYuanchu Xie                     Self::register_percpu_buf(guest_memory, state, unsafe {
3585f18ac3bSYuanchu Xie                         self.transport.as_register()
3595f18ac3bSYuanchu Xie                     })
3605f18ac3bSYuanchu Xie                 } else {
3615f18ac3bSYuanchu Xie                     debug!("received register without reset");
3625f18ac3bSYuanchu Xie                     Self::error()
3635f18ac3bSYuanchu Xie                 }
3645f18ac3bSYuanchu Xie             }
3655f18ac3bSYuanchu Xie             PvmemcontrolTransportCommand::Ready => {
3665f18ac3bSYuanchu Xie                 if let PvmemcontrolState::PercpuInit(state) = state {
3675f18ac3bSYuanchu Xie                     Self::ready(state)
3685f18ac3bSYuanchu Xie                 } else {
3695f18ac3bSYuanchu Xie                     debug!("received ready without reset");
3705f18ac3bSYuanchu Xie                     Self::error()
3715f18ac3bSYuanchu Xie                 }
3725f18ac3bSYuanchu Xie             }
3735f18ac3bSYuanchu Xie             PvmemcontrolTransportCommand::Disconnect => Self::error(),
3745f18ac3bSYuanchu Xie             PvmemcontrolTransportCommand::Ack => {
3755f18ac3bSYuanchu Xie                 debug!("received ack as command");
3765f18ac3bSYuanchu Xie                 Self::error()
3775f18ac3bSYuanchu Xie             }
3785f18ac3bSYuanchu Xie             PvmemcontrolTransportCommand::Error => {
3795f18ac3bSYuanchu Xie                 debug!("received error as command");
3805f18ac3bSYuanchu Xie                 Self::error()
3815f18ac3bSYuanchu Xie             }
3825f18ac3bSYuanchu Xie         }
3835f18ac3bSYuanchu Xie     }
3845f18ac3bSYuanchu Xie 
3855f18ac3bSYuanchu Xie     /// read from the transport
read_transport(&self, offset: u64, data: &mut [u8])3865f18ac3bSYuanchu Xie     fn read_transport(&self, offset: u64, data: &mut [u8]) {
3875f18ac3bSYuanchu Xie         self.transport
3885f18ac3bSYuanchu Xie             .as_slice()
3895f18ac3bSYuanchu Xie             .iter()
3905f18ac3bSYuanchu Xie             .skip(offset as usize)
3915f18ac3bSYuanchu Xie             .zip(data.iter_mut())
3925f18ac3bSYuanchu Xie             .for_each(|(src, dest)| *dest = *src)
3935f18ac3bSYuanchu Xie     }
3945f18ac3bSYuanchu Xie 
3955f18ac3bSYuanchu Xie     /// can only write to transport payload
3965f18ac3bSYuanchu Xie     /// command is a special register that needs separate dispatching
write_transport(&mut self, offset: u64, data: &[u8])3975f18ac3bSYuanchu Xie     fn write_transport(&mut self, offset: u64, data: &[u8]) {
3985f18ac3bSYuanchu Xie         self.transport
3995f18ac3bSYuanchu Xie             .payload
4005f18ac3bSYuanchu Xie             .as_mut_slice()
4015f18ac3bSYuanchu Xie             .iter_mut()
4025f18ac3bSYuanchu Xie             .skip(offset as usize)
4035f18ac3bSYuanchu Xie             .zip(data.iter())
4045f18ac3bSYuanchu Xie             .for_each(|(dest, src)| *dest = *src)
4055f18ac3bSYuanchu Xie     }
4065f18ac3bSYuanchu Xie 
find_connection(&self, conn: GuestConnection) -> Option<GuestAddress>4075f18ac3bSYuanchu Xie     fn find_connection(&self, conn: GuestConnection) -> Option<GuestAddress> {
4085f18ac3bSYuanchu Xie         match &self.state {
4095f18ac3bSYuanchu Xie             PvmemcontrolState::Ready(map) => map.get(&conn).copied(),
4105f18ac3bSYuanchu Xie             _ => None,
4115f18ac3bSYuanchu Xie         }
4125f18ac3bSYuanchu Xie     }
4135f18ac3bSYuanchu Xie }
4145f18ac3bSYuanchu Xie 
4155f18ac3bSYuanchu Xie pub struct PvmemcontrolBusDevice {
4165f18ac3bSYuanchu Xie     mem: GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>,
4175f18ac3bSYuanchu Xie     dev: RwLock<PvmemcontrolDevice>,
4185f18ac3bSYuanchu Xie }
4195f18ac3bSYuanchu Xie 
4205f18ac3bSYuanchu Xie pub struct PvmemcontrolPciDevice {
4215f18ac3bSYuanchu Xie     id: String,
4225f18ac3bSYuanchu Xie     configuration: PciConfiguration,
4235f18ac3bSYuanchu Xie     bar_regions: Vec<PciBarConfiguration>,
4245f18ac3bSYuanchu Xie }
4255f18ac3bSYuanchu Xie 
4265f18ac3bSYuanchu Xie impl PvmemcontrolBusDevice {
4275f18ac3bSYuanchu Xie     /// f is called with the host address of `range_base` and only when
4285f18ac3bSYuanchu Xie     /// [`range_base`, `range_base` + `range_len`) is present in the guest
operate_on_memory_range<F>(&self, addr: u64, length: u64, f: F) -> result::Result<(), Error> where F: FnOnce(*mut libc::c_void, libc::size_t) -> libc::c_int,4295f18ac3bSYuanchu Xie     fn operate_on_memory_range<F>(&self, addr: u64, length: u64, f: F) -> result::Result<(), Error>
4305f18ac3bSYuanchu Xie     where
4315f18ac3bSYuanchu Xie         F: FnOnce(*mut libc::c_void, libc::size_t) -> libc::c_int,
4325f18ac3bSYuanchu Xie     {
4335f18ac3bSYuanchu Xie         let memory = self.mem.memory();
4345f18ac3bSYuanchu Xie         let range_base = GuestAddress(addr);
4355f18ac3bSYuanchu Xie         let range_len = usize::try_from(length).map_err(|_| Error::InvalidRequest)?;
4365f18ac3bSYuanchu Xie 
4375f18ac3bSYuanchu Xie         // assume guest memory is not interleaved with vmm memory on the host.
4385f18ac3bSYuanchu Xie         if !memory.check_range(range_base, range_len) {
4395f18ac3bSYuanchu Xie             return Err(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(
4405f18ac3bSYuanchu Xie                 range_base,
4415f18ac3bSYuanchu Xie             )));
4425f18ac3bSYuanchu Xie         }
4435f18ac3bSYuanchu Xie         let hva = memory
4445f18ac3bSYuanchu Xie             .get_host_address(range_base)
4455f18ac3bSYuanchu Xie             .map_err(Error::GuestMemory)?;
4465f18ac3bSYuanchu Xie         let res = f(hva as *mut libc::c_void, range_len as libc::size_t);
4475f18ac3bSYuanchu Xie         if res != 0 {
4485f18ac3bSYuanchu Xie             return Err(Error::LibcFail(io::Error::last_os_error()));
4495f18ac3bSYuanchu Xie         }
4505f18ac3bSYuanchu Xie         Ok(())
4515f18ac3bSYuanchu Xie     }
4525f18ac3bSYuanchu Xie 
madvise(&self, addr: u64, length: u64, advice: libc::c_int) -> result::Result<(), Error>4535f18ac3bSYuanchu Xie     fn madvise(&self, addr: u64, length: u64, advice: libc::c_int) -> result::Result<(), Error> {
4545f18ac3bSYuanchu Xie         // SAFETY: [`base`, `base` + `len`) is guest memory
4555f18ac3bSYuanchu Xie         self.operate_on_memory_range(addr, length, |base, len| unsafe {
4565f18ac3bSYuanchu Xie             libc::madvise(base, len, advice)
4575f18ac3bSYuanchu Xie         })
4585f18ac3bSYuanchu Xie     }
4595f18ac3bSYuanchu Xie 
mlock(&self, addr: u64, length: u64, on_default: bool) -> result::Result<(), Error>4605f18ac3bSYuanchu Xie     fn mlock(&self, addr: u64, length: u64, on_default: bool) -> result::Result<(), Error> {
4615f18ac3bSYuanchu Xie         // SAFETY: [`base`, `base` + `len`) is guest memory
4625f18ac3bSYuanchu Xie         self.operate_on_memory_range(addr, length, |base, len| unsafe {
4635f18ac3bSYuanchu Xie             libc::mlock2(base, len, if on_default { libc::MLOCK_ONFAULT } else { 0 })
4645f18ac3bSYuanchu Xie         })
4655f18ac3bSYuanchu Xie     }
4665f18ac3bSYuanchu Xie 
munlock(&self, addr: u64, length: u64) -> result::Result<(), Error>4675f18ac3bSYuanchu Xie     fn munlock(&self, addr: u64, length: u64) -> result::Result<(), Error> {
4685f18ac3bSYuanchu Xie         // SAFETY: [`base`, `base` + `len`) is guest memory
4695f18ac3bSYuanchu Xie         self.operate_on_memory_range(addr, length, |base, len| unsafe {
4705f18ac3bSYuanchu Xie             libc::munlock(base, len)
4715f18ac3bSYuanchu Xie         })
4725f18ac3bSYuanchu Xie     }
4735f18ac3bSYuanchu Xie 
mprotect( &self, addr: u64, length: u64, protection: libc::c_int, ) -> result::Result<(), Error>4745f18ac3bSYuanchu Xie     fn mprotect(
4755f18ac3bSYuanchu Xie         &self,
4765f18ac3bSYuanchu Xie         addr: u64,
4775f18ac3bSYuanchu Xie         length: u64,
4785f18ac3bSYuanchu Xie         protection: libc::c_int,
4795f18ac3bSYuanchu Xie     ) -> result::Result<(), Error> {
4805f18ac3bSYuanchu Xie         // SAFETY: [`base`, `base` + `len`) is guest memory
4815f18ac3bSYuanchu Xie         self.operate_on_memory_range(addr, length, |base, len| unsafe {
4825f18ac3bSYuanchu Xie             libc::mprotect(base, len, protection)
4835f18ac3bSYuanchu Xie         })
4845f18ac3bSYuanchu Xie     }
4855f18ac3bSYuanchu Xie 
set_vma_anon_name(&self, addr: u64, length: u64, name: u64) -> result::Result<(), Error>4865f18ac3bSYuanchu Xie     fn set_vma_anon_name(&self, addr: u64, length: u64, name: u64) -> result::Result<(), Error> {
48710ee003dSBo Chen         let name = (name != 0).then(|| CString::new(format!("pvmemcontrol-{name}")).unwrap());
4885f18ac3bSYuanchu Xie         let name_ptr = if let Some(name) = &name {
4895f18ac3bSYuanchu Xie             name.as_ptr()
4905f18ac3bSYuanchu Xie         } else {
4915f18ac3bSYuanchu Xie             std::ptr::null()
4925f18ac3bSYuanchu Xie         };
4935f18ac3bSYuanchu Xie         debug!("addr {:X} length {} name {:?}", addr, length, name);
4945f18ac3bSYuanchu Xie 
4955f18ac3bSYuanchu Xie         // SAFETY: [`base`, `base` + `len`) is guest memory
4965f18ac3bSYuanchu Xie         self.operate_on_memory_range(addr, length, |base, len| unsafe {
4975f18ac3bSYuanchu Xie             libc::prctl(
4985f18ac3bSYuanchu Xie                 libc::PR_SET_VMA,
4995f18ac3bSYuanchu Xie                 libc::PR_SET_VMA_ANON_NAME,
5005f18ac3bSYuanchu Xie                 base,
5015f18ac3bSYuanchu Xie                 len,
5025f18ac3bSYuanchu Xie                 name_ptr,
5035f18ac3bSYuanchu Xie             )
5045f18ac3bSYuanchu Xie         })
5055f18ac3bSYuanchu Xie     }
5065f18ac3bSYuanchu Xie 
process_request( &self, func_code: FunctionCode, addr: u64, length: u64, arg: u64, ) -> Result<PvmemcontrolResp, Error>5075f18ac3bSYuanchu Xie     fn process_request(
5085f18ac3bSYuanchu Xie         &self,
5095f18ac3bSYuanchu Xie         func_code: FunctionCode,
5105f18ac3bSYuanchu Xie         addr: u64,
5115f18ac3bSYuanchu Xie         length: u64,
5125f18ac3bSYuanchu Xie         arg: u64,
5135f18ac3bSYuanchu Xie     ) -> Result<PvmemcontrolResp, Error> {
5145f18ac3bSYuanchu Xie         let result = match func_code {
5155f18ac3bSYuanchu Xie             FunctionCode::Info => {
5165f18ac3bSYuanchu Xie                 return Ok(PvmemcontrolResp {
5175f18ac3bSYuanchu Xie                     ret_errno: 0.into(),
5185f18ac3bSYuanchu Xie                     ret_code: 0.into(),
5195f18ac3bSYuanchu Xie                     ret_value: get_page_size().into(),
5205f18ac3bSYuanchu Xie                     arg0: MAJOR_VERSION.into(),
5215f18ac3bSYuanchu Xie                     arg1: MINOR_VERSION.into(),
5225f18ac3bSYuanchu Xie                 })
5235f18ac3bSYuanchu Xie             }
5245f18ac3bSYuanchu Xie             FunctionCode::Dontneed => self.madvise(addr, length, libc::MADV_DONTNEED),
5255f18ac3bSYuanchu Xie             FunctionCode::Remove => self.madvise(addr, length, libc::MADV_REMOVE),
5265f18ac3bSYuanchu Xie             FunctionCode::Free => self.madvise(addr, length, libc::MADV_FREE),
5275f18ac3bSYuanchu Xie             FunctionCode::Pageout => self.madvise(addr, length, libc::MADV_PAGEOUT),
5285f18ac3bSYuanchu Xie             FunctionCode::Dontdump => self.madvise(addr, length, libc::MADV_DONTDUMP),
5295f18ac3bSYuanchu Xie             FunctionCode::SetVMAAnonName => self.set_vma_anon_name(addr, length, arg),
5305f18ac3bSYuanchu Xie             FunctionCode::Mlock => self.mlock(addr, length, false),
5315f18ac3bSYuanchu Xie             FunctionCode::Munlock => self.munlock(addr, length),
5325f18ac3bSYuanchu Xie             FunctionCode::MprotectNone => self.mprotect(addr, length, libc::PROT_NONE),
5335f18ac3bSYuanchu Xie             FunctionCode::MprotectR => self.mprotect(addr, length, libc::PROT_READ),
5345f18ac3bSYuanchu Xie             FunctionCode::MprotectW => self.mprotect(addr, length, libc::PROT_WRITE),
5355f18ac3bSYuanchu Xie             FunctionCode::MprotectRW => {
5365f18ac3bSYuanchu Xie                 self.mprotect(addr, length, libc::PROT_READ | libc::PROT_WRITE)
5375f18ac3bSYuanchu Xie             }
5385f18ac3bSYuanchu Xie             FunctionCode::Mergeable => self.madvise(addr, length, libc::MADV_MERGEABLE),
5395f18ac3bSYuanchu Xie             FunctionCode::Unmergeable => self.madvise(addr, length, libc::MADV_UNMERGEABLE),
5405f18ac3bSYuanchu Xie         };
5415f18ac3bSYuanchu Xie         result.map(|_| PvmemcontrolResp::default())
5425f18ac3bSYuanchu Xie     }
5435f18ac3bSYuanchu Xie 
5445f18ac3bSYuanchu Xie     fn handle_request(
5455f18ac3bSYuanchu Xie         &self,
5465f18ac3bSYuanchu Xie         PvmemcontrolReq {
5475f18ac3bSYuanchu Xie             func_code,
5485f18ac3bSYuanchu Xie             addr,
5495f18ac3bSYuanchu Xie             length,
5505f18ac3bSYuanchu Xie             arg,
5515f18ac3bSYuanchu Xie         }: PvmemcontrolReq,
5525f18ac3bSYuanchu Xie     ) -> Result<PvmemcontrolResp, Error> {
5535f18ac3bSYuanchu Xie         let (func_code, addr, length, arg) = (
5545f18ac3bSYuanchu Xie             func_code.to_native(),
5555f18ac3bSYuanchu Xie             addr.to_native(),
5565f18ac3bSYuanchu Xie             length.to_native(),
5575f18ac3bSYuanchu Xie             arg.to_native(),
5585f18ac3bSYuanchu Xie         );
5595f18ac3bSYuanchu Xie 
5605f18ac3bSYuanchu Xie         let resp_or_err = FunctionCode::try_from(func_code)
5615f18ac3bSYuanchu Xie             .map_err(|_| Error::UnknownFunctionCode(func_code))
5625f18ac3bSYuanchu Xie             .and_then(|func_code| self.process_request(func_code, addr, length, arg));
5635f18ac3bSYuanchu Xie 
5645f18ac3bSYuanchu Xie         let resp = match resp_or_err {
5655f18ac3bSYuanchu Xie             Ok(resp) => resp,
5665f18ac3bSYuanchu Xie             Err(e) => match e {
5675f18ac3bSYuanchu Xie                 Error::InvalidArgument(arg) => PvmemcontrolResp {
5685f18ac3bSYuanchu Xie                     ret_errno: (libc::EINVAL as u32).into(),
5695f18ac3bSYuanchu Xie                     ret_code: (arg as u32).into(),
5705f18ac3bSYuanchu Xie                     ..Default::default()
5715f18ac3bSYuanchu Xie                 },
5725f18ac3bSYuanchu Xie                 Error::LibcFail(err) => PvmemcontrolResp {
5735f18ac3bSYuanchu Xie                     ret_errno: (err.raw_os_error().unwrap_or(libc::EFAULT) as u32).into(),
5745f18ac3bSYuanchu Xie                     ret_code: 0u32.into(),
5755f18ac3bSYuanchu Xie                     ..Default::default()
5765f18ac3bSYuanchu Xie                 },
5775f18ac3bSYuanchu Xie                 Error::UnknownFunctionCode(func_code) => PvmemcontrolResp {
5785f18ac3bSYuanchu Xie                     ret_errno: (libc::EOPNOTSUPP as u32).into(),
5795f18ac3bSYuanchu Xie                     ret_code: (func_code as u32).into(),
5805f18ac3bSYuanchu Xie                     ..Default::default()
5815f18ac3bSYuanchu Xie                 },
5825f18ac3bSYuanchu Xie                 Error::GuestMemory(err) => {
5835f18ac3bSYuanchu Xie                     warn!("{}", err);
5845f18ac3bSYuanchu Xie                     PvmemcontrolResp {
5855f18ac3bSYuanchu Xie                         ret_errno: (libc::EINVAL as u32).into(),
5865f18ac3bSYuanchu Xie                         ret_code: (func_code as u32).into(),
5875f18ac3bSYuanchu Xie                         ..Default::default()
5885f18ac3bSYuanchu Xie                     }
5895f18ac3bSYuanchu Xie                 }
5905f18ac3bSYuanchu Xie                 // device error, stop responding
5915f18ac3bSYuanchu Xie                 other => return Err(other),
5925f18ac3bSYuanchu Xie             },
5935f18ac3bSYuanchu Xie         };
5945f18ac3bSYuanchu Xie         Ok(resp)
5955f18ac3bSYuanchu Xie     }
5965f18ac3bSYuanchu Xie 
handle_pvmemcontrol_request(&self, guest_addr: GuestAddress)5975f18ac3bSYuanchu Xie     fn handle_pvmemcontrol_request(&self, guest_addr: GuestAddress) {
5985f18ac3bSYuanchu Xie         let request: PvmemcontrolReq = if let Ok(x) = self.mem.memory().read_obj(guest_addr) {
5995f18ac3bSYuanchu Xie             x
6005f18ac3bSYuanchu Xie         } else {
6015f18ac3bSYuanchu Xie             warn!("cannot read from guest address {:#x}", guest_addr.0);
6025f18ac3bSYuanchu Xie             return;
6035f18ac3bSYuanchu Xie         };
6045f18ac3bSYuanchu Xie 
6055f18ac3bSYuanchu Xie         let response: PvmemcontrolResp = match self.handle_request(request) {
6065f18ac3bSYuanchu Xie             Ok(x) => x,
6075f18ac3bSYuanchu Xie             Err(e) => {
6085f18ac3bSYuanchu Xie                 warn!("cannot process request {:?} with error {}", request, e);
6095f18ac3bSYuanchu Xie                 return;
6105f18ac3bSYuanchu Xie             }
6115f18ac3bSYuanchu Xie         };
6125f18ac3bSYuanchu Xie 
6135f18ac3bSYuanchu Xie         if self.mem.memory().write_obj(response, guest_addr).is_err() {
6145f18ac3bSYuanchu Xie             warn!("cannot write to guest address {:#x}", guest_addr.0);
6155f18ac3bSYuanchu Xie         }
6165f18ac3bSYuanchu Xie     }
6175f18ac3bSYuanchu Xie 
handle_guest_write(&self, offset: u64, data: &[u8])6185f18ac3bSYuanchu Xie     fn handle_guest_write(&self, offset: u64, data: &[u8]) {
6195f18ac3bSYuanchu Xie         if offset as usize != std::mem::offset_of!(PvmemcontrolTransport, command) {
6205f18ac3bSYuanchu Xie             if data.len() != 4 && data.len() != 8 {
6215f18ac3bSYuanchu Xie                 warn!("guest write is not 4 or 8 bytes long");
6225f18ac3bSYuanchu Xie                 return;
6235f18ac3bSYuanchu Xie             }
6245f18ac3bSYuanchu Xie             self.dev.write().unwrap().write_transport(offset, data);
6255f18ac3bSYuanchu Xie             return;
6265f18ac3bSYuanchu Xie         }
6275f18ac3bSYuanchu Xie         let data = if data.len() == 4 {
6285f18ac3bSYuanchu Xie             let mut d = [0u8; 4];
6295f18ac3bSYuanchu Xie             d.iter_mut()
6305f18ac3bSYuanchu Xie                 .zip(data.iter())
6315f18ac3bSYuanchu Xie                 .for_each(|(d, data)| *d = *data);
6325f18ac3bSYuanchu Xie             d
6335f18ac3bSYuanchu Xie         } else {
6345f18ac3bSYuanchu Xie             warn!("guest write with non u32 at command register");
6355f18ac3bSYuanchu Xie             return;
6365f18ac3bSYuanchu Xie         };
6375f18ac3bSYuanchu Xie         let data_cmd = u32::from_le_bytes(data);
6385f18ac3bSYuanchu Xie         let command = PvmemcontrolTransportCommand::try_from(data_cmd);
6395f18ac3bSYuanchu Xie 
6405f18ac3bSYuanchu Xie         match command {
6415f18ac3bSYuanchu Xie             Ok(command) => self.dev.write().unwrap().run_command(&self.mem, command),
6425f18ac3bSYuanchu Xie             Err(_) => {
6435f18ac3bSYuanchu Xie                 GuestConnection::try_from(data_cmd)
6445f18ac3bSYuanchu Xie                     .and_then(|conn| {
6455f18ac3bSYuanchu Xie                         self.dev
6465f18ac3bSYuanchu Xie                             .read()
6475f18ac3bSYuanchu Xie                             .unwrap()
6485f18ac3bSYuanchu Xie                             .find_connection(conn)
6495f18ac3bSYuanchu Xie                             .ok_or(Error::InvalidConnection(conn.command))
6505f18ac3bSYuanchu Xie                     })
6515f18ac3bSYuanchu Xie                     .map(|gpa| self.handle_pvmemcontrol_request(gpa))
6525f18ac3bSYuanchu Xie                     .unwrap_or_else(|err| warn!("{:?}", err));
6535f18ac3bSYuanchu Xie             }
6545f18ac3bSYuanchu Xie         }
6555f18ac3bSYuanchu Xie     }
6565f18ac3bSYuanchu Xie 
handle_guest_read(&self, offset: u64, data: &mut [u8])6575f18ac3bSYuanchu Xie     fn handle_guest_read(&self, offset: u64, data: &mut [u8]) {
6585f18ac3bSYuanchu Xie         self.dev.read().unwrap().read_transport(offset, data)
6595f18ac3bSYuanchu Xie     }
6605f18ac3bSYuanchu Xie }
6615f18ac3bSYuanchu Xie 
6625f18ac3bSYuanchu Xie impl PvmemcontrolDevice {
make_device( id: String, mem: GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>, ) -> (PvmemcontrolPciDevice, PvmemcontrolBusDevice)6635f18ac3bSYuanchu Xie     pub fn make_device(
6645f18ac3bSYuanchu Xie         id: String,
6655f18ac3bSYuanchu Xie         mem: GuestMemoryAtomic<GuestMemoryMmap<AtomicBitmap>>,
6665f18ac3bSYuanchu Xie     ) -> (PvmemcontrolPciDevice, PvmemcontrolBusDevice) {
6675f18ac3bSYuanchu Xie         let dev = RwLock::new(PvmemcontrolDevice::error());
6685f18ac3bSYuanchu Xie         let mut configuration = PciConfiguration::new(
6695f18ac3bSYuanchu Xie             PVMEMCONTROL_VENDOR_ID,
6705f18ac3bSYuanchu Xie             PVMEMCONTROL_DEVICE_ID,
6715f18ac3bSYuanchu Xie             0x1,
6725f18ac3bSYuanchu Xie             PciClassCode::BaseSystemPeripheral,
6735f18ac3bSYuanchu Xie             &PvmemcontrolSubclass::Other,
6745f18ac3bSYuanchu Xie             None,
6755f18ac3bSYuanchu Xie             PciHeaderType::Device,
6765f18ac3bSYuanchu Xie             PVMEMCONTROL_SUBSYSTEM_VENDOR_ID,
6775f18ac3bSYuanchu Xie             PVMEMCONTROL_SUBSYSTEM_ID,
6785f18ac3bSYuanchu Xie             None,
6795f18ac3bSYuanchu Xie             None,
6805f18ac3bSYuanchu Xie         );
6815f18ac3bSYuanchu Xie         let command: [u8; 2] = [0x03, 0x01]; // memory, io, SERR#
6825f18ac3bSYuanchu Xie 
6835f18ac3bSYuanchu Xie         configuration.write_config_register(1, 0, &command);
6845f18ac3bSYuanchu Xie         (
6855f18ac3bSYuanchu Xie             PvmemcontrolPciDevice {
6865f18ac3bSYuanchu Xie                 id,
6875f18ac3bSYuanchu Xie                 configuration,
6885f18ac3bSYuanchu Xie                 bar_regions: Vec::new(),
6895f18ac3bSYuanchu Xie             },
6905f18ac3bSYuanchu Xie             PvmemcontrolBusDevice { mem, dev },
6915f18ac3bSYuanchu Xie         )
6925f18ac3bSYuanchu Xie     }
6935f18ac3bSYuanchu Xie }
6945f18ac3bSYuanchu Xie 
6955f18ac3bSYuanchu Xie impl PciDevice for PvmemcontrolPciDevice {
write_config_register( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>)6965f18ac3bSYuanchu Xie     fn write_config_register(
6975f18ac3bSYuanchu Xie         &mut self,
6985f18ac3bSYuanchu Xie         reg_idx: usize,
6995f18ac3bSYuanchu Xie         offset: u64,
7005f18ac3bSYuanchu Xie         data: &[u8],
701aaf86ef2SBo Chen     ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
702cb52cf91SBo Chen         (
7035f18ac3bSYuanchu Xie             self.configuration
704cb52cf91SBo Chen                 .write_config_register(reg_idx, offset, data),
705cb52cf91SBo Chen             None,
706cb52cf91SBo Chen         )
7075f18ac3bSYuanchu Xie     }
7085f18ac3bSYuanchu Xie 
read_config_register(&mut self, reg_idx: usize) -> u327095f18ac3bSYuanchu Xie     fn read_config_register(&mut self, reg_idx: usize) -> u32 {
7105f18ac3bSYuanchu Xie         self.configuration.read_config_register(reg_idx)
7115f18ac3bSYuanchu Xie     }
7125f18ac3bSYuanchu Xie 
as_any_mut(&mut self) -> &mut dyn std::any::Any713d99f2942SWei Liu     fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
7145f18ac3bSYuanchu Xie         self
7155f18ac3bSYuanchu Xie     }
7165f18ac3bSYuanchu Xie 
id(&self) -> Option<String>7175f18ac3bSYuanchu Xie     fn id(&self) -> Option<String> {
7185f18ac3bSYuanchu Xie         Some(self.id.clone())
7195f18ac3bSYuanchu Xie     }
7205f18ac3bSYuanchu Xie 
allocate_bars( &mut self, _allocator: &Arc<Mutex<SystemAllocator>>, mmio32_allocator: &mut AddressAllocator, _mmio64_allocator: &mut AddressAllocator, resources: Option<Vec<Resource>>, ) -> Result<Vec<PciBarConfiguration>, PciDeviceError>7215f18ac3bSYuanchu Xie     fn allocate_bars(
7225f18ac3bSYuanchu Xie         &mut self,
7235f18ac3bSYuanchu Xie         _allocator: &Arc<Mutex<SystemAllocator>>,
7245f18ac3bSYuanchu Xie         mmio32_allocator: &mut AddressAllocator,
7255f18ac3bSYuanchu Xie         _mmio64_allocator: &mut AddressAllocator,
7265f18ac3bSYuanchu Xie         resources: Option<Vec<Resource>>,
7275f18ac3bSYuanchu Xie     ) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
7285f18ac3bSYuanchu Xie         let mut bars = Vec::new();
7295f18ac3bSYuanchu Xie         let region_type = PciBarRegionType::Memory32BitRegion;
7305f18ac3bSYuanchu Xie         let bar_id = 0;
7315f18ac3bSYuanchu Xie         let region_size = PVMEMCONTROL_DEVICE_MMIO_SIZE;
7325f18ac3bSYuanchu Xie         let restoring = resources.is_some();
7335f18ac3bSYuanchu Xie         let bar_addr = mmio32_allocator
7345f18ac3bSYuanchu Xie             .allocate(None, region_size, Some(PVMEMCONTROL_DEVICE_MMIO_ALIGN))
7355f18ac3bSYuanchu Xie             .ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
7365f18ac3bSYuanchu Xie 
7375f18ac3bSYuanchu Xie         let bar = PciBarConfiguration::default()
7385f18ac3bSYuanchu Xie             .set_index(bar_id as usize)
7395f18ac3bSYuanchu Xie             .set_address(bar_addr.raw_value())
7405f18ac3bSYuanchu Xie             .set_size(region_size)
7415f18ac3bSYuanchu Xie             .set_region_type(region_type)
7425f18ac3bSYuanchu Xie             .set_prefetchable(PciBarPrefetchable::NotPrefetchable);
7435f18ac3bSYuanchu Xie 
7445f18ac3bSYuanchu Xie         if !restoring {
7455f18ac3bSYuanchu Xie             self.configuration
7465f18ac3bSYuanchu Xie                 .add_pci_bar(&bar)
7475f18ac3bSYuanchu Xie                 .map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?;
7485f18ac3bSYuanchu Xie         }
7495f18ac3bSYuanchu Xie 
7505f18ac3bSYuanchu Xie         bars.push(bar);
7515f18ac3bSYuanchu Xie         self.bar_regions.clone_from(&bars);
7525f18ac3bSYuanchu Xie         Ok(bars)
7535f18ac3bSYuanchu Xie     }
7545f18ac3bSYuanchu Xie 
free_bars( &mut self, _allocator: &mut SystemAllocator, mmio32_allocator: &mut AddressAllocator, _mmio64_allocator: &mut AddressAllocator, ) -> Result<(), PciDeviceError>7555f18ac3bSYuanchu Xie     fn free_bars(
7565f18ac3bSYuanchu Xie         &mut self,
7575f18ac3bSYuanchu Xie         _allocator: &mut SystemAllocator,
7585f18ac3bSYuanchu Xie         mmio32_allocator: &mut AddressAllocator,
7595f18ac3bSYuanchu Xie         _mmio64_allocator: &mut AddressAllocator,
7605f18ac3bSYuanchu Xie     ) -> Result<(), PciDeviceError> {
7615f18ac3bSYuanchu Xie         for bar in self.bar_regions.drain(..) {
7625f18ac3bSYuanchu Xie             mmio32_allocator.free(GuestAddress(bar.addr()), bar.size())
7635f18ac3bSYuanchu Xie         }
7645f18ac3bSYuanchu Xie         Ok(())
7655f18ac3bSYuanchu Xie     }
7665f18ac3bSYuanchu Xie 
move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), io::Error>7675f18ac3bSYuanchu Xie     fn move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), io::Error> {
7685f18ac3bSYuanchu Xie         for bar in self.bar_regions.iter_mut() {
7695f18ac3bSYuanchu Xie             if bar.addr() == old_base {
7705f18ac3bSYuanchu Xie                 *bar = bar.set_address(new_base);
7715f18ac3bSYuanchu Xie             }
7725f18ac3bSYuanchu Xie         }
7735f18ac3bSYuanchu Xie         Ok(())
7745f18ac3bSYuanchu Xie     }
7755f18ac3bSYuanchu Xie }
7765f18ac3bSYuanchu Xie 
7775f18ac3bSYuanchu Xie impl Pausable for PvmemcontrolPciDevice {
pause(&mut self) -> std::result::Result<(), MigratableError>7785f18ac3bSYuanchu Xie     fn pause(&mut self) -> std::result::Result<(), MigratableError> {
7795f18ac3bSYuanchu Xie         Ok(())
7805f18ac3bSYuanchu Xie     }
7815f18ac3bSYuanchu Xie 
resume(&mut self) -> std::result::Result<(), MigratableError>7825f18ac3bSYuanchu Xie     fn resume(&mut self) -> std::result::Result<(), MigratableError> {
7835f18ac3bSYuanchu Xie         Ok(())
7845f18ac3bSYuanchu Xie     }
7855f18ac3bSYuanchu Xie }
7865f18ac3bSYuanchu Xie 
7875f18ac3bSYuanchu Xie impl Snapshottable for PvmemcontrolPciDevice {
id(&self) -> String7885f18ac3bSYuanchu Xie     fn id(&self) -> String {
7895f18ac3bSYuanchu Xie         self.id.clone()
7905f18ac3bSYuanchu Xie     }
7915f18ac3bSYuanchu Xie 
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>7925f18ac3bSYuanchu Xie     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
7935f18ac3bSYuanchu Xie         let mut snapshot = Snapshot::new_from_state(&())?;
7945f18ac3bSYuanchu Xie 
7955f18ac3bSYuanchu Xie         // Snapshot PciConfiguration
7965f18ac3bSYuanchu Xie         snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
7975f18ac3bSYuanchu Xie 
7985f18ac3bSYuanchu Xie         Ok(snapshot)
7995f18ac3bSYuanchu Xie     }
8005f18ac3bSYuanchu Xie }
8015f18ac3bSYuanchu Xie 
8025f18ac3bSYuanchu Xie impl Transportable for PvmemcontrolPciDevice {}
8035f18ac3bSYuanchu Xie impl Migratable for PvmemcontrolPciDevice {}
8045f18ac3bSYuanchu Xie 
8055f18ac3bSYuanchu Xie impl BusDeviceSync for PvmemcontrolBusDevice {
read(&self, _base: u64, offset: u64, data: &mut [u8])8065f18ac3bSYuanchu Xie     fn read(&self, _base: u64, offset: u64, data: &mut [u8]) {
8075f18ac3bSYuanchu Xie         self.handle_guest_read(offset, data)
8085f18ac3bSYuanchu Xie     }
8095f18ac3bSYuanchu Xie 
write(&self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>8105f18ac3bSYuanchu Xie     fn write(&self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
8115f18ac3bSYuanchu Xie         self.handle_guest_write(offset, data);
8125f18ac3bSYuanchu Xie         None
8135f18ac3bSYuanchu Xie     }
8145f18ac3bSYuanchu Xie }
815