mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-01 17:35:19 +00:00
pci: vfio_user: Allow a BAR to have multiple user memory regions
Similar to what's being supported for vfio devices, vfio-user devices may also have BARs that need multiple kvm user memory regions, e.g. device regions with `VFIO_REGION_INFO_CAP_SPARSE_MMAP`. Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
parent
1dfe4eda5c
commit
bf39146caa
@ -211,10 +211,10 @@ impl Interrupt {
|
|||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct UserMemoryRegion {
|
pub struct UserMemoryRegion {
|
||||||
slot: u32,
|
pub slot: u32,
|
||||||
start: u64,
|
pub start: u64,
|
||||||
size: u64,
|
pub size: u64,
|
||||||
host_addr: u64,
|
pub host_addr: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -223,7 +223,6 @@ pub struct MmioRegion {
|
|||||||
pub length: GuestUsize,
|
pub length: GuestUsize,
|
||||||
pub(crate) type_: PciBarRegionType,
|
pub(crate) type_: PciBarRegionType,
|
||||||
pub(crate) index: u32,
|
pub(crate) index: u32,
|
||||||
pub(crate) mem_slot: Option<u32>,
|
|
||||||
pub(crate) host_addr: Option<u64>,
|
pub(crate) host_addr: Option<u64>,
|
||||||
pub(crate) mmap_size: Option<usize>,
|
pub(crate) mmap_size: Option<usize>,
|
||||||
pub(crate) user_memory_regions: Vec<UserMemoryRegion>,
|
pub(crate) user_memory_regions: Vec<UserMemoryRegion>,
|
||||||
@ -546,7 +545,6 @@ impl VfioCommon {
|
|||||||
length: region_size,
|
length: region_size,
|
||||||
type_: region_type,
|
type_: region_type,
|
||||||
index: bar_id as u32,
|
index: bar_id as u32,
|
||||||
mem_slot: None,
|
|
||||||
host_addr: None,
|
host_addr: None,
|
||||||
mmap_size: None,
|
mmap_size: None,
|
||||||
user_memory_regions: Vec::new(),
|
user_memory_regions: Vec::new(),
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::vfio::{Interrupt, Vfio, VfioCommon, VfioError};
|
use crate::vfio::{Interrupt, UserMemoryRegion, Vfio, VfioCommon, VfioError};
|
||||||
use crate::{BarReprogrammingParams, PciBarConfiguration, VfioPciError};
|
use crate::{BarReprogrammingParams, PciBarConfiguration, VfioPciError};
|
||||||
use crate::{
|
use crate::{
|
||||||
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
||||||
@ -174,22 +174,30 @@ impl VfioUserPciDevice {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let slot = mem_slot();
|
let user_memory_regions = vec![UserMemoryRegion {
|
||||||
let mem_region = vm.make_user_memory_region(
|
slot: mem_slot(),
|
||||||
slot,
|
start: mmio_region.start.0,
|
||||||
mmio_region.start.0,
|
size: mmio_region.length as u64,
|
||||||
mmio_region.length as u64,
|
host_addr: host_addr as u64,
|
||||||
host_addr as u64,
|
}];
|
||||||
false,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
vm.create_user_memory_region(mem_region)
|
for user_memory_region in user_memory_regions.iter() {
|
||||||
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
|
let mem_region = vm.make_user_memory_region(
|
||||||
|
user_memory_region.slot,
|
||||||
|
user_memory_region.start,
|
||||||
|
user_memory_region.size,
|
||||||
|
user_memory_region.host_addr,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.create_user_memory_region(mem_region)
|
||||||
|
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
|
||||||
|
}
|
||||||
|
|
||||||
mmio_region.mem_slot = Some(slot);
|
|
||||||
mmio_region.host_addr = Some(host_addr as u64);
|
mmio_region.host_addr = Some(host_addr as u64);
|
||||||
mmio_region.mmap_size = Some(mmio_region.length as usize);
|
mmio_region.mmap_size = Some(mmio_region.length as usize);
|
||||||
|
mmio_region.user_memory_regions = user_memory_regions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,17 +206,13 @@ impl VfioUserPciDevice {
|
|||||||
|
|
||||||
pub fn unmap_mmio_regions(&mut self) {
|
pub fn unmap_mmio_regions(&mut self) {
|
||||||
for mmio_region in self.common.mmio_regions.iter() {
|
for mmio_region in self.common.mmio_regions.iter() {
|
||||||
if let (Some(host_addr), Some(mmap_size), Some(mem_slot)) = (
|
for user_memory_region in mmio_region.user_memory_regions.iter() {
|
||||||
mmio_region.host_addr,
|
|
||||||
mmio_region.mmap_size,
|
|
||||||
mmio_region.mem_slot,
|
|
||||||
) {
|
|
||||||
// Remove region
|
// Remove region
|
||||||
let r = self.vm.make_user_memory_region(
|
let r = self.vm.make_user_memory_region(
|
||||||
mem_slot,
|
user_memory_region.slot,
|
||||||
mmio_region.start.raw_value(),
|
user_memory_region.start,
|
||||||
mmap_size as u64,
|
user_memory_region.size,
|
||||||
host_addr as u64,
|
user_memory_region.host_addr,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@ -216,7 +220,11 @@ impl VfioUserPciDevice {
|
|||||||
if let Err(e) = self.vm.remove_user_memory_region(r) {
|
if let Err(e) = self.vm.remove_user_memory_region(r) {
|
||||||
error!("Could not remove the userspace memory region: {}", e);
|
error!("Could not remove the userspace memory region: {}", e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (Some(host_addr), Some(mmap_size)) =
|
||||||
|
(mmio_region.host_addr, mmio_region.mmap_size)
|
||||||
|
{
|
||||||
let ret = unsafe { libc::munmap(host_addr as *mut libc::c_void, mmap_size) };
|
let ret = unsafe { libc::munmap(host_addr as *mut libc::c_void, mmap_size) };
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
error!(
|
error!(
|
||||||
@ -450,35 +458,41 @@ impl PciDevice for VfioUserPciDevice {
|
|||||||
if mmio_region.start.raw_value() == old_base {
|
if mmio_region.start.raw_value() == old_base {
|
||||||
mmio_region.start = GuestAddress(new_base);
|
mmio_region.start = GuestAddress(new_base);
|
||||||
|
|
||||||
if let Some(mem_slot) = mmio_region.mem_slot {
|
for user_memory_region in mmio_region.user_memory_regions.iter_mut() {
|
||||||
if let Some(host_addr) = mmio_region.host_addr {
|
// Remove old region
|
||||||
// Remove original region
|
let old_region = self.vm.make_user_memory_region(
|
||||||
let old_region = self.vm.make_user_memory_region(
|
user_memory_region.slot,
|
||||||
mem_slot,
|
user_memory_region.start,
|
||||||
old_base,
|
user_memory_region.size,
|
||||||
mmio_region.length as u64,
|
user_memory_region.host_addr,
|
||||||
host_addr as u64,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
self.vm
|
self.vm
|
||||||
.remove_user_memory_region(old_region)
|
.remove_user_memory_region(old_region)
|
||||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
||||||
|
|
||||||
let new_region = self.vm.make_user_memory_region(
|
// Update the user memory region with the correct start address.
|
||||||
mem_slot,
|
if new_base > old_base {
|
||||||
new_base,
|
user_memory_region.start += new_base - old_base;
|
||||||
mmio_region.length as u64,
|
} else {
|
||||||
host_addr as u64,
|
user_memory_region.start -= old_base - new_base;
|
||||||
false,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.vm
|
|
||||||
.create_user_memory_region(new_region)
|
|
||||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert new region
|
||||||
|
let new_region = self.vm.make_user_memory_region(
|
||||||
|
user_memory_region.slot,
|
||||||
|
user_memory_region.start,
|
||||||
|
user_memory_region.size,
|
||||||
|
user_memory_region.host_addr,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.vm
|
||||||
|
.create_user_memory_region(new_region)
|
||||||
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
||||||
}
|
}
|
||||||
info!("Moved bar 0x{:x} -> 0x{:x}", old_base, new_base);
|
info!("Moved bar 0x{:x} -> 0x{:x}", old_base, new_base);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user