mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 21:00:55 +00:00
oh my god, we have a console
This commit is contained in:
parent
6ca61410ad
commit
15ba27e573
@ -1,4 +1,3 @@
|
|||||||
use xencall::domctl::DomainControl;
|
|
||||||
use xencall::sys::CreateDomain;
|
use xencall::sys::CreateDomain;
|
||||||
use xencall::{XenCall, XenCallError};
|
use xencall::{XenCall, XenCallError};
|
||||||
|
|
||||||
@ -6,8 +5,7 @@ fn main() -> Result<(), XenCallError> {
|
|||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let call = XenCall::open()?;
|
let call = XenCall::open()?;
|
||||||
let domctl: DomainControl = DomainControl::new(&call);
|
let domid = call.create_domain(CreateDomain::default())?;
|
||||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
|
||||||
println!("created domain {}", domid);
|
println!("created domain {}", domid);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
use xencall::domctl::DomainControl;
|
|
||||||
use xencall::{XenCall, XenCallError};
|
use xencall::{XenCall, XenCallError};
|
||||||
|
|
||||||
fn main() -> Result<(), XenCallError> {
|
fn main() -> Result<(), XenCallError> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let call = XenCall::open()?;
|
let call = XenCall::open()?;
|
||||||
let domctl: DomainControl = DomainControl::new(&call);
|
let info = call.get_domain_info(1)?;
|
||||||
let info = domctl.get_domain_info(1)?;
|
|
||||||
println!("{:?}", info);
|
println!("{:?}", info);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
use xencall::domctl::DomainControl;
|
|
||||||
use xencall::{XenCall, XenCallError};
|
use xencall::{XenCall, XenCallError};
|
||||||
|
|
||||||
fn main() -> Result<(), XenCallError> {
|
fn main() -> Result<(), XenCallError> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let call = XenCall::open()?;
|
let call = XenCall::open()?;
|
||||||
let domctl: DomainControl = DomainControl::new(&call);
|
let context = call.get_vcpu_context(224, 0)?;
|
||||||
let context = domctl.get_vcpu_context(224, 0)?;
|
|
||||||
println!("{:?}", context);
|
println!("{:?}", context);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +1,28 @@
|
|||||||
pub mod domctl;
|
|
||||||
pub mod memory;
|
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
|
|
||||||
use crate::sys::{
|
use crate::sys::{
|
||||||
EvtChnAllocUnbound, Hypercall, MmapBatch, MmapResource, MultiCallEntry, XenCapabilitiesInfo,
|
AddressSize, ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
|
||||||
HYPERVISOR_EVENT_CHANNEL_OP, HYPERVISOR_MULTICALL, HYPERVISOR_XEN_VERSION, XENVER_CAPABILITIES,
|
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 libc::{c_int, mmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use nix::errno::Errno;
|
use nix::errno::Errno;
|
||||||
use std::error::Error;
|
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::fmt::{Display, Formatter};
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::os::fd::AsRawFd;
|
use std::os::fd::AsRawFd;
|
||||||
use std::ptr::addr_of_mut;
|
use std::ptr::addr_of_mut;
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
pub struct XenCall {
|
pub struct XenCall {
|
||||||
pub handle: File,
|
pub handle: File,
|
||||||
@ -251,4 +259,353 @@ impl XenCall {
|
|||||||
self.evtchn_op(6, addr_of_mut!(alloc_unbound) as c_ulong)?;
|
self.evtchn_op(6, addr_of_mut!(alloc_unbound) as c_ulong)?;
|
||||||
Ok(alloc_unbound.port)
|
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(|_| ())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(|_| ())
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,10 +32,6 @@ env_logger = "0.10.1"
|
|||||||
[lib]
|
[lib]
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "xenclient-simple"
|
|
||||||
path = "examples/simple.rs"
|
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "xenclient-boot"
|
name = "xenclient-boot"
|
||||||
path = "examples/boot.rs"
|
path = "examples/boot.rs"
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
use std::fs::read;
|
|
||||||
use std::{env, process};
|
use std::{env, process};
|
||||||
use xencall::domctl::DomainControl;
|
use xenclient::create::DomainConfig;
|
||||||
use xencall::memory::MemoryControl;
|
use xenclient::{XenClient, XenClientError};
|
||||||
use xencall::sys::CreateDomain;
|
|
||||||
use xencall::XenCall;
|
|
||||||
use xenclient::boot::BootSetup;
|
|
||||||
use xenclient::elfloader::ElfImageLoader;
|
|
||||||
use xenclient::XenClientError;
|
|
||||||
use xenevtchn::EventChannel;
|
|
||||||
|
|
||||||
fn main() -> Result<(), XenClientError> {
|
fn main() -> Result<(), XenClientError> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
@ -19,40 +12,15 @@ fn main() -> Result<(), XenClientError> {
|
|||||||
}
|
}
|
||||||
let kernel_image_path = args.get(1).expect("argument not specified");
|
let kernel_image_path = args.get(1).expect("argument not specified");
|
||||||
let initrd_path = args.get(2).expect("argument not specified");
|
let initrd_path = args.get(2).expect("argument not specified");
|
||||||
let call = XenCall::open()?;
|
let mut client = XenClient::open()?;
|
||||||
let domctl = DomainControl::new(&call);
|
let config = DomainConfig {
|
||||||
let domain = CreateDomain {
|
|
||||||
max_vcpus: 1,
|
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)?;
|
let domid = client.create(config)?;
|
||||||
boot(
|
println!("created domain {}", domid);
|
||||||
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()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -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(())
|
|
||||||
}
|
|
@ -16,8 +16,6 @@ use std::cmp::{max, min};
|
|||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use xencall::domctl::DomainControl;
|
|
||||||
use xencall::memory::MemoryControl;
|
|
||||||
use xencall::sys::{VcpuGuestContext, MMUEXT_PIN_L4_TABLE};
|
use xencall::sys::{VcpuGuestContext, MMUEXT_PIN_L4_TABLE};
|
||||||
use xencall::XenCall;
|
use xencall::XenCall;
|
||||||
|
|
||||||
@ -41,9 +39,8 @@ pub struct BootImageInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct BootSetup<'a> {
|
pub struct BootSetup<'a> {
|
||||||
domctl: &'a DomainControl<'a>,
|
call: &'a XenCall,
|
||||||
memctl: &'a MemoryControl<'a>,
|
pub phys: PhysicalPages<'a>,
|
||||||
phys: PhysicalPages<'a>,
|
|
||||||
domid: u32,
|
domid: u32,
|
||||||
virt_alloc_end: u64,
|
virt_alloc_end: u64,
|
||||||
pfn_alloc_end: u64,
|
pfn_alloc_end: u64,
|
||||||
@ -55,7 +52,7 @@ pub struct BootSetup<'a> {
|
|||||||
pub struct DomainSegment {
|
pub struct DomainSegment {
|
||||||
vstart: u64,
|
vstart: u64,
|
||||||
_vend: u64,
|
_vend: u64,
|
||||||
pfn: u64,
|
pub pfn: u64,
|
||||||
addr: u64,
|
addr: u64,
|
||||||
size: u64,
|
size: u64,
|
||||||
pages: u64,
|
pages: u64,
|
||||||
@ -87,15 +84,9 @@ pub struct BootState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BootSetup<'_> {
|
impl BootSetup<'_> {
|
||||||
pub fn new<'a>(
|
pub fn new(call: &XenCall, domid: u32) -> BootSetup {
|
||||||
call: &'a XenCall,
|
|
||||||
domctl: &'a DomainControl<'a>,
|
|
||||||
memctl: &'a MemoryControl<'a>,
|
|
||||||
domid: u32,
|
|
||||||
) -> BootSetup<'a> {
|
|
||||||
BootSetup {
|
BootSetup {
|
||||||
domctl,
|
call,
|
||||||
memctl,
|
|
||||||
phys: PhysicalPages::new(call, domid),
|
phys: PhysicalPages::new(call, domid),
|
||||||
domid,
|
domid,
|
||||||
virt_alloc_end: 0,
|
virt_alloc_end: 0,
|
||||||
@ -106,7 +97,7 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_memory(&mut self, total_pages: u64) -> Result<(), XenClientError> {
|
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 mut vmemranges: Vec<VmemRange> = Vec::new();
|
||||||
let stub = VmemRange {
|
let stub = VmemRange {
|
||||||
@ -162,7 +153,7 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let extents_init_slice = extents_init.as_slice();
|
let extents_init_slice = extents_init.as_slice();
|
||||||
let extents = self.memctl.populate_physmap(
|
let extents = self.call.populate_physmap(
|
||||||
self.domid,
|
self.domid,
|
||||||
count,
|
count,
|
||||||
SUPERPAGE_2MB_SHIFT as u32,
|
SUPERPAGE_2MB_SHIFT as u32,
|
||||||
@ -191,7 +182,7 @@ impl BootSetup<'_> {
|
|||||||
let p2m_end_idx = p2m_idx + allocsz as usize;
|
let p2m_end_idx = p2m_idx + allocsz as usize;
|
||||||
let input_extent_starts = &p2m[p2m_idx..p2m_end_idx];
|
let input_extent_starts = &p2m[p2m_idx..p2m_end_idx];
|
||||||
let result =
|
let result =
|
||||||
self.memctl
|
self.call
|
||||||
.populate_physmap(self.domid, allocsz, 0, 0, input_extent_starts)?;
|
.populate_physmap(self.domid, allocsz, 0, 0, input_extent_starts)?;
|
||||||
|
|
||||||
if result.len() != allocsz as usize {
|
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 pfn = (image_info.virt_hypercall - image_info.virt_base) >> X86_PAGE_SHIFT;
|
||||||
let mfn = self.phys.p2m[pfn as usize];
|
let mfn = self.phys.p2m[pfn as usize];
|
||||||
self.domctl.hypercall_init(self.domid, mfn)?;
|
self.call.hypercall_init(self.domid, mfn)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,8 +232,6 @@ impl BootSetup<'_> {
|
|||||||
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
|
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
|
||||||
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);
|
let total_pages = mem_mb << (20 - X86_PAGE_SHIFT);
|
||||||
self.initialize_memory(total_pages)?;
|
self.initialize_memory(total_pages)?;
|
||||||
@ -284,8 +273,8 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let initrd_segment = initrd_segment.unwrap();
|
let initrd_segment = initrd_segment.unwrap();
|
||||||
let store_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.domctl.call.evtchn_alloc_unbound(self.domid, 0)?;
|
let console_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0)?;
|
||||||
let state = BootState {
|
let state = BootState {
|
||||||
kernel_segment,
|
kernel_segment,
|
||||||
start_info_segment,
|
start_info_segment,
|
||||||
@ -306,7 +295,7 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn boot(&mut self, state: &mut BootState, cmdline: &str) -> Result<(), XenClientError> {
|
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;
|
let shared_info_frame = domain_info.shared_info_frame;
|
||||||
state.shared_info_frame = shared_info_frame;
|
state.shared_info_frame = shared_info_frame;
|
||||||
self.setup_page_tables(state)?;
|
self.setup_page_tables(state)?;
|
||||||
@ -317,7 +306,7 @@ impl BootSetup<'_> {
|
|||||||
self.phys.unmap(pg_pfn)?;
|
self.phys.unmap(pg_pfn)?;
|
||||||
self.phys.unmap(state.p2m_segment.pfn)?;
|
self.phys.unmap(state.p2m_segment.pfn)?;
|
||||||
let pg_mfn = self.phys.p2m[pg_pfn as usize];
|
let pg_mfn = self.phys.p2m[pg_pfn as usize];
|
||||||
self.memctl
|
self.call
|
||||||
.mmuext(self.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)?;
|
.mmuext(self.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)?;
|
||||||
self.setup_shared_info(state.shared_info_frame)?;
|
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_ss = vcpu.user_regs.ss as u64;
|
||||||
vcpu.kernel_sp = vcpu.user_regs.rsp;
|
vcpu.kernel_sp = vcpu.user_regs.rsp;
|
||||||
debug!("vcpu context: {:?}", vcpu);
|
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.phys.unmap_all()?;
|
||||||
self.gnttab_seed(state)?;
|
self.gnttab_seed(state)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -356,13 +345,10 @@ impl BootSetup<'_> {
|
|||||||
let console_gfn = self.phys.p2m[state.console_segment.pfn as usize];
|
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 xenstore_gfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
|
||||||
let addr = self
|
let addr = self
|
||||||
.domctl
|
|
||||||
.call
|
.call
|
||||||
.mmap(0, 1 << XEN_PAGE_SHIFT)
|
.mmap(0, 1 << XEN_PAGE_SHIFT)
|
||||||
.ok_or(XenClientError::new("failed to mmap for resource"))?;
|
.ok_or(XenClientError::new("failed to mmap for resource"))?;
|
||||||
self.domctl
|
self.call.map_resource(self.domid, 1, 0, 0, 1, addr)?;
|
||||||
.call
|
|
||||||
.map_resource(self.domid, 1, 0, 0, 1, addr)?;
|
|
||||||
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
|
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
|
||||||
entries[0].flags = 1 << 0;
|
entries[0].flags = 1 << 0;
|
||||||
entries[0].domid = 0;
|
entries[0].domid = 0;
|
||||||
|
@ -1,19 +1,27 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct DomainConfig {
|
pub struct DomainConfig {
|
||||||
vm_entries: HashMap<String, String>,
|
pub max_vcpus: u32,
|
||||||
domain_entries: HashMap<String, String>,
|
pub mem_mb: u64,
|
||||||
|
pub kernel_path: String,
|
||||||
|
pub initrd_path: String,
|
||||||
|
pub cmdline: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PvDomainConfig {
|
pub struct PvDomainStore {
|
||||||
kernel: String,
|
kernel: String,
|
||||||
ramdisk: Option<String>,
|
ramdisk: Option<String>,
|
||||||
cmdline: Option<String>,
|
cmdline: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DomainConfig {
|
pub struct DomainStore {
|
||||||
pub fn new() -> DomainConfig {
|
vm_entries: HashMap<String, String>,
|
||||||
DomainConfig {
|
domain_entries: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DomainStore {
|
||||||
|
pub fn new() -> DomainStore {
|
||||||
|
DomainStore {
|
||||||
vm_entries: HashMap::new(),
|
vm_entries: HashMap::new(),
|
||||||
domain_entries: HashMap::new(),
|
domain_entries: HashMap::new(),
|
||||||
}
|
}
|
||||||
@ -43,7 +51,7 @@ impl DomainConfig {
|
|||||||
|
|
||||||
pub fn configure_cpus(&mut self, _maxvcpus: u32) {}
|
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_str("image/ostype", "linux");
|
||||||
self.put_vm("image/kernel", pv.kernel);
|
self.put_vm("image/kernel", pv.kernel);
|
||||||
|
|
||||||
@ -67,15 +75,15 @@ impl DomainConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DomainConfig {
|
impl Default for DomainStore {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
DomainConfig::new()
|
DomainStore::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PvDomainConfig {
|
impl PvDomainStore {
|
||||||
pub fn new(kernel: String, ramdisk: Option<String>, cmdline: Option<String>) -> PvDomainConfig {
|
pub fn new(kernel: String, ramdisk: Option<String>, cmdline: Option<String>) -> PvDomainStore {
|
||||||
PvDomainConfig {
|
PvDomainStore {
|
||||||
kernel,
|
kernel,
|
||||||
ramdisk,
|
ramdisk,
|
||||||
cmdline,
|
cmdline,
|
||||||
|
@ -5,16 +5,19 @@ pub mod mem;
|
|||||||
pub mod sys;
|
pub mod sys;
|
||||||
mod x86;
|
mod x86;
|
||||||
|
|
||||||
|
use crate::boot::BootSetup;
|
||||||
use crate::create::DomainConfig;
|
use crate::create::DomainConfig;
|
||||||
|
use crate::elfloader::ElfImageLoader;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::fs::read;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
use xencall::domctl::DomainControl;
|
use uuid::Uuid;
|
||||||
use xencall::sys::CreateDomain;
|
use xencall::sys::CreateDomain;
|
||||||
use xencall::{XenCall, XenCallError};
|
use xencall::{XenCall, XenCallError};
|
||||||
use xenevtchn::EventChannelError;
|
use xenevtchn::EventChannelError;
|
||||||
use xenstore::bus::XsdBusError;
|
use xenstore::bus::XsdBusError;
|
||||||
use xenstore::client::{XsdClient, XsdInterface};
|
use xenstore::client::{XsPermissions, XsdClient, XsdInterface};
|
||||||
|
|
||||||
pub struct XenClient {
|
pub struct XenClient {
|
||||||
store: XsdClient,
|
store: XsdClient,
|
||||||
@ -83,29 +86,208 @@ impl XenClient {
|
|||||||
Ok(XenClient { store, call })
|
Ok(XenClient { store, call })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&mut self, config: DomainConfig) -> Result<(), XenClientError> {
|
pub fn create(&mut self, config: DomainConfig) -> Result<u32, XenClientError> {
|
||||||
let domctl = DomainControl::new(&self.call);
|
let domain = CreateDomain {
|
||||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
max_vcpus: config.max_vcpus,
|
||||||
let domain = self.store.get_domain_path(domid)?;
|
..Default::default()
|
||||||
let vm = self.store.read_string(format!("{}/vm", domain).as_str())?;
|
};
|
||||||
|
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()?;
|
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() {
|
tx.write_string(
|
||||||
let path = format!("{}/{}", domain, key);
|
format!("{}/backend-id", frontend_path).as_str(),
|
||||||
tx.write(path.as_str(), value.into_bytes())?;
|
"0",
|
||||||
}
|
)?;
|
||||||
|
tx.write_string(
|
||||||
let domid_path = format!("{}/domid", domain);
|
format!("{}/limit", frontend_path).as_str(),
|
||||||
tx.write(domid_path.as_str(), domid.to_string().into_bytes())?;
|
"1048576",
|
||||||
|
)?;
|
||||||
for (key, value) in config.clone_domain_entries() {
|
tx.write_string(
|
||||||
let path = format!("{}/{}", vm, key);
|
format!("{}/type", frontend_path).as_str(),
|
||||||
tx.write(path.as_str(), value.into_bytes())?;
|
"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()?;
|
tx.commit()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::sys::{XsdMessageHeader, XSD_ERROR};
|
use crate::sys::{XsdMessageHeader, XSD_ERROR};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::{CString, FromVecWithNulError, NulError};
|
use std::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
|
||||||
use std::fs::metadata;
|
use std::fs::metadata;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::mem::size_of;
|
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 {
|
pub struct XsdSocket {
|
||||||
handle: UnixStream,
|
handle: UnixStream,
|
||||||
}
|
}
|
||||||
@ -95,7 +101,7 @@ pub struct XsdResponse {
|
|||||||
|
|
||||||
impl XsdResponse {
|
impl XsdResponse {
|
||||||
pub fn parse_string(&self) -> Result<String, XsdBusError> {
|
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> {
|
pub fn parse_string_vec(&self) -> Result<Vec<String>, XsdBusError> {
|
||||||
@ -114,8 +120,10 @@ impl XsdResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_bool(&self) -> Result<bool, XsdBusError> {
|
pub fn parse_bool(&self) -> Result<bool, XsdBusError> {
|
||||||
if self.payload.len() != 1 {
|
if self.payload.is_empty() {
|
||||||
Err(XsdBusError::new("Expected payload to be a single byte."))
|
Err(XsdBusError::new(
|
||||||
|
"Expected bool payload to be at least one byte.",
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(self.payload[0] == 0)
|
Ok(self.payload[0] == 0)
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,23 @@ pub struct XsdClient {
|
|||||||
pub socket: XsdSocket,
|
pub socket: XsdSocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct XsPermissions {
|
||||||
|
pub id: u32,
|
||||||
|
pub perms: u32,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait XsdInterface {
|
pub trait XsdInterface {
|
||||||
fn list(&mut self, path: &str) -> Result<Vec<String>, XsdBusError>;
|
fn list(&mut self, path: &str) -> Result<Vec<String>, XsdBusError>;
|
||||||
fn read(&mut self, path: &str) -> Result<Vec<u8>, XsdBusError>;
|
fn read(&mut self, path: &str) -> Result<Vec<u8>, XsdBusError>;
|
||||||
fn read_string(&mut self, path: &str) -> Result<String, 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(&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 mkdir(&mut self, path: &str) -> Result<bool, XsdBusError>;
|
||||||
fn rm(&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 {
|
impl XsdClient {
|
||||||
@ -53,8 +62,9 @@ impl XsdClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn transaction(&mut self) -> Result<XsdTransaction, XsdBusError> {
|
pub fn transaction(&mut self) -> Result<XsdTransaction, XsdBusError> {
|
||||||
let response = self.socket.send(0, XSD_TRANSACTION_START, &[])?;
|
let response = self.socket.send_single(0, XSD_TRANSACTION_START, "")?;
|
||||||
let tx = response.parse_string()?.parse::<u32>()?;
|
let str = response.parse_string()?;
|
||||||
|
let tx = str.parse::<u32>()?;
|
||||||
Ok(XsdTransaction { client: self, tx })
|
Ok(XsdTransaction { client: self, tx })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +78,7 @@ impl XsdClient {
|
|||||||
pub fn introduce_domain(
|
pub fn introduce_domain(
|
||||||
&mut self,
|
&mut self,
|
||||||
domid: u32,
|
domid: u32,
|
||||||
mfn: u32,
|
mfn: u64,
|
||||||
eventchn: u32,
|
eventchn: u32,
|
||||||
) -> Result<String, XsdBusError> {
|
) -> Result<String, XsdBusError> {
|
||||||
let response = self.socket.send_multiple(
|
let response = self.socket.send_multiple(
|
||||||
@ -106,8 +116,8 @@ impl XsdInterface for XsdClient {
|
|||||||
self.write(0, path, data)
|
self.write(0, path, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError> {
|
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError> {
|
||||||
self.write(0, path, data.into_bytes())
|
self.write(0, path, data.as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
||||||
@ -136,8 +146,8 @@ impl XsdInterface for XsdTransaction<'_> {
|
|||||||
self.client.write(self.tx, path, data)
|
self.client.write(self.tx, path, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError> {
|
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError> {
|
||||||
self.client.write(self.tx, path, data.into_bytes())
|
self.client.write(self.tx, path, data.as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
||||||
|
Loading…
Reference in New Issue
Block a user