2024-01-30 18:09:26 -08:00
|
|
|
pub mod error;
|
2024-01-09 15:40:17 -08:00
|
|
|
pub mod sys;
|
2024-01-08 20:45:16 -08:00
|
|
|
|
2024-01-30 18:09:26 -08:00
|
|
|
use crate::error::{Error, Result};
|
2024-01-09 22:39:32 -08:00
|
|
|
use crate::sys::{
|
2024-06-20 19:42:45 -07:00
|
|
|
AddToPhysmap, AddressSize, AssignDevice, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
|
|
|
|
EvtChnAllocUnbound, GetDomainInfo, GetPageFrameInfo3, HvmContext, HvmParam, Hypercall,
|
|
|
|
HypercallInit, IoMemPermission, IoPortPermission, IrqPermission, MaxMem, MaxVcpus, MemoryMap,
|
|
|
|
MemoryReservation, MmapBatch, MmapResource, MmuExtOp, MultiCallEntry, PagingMempool,
|
|
|
|
PciAssignDevice, XenCapabilitiesInfo, DOMCTL_DEV_PCI, HYPERVISOR_DOMCTL,
|
|
|
|
HYPERVISOR_EVENT_CHANNEL_OP, HYPERVISOR_HVM_OP, HYPERVISOR_MEMORY_OP, HYPERVISOR_MMUEXT_OP,
|
|
|
|
HYPERVISOR_MULTICALL, HYPERVISOR_XEN_VERSION, XENVER_CAPABILITIES, XEN_DOMCTL_ASSIGN_DEVICE,
|
|
|
|
XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN, XEN_DOMCTL_GETDOMAININFO,
|
|
|
|
XEN_DOMCTL_GETHVMCONTEXT, XEN_DOMCTL_GETPAGEFRAMEINFO3, XEN_DOMCTL_HYPERCALL_INIT,
|
|
|
|
XEN_DOMCTL_IOMEM_PERMISSION, XEN_DOMCTL_IOPORT_PERMISSION, XEN_DOMCTL_IRQ_PERMISSION,
|
|
|
|
XEN_DOMCTL_MAX_MEM, XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_PAUSEDOMAIN, XEN_DOMCTL_SETHVMCONTEXT,
|
|
|
|
XEN_DOMCTL_SETVCPUCONTEXT, XEN_DOMCTL_SET_ADDRESS_SIZE, XEN_DOMCTL_SET_PAGING_MEMPOOL_SIZE,
|
|
|
|
XEN_DOMCTL_UNPAUSEDOMAIN, XEN_MEM_ADD_TO_PHYSMAP, XEN_MEM_CLAIM_PAGES, XEN_MEM_MEMORY_MAP,
|
2024-04-29 10:02:20 -07:00
|
|
|
XEN_MEM_POPULATE_PHYSMAP,
|
2024-01-09 22:39:32 -08:00
|
|
|
};
|
2024-06-20 19:42:45 -07:00
|
|
|
use libc::{c_int, mmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
|
2024-01-11 12:21:33 -08:00
|
|
|
use log::trace;
|
2024-01-08 20:45:16 -08:00
|
|
|
use nix::errno::Errno;
|
2024-01-17 05:22:47 -08:00
|
|
|
use std::ffi::{c_long, c_uint, c_ulong, c_void};
|
2024-04-02 00:56:18 +00:00
|
|
|
use std::sync::Arc;
|
2024-06-20 19:42:45 -07:00
|
|
|
use std::time::Duration;
|
2024-04-29 10:02:20 -07:00
|
|
|
use sys::{
|
2024-06-28 15:13:57 -07:00
|
|
|
CpuId, E820Entry, ForeignMemoryMap, PhysdevMapPirq, Sysctl, SysctlCputopo, SysctlCputopoinfo,
|
|
|
|
SysctlPhysinfo, SysctlPmOp, SysctlPmOpValue, SysctlSetCpuFreqGov, SysctlValue,
|
|
|
|
VcpuGuestContextAny, HYPERVISOR_PHYSDEV_OP, HYPERVISOR_SYSCTL, PHYSDEVOP_MAP_PIRQ,
|
|
|
|
XEN_DOMCTL_MAX_INTERFACE_VERSION, XEN_DOMCTL_MIN_INTERFACE_VERSION, XEN_MEM_SET_MEMORY_MAP,
|
|
|
|
XEN_SYSCTL_CPUTOPOINFO, XEN_SYSCTL_MAX_INTERFACE_VERSION, XEN_SYSCTL_MIN_INTERFACE_VERSION,
|
|
|
|
XEN_SYSCTL_PHYSINFO, XEN_SYSCTL_PM_OP, XEN_SYSCTL_PM_OP_DISABLE_TURBO,
|
|
|
|
XEN_SYSCTL_PM_OP_ENABLE_TURBO,
|
2024-04-29 10:02:20 -07:00
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
use tokio::sync::Semaphore;
|
2024-06-20 19:42:45 -07:00
|
|
|
use tokio::time::sleep;
|
2024-01-30 18:09:26 -08:00
|
|
|
|
2024-01-08 20:45:16 -08:00
|
|
|
use std::fs::{File, OpenOptions};
|
|
|
|
use std::os::fd::AsRawFd;
|
2024-06-20 19:42:45 -07:00
|
|
|
use std::ptr::{addr_of_mut, null_mut};
|
2024-01-17 05:22:47 -08:00
|
|
|
use std::slice;
|
2024-01-08 20:45:16 -08:00
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
#[derive(Clone)]
|
2024-01-08 20:45:16 -08:00
|
|
|
pub struct XenCall {
|
2024-04-02 00:56:18 +00:00
|
|
|
pub handle: Arc<File>,
|
|
|
|
semaphore: Arc<Semaphore>,
|
2024-03-10 00:22:24 +00:00
|
|
|
domctl_interface_version: u32,
|
2024-06-28 15:13:57 -07:00
|
|
|
sysctl_interface_version: u32,
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl XenCall {
|
2024-03-10 00:22:24 +00:00
|
|
|
pub fn open(current_domid: u32) -> Result<XenCall> {
|
|
|
|
let handle = OpenOptions::new()
|
2024-01-08 20:45:16 -08:00
|
|
|
.read(true)
|
|
|
|
.write(true)
|
|
|
|
.open("/dev/xen/privcmd")?;
|
2024-03-10 00:22:24 +00:00
|
|
|
let domctl_interface_version =
|
|
|
|
XenCall::detect_domctl_interface_version(&handle, current_domid)?;
|
2024-06-28 15:13:57 -07:00
|
|
|
let sysctl_interface_version = XenCall::detect_sysctl_interface_version(&handle)?;
|
2024-03-10 00:22:24 +00:00
|
|
|
Ok(XenCall {
|
2024-04-02 00:56:18 +00:00
|
|
|
handle: Arc::new(handle),
|
|
|
|
semaphore: Arc::new(Semaphore::new(1)),
|
2024-03-10 00:22:24 +00:00
|
|
|
domctl_interface_version,
|
2024-06-28 15:13:57 -07:00
|
|
|
sysctl_interface_version,
|
2024-03-10 00:22:24 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn detect_domctl_interface_version(handle: &File, current_domid: u32) -> Result<u32> {
|
|
|
|
for version in XEN_DOMCTL_MIN_INTERFACE_VERSION..XEN_DOMCTL_MAX_INTERFACE_VERSION + 1 {
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_GETDOMAININFO,
|
|
|
|
interface_version: version,
|
|
|
|
domid: current_domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
get_domain_info: GetDomainInfo::default(),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
let mut call = Hypercall {
|
|
|
|
op: HYPERVISOR_DOMCTL,
|
|
|
|
arg: [addr_of_mut!(domctl) as u64, 0, 0, 0, 0],
|
|
|
|
};
|
|
|
|
let result = sys::hypercall(handle.as_raw_fd(), &mut call).unwrap_or(-1);
|
|
|
|
if result == 0 {
|
|
|
|
return Ok(version);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(Error::XenVersionUnsupported)
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
|
2024-06-28 15:13:57 -07:00
|
|
|
fn detect_sysctl_interface_version(handle: &File) -> Result<u32> {
|
|
|
|
for version in XEN_SYSCTL_MIN_INTERFACE_VERSION..XEN_SYSCTL_MAX_INTERFACE_VERSION + 1 {
|
|
|
|
let mut sysctl = Sysctl {
|
|
|
|
cmd: XEN_SYSCTL_CPUTOPOINFO,
|
|
|
|
interface_version: version,
|
|
|
|
value: SysctlValue {
|
|
|
|
cputopoinfo: SysctlCputopoinfo {
|
|
|
|
num_cpus: 0,
|
2024-06-29 15:43:08 -07:00
|
|
|
handle: 0,
|
2024-06-28 15:13:57 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
let mut call = Hypercall {
|
|
|
|
op: HYPERVISOR_SYSCTL,
|
|
|
|
arg: [addr_of_mut!(sysctl) as u64, 0, 0, 0, 0],
|
|
|
|
};
|
|
|
|
let result = sys::hypercall(handle.as_raw_fd(), &mut call).unwrap_or(-1);
|
|
|
|
if result == 0 {
|
|
|
|
return Ok(version);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(Error::XenVersionUnsupported)
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn mmap(&self, addr: u64, len: u64) -> Option<u64> {
|
|
|
|
let _permit = self.semaphore.acquire().await.ok()?;
|
2024-01-11 12:21:33 -08:00
|
|
|
trace!(
|
|
|
|
"call fd={} mmap addr={:#x} len={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
addr,
|
|
|
|
len
|
|
|
|
);
|
2024-01-10 16:07:57 -08:00
|
|
|
unsafe {
|
|
|
|
let ptr = mmap(
|
|
|
|
addr as *mut c_void,
|
|
|
|
len as usize,
|
|
|
|
PROT_READ | PROT_WRITE,
|
|
|
|
MAP_SHARED,
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
if ptr == MAP_FAILED {
|
|
|
|
None
|
|
|
|
} else {
|
2024-03-31 01:44:28 +00:00
|
|
|
trace!(
|
|
|
|
"call fd={} mmap addr={:#x} len={} = {:#x}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
addr,
|
|
|
|
len,
|
|
|
|
ptr as u64,
|
|
|
|
);
|
2024-01-10 16:07:57 -08:00
|
|
|
Some(ptr as u64)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall(&self, op: c_ulong, arg: [c_ulong; 5]) -> Result<c_long> {
|
|
|
|
let _permit = self.semaphore.acquire().await?;
|
2024-01-11 12:21:33 -08:00
|
|
|
trace!(
|
2024-02-06 10:28:39 +00:00
|
|
|
"call fd={} hypercall op={:#x} arg={:?}",
|
2024-01-11 12:21:33 -08:00
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
op,
|
|
|
|
arg
|
|
|
|
);
|
2024-01-08 20:45:16 -08:00
|
|
|
unsafe {
|
2024-01-09 15:40:17 -08:00
|
|
|
let mut call = Hypercall { op, arg };
|
|
|
|
let result = sys::hypercall(self.handle.as_raw_fd(), &mut call)?;
|
|
|
|
Ok(result as c_long)
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall0(&self, op: c_ulong) -> Result<c_long> {
|
|
|
|
self.hypercall(op, [0, 0, 0, 0, 0]).await
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall1(&self, op: c_ulong, arg1: c_ulong) -> Result<c_long> {
|
|
|
|
self.hypercall(op, [arg1, 0, 0, 0, 0]).await
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall2(&self, op: c_ulong, arg1: c_ulong, arg2: c_ulong) -> Result<c_long> {
|
|
|
|
self.hypercall(op, [arg1, arg2, 0, 0, 0]).await
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall3(
|
2024-01-10 08:57:44 -08:00
|
|
|
&self,
|
2024-01-08 20:45:16 -08:00
|
|
|
op: c_ulong,
|
|
|
|
arg1: c_ulong,
|
|
|
|
arg2: c_ulong,
|
|
|
|
arg3: c_ulong,
|
2024-01-30 18:09:26 -08:00
|
|
|
) -> Result<c_long> {
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall(op, [arg1, arg2, arg3, 0, 0]).await
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall4(
|
2024-01-10 08:57:44 -08:00
|
|
|
&self,
|
2024-01-08 20:45:16 -08:00
|
|
|
op: c_ulong,
|
|
|
|
arg1: c_ulong,
|
|
|
|
arg2: c_ulong,
|
|
|
|
arg3: c_ulong,
|
|
|
|
arg4: c_ulong,
|
2024-01-30 18:09:26 -08:00
|
|
|
) -> Result<c_long> {
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall(op, [arg1, arg2, arg3, arg4, 0]).await
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall5(
|
2024-01-10 08:57:44 -08:00
|
|
|
&self,
|
2024-01-08 20:45:16 -08:00
|
|
|
op: c_ulong,
|
|
|
|
arg1: c_ulong,
|
|
|
|
arg2: c_ulong,
|
|
|
|
arg3: c_ulong,
|
|
|
|
arg4: c_ulong,
|
|
|
|
arg5: c_ulong,
|
2024-01-30 18:09:26 -08:00
|
|
|
) -> Result<c_long> {
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall(op, [arg1, arg2, arg3, arg4, arg5]).await
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|
2024-01-09 22:39:32 -08:00
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn multicall(&self, calls: &mut [MultiCallEntry]) -> Result<()> {
|
2024-01-11 12:21:33 -08:00
|
|
|
trace!(
|
|
|
|
"call fd={} multicall calls={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
calls
|
|
|
|
);
|
|
|
|
self.hypercall2(
|
|
|
|
HYPERVISOR_MULTICALL,
|
|
|
|
calls.as_mut_ptr() as c_ulong,
|
|
|
|
calls.len() as c_ulong,
|
2024-04-02 00:56:18 +00:00
|
|
|
)
|
|
|
|
.await?;
|
2024-01-11 12:21:33 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn map_resource(
|
2024-01-16 23:07:34 -08:00
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
typ: u32,
|
|
|
|
id: u32,
|
|
|
|
idx: u32,
|
|
|
|
num: u64,
|
|
|
|
addr: u64,
|
2024-01-30 18:09:26 -08:00
|
|
|
) -> Result<()> {
|
2024-04-02 00:56:18 +00:00
|
|
|
let _permit = self.semaphore.acquire().await?;
|
2024-01-16 23:07:34 -08:00
|
|
|
let mut resource = MmapResource {
|
|
|
|
dom: domid as u16,
|
|
|
|
typ,
|
|
|
|
id,
|
|
|
|
idx,
|
|
|
|
num,
|
|
|
|
addr,
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
sys::mmap_resource(self.handle.as_raw_fd(), &mut resource)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn mmap_batch(
|
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
num: u64,
|
|
|
|
addr: u64,
|
|
|
|
mfns: Vec<u64>,
|
|
|
|
) -> Result<c_long> {
|
|
|
|
let _permit = self.semaphore.acquire().await?;
|
2024-01-11 12:21:33 -08:00
|
|
|
trace!(
|
|
|
|
"call fd={} mmap_batch domid={} num={} addr={:#x} mfns={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
num,
|
|
|
|
addr,
|
|
|
|
mfns
|
|
|
|
);
|
2024-01-09 22:39:32 -08:00
|
|
|
unsafe {
|
2024-01-10 16:07:57 -08:00
|
|
|
let mut mfns = mfns.clone();
|
|
|
|
let mut errors = vec![0i32; mfns.len()];
|
|
|
|
let mut batch = MmapBatch {
|
2024-01-10 19:18:48 -08:00
|
|
|
num: num as u32,
|
2024-01-10 16:07:57 -08:00
|
|
|
domid: domid as u16,
|
|
|
|
addr,
|
2024-06-20 19:42:45 -07:00
|
|
|
mfns: mfns.as_mut_ptr() as u64,
|
|
|
|
errors: errors.as_mut_ptr() as u64,
|
2024-01-10 16:07:57 -08:00
|
|
|
};
|
2024-01-20 20:29:36 -08:00
|
|
|
|
|
|
|
let result = sys::mmapbatch(self.handle.as_raw_fd(), &mut batch);
|
|
|
|
if let Err(errno) = result {
|
|
|
|
if errno != Errno::ENOENT {
|
2024-04-02 00:56:18 +00:00
|
|
|
return Err(Error::MmapBatchFailed(errno))?;
|
2024-01-20 20:29:36 -08:00
|
|
|
}
|
|
|
|
|
2024-06-20 19:42:45 -07:00
|
|
|
sleep(Duration::from_micros(100)).await;
|
2024-01-20 20:29:36 -08:00
|
|
|
|
|
|
|
let mut i: usize = 0;
|
|
|
|
let mut paged: usize = 0;
|
|
|
|
loop {
|
|
|
|
if errors[i] != libc::ENOENT {
|
|
|
|
i += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
paged += 1;
|
|
|
|
let mut batch = MmapBatch {
|
|
|
|
num: 1,
|
|
|
|
domid: domid as u16,
|
|
|
|
addr: addr + ((i as u64) << 12),
|
2024-06-20 19:42:45 -07:00
|
|
|
mfns: mfns.as_mut_ptr().add(i) as u64,
|
|
|
|
errors: errors.as_mut_ptr().add(i) as u64,
|
2024-01-20 20:29:36 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
i += 1;
|
|
|
|
if i < num as usize {
|
|
|
|
if errors[i] != libc::ENOENT {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
batch.num += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = sys::mmapbatch(self.handle.as_raw_fd(), &mut batch);
|
|
|
|
if let Err(n) = result {
|
|
|
|
if n != Errno::ENOENT {
|
2024-04-02 00:56:18 +00:00
|
|
|
return Err(Error::MmapBatchFailed(n))?;
|
2024-01-20 20:29:36 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if i < num as usize {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let count = result.unwrap();
|
|
|
|
if count <= 0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ok(paged as c_long);
|
|
|
|
}
|
|
|
|
Ok(result.unwrap() as c_long)
|
2024-01-09 22:39:32 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn get_version_capabilities(&self) -> Result<XenCapabilitiesInfo> {
|
2024-01-11 12:21:33 -08:00
|
|
|
trace!(
|
|
|
|
"call fd={} get_version_capabilities",
|
|
|
|
self.handle.as_raw_fd()
|
|
|
|
);
|
2024-01-10 19:18:48 -08:00
|
|
|
let mut info = XenCapabilitiesInfo {
|
2024-01-09 22:39:32 -08:00
|
|
|
capabilities: [0; 1024],
|
|
|
|
};
|
|
|
|
self.hypercall2(
|
|
|
|
HYPERVISOR_XEN_VERSION,
|
|
|
|
XENVER_CAPABILITIES,
|
2024-01-10 19:18:48 -08:00
|
|
|
addr_of_mut!(info) as c_ulong,
|
2024-04-02 00:56:18 +00:00
|
|
|
)
|
|
|
|
.await?;
|
2024-01-09 22:39:32 -08:00
|
|
|
Ok(info)
|
|
|
|
}
|
2024-01-17 01:41:17 -08:00
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn evtchn_op(&self, cmd: c_int, arg: u64) -> Result<()> {
|
|
|
|
self.hypercall2(HYPERVISOR_EVENT_CHANNEL_OP, cmd as c_ulong, arg)
|
|
|
|
.await?;
|
2024-01-17 01:41:17 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn evtchn_alloc_unbound(&self, domid: u32, remote_domid: u32) -> Result<u32> {
|
2024-01-17 01:41:17 -08:00
|
|
|
let mut alloc_unbound = EvtChnAllocUnbound {
|
|
|
|
dom: domid as u16,
|
|
|
|
remote_dom: remote_domid as u16,
|
|
|
|
port: 0,
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.evtchn_op(6, addr_of_mut!(alloc_unbound) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 01:41:17 -08:00
|
|
|
Ok(alloc_unbound.port)
|
|
|
|
}
|
2024-01-17 05:22:47 -08:00
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} get_domain_info domid={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_GETDOMAININFO,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
2024-03-10 00:22:24 +00:00
|
|
|
get_domain_info: GetDomainInfo::default(),
|
2024-01-17 05:22:47 -08:00
|
|
|
},
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(unsafe { domctl.value.get_domain_info })
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn create_domain(&self, create_domain: CreateDomain) -> Result<u32> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} create_domain create_domain={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
create_domain
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_CREATEDOMAIN,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid: 0,
|
|
|
|
value: DomCtlValue { create_domain },
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(domctl.domid)
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn pause_domain(&self, domid: u32) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} pause_domain domid={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_PAUSEDOMAIN,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue { pad: [0; 128] },
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn unpause_domain(&self, domid: u32) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} unpause_domain domid={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_UNPAUSEDOMAIN,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue { pad: [0; 128] },
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} set_max_mem domid={} memkb={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
memkb
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_MAX_MEM,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
max_mem: MaxMem { max_memkb: memkb },
|
|
|
|
},
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn set_max_vcpus(&self, domid: u32, max_vcpus: u32) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} set_max_vcpus domid={} max_vcpus={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
max_vcpus
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_MAX_VCPUS,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
max_cpus: MaxVcpus { max_vcpus },
|
|
|
|
},
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn set_address_size(&self, domid: u32, size: u32) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} set_address_size domid={} size={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
size,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_SET_ADDRESS_SIZE,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
address_size: AddressSize { size },
|
|
|
|
},
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn set_vcpu_context(
|
2024-01-17 05:22:47 -08:00
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
vcpu: u32,
|
2024-06-20 19:42:45 -07:00
|
|
|
mut context: VcpuGuestContextAny,
|
2024-01-30 18:09:26 -08:00
|
|
|
) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} set_vcpu_context domid={} context={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
2024-06-20 19:42:45 -07:00
|
|
|
unsafe { context.value }
|
2024-01-17 05:22:47 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_SETVCPUCONTEXT,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
vcpu_context: DomCtlVcpuContext {
|
|
|
|
vcpu,
|
2024-06-20 19:42:45 -07:00
|
|
|
ctx: addr_of_mut!(context) as c_ulong,
|
2024-01-17 05:22:47 -08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn get_page_frame_info(&self, domid: u32, frames: &[u64]) -> Result<Vec<u64>> {
|
2024-01-17 05:22:47 -08:00
|
|
|
let mut buffer: Vec<u64> = frames.to_vec();
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_GETPAGEFRAMEINFO3,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
get_page_frame_info: GetPageFrameInfo3 {
|
|
|
|
num: buffer.len() as u64,
|
|
|
|
array: buffer.as_mut_ptr() as c_ulong,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
let slice = unsafe {
|
|
|
|
slice::from_raw_parts_mut(
|
|
|
|
domctl.value.get_page_frame_info.array as *mut u64,
|
|
|
|
domctl.value.get_page_frame_info.num as usize,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
Ok(slice.to_vec())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} hypercall_init domid={} gmfn={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
gmfn
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_HYPERCALL_INIT,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
hypercall_init: HypercallInit { gmfn },
|
|
|
|
},
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn destroy_domain(&self, domid: u32) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!(
|
|
|
|
"domctl fd={} destroy_domain domid={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_DESTROYDOMAIN,
|
2024-03-10 00:22:24 +00:00
|
|
|
interface_version: self.domctl_interface_version,
|
2024-01-17 05:22:47 -08:00
|
|
|
domid,
|
|
|
|
value: DomCtlValue { pad: [0; 128] },
|
|
|
|
};
|
2024-04-02 00:56:18 +00:00
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
2024-01-17 05:22:47 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-29 10:02:20 -07:00
|
|
|
pub async fn get_memory_map(&self, max_entries: u32) -> Result<Vec<E820Entry>> {
|
2024-01-17 05:22:47 -08:00
|
|
|
let mut memory_map = MemoryMap {
|
2024-04-29 10:02:20 -07:00
|
|
|
count: max_entries,
|
2024-01-17 05:22:47 -08:00
|
|
|
buffer: 0,
|
|
|
|
};
|
2024-04-29 10:02:20 -07:00
|
|
|
let mut entries = vec![E820Entry::default(); max_entries as usize];
|
|
|
|
memory_map.buffer = entries.as_mut_ptr() as c_ulong;
|
2024-01-17 05:22:47 -08:00
|
|
|
self.hypercall2(
|
|
|
|
HYPERVISOR_MEMORY_OP,
|
|
|
|
XEN_MEM_MEMORY_MAP as c_ulong,
|
|
|
|
addr_of_mut!(memory_map) as c_ulong,
|
2024-04-02 00:56:18 +00:00
|
|
|
)
|
|
|
|
.await?;
|
2024-04-29 10:02:20 -07:00
|
|
|
entries.truncate(memory_map.count as usize);
|
|
|
|
Ok(entries)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn set_memory_map(
|
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
entries: Vec<E820Entry>,
|
|
|
|
) -> Result<Vec<E820Entry>> {
|
2024-06-20 19:42:45 -07:00
|
|
|
trace!(
|
|
|
|
"fd={} set_memory_map domid={} entries={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
entries
|
|
|
|
);
|
2024-04-29 10:02:20 -07:00
|
|
|
let mut memory_map = ForeignMemoryMap {
|
|
|
|
domid: domid as u16,
|
|
|
|
map: MemoryMap {
|
|
|
|
count: entries.len() as u32,
|
|
|
|
buffer: entries.as_ptr() as u64,
|
|
|
|
},
|
|
|
|
};
|
2024-01-17 05:22:47 -08:00
|
|
|
self.hypercall2(
|
|
|
|
HYPERVISOR_MEMORY_OP,
|
2024-04-29 10:02:20 -07:00
|
|
|
XEN_MEM_SET_MEMORY_MAP as c_ulong,
|
2024-01-17 05:22:47 -08:00
|
|
|
addr_of_mut!(memory_map) as c_ulong,
|
2024-04-02 00:56:18 +00:00
|
|
|
)
|
|
|
|
.await?;
|
2024-04-29 10:02:20 -07:00
|
|
|
Ok(entries)
|
2024-01-17 05:22:47 -08:00
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn populate_physmap(
|
2024-01-17 05:22:47 -08:00
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
nr_extents: u64,
|
|
|
|
extent_order: u32,
|
|
|
|
mem_flags: u32,
|
|
|
|
extent_starts: &[u64],
|
2024-01-30 18:09:26 -08:00
|
|
|
) -> Result<Vec<u64>> {
|
2024-01-17 05:22:47 -08:00
|
|
|
trace!("memory fd={} populate_physmap domid={} nr_extents={} extent_order={} mem_flags={} extent_starts={:?}", self.handle.as_raw_fd(), domid, nr_extents, extent_order, mem_flags, extent_starts);
|
|
|
|
let mut extent_starts = extent_starts.to_vec();
|
|
|
|
let ptr = extent_starts.as_mut_ptr();
|
|
|
|
|
|
|
|
let mut reservation = MemoryReservation {
|
|
|
|
extent_start: ptr as c_ulong,
|
|
|
|
nr_extents,
|
|
|
|
extent_order,
|
|
|
|
mem_flags,
|
|
|
|
domid: domid as u16,
|
|
|
|
};
|
|
|
|
|
2024-06-20 19:42:45 -07:00
|
|
|
let code = self
|
|
|
|
.hypercall2(
|
|
|
|
HYPERVISOR_MEMORY_OP,
|
2024-01-17 05:22:47 -08:00
|
|
|
XEN_MEM_POPULATE_PHYSMAP as c_ulong,
|
|
|
|
addr_of_mut!(reservation) as c_ulong,
|
2024-06-20 19:42:45 -07:00
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
if code as usize != extent_starts.len() {
|
2024-01-30 18:09:26 -08:00
|
|
|
return Err(Error::PopulatePhysmapFailed);
|
2024-01-17 05:22:47 -08:00
|
|
|
}
|
|
|
|
let extents = extent_starts[0..code as usize].to_vec();
|
|
|
|
Ok(extents)
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn claim_pages(&self, domid: u32, pages: u64) -> Result<()> {
|
2024-01-20 21:06:28 -08:00
|
|
|
trace!(
|
|
|
|
"memory fd={} claim_pages domid={} pages={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
pages
|
|
|
|
);
|
|
|
|
let mut reservation = MemoryReservation {
|
|
|
|
extent_start: 0,
|
|
|
|
nr_extents: pages,
|
|
|
|
extent_order: 0,
|
|
|
|
mem_flags: 0,
|
|
|
|
domid: domid as u16,
|
|
|
|
};
|
|
|
|
self.hypercall2(
|
|
|
|
HYPERVISOR_MEMORY_OP,
|
|
|
|
XEN_MEM_CLAIM_PAGES as c_ulong,
|
|
|
|
addr_of_mut!(reservation) as c_ulong,
|
2024-04-02 00:56:18 +00:00
|
|
|
)
|
|
|
|
.await?;
|
2024-01-20 21:06:28 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-06-20 19:42:45 -07:00
|
|
|
pub async fn add_to_physmap(&self, domid: u32, space: u32, idx: u64, pfn: u64) -> Result<()> {
|
|
|
|
trace!(
|
|
|
|
"memory fd={} add_to_physmap domid={} space={} idx={} pfn={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
space,
|
|
|
|
idx,
|
|
|
|
pfn,
|
|
|
|
);
|
|
|
|
let mut add = AddToPhysmap {
|
|
|
|
domid: domid as u16,
|
|
|
|
size: 0,
|
|
|
|
space,
|
|
|
|
idx,
|
|
|
|
gpfn: pfn,
|
|
|
|
};
|
|
|
|
self.hypercall2(
|
|
|
|
HYPERVISOR_MEMORY_OP,
|
|
|
|
XEN_MEM_ADD_TO_PHYSMAP as c_ulong,
|
|
|
|
addr_of_mut!(add) as c_ulong,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-02 00:56:18 +00:00
|
|
|
pub async fn mmuext(&self, domid: u32, cmd: c_uint, arg1: u64, arg2: u64) -> Result<()> {
|
2024-01-17 05:22:47 -08:00
|
|
|
let mut ops = MmuExtOp { cmd, arg1, arg2 };
|
|
|
|
|
|
|
|
self.hypercall4(
|
|
|
|
HYPERVISOR_MMUEXT_OP,
|
|
|
|
addr_of_mut!(ops) as c_ulong,
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
domid as c_ulong,
|
|
|
|
)
|
2024-04-02 00:56:18 +00:00
|
|
|
.await
|
2024-01-17 05:22:47 -08:00
|
|
|
.map(|_| ())
|
|
|
|
}
|
2024-04-29 10:02:20 -07:00
|
|
|
|
|
|
|
pub async fn iomem_permission(
|
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
first_mfn: u64,
|
|
|
|
nr_mfns: u64,
|
|
|
|
allow: bool,
|
|
|
|
) -> Result<()> {
|
|
|
|
trace!(
|
|
|
|
"domctl fd={} iomem_permission domid={} first_mfn={:#x}, nr_mfns={:#x} allow={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
first_mfn,
|
|
|
|
nr_mfns,
|
|
|
|
allow,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_IOMEM_PERMISSION,
|
|
|
|
interface_version: self.domctl_interface_version,
|
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
iomem_permission: IoMemPermission {
|
|
|
|
first_mfn,
|
|
|
|
nr_mfns,
|
|
|
|
allow: if allow { 1 } else { 0 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn ioport_permission(
|
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
first_port: u32,
|
|
|
|
nr_ports: u32,
|
|
|
|
allow: bool,
|
|
|
|
) -> Result<()> {
|
|
|
|
trace!(
|
|
|
|
"domctl fd={} ioport_permission domid={} first_port={:#x}, nr_ports={:#x} allow={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
first_port,
|
|
|
|
nr_ports,
|
|
|
|
allow,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_IOPORT_PERMISSION,
|
|
|
|
interface_version: self.domctl_interface_version,
|
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
ioport_permission: IoPortPermission {
|
|
|
|
first_port,
|
|
|
|
nr_ports,
|
|
|
|
allow: if allow { 1 } else { 0 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn irq_permission(&self, domid: u32, irq: u32, allow: bool) -> Result<()> {
|
|
|
|
trace!(
|
|
|
|
"domctl fd={} irq_permission domid={} irq={} allow={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
irq,
|
|
|
|
allow,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_IRQ_PERMISSION,
|
|
|
|
interface_version: self.domctl_interface_version,
|
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
irq_permission: IrqPermission {
|
|
|
|
pirq: irq,
|
|
|
|
allow: if allow { 1 } else { 0 },
|
|
|
|
pad: [0; 3],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-06-20 19:42:45 -07:00
|
|
|
#[allow(clippy::field_reassign_with_default)]
|
2024-04-29 10:02:20 -07:00
|
|
|
pub async fn map_pirq(&self, domid: u32, index: isize, pirq: Option<u32>) -> Result<u32> {
|
|
|
|
trace!(
|
|
|
|
"physdev fd={} map_pirq domid={} index={} pirq={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
index,
|
|
|
|
pirq,
|
|
|
|
);
|
2024-05-05 13:39:53 -07:00
|
|
|
let mut physdev = PhysdevMapPirq {
|
|
|
|
domid: domid as u16,
|
|
|
|
typ: 0x1,
|
|
|
|
index: index as c_int,
|
|
|
|
pirq: pirq.map(|x| x as c_int).unwrap_or(index as c_int),
|
|
|
|
..Default::default()
|
|
|
|
};
|
2024-04-29 10:02:20 -07:00
|
|
|
physdev.domid = domid as u16;
|
|
|
|
physdev.typ = 0x1;
|
|
|
|
physdev.index = index as c_int;
|
|
|
|
physdev.pirq = pirq.map(|x| x as c_int).unwrap_or(index as c_int);
|
|
|
|
self.hypercall2(
|
|
|
|
HYPERVISOR_PHYSDEV_OP,
|
|
|
|
PHYSDEVOP_MAP_PIRQ,
|
|
|
|
addr_of_mut!(physdev) as c_ulong,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
Ok(physdev.pirq as u32)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn assign_device(&self, domid: u32, sbdf: u32, flags: u32) -> Result<()> {
|
|
|
|
trace!(
|
|
|
|
"domctl fd={} assign_device domid={} sbdf={} flags={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
sbdf,
|
|
|
|
flags,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_ASSIGN_DEVICE,
|
|
|
|
interface_version: self.domctl_interface_version,
|
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
assign_device: AssignDevice {
|
|
|
|
device: DOMCTL_DEV_PCI,
|
|
|
|
flags,
|
|
|
|
pci_assign_device: PciAssignDevice { sbdf, padding: 0 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-06-20 19:42:45 -07:00
|
|
|
|
|
|
|
#[allow(clippy::field_reassign_with_default)]
|
|
|
|
pub async fn set_hvm_param(&self, domid: u32, index: u32, value: u64) -> Result<()> {
|
|
|
|
trace!(
|
|
|
|
"set_hvm_param fd={} domid={} index={} value={:?}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
index,
|
|
|
|
value,
|
|
|
|
);
|
|
|
|
let mut param = HvmParam::default();
|
|
|
|
param.domid = domid as u16;
|
|
|
|
param.index = index;
|
|
|
|
param.value = value;
|
|
|
|
self.hypercall2(HYPERVISOR_HVM_OP, 0, addr_of_mut!(param) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_hvm_context(&self, domid: u32, buffer: Option<&mut [u8]>) -> Result<u32> {
|
|
|
|
trace!(
|
|
|
|
"domctl fd={} get_hvm_context domid={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_GETHVMCONTEXT,
|
|
|
|
interface_version: self.domctl_interface_version,
|
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
hvm_context: HvmContext {
|
|
|
|
size: buffer.as_ref().map(|x| x.len()).unwrap_or(0) as u32,
|
|
|
|
buffer: buffer.map(|x| x.as_mut_ptr()).unwrap_or(null_mut()) as u64,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(unsafe { domctl.value.hvm_context.size })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn set_hvm_context(&self, domid: u32, buffer: &mut [u8]) -> Result<u32> {
|
|
|
|
trace!(
|
|
|
|
"domctl fd={} set_hvm_context domid={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_SETHVMCONTEXT,
|
|
|
|
interface_version: self.domctl_interface_version,
|
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
hvm_context: HvmContext {
|
|
|
|
size: buffer.len() as u32,
|
|
|
|
buffer: buffer.as_ptr() as u64,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(unsafe { domctl.value.hvm_context.size })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn set_paging_mempool_size(&self, domid: u32, size: u64) -> Result<()> {
|
|
|
|
trace!(
|
|
|
|
"domctl fd={} set_paging_mempool_size domid={} size={}",
|
|
|
|
self.handle.as_raw_fd(),
|
|
|
|
domid,
|
|
|
|
size,
|
|
|
|
);
|
|
|
|
let mut domctl = DomCtl {
|
|
|
|
cmd: XEN_DOMCTL_SET_PAGING_MEMPOOL_SIZE,
|
|
|
|
interface_version: self.domctl_interface_version,
|
|
|
|
domid,
|
|
|
|
value: DomCtlValue {
|
|
|
|
paging_mempool: PagingMempool { size },
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-06-28 15:13:57 -07:00
|
|
|
|
|
|
|
pub async fn cpu_topology(&self) -> Result<Vec<SysctlCputopo>> {
|
|
|
|
let mut sysctl = Sysctl {
|
|
|
|
cmd: XEN_SYSCTL_CPUTOPOINFO,
|
|
|
|
interface_version: self.sysctl_interface_version,
|
|
|
|
value: SysctlValue {
|
|
|
|
cputopoinfo: SysctlCputopoinfo {
|
|
|
|
num_cpus: 0,
|
2024-06-29 15:43:08 -07:00
|
|
|
handle: 0,
|
2024-06-28 15:13:57 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_SYSCTL, addr_of_mut!(sysctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
let cpus = unsafe { sysctl.value.cputopoinfo.num_cpus };
|
|
|
|
let mut topos = vec![
|
|
|
|
SysctlCputopo {
|
|
|
|
core: 0,
|
|
|
|
socket: 0,
|
|
|
|
node: 0
|
|
|
|
};
|
|
|
|
cpus as usize
|
|
|
|
];
|
|
|
|
let mut sysctl = Sysctl {
|
|
|
|
cmd: XEN_SYSCTL_CPUTOPOINFO,
|
|
|
|
interface_version: self.sysctl_interface_version,
|
|
|
|
value: SysctlValue {
|
|
|
|
cputopoinfo: SysctlCputopoinfo {
|
|
|
|
num_cpus: cpus,
|
2024-06-29 15:43:08 -07:00
|
|
|
handle: topos.as_mut_ptr() as c_ulong,
|
2024-06-28 15:13:57 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_SYSCTL, addr_of_mut!(sysctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(topos)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn phys_info(&self) -> Result<SysctlPhysinfo> {
|
|
|
|
let mut sysctl = Sysctl {
|
|
|
|
cmd: XEN_SYSCTL_PHYSINFO,
|
|
|
|
interface_version: self.sysctl_interface_version,
|
|
|
|
value: SysctlValue {
|
|
|
|
phys_info: SysctlPhysinfo::default(),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_SYSCTL, addr_of_mut!(sysctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(unsafe { sysctl.value.phys_info })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn set_cpufreq_gov(&self, cpuid: CpuId, gov: impl AsRef<str>) -> Result<()> {
|
|
|
|
match cpuid {
|
|
|
|
CpuId::All => {
|
|
|
|
let phys_info = self.phys_info().await?;
|
|
|
|
for cpuid in 0..phys_info.max_cpu_id + 1 {
|
|
|
|
self.do_set_cpufreq_gov(cpuid, gov.as_ref()).await?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CpuId::Single(id) => {
|
|
|
|
self.do_set_cpufreq_gov(id, gov).await?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn do_set_cpufreq_gov(&self, cpuid: u32, gov: impl AsRef<str>) -> Result<()> {
|
|
|
|
let governor = gov.as_ref().as_bytes().to_vec();
|
|
|
|
if governor.len() > 15 {
|
|
|
|
return Err(Error::ValueTooLong);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut scaling_governor = [0u8; 16];
|
|
|
|
|
|
|
|
// leave space for the last byte to be zero at all times.
|
|
|
|
for i in 0..15usize {
|
|
|
|
if i >= governor.len() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
scaling_governor[i] = governor[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut sysctl = Sysctl {
|
|
|
|
cmd: XEN_SYSCTL_PM_OP,
|
|
|
|
interface_version: self.sysctl_interface_version,
|
|
|
|
value: SysctlValue {
|
|
|
|
pm_op: SysctlPmOp {
|
|
|
|
cmd: XEN_SYSCTL_PM_OP_ENABLE_TURBO,
|
|
|
|
cpuid,
|
|
|
|
value: SysctlPmOpValue {
|
|
|
|
set_gov: SysctlSetCpuFreqGov { scaling_governor },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_SYSCTL, addr_of_mut!(sysctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn set_turbo_mode(&self, cpuid: CpuId, enable: bool) -> Result<()> {
|
|
|
|
match cpuid {
|
|
|
|
CpuId::All => {
|
|
|
|
let phys_info = self.phys_info().await?;
|
|
|
|
for cpuid in 0..phys_info.max_cpu_id + 1 {
|
|
|
|
self.do_set_turbo_mode(cpuid, enable).await?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CpuId::Single(id) => {
|
|
|
|
self.do_set_turbo_mode(id, enable).await?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn do_set_turbo_mode(&self, cpuid: u32, enable: bool) -> Result<()> {
|
|
|
|
let mut sysctl = Sysctl {
|
|
|
|
cmd: XEN_SYSCTL_PM_OP,
|
|
|
|
interface_version: self.sysctl_interface_version,
|
|
|
|
value: SysctlValue {
|
|
|
|
pm_op: SysctlPmOp {
|
|
|
|
cmd: if enable {
|
|
|
|
XEN_SYSCTL_PM_OP_ENABLE_TURBO
|
|
|
|
} else {
|
|
|
|
XEN_SYSCTL_PM_OP_DISABLE_TURBO
|
|
|
|
},
|
|
|
|
cpuid,
|
|
|
|
value: SysctlPmOpValue { pad: [0u8; 128] },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.hypercall1(HYPERVISOR_SYSCTL, addr_of_mut!(sysctl) as c_ulong)
|
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-01-08 20:45:16 -08:00
|
|
|
}
|