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