oh my god, we have a console

This commit is contained in:
Alex Zenla 2024-01-17 05:22:47 -08:00
parent 6ca61410ad
commit 15ba27e573
No known key found for this signature in database
GPG Key ID: 067B238899B51269
14 changed files with 643 additions and 559 deletions

View File

@ -1,4 +1,3 @@
use xencall::domctl::DomainControl;
use xencall::sys::CreateDomain;
use xencall::{XenCall, XenCallError};
@ -6,8 +5,7 @@ fn main() -> Result<(), XenCallError> {
env_logger::init();
let call = XenCall::open()?;
let domctl: DomainControl = DomainControl::new(&call);
let domid = domctl.create_domain(CreateDomain::default())?;
let domid = call.create_domain(CreateDomain::default())?;
println!("created domain {}", domid);
Ok(())
}

View File

@ -1,12 +1,10 @@
use xencall::domctl::DomainControl;
use xencall::{XenCall, XenCallError};
fn main() -> Result<(), XenCallError> {
env_logger::init();
let call = XenCall::open()?;
let domctl: DomainControl = DomainControl::new(&call);
let info = domctl.get_domain_info(1)?;
let info = call.get_domain_info(1)?;
println!("{:?}", info);
Ok(())
}

View File

@ -1,12 +1,10 @@
use xencall::domctl::DomainControl;
use xencall::{XenCall, XenCallError};
fn main() -> Result<(), XenCallError> {
env_logger::init();
let call = XenCall::open()?;
let domctl: DomainControl = DomainControl::new(&call);
let context = domctl.get_vcpu_context(224, 0)?;
let context = call.get_vcpu_context(224, 0)?;
println!("{:?}", context);
Ok(())
}

View File

@ -1,301 +0,0 @@
use crate::sys::{
AddressSize, ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
GetDomainInfo, GetPageFrameInfo3, HypercallInit, MaxMem, MaxVcpus, VcpuGuestContext,
VcpuGuestContextAny, HYPERVISOR_DOMCTL, XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN,
XEN_DOMCTL_GETDOMAININFO, XEN_DOMCTL_GETPAGEFRAMEINFO3, XEN_DOMCTL_GETVCPUCONTEXT,
XEN_DOMCTL_HYPERCALL_INIT, XEN_DOMCTL_INTERFACE_VERSION, XEN_DOMCTL_MAX_MEM,
XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_PAUSEDOMAIN, XEN_DOMCTL_SETVCPUCONTEXT,
XEN_DOMCTL_SET_ADDRESS_SIZE, XEN_DOMCTL_UNPAUSEDOMAIN,
};
use crate::{XenCall, XenCallError};
use log::trace;
use std::ffi::c_ulong;
use std::os::fd::AsRawFd;
use std::ptr::addr_of_mut;
use std::slice;
pub struct DomainControl<'a> {
pub call: &'a XenCall,
}
impl DomainControl<'_> {
pub fn new(call: &XenCall) -> DomainControl {
DomainControl { call }
}
pub fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo, XenCallError> {
trace!(
"domctl fd={} get_domain_info domid={}",
self.call.handle.as_raw_fd(),
domid
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETDOMAININFO,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
get_domain_info: GetDomainInfo {
domid: 0,
pad1: 0,
flags: 0,
total_pages: 0,
max_pages: 0,
outstanding_pages: 0,
shr_pages: 0,
paged_pages: 0,
shared_info_frame: 0,
cpu_time: 0,
number_online_vcpus: 0,
max_vcpu_id: 0,
ssidref: 0,
handle: [0; 16],
cpupool: 0,
gpaddr_bits: 0,
pad2: [0; 7],
arch: ArchDomainConfig {
emulation_flags: 0,
misc_flags: 0,
},
},
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(unsafe { domctl.value.get_domain_info })
}
pub fn create_domain(&self, create_domain: CreateDomain) -> Result<u32, XenCallError> {
trace!(
"domctl fd={} create_domain create_domain={:?}",
self.call.handle.as_raw_fd(),
create_domain
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_CREATEDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid: 0,
value: DomCtlValue { create_domain },
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(domctl.domid)
}
pub fn pause_domain(&self, domid: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} pause_domain domid={:?}",
self.call.handle.as_raw_fd(),
domid,
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_PAUSEDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn unpause_domain(&self, domid: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} unpause_domain domid={:?}",
self.call.handle.as_raw_fd(),
domid,
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_UNPAUSEDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<(), XenCallError> {
trace!(
"domctl fd={} set_max_mem domid={} memkb={}",
self.call.handle.as_raw_fd(),
domid,
memkb
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_MAX_MEM,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
max_mem: MaxMem { max_memkb: memkb },
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn set_max_vcpus(&self, domid: u32, max_vcpus: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} set_max_vcpus domid={} max_vcpus={}",
self.call.handle.as_raw_fd(),
domid,
max_vcpus
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_MAX_VCPUS,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
max_cpus: MaxVcpus { max_vcpus },
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn set_address_size(&self, domid: u32, size: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} set_address_size domid={} size={}",
self.call.handle.as_raw_fd(),
domid,
size,
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_SET_ADDRESS_SIZE,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
address_size: AddressSize { size },
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn get_vcpu_context(
&self,
domid: u32,
vcpu: u32,
) -> Result<VcpuGuestContext, XenCallError> {
trace!(
"domctl fd={} get_vcpu_context domid={}",
self.call.handle.as_raw_fd(),
domid,
);
let mut wrapper = VcpuGuestContextAny {
value: VcpuGuestContext::default(),
};
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETVCPUCONTEXT,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
vcpu_context: DomCtlVcpuContext {
vcpu,
ctx: addr_of_mut!(wrapper) as c_ulong,
},
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(unsafe { wrapper.value })
}
pub fn set_vcpu_context(
&self,
domid: u32,
vcpu: u32,
context: &VcpuGuestContext,
) -> Result<(), XenCallError> {
trace!(
"domctl fd={} set_vcpu_context domid={} context={:?}",
self.call.handle.as_raw_fd(),
domid,
context,
);
let mut value = VcpuGuestContextAny { value: *context };
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_SETVCPUCONTEXT,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
vcpu_context: DomCtlVcpuContext {
vcpu,
ctx: addr_of_mut!(value) as c_ulong,
},
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn get_page_frame_info(
&self,
domid: u32,
frames: &[u64],
) -> Result<Vec<u64>, XenCallError> {
let mut buffer: Vec<u64> = frames.to_vec();
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETPAGEFRAMEINFO3,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
get_page_frame_info: GetPageFrameInfo3 {
num: buffer.len() as u64,
array: buffer.as_mut_ptr() as c_ulong,
},
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
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())
}
pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> {
trace!(
"domctl fd={} hypercall_init domid={} gmfn={}",
self.call.handle.as_raw_fd(),
domid,
gmfn
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_HYPERCALL_INIT,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
hypercall_init: HypercallInit { gmfn },
},
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn destroy_domain(&self, domid: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} destroy_domain domid={}",
self.call.handle.as_raw_fd(),
domid
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_DESTROYDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
}

View File

@ -1,20 +1,28 @@
pub mod domctl;
pub mod memory;
pub mod sys;
use crate::sys::{
EvtChnAllocUnbound, Hypercall, MmapBatch, MmapResource, MultiCallEntry, XenCapabilitiesInfo,
HYPERVISOR_EVENT_CHANNEL_OP, HYPERVISOR_MULTICALL, HYPERVISOR_XEN_VERSION, XENVER_CAPABILITIES,
AddressSize, ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
EvtChnAllocUnbound, GetDomainInfo, GetPageFrameInfo3, Hypercall, HypercallInit, MaxMem,
MaxVcpus, MemoryMap, MemoryReservation, MmapBatch, MmapResource, MmuExtOp, MultiCallEntry,
VcpuGuestContext, VcpuGuestContextAny, XenCapabilitiesInfo, HYPERVISOR_DOMCTL,
HYPERVISOR_EVENT_CHANNEL_OP, HYPERVISOR_MEMORY_OP, HYPERVISOR_MMUEXT_OP, HYPERVISOR_MULTICALL,
HYPERVISOR_XEN_VERSION, XENVER_CAPABILITIES, XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN,
XEN_DOMCTL_GETDOMAININFO, XEN_DOMCTL_GETPAGEFRAMEINFO3, XEN_DOMCTL_GETVCPUCONTEXT,
XEN_DOMCTL_HYPERCALL_INIT, XEN_DOMCTL_INTERFACE_VERSION, XEN_DOMCTL_MAX_MEM,
XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_PAUSEDOMAIN, XEN_DOMCTL_SETVCPUCONTEXT,
XEN_DOMCTL_SET_ADDRESS_SIZE, XEN_DOMCTL_UNPAUSEDOMAIN, XEN_MEM_MEMORY_MAP,
XEN_MEM_POPULATE_PHYSMAP,
};
use libc::{c_int, mmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
use log::trace;
use nix::errno::Errno;
use std::error::Error;
use std::ffi::{c_long, c_ulong, c_void};
use std::ffi::{c_long, c_uint, c_ulong, c_void};
use std::fmt::{Display, Formatter};
use std::fs::{File, OpenOptions};
use std::os::fd::AsRawFd;
use std::ptr::addr_of_mut;
use std::slice;
pub struct XenCall {
pub handle: File,
@ -251,4 +259,353 @@ impl XenCall {
self.evtchn_op(6, addr_of_mut!(alloc_unbound) as c_ulong)?;
Ok(alloc_unbound.port)
}
pub fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo, XenCallError> {
trace!(
"domctl fd={} get_domain_info domid={}",
self.handle.as_raw_fd(),
domid
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETDOMAININFO,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
get_domain_info: GetDomainInfo {
domid: 0,
pad1: 0,
flags: 0,
total_pages: 0,
max_pages: 0,
outstanding_pages: 0,
shr_pages: 0,
paged_pages: 0,
shared_info_frame: 0,
cpu_time: 0,
number_online_vcpus: 0,
max_vcpu_id: 0,
ssidref: 0,
handle: [0; 16],
cpupool: 0,
gpaddr_bits: 0,
pad2: [0; 7],
arch: ArchDomainConfig {
emulation_flags: 0,
misc_flags: 0,
},
},
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(unsafe { domctl.value.get_domain_info })
}
pub fn create_domain(&self, create_domain: CreateDomain) -> Result<u32, XenCallError> {
trace!(
"domctl fd={} create_domain create_domain={:?}",
self.handle.as_raw_fd(),
create_domain
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_CREATEDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid: 0,
value: DomCtlValue { create_domain },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(domctl.domid)
}
pub fn pause_domain(&self, domid: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} pause_domain domid={:?}",
self.handle.as_raw_fd(),
domid,
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_PAUSEDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn unpause_domain(&self, domid: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} unpause_domain domid={:?}",
self.handle.as_raw_fd(),
domid,
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_UNPAUSEDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<(), XenCallError> {
trace!(
"domctl fd={} set_max_mem domid={} memkb={}",
self.handle.as_raw_fd(),
domid,
memkb
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_MAX_MEM,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
max_mem: MaxMem { max_memkb: memkb },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn set_max_vcpus(&self, domid: u32, max_vcpus: u32) -> Result<(), XenCallError> {
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,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
max_cpus: MaxVcpus { max_vcpus },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn set_address_size(&self, domid: u32, size: u32) -> Result<(), XenCallError> {
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,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
address_size: AddressSize { size },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn get_vcpu_context(
&self,
domid: u32,
vcpu: u32,
) -> Result<VcpuGuestContext, XenCallError> {
trace!(
"domctl fd={} get_vcpu_context domid={}",
self.handle.as_raw_fd(),
domid,
);
let mut wrapper = VcpuGuestContextAny {
value: VcpuGuestContext::default(),
};
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETVCPUCONTEXT,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
vcpu_context: DomCtlVcpuContext {
vcpu,
ctx: addr_of_mut!(wrapper) as c_ulong,
},
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(unsafe { wrapper.value })
}
pub fn set_vcpu_context(
&self,
domid: u32,
vcpu: u32,
context: &VcpuGuestContext,
) -> Result<(), XenCallError> {
trace!(
"domctl fd={} set_vcpu_context domid={} context={:?}",
self.handle.as_raw_fd(),
domid,
context,
);
let mut value = VcpuGuestContextAny { value: *context };
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_SETVCPUCONTEXT,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
vcpu_context: DomCtlVcpuContext {
vcpu,
ctx: addr_of_mut!(value) as c_ulong,
},
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn get_page_frame_info(
&self,
domid: u32,
frames: &[u64],
) -> Result<Vec<u64>, XenCallError> {
let mut buffer: Vec<u64> = frames.to_vec();
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETPAGEFRAMEINFO3,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
get_page_frame_info: GetPageFrameInfo3 {
num: buffer.len() as u64,
array: buffer.as_mut_ptr() as c_ulong,
},
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
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())
}
pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> {
trace!(
"domctl fd={} hypercall_init domid={} gmfn={}",
self.handle.as_raw_fd(),
domid,
gmfn
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_HYPERCALL_INIT,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue {
hypercall_init: HypercallInit { gmfn },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn destroy_domain(&self, domid: u32) -> Result<(), XenCallError> {
trace!(
"domctl fd={} destroy_domain domid={}",
self.handle.as_raw_fd(),
domid
);
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_DESTROYDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(())
}
pub fn get_memory_map(&self, size_of_entry: usize) -> Result<Vec<u8>, XenCallError> {
let mut memory_map = MemoryMap {
count: 0,
buffer: 0,
};
self.hypercall2(
HYPERVISOR_MEMORY_OP,
XEN_MEM_MEMORY_MAP as c_ulong,
addr_of_mut!(memory_map) as c_ulong,
)?;
let mut buffer = vec![0u8; memory_map.count as usize * size_of_entry];
memory_map.buffer = buffer.as_mut_ptr() as c_ulong;
self.hypercall2(
HYPERVISOR_MEMORY_OP,
XEN_MEM_MEMORY_MAP as c_ulong,
addr_of_mut!(memory_map) as c_ulong,
)?;
Ok(buffer)
}
pub fn populate_physmap(
&self,
domid: u32,
nr_extents: u64,
extent_order: u32,
mem_flags: u32,
extent_starts: &[u64],
) -> Result<Vec<u64>, XenCallError> {
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,
};
let calls = &mut [MultiCallEntry {
op: HYPERVISOR_MEMORY_OP,
result: 0,
args: [
XEN_MEM_POPULATE_PHYSMAP as c_ulong,
addr_of_mut!(reservation) as c_ulong,
0,
0,
0,
0,
],
}];
self.multicall(calls)?;
let code = calls[0].result;
if code > !0xfff {
return Err(XenCallError::new(
format!("failed to populate physmap: {:#x}", code).as_str(),
));
}
if code as usize > extent_starts.len() {
return Err(XenCallError::new("failed to populate physmap"));
}
let extents = extent_starts[0..code as usize].to_vec();
Ok(extents)
}
pub fn mmuext(
&self,
domid: u32,
cmd: c_uint,
arg1: u64,
arg2: u64,
) -> Result<(), XenCallError> {
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,
)
.map(|_| ())
}
}

View File

@ -1,106 +0,0 @@
use crate::sys::{
MemoryMap, MemoryReservation, MmuExtOp, MultiCallEntry, HYPERVISOR_MEMORY_OP,
HYPERVISOR_MMUEXT_OP, XEN_MEM_MEMORY_MAP, XEN_MEM_POPULATE_PHYSMAP,
};
use crate::{XenCall, XenCallError};
use log::trace;
use std::ffi::{c_uint, c_ulong};
use std::os::fd::AsRawFd;
use std::ptr::addr_of_mut;
pub struct MemoryControl<'a> {
call: &'a XenCall,
}
impl MemoryControl<'_> {
pub fn new(call: &XenCall) -> MemoryControl {
MemoryControl { call }
}
pub fn get_memory_map(&self, size_of_entry: usize) -> Result<Vec<u8>, XenCallError> {
let mut memory_map = MemoryMap {
count: 0,
buffer: 0,
};
self.call.hypercall2(
HYPERVISOR_MEMORY_OP,
XEN_MEM_MEMORY_MAP as c_ulong,
addr_of_mut!(memory_map) as c_ulong,
)?;
let mut buffer = vec![0u8; memory_map.count as usize * size_of_entry];
memory_map.buffer = buffer.as_mut_ptr() as c_ulong;
self.call.hypercall2(
HYPERVISOR_MEMORY_OP,
XEN_MEM_MEMORY_MAP as c_ulong,
addr_of_mut!(memory_map) as c_ulong,
)?;
Ok(buffer)
}
pub fn populate_physmap(
&self,
domid: u32,
nr_extents: u64,
extent_order: u32,
mem_flags: u32,
extent_starts: &[u64],
) -> Result<Vec<u64>, XenCallError> {
trace!("memory fd={} populate_physmap domid={} nr_extents={} extent_order={} mem_flags={} extent_starts={:?}", self.call.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,
};
let calls = &mut [MultiCallEntry {
op: HYPERVISOR_MEMORY_OP,
result: 0,
args: [
XEN_MEM_POPULATE_PHYSMAP as c_ulong,
addr_of_mut!(reservation) as c_ulong,
0,
0,
0,
0,
],
}];
self.call.multicall(calls)?;
let code = calls[0].result;
if code > !0xfff {
return Err(XenCallError::new(
format!("failed to populate physmap: {:#x}", code).as_str(),
));
}
if code as usize > extent_starts.len() {
return Err(XenCallError::new("failed to populate physmap"));
}
let extents = extent_starts[0..code as usize].to_vec();
Ok(extents)
}
pub fn mmuext(
&self,
domid: u32,
cmd: c_uint,
arg1: u64,
arg2: u64,
) -> Result<(), XenCallError> {
let mut ops = MmuExtOp { cmd, arg1, arg2 };
self.call
.hypercall4(
HYPERVISOR_MMUEXT_OP,
addr_of_mut!(ops) as c_ulong,
1,
0,
domid as c_ulong,
)
.map(|_| ())
}
}

View File

@ -32,10 +32,6 @@ env_logger = "0.10.1"
[lib]
path = "src/lib.rs"
[[example]]
name = "xenclient-simple"
path = "examples/simple.rs"
[[example]]
name = "xenclient-boot"
path = "examples/boot.rs"

View File

@ -1,13 +1,6 @@
use std::fs::read;
use std::{env, process};
use xencall::domctl::DomainControl;
use xencall::memory::MemoryControl;
use xencall::sys::CreateDomain;
use xencall::XenCall;
use xenclient::boot::BootSetup;
use xenclient::elfloader::ElfImageLoader;
use xenclient::XenClientError;
use xenevtchn::EventChannel;
use xenclient::create::DomainConfig;
use xenclient::{XenClient, XenClientError};
fn main() -> Result<(), XenClientError> {
env_logger::init();
@ -19,40 +12,15 @@ fn main() -> Result<(), XenClientError> {
}
let kernel_image_path = args.get(1).expect("argument not specified");
let initrd_path = args.get(2).expect("argument not specified");
let call = XenCall::open()?;
let domctl = DomainControl::new(&call);
let domain = CreateDomain {
let mut client = XenClient::open()?;
let config = DomainConfig {
max_vcpus: 1,
..Default::default()
mem_mb: 512,
kernel_path: kernel_image_path.to_string(),
initrd_path: initrd_path.to_string(),
cmdline: "debug elevator=noop".to_string(),
};
let domid = domctl.create_domain(domain)?;
boot(
domid,
kernel_image_path.as_str(),
initrd_path.as_str(),
&call,
&domctl,
)?;
Ok(())
}
fn boot(
domid: u32,
kernel_image_path: &str,
initrd_path: &str,
call: &XenCall,
domctl: &DomainControl,
) -> Result<(), XenClientError> {
println!("domain created: {:?}", domid);
let image_loader = ElfImageLoader::load_file_kernel(kernel_image_path)?;
let memctl = MemoryControl::new(call);
let mut boot = BootSetup::new(call, domctl, &memctl, domid);
let initrd = read(initrd_path)?;
let mut state = boot.initialize(&image_loader, initrd.as_slice(), 1, 512)?;
boot.boot(&mut state, "debug elevator=noop")?;
domctl.unpause_domain(domid)?;
let _evtchn = EventChannel::open()?;
let domid = client.create(config)?;
println!("created domain {}", domid);
Ok(())
}

View File

@ -1,18 +0,0 @@
use xenclient::create::{DomainConfig, PvDomainConfig};
use xenclient::{XenClient, XenClientError};
fn main() -> Result<(), XenClientError> {
env_logger::init();
let mut client = XenClient::open()?;
let mut config = DomainConfig::new();
config.configure_cpus(1);
config.configure_memory(524288, 524288, 0);
config.configure_pv(PvDomainConfig::new(
"/boot/vmlinuz-6.1.0-17-amd64".to_string(),
None,
None,
));
client.create(config)?;
Ok(())
}

View File

@ -16,8 +16,6 @@ use std::cmp::{max, min};
use std::ffi::c_void;
use std::mem::size_of;
use std::slice;
use xencall::domctl::DomainControl;
use xencall::memory::MemoryControl;
use xencall::sys::{VcpuGuestContext, MMUEXT_PIN_L4_TABLE};
use xencall::XenCall;
@ -41,9 +39,8 @@ pub struct BootImageInfo {
}
pub struct BootSetup<'a> {
domctl: &'a DomainControl<'a>,
memctl: &'a MemoryControl<'a>,
phys: PhysicalPages<'a>,
call: &'a XenCall,
pub phys: PhysicalPages<'a>,
domid: u32,
virt_alloc_end: u64,
pfn_alloc_end: u64,
@ -55,7 +52,7 @@ pub struct BootSetup<'a> {
pub struct DomainSegment {
vstart: u64,
_vend: u64,
pfn: u64,
pub pfn: u64,
addr: u64,
size: u64,
pages: u64,
@ -87,15 +84,9 @@ pub struct BootState {
}
impl BootSetup<'_> {
pub fn new<'a>(
call: &'a XenCall,
domctl: &'a DomainControl<'a>,
memctl: &'a MemoryControl<'a>,
domid: u32,
) -> BootSetup<'a> {
pub fn new(call: &XenCall, domid: u32) -> BootSetup {
BootSetup {
domctl,
memctl,
call,
phys: PhysicalPages::new(call, domid),
domid,
virt_alloc_end: 0,
@ -106,7 +97,7 @@ impl BootSetup<'_> {
}
fn initialize_memory(&mut self, total_pages: u64) -> Result<(), XenClientError> {
self.domctl.set_address_size(self.domid, 64)?;
self.call.set_address_size(self.domid, 64)?;
let mut vmemranges: Vec<VmemRange> = Vec::new();
let stub = VmemRange {
@ -162,7 +153,7 @@ impl BootSetup<'_> {
}
let extents_init_slice = extents_init.as_slice();
let extents = self.memctl.populate_physmap(
let extents = self.call.populate_physmap(
self.domid,
count,
SUPERPAGE_2MB_SHIFT as u32,
@ -191,7 +182,7 @@ impl BootSetup<'_> {
let p2m_end_idx = p2m_idx + allocsz as usize;
let input_extent_starts = &p2m[p2m_idx..p2m_end_idx];
let result =
self.memctl
self.call
.populate_physmap(self.domid, allocsz, 0, 0, input_extent_starts)?;
if result.len() != allocsz as usize {
@ -226,7 +217,7 @@ impl BootSetup<'_> {
let pfn = (image_info.virt_hypercall - image_info.virt_base) >> X86_PAGE_SHIFT;
let mfn = self.phys.p2m[pfn as usize];
self.domctl.hypercall_init(self.domid, mfn)?;
self.call.hypercall_init(self.domid, mfn)?;
Ok(())
}
@ -241,8 +232,6 @@ impl BootSetup<'_> {
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
max_vcpus, mem_mb
);
self.domctl.set_max_vcpus(self.domid, max_vcpus)?;
self.domctl.set_max_mem(self.domid, mem_mb * 1024)?;
let total_pages = mem_mb << (20 - X86_PAGE_SHIFT);
self.initialize_memory(total_pages)?;
@ -284,8 +273,8 @@ impl BootSetup<'_> {
}
let initrd_segment = initrd_segment.unwrap();
let store_evtchn = self.domctl.call.evtchn_alloc_unbound(self.domid, 0)?;
let console_evtchn = self.domctl.call.evtchn_alloc_unbound(self.domid, 0)?;
let store_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0)?;
let console_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0)?;
let state = BootState {
kernel_segment,
start_info_segment,
@ -306,7 +295,7 @@ impl BootSetup<'_> {
}
pub fn boot(&mut self, state: &mut BootState, cmdline: &str) -> Result<(), XenClientError> {
let domain_info = self.domctl.get_domain_info(self.domid)?;
let domain_info = self.call.get_domain_info(self.domid)?;
let shared_info_frame = domain_info.shared_info_frame;
state.shared_info_frame = shared_info_frame;
self.setup_page_tables(state)?;
@ -317,7 +306,7 @@ impl BootSetup<'_> {
self.phys.unmap(pg_pfn)?;
self.phys.unmap(state.p2m_segment.pfn)?;
let pg_mfn = self.phys.p2m[pg_pfn as usize];
self.memctl
self.call
.mmuext(self.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)?;
self.setup_shared_info(state.shared_info_frame)?;
@ -346,7 +335,7 @@ impl BootSetup<'_> {
vcpu.kernel_ss = vcpu.user_regs.ss as u64;
vcpu.kernel_sp = vcpu.user_regs.rsp;
debug!("vcpu context: {:?}", vcpu);
self.domctl.set_vcpu_context(self.domid, 0, &vcpu)?;
self.call.set_vcpu_context(self.domid, 0, &vcpu)?;
self.phys.unmap_all()?;
self.gnttab_seed(state)?;
Ok(())
@ -356,13 +345,10 @@ impl BootSetup<'_> {
let console_gfn = self.phys.p2m[state.console_segment.pfn as usize];
let xenstore_gfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
let addr = self
.domctl
.call
.mmap(0, 1 << XEN_PAGE_SHIFT)
.ok_or(XenClientError::new("failed to mmap for resource"))?;
self.domctl
.call
.map_resource(self.domid, 1, 0, 0, 1, addr)?;
self.call.map_resource(self.domid, 1, 0, 0, 1, addr)?;
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
entries[0].flags = 1 << 0;
entries[0].domid = 0;

View File

@ -1,19 +1,27 @@
use std::collections::HashMap;
pub struct DomainConfig {
vm_entries: HashMap<String, String>,
domain_entries: HashMap<String, String>,
pub max_vcpus: u32,
pub mem_mb: u64,
pub kernel_path: String,
pub initrd_path: String,
pub cmdline: String,
}
pub struct PvDomainConfig {
pub struct PvDomainStore {
kernel: String,
ramdisk: Option<String>,
cmdline: Option<String>,
}
impl DomainConfig {
pub fn new() -> DomainConfig {
DomainConfig {
pub struct DomainStore {
vm_entries: HashMap<String, String>,
domain_entries: HashMap<String, String>,
}
impl DomainStore {
pub fn new() -> DomainStore {
DomainStore {
vm_entries: HashMap::new(),
domain_entries: HashMap::new(),
}
@ -43,7 +51,7 @@ impl DomainConfig {
pub fn configure_cpus(&mut self, _maxvcpus: u32) {}
pub fn configure_pv(&mut self, pv: PvDomainConfig) {
pub fn configure_pv(&mut self, pv: PvDomainStore) {
self.put_vm_str("image/ostype", "linux");
self.put_vm("image/kernel", pv.kernel);
@ -67,15 +75,15 @@ impl DomainConfig {
}
}
impl Default for DomainConfig {
impl Default for DomainStore {
fn default() -> Self {
DomainConfig::new()
DomainStore::new()
}
}
impl PvDomainConfig {
pub fn new(kernel: String, ramdisk: Option<String>, cmdline: Option<String>) -> PvDomainConfig {
PvDomainConfig {
impl PvDomainStore {
pub fn new(kernel: String, ramdisk: Option<String>, cmdline: Option<String>) -> PvDomainStore {
PvDomainStore {
kernel,
ramdisk,
cmdline,

View File

@ -5,16 +5,19 @@ pub mod mem;
pub mod sys;
mod x86;
use crate::boot::BootSetup;
use crate::create::DomainConfig;
use crate::elfloader::ElfImageLoader;
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fs::read;
use std::string::FromUtf8Error;
use xencall::domctl::DomainControl;
use uuid::Uuid;
use xencall::sys::CreateDomain;
use xencall::{XenCall, XenCallError};
use xenevtchn::EventChannelError;
use xenstore::bus::XsdBusError;
use xenstore::client::{XsdClient, XsdInterface};
use xenstore::client::{XsPermissions, XsdClient, XsdInterface};
pub struct XenClient {
store: XsdClient,
@ -83,29 +86,208 @@ impl XenClient {
Ok(XenClient { store, call })
}
pub fn create(&mut self, config: DomainConfig) -> Result<(), XenClientError> {
let domctl = DomainControl::new(&self.call);
let domid = domctl.create_domain(CreateDomain::default())?;
let domain = self.store.get_domain_path(domid)?;
let vm = self.store.read_string(format!("{}/vm", domain).as_str())?;
pub fn create(&mut self, config: DomainConfig) -> Result<u32, XenClientError> {
let domain = CreateDomain {
max_vcpus: config.max_vcpus,
..Default::default()
};
let domid = self.call.create_domain(domain)?;
let dom_path = self.store.get_domain_path(domid)?;
let uuid_string = Uuid::from_bytes(domain.handle).to_string();
let vm_path = format!("/vm/{}", uuid_string);
let libxl_path = format!("/libxl/{}", domid);
let ro_perm = XsPermissions { id: 0, perms: 0 };
let rw_perm = XsPermissions { id: 0, perms: 0 };
let no_perm = XsPermissions { id: 0, perms: 0 };
{
let mut tx = self.store.transaction()?;
tx.rm(dom_path.as_str())?;
tx.mknod(dom_path.as_str(), &ro_perm)?;
tx.rm(vm_path.as_str())?;
tx.mknod(vm_path.as_str(), &ro_perm)?;
tx.rm(libxl_path.as_str())?;
tx.mknod(vm_path.as_str(), &no_perm)?;
tx.mknod(format!("{}/device", vm_path).as_str(), &no_perm)?;
tx.write_string(format!("{}/vm", dom_path).as_str(), &vm_path)?;
tx.mknod(format!("{}/cpu", dom_path).as_str(), &ro_perm)?;
tx.mknod(format!("{}/memory", dom_path).as_str(), &ro_perm)?;
tx.mknod(format!("{}/control", dom_path).as_str(), &ro_perm)?;
tx.mknod(format!("{}/control/shutdown", dom_path).as_str(), &rw_perm)?;
tx.mknod(
format!("{}/control/feature-poweroff", dom_path).as_str(),
&rw_perm,
)?;
tx.mknod(
format!("{}/control/feature-reboot", dom_path).as_str(),
&rw_perm,
)?;
tx.mknod(
format!("{}/control/feature-suspend", dom_path).as_str(),
&rw_perm,
)?;
tx.mknod(format!("{}/control/sysrq", dom_path).as_str(), &rw_perm)?;
tx.mknod(format!("{}/data", dom_path).as_str(), &rw_perm)?;
tx.mknod(format!("{}/drivers", dom_path).as_str(), &rw_perm)?;
tx.mknod(format!("{}/feature", dom_path).as_str(), &rw_perm)?;
tx.mknod(format!("{}/attr", dom_path).as_str(), &rw_perm)?;
tx.mknod(format!("{}/error", dom_path).as_str(), &rw_perm)?;
tx.write_string(
format!("{}/uuid", vm_path).as_str(),
&Uuid::from_bytes(domain.handle).to_string(),
)?;
tx.write_string(
format!("{}/name", vm_path).as_str(),
"mycelium",
)?;
tx.write_string(format!("{}/type", libxl_path).as_str(), "pv")?;
tx.commit()?;
}
self.call.set_max_vcpus(domid, config.max_vcpus)?;
self.call.set_max_mem(domid, config.mem_mb * 1024)?;
let image_loader = ElfImageLoader::load_file_kernel(config.kernel_path.as_str())?;
let console_evtchn: u32;
let xenstore_evtchn: u32;
let console_mfn: u64;
let xenstore_mfn: u64;
{
let mut boot = BootSetup::new(&self.call, domid);
let initrd = read(config.initrd_path.as_str())?;
let mut state = boot.initialize(
&image_loader,
initrd.as_slice(),
config.max_vcpus,
config.mem_mb,
)?;
boot.boot(&mut state, config.cmdline.as_str())?;
console_evtchn = state.console_evtchn;
xenstore_evtchn = state.store_evtchn;
console_mfn = boot.phys.p2m[state.console_segment.pfn as usize];
xenstore_mfn = boot.phys.p2m[state.xenstore_segment.pfn as usize];
}
{
let mut tx = self.store.transaction()?;
tx.write_string(
format!("{}/image/os_type", vm_path).as_str(),
"linux",
)?;
tx.write_string(
format!("{}/image/kernel", vm_path).as_str(),
&config.kernel_path,
)?;
tx.write_string(
format!("{}/image/ramdisk", vm_path).as_str(),
&config.initrd_path,
)?;
tx.write_string(
format!("{}/image/cmdline", vm_path).as_str(),
&config.cmdline,
)?;
tx.write_string(
format!("{}/memory/static-max", dom_path).as_str(),
&(config.mem_mb * 1024).to_string(),
)?;
tx.write_string(
format!("{}/memory/target", dom_path).as_str(),
&(config.mem_mb * 1024).to_string(),
)?;
tx.write_string(
format!("{}/memory/videoram", dom_path).as_str(),
"0",
)?;
tx.write_string(format!("{}/domid", dom_path).as_str(), &domid.to_string())?;
tx.write_string(
format!("{}/store/port", dom_path).as_str(),
&xenstore_evtchn.to_string(),
)?;
tx.write_string(
format!("{}/store/ring-ref", dom_path).as_str(),
&xenstore_mfn.to_string(),
)?;
for i in 0..config.max_vcpus {
tx.write_string(
format!("{}/cpu/{}/availability", dom_path, i).as_str(),
"online",
)?;
}
tx.commit()?;
}
self.console_device_add(&dom_path.to_string(), domid, console_evtchn, console_mfn)?;
self.store
.introduce_domain(domid, xenstore_mfn, xenstore_evtchn)?;
self.call.unpause_domain(domid)?;
Ok(domid)
}
fn console_device_add(
&mut self,
dom_path: &String,
domid: u32,
port: u32,
mfn: u64,
) -> Result<(), XenClientError> {
let frontend_path = format!("{}/console", dom_path);
let backend_path = format!("{}/backend/console/{}/{}", dom_path, domid, 0);
let mut tx = self.store.transaction()?;
tx.write_string(
format!("{}/frontend-id", backend_path).as_str(),
&domid.to_string(),
)?;
tx.write_string(
format!("{}/online", backend_path).as_str(),
"1",
)?;
tx.write_string(format!("{}/state", backend_path).as_str(), "1")?;
tx.write_string(
format!("{}/protocol", backend_path).as_str(),
"vt100",
)?;
for (key, value) in config.clone_domain_entries() {
let path = format!("{}/{}", domain, key);
tx.write(path.as_str(), value.into_bytes())?;
}
let domid_path = format!("{}/domid", domain);
tx.write(domid_path.as_str(), domid.to_string().into_bytes())?;
for (key, value) in config.clone_domain_entries() {
let path = format!("{}/{}", vm, key);
tx.write(path.as_str(), value.into_bytes())?;
}
tx.write_string(
format!("{}/backend-id", frontend_path).as_str(),
"0",
)?;
tx.write_string(
format!("{}/limit", frontend_path).as_str(),
"1048576",
)?;
tx.write_string(
format!("{}/type", frontend_path).as_str(),
"xenconsoled",
)?;
tx.write_string(
format!("{}/output", frontend_path).as_str(),
"pty",
)?;
tx.write_string(format!("{}/tty", frontend_path).as_str(), "")?;
tx.write_string(
format!("{}/port", frontend_path).as_str(),
&port.to_string(),
)?;
tx.write_string(
format!("{}/ring-ref", frontend_path).as_str(),
&mfn.to_string(),
)?;
tx.commit()?;
Ok(())
}
}

View File

@ -1,6 +1,6 @@
use crate::sys::{XsdMessageHeader, XSD_ERROR};
use std::error::Error;
use std::ffi::{CString, FromVecWithNulError, NulError};
use std::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
use std::fs::metadata;
use std::io::{Read, Write};
use std::mem::size_of;
@ -83,6 +83,12 @@ impl From<ParseIntError> for XsdBusError {
}
}
impl From<IntoStringError> for XsdBusError {
fn from(_: IntoStringError) -> Self {
XsdBusError::new("Unable to coerce data into a string.")
}
}
pub struct XsdSocket {
handle: UnixStream,
}
@ -95,7 +101,7 @@ pub struct XsdResponse {
impl XsdResponse {
pub fn parse_string(&self) -> Result<String, XsdBusError> {
Ok(String::from_utf8(self.payload.clone())?)
Ok(CString::from_vec_with_nul(self.payload.clone())?.into_string()?)
}
pub fn parse_string_vec(&self) -> Result<Vec<String>, XsdBusError> {
@ -114,8 +120,10 @@ impl XsdResponse {
}
pub fn parse_bool(&self) -> Result<bool, XsdBusError> {
if self.payload.len() != 1 {
Err(XsdBusError::new("Expected payload to be a single byte."))
if self.payload.is_empty() {
Err(XsdBusError::new(
"Expected bool payload to be at least one byte.",
))
} else {
Ok(self.payload[0] == 0)
}

View File

@ -9,14 +9,23 @@ pub struct XsdClient {
pub socket: XsdSocket,
}
pub struct XsPermissions {
pub id: u32,
pub perms: u32,
}
pub trait XsdInterface {
fn list(&mut self, path: &str) -> Result<Vec<String>, XsdBusError>;
fn read(&mut self, path: &str) -> Result<Vec<u8>, XsdBusError>;
fn read_string(&mut self, path: &str) -> Result<String, XsdBusError>;
fn write(&mut self, path: &str, data: Vec<u8>) -> Result<bool, XsdBusError>;
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError>;
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError>;
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError>;
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError>;
fn mknod(&mut self, path: &str, _perm: &XsPermissions) -> Result<bool, XsdBusError> {
self.write_string(path, "")
}
}
impl XsdClient {
@ -53,8 +62,9 @@ impl XsdClient {
}
pub fn transaction(&mut self) -> Result<XsdTransaction, XsdBusError> {
let response = self.socket.send(0, XSD_TRANSACTION_START, &[])?;
let tx = response.parse_string()?.parse::<u32>()?;
let response = self.socket.send_single(0, XSD_TRANSACTION_START, "")?;
let str = response.parse_string()?;
let tx = str.parse::<u32>()?;
Ok(XsdTransaction { client: self, tx })
}
@ -68,7 +78,7 @@ impl XsdClient {
pub fn introduce_domain(
&mut self,
domid: u32,
mfn: u32,
mfn: u64,
eventchn: u32,
) -> Result<String, XsdBusError> {
let response = self.socket.send_multiple(
@ -106,8 +116,8 @@ impl XsdInterface for XsdClient {
self.write(0, path, data)
}
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError> {
self.write(0, path, data.into_bytes())
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError> {
self.write(0, path, data.as_bytes().to_vec())
}
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {
@ -136,8 +146,8 @@ impl XsdInterface for XsdTransaction<'_> {
self.client.write(self.tx, path, data)
}
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError> {
self.client.write(self.tx, path, data.into_bytes())
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError> {
self.client.write(self.tx, path, data.as_bytes().to_vec())
}
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {