diff --git a/xencall/examples/domain_create.rs b/xencall/examples/domain_create.rs index ff3cd65..3d8d026 100644 --- a/xencall/examples/domain_create.rs +++ b/xencall/examples/domain_create.rs @@ -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(()) } diff --git a/xencall/examples/domain_info.rs b/xencall/examples/domain_info.rs index c6a5ef2..cffa04a 100644 --- a/xencall/examples/domain_info.rs +++ b/xencall/examples/domain_info.rs @@ -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(()) } diff --git a/xencall/examples/vcpu_context.rs b/xencall/examples/vcpu_context.rs index b46e879..c83188c 100644 --- a/xencall/examples/vcpu_context.rs +++ b/xencall/examples/vcpu_context.rs @@ -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(()) } diff --git a/xencall/src/domctl.rs b/xencall/src/domctl.rs deleted file mode 100644 index 79bd60d..0000000 --- a/xencall/src/domctl.rs +++ /dev/null @@ -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 { - 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 { - 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 { - 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, XenCallError> { - let mut buffer: Vec = 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(()) - } -} diff --git a/xencall/src/lib.rs b/xencall/src/lib.rs index eaa549b..ae4e224 100644 --- a/xencall/src/lib.rs +++ b/xencall/src/lib.rs @@ -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 { + 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 { + 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 { + 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, XenCallError> { + let mut buffer: Vec = 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, 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, 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(|_| ()) + } } diff --git a/xencall/src/memory.rs b/xencall/src/memory.rs deleted file mode 100644 index 304a3df..0000000 --- a/xencall/src/memory.rs +++ /dev/null @@ -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, 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, 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(|_| ()) - } -} diff --git a/xenclient/Cargo.toml b/xenclient/Cargo.toml index 9308ca6..af5f4be 100644 --- a/xenclient/Cargo.toml +++ b/xenclient/Cargo.toml @@ -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" diff --git a/xenclient/examples/boot.rs b/xenclient/examples/boot.rs index 2aad3c9..8e62750 100644 --- a/xenclient/examples/boot.rs +++ b/xenclient/examples/boot.rs @@ -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(()) } diff --git a/xenclient/examples/simple.rs b/xenclient/examples/simple.rs deleted file mode 100644 index 65fa6b8..0000000 --- a/xenclient/examples/simple.rs +++ /dev/null @@ -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(()) -} diff --git a/xenclient/src/boot.rs b/xenclient/src/boot.rs index 1c72954..3caea19 100644 --- a/xenclient/src/boot.rs +++ b/xenclient/src/boot.rs @@ -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 = 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; diff --git a/xenclient/src/create.rs b/xenclient/src/create.rs index 08bdb64..a1aea43 100644 --- a/xenclient/src/create.rs +++ b/xenclient/src/create.rs @@ -1,19 +1,27 @@ use std::collections::HashMap; pub struct DomainConfig { - vm_entries: HashMap, - domain_entries: HashMap, + 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, cmdline: Option, } -impl DomainConfig { - pub fn new() -> DomainConfig { - DomainConfig { +pub struct DomainStore { + vm_entries: HashMap, + domain_entries: HashMap, +} + +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, cmdline: Option) -> PvDomainConfig { - PvDomainConfig { +impl PvDomainStore { + pub fn new(kernel: String, ramdisk: Option, cmdline: Option) -> PvDomainStore { + PvDomainStore { kernel, ramdisk, cmdline, diff --git a/xenclient/src/lib.rs b/xenclient/src/lib.rs index d617faa..3c19e1a 100644 --- a/xenclient/src/lib.rs +++ b/xenclient/src/lib.rs @@ -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 { + 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(()) } } diff --git a/xenstore/src/bus.rs b/xenstore/src/bus.rs index 1191e27..9c22b20 100644 --- a/xenstore/src/bus.rs +++ b/xenstore/src/bus.rs @@ -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 for XsdBusError { } } +impl From 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 { - 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, XsdBusError> { @@ -114,8 +120,10 @@ impl XsdResponse { } pub fn parse_bool(&self) -> Result { - 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) } diff --git a/xenstore/src/client.rs b/xenstore/src/client.rs index 750341f..90aa9c7 100644 --- a/xenstore/src/client.rs +++ b/xenstore/src/client.rs @@ -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, XsdBusError>; fn read(&mut self, path: &str) -> Result, XsdBusError>; fn read_string(&mut self, path: &str) -> Result; fn write(&mut self, path: &str, data: Vec) -> Result; - fn write_string(&mut self, path: &str, data: String) -> Result; + fn write_string(&mut self, path: &str, data: &str) -> Result; fn mkdir(&mut self, path: &str) -> Result; fn rm(&mut self, path: &str) -> Result; + + fn mknod(&mut self, path: &str, _perm: &XsPermissions) -> Result { + self.write_string(path, "") + } } impl XsdClient { @@ -53,8 +62,9 @@ impl XsdClient { } pub fn transaction(&mut self) -> Result { - let response = self.socket.send(0, XSD_TRANSACTION_START, &[])?; - let tx = response.parse_string()?.parse::()?; + let response = self.socket.send_single(0, XSD_TRANSACTION_START, "")?; + let str = response.parse_string()?; + let tx = str.parse::()?; 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 { 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 { - self.write(0, path, data.into_bytes()) + fn write_string(&mut self, path: &str, data: &str) -> Result { + self.write(0, path, data.as_bytes().to_vec()) } fn mkdir(&mut self, path: &str) -> Result { @@ -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 { - self.client.write(self.tx, path, data.into_bytes()) + fn write_string(&mut self, path: &str, data: &str) -> Result { + self.client.write(self.tx, path, data.as_bytes().to_vec()) } fn mkdir(&mut self, path: &str) -> Result {