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::{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(())
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
use crate::sys::{
|
||||
EvtChnAllocUnbound, Hypercall, MmapBatch, MmapResource, MultiCallEntry, XenCapabilitiesInfo,
|
||||
HYPERVISOR_EVENT_CHANNEL_OP, HYPERVISOR_MULTICALL, HYPERVISOR_XEN_VERSION, XENVER_CAPABILITIES,
|
||||
AddressSize, ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
|
||||
EvtChnAllocUnbound, GetDomainInfo, GetPageFrameInfo3, Hypercall, HypercallInit, MaxMem,
|
||||
MaxVcpus, MemoryMap, MemoryReservation, MmapBatch, MmapResource, MmuExtOp, MultiCallEntry,
|
||||
VcpuGuestContext, VcpuGuestContextAny, XenCapabilitiesInfo, HYPERVISOR_DOMCTL,
|
||||
HYPERVISOR_EVENT_CHANNEL_OP, HYPERVISOR_MEMORY_OP, HYPERVISOR_MMUEXT_OP, HYPERVISOR_MULTICALL,
|
||||
HYPERVISOR_XEN_VERSION, XENVER_CAPABILITIES, XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN,
|
||||
XEN_DOMCTL_GETDOMAININFO, XEN_DOMCTL_GETPAGEFRAMEINFO3, XEN_DOMCTL_GETVCPUCONTEXT,
|
||||
XEN_DOMCTL_HYPERCALL_INIT, XEN_DOMCTL_INTERFACE_VERSION, XEN_DOMCTL_MAX_MEM,
|
||||
XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_PAUSEDOMAIN, XEN_DOMCTL_SETVCPUCONTEXT,
|
||||
XEN_DOMCTL_SET_ADDRESS_SIZE, XEN_DOMCTL_UNPAUSEDOMAIN, XEN_MEM_MEMORY_MAP,
|
||||
XEN_MEM_POPULATE_PHYSMAP,
|
||||
};
|
||||
use libc::{c_int, mmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
|
||||
use log::trace;
|
||||
use nix::errno::Errno;
|
||||
use std::error::Error;
|
||||
use std::ffi::{c_long, c_ulong, c_void};
|
||||
use std::ffi::{c_long, c_uint, c_ulong, c_void};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::ptr::addr_of_mut;
|
||||
use std::slice;
|
||||
|
||||
pub struct XenCall {
|
||||
pub handle: File,
|
||||
@ -251,4 +259,353 @@ impl XenCall {
|
||||
self.evtchn_op(6, addr_of_mut!(alloc_unbound) as c_ulong)?;
|
||||
Ok(alloc_unbound.port)
|
||||
}
|
||||
|
||||
pub fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo, XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} get_domain_info domid={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_GETDOMAININFO,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
get_domain_info: GetDomainInfo {
|
||||
domid: 0,
|
||||
pad1: 0,
|
||||
flags: 0,
|
||||
total_pages: 0,
|
||||
max_pages: 0,
|
||||
outstanding_pages: 0,
|
||||
shr_pages: 0,
|
||||
paged_pages: 0,
|
||||
shared_info_frame: 0,
|
||||
cpu_time: 0,
|
||||
number_online_vcpus: 0,
|
||||
max_vcpu_id: 0,
|
||||
ssidref: 0,
|
||||
handle: [0; 16],
|
||||
cpupool: 0,
|
||||
gpaddr_bits: 0,
|
||||
pad2: [0; 7],
|
||||
arch: ArchDomainConfig {
|
||||
emulation_flags: 0,
|
||||
misc_flags: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(unsafe { domctl.value.get_domain_info })
|
||||
}
|
||||
|
||||
pub fn create_domain(&self, create_domain: CreateDomain) -> Result<u32, XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} create_domain create_domain={:?}",
|
||||
self.handle.as_raw_fd(),
|
||||
create_domain
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_CREATEDOMAIN,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid: 0,
|
||||
value: DomCtlValue { create_domain },
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(domctl.domid)
|
||||
}
|
||||
|
||||
pub fn pause_domain(&self, domid: u32) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} pause_domain domid={:?}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_PAUSEDOMAIN,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue { pad: [0; 128] },
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unpause_domain(&self, domid: u32) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} unpause_domain domid={:?}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_UNPAUSEDOMAIN,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue { pad: [0; 128] },
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} set_max_mem domid={} memkb={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
memkb
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_MAX_MEM,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
max_mem: MaxMem { max_memkb: memkb },
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_max_vcpus(&self, domid: u32, max_vcpus: u32) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} set_max_vcpus domid={} max_vcpus={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
max_vcpus
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_MAX_VCPUS,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
max_cpus: MaxVcpus { max_vcpus },
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_address_size(&self, domid: u32, size: u32) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} set_address_size domid={} size={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
size,
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_SET_ADDRESS_SIZE,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
address_size: AddressSize { size },
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_vcpu_context(
|
||||
&self,
|
||||
domid: u32,
|
||||
vcpu: u32,
|
||||
) -> Result<VcpuGuestContext, XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} get_vcpu_context domid={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
);
|
||||
let mut wrapper = VcpuGuestContextAny {
|
||||
value: VcpuGuestContext::default(),
|
||||
};
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_GETVCPUCONTEXT,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
vcpu_context: DomCtlVcpuContext {
|
||||
vcpu,
|
||||
ctx: addr_of_mut!(wrapper) as c_ulong,
|
||||
},
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(unsafe { wrapper.value })
|
||||
}
|
||||
|
||||
pub fn set_vcpu_context(
|
||||
&self,
|
||||
domid: u32,
|
||||
vcpu: u32,
|
||||
context: &VcpuGuestContext,
|
||||
) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} set_vcpu_context domid={} context={:?}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
context,
|
||||
);
|
||||
|
||||
let mut value = VcpuGuestContextAny { value: *context };
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_SETVCPUCONTEXT,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
vcpu_context: DomCtlVcpuContext {
|
||||
vcpu,
|
||||
ctx: addr_of_mut!(value) as c_ulong,
|
||||
},
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_page_frame_info(
|
||||
&self,
|
||||
domid: u32,
|
||||
frames: &[u64],
|
||||
) -> Result<Vec<u64>, XenCallError> {
|
||||
let mut buffer: Vec<u64> = frames.to_vec();
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_GETPAGEFRAMEINFO3,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
get_page_frame_info: GetPageFrameInfo3 {
|
||||
num: buffer.len() as u64,
|
||||
array: buffer.as_mut_ptr() as c_ulong,
|
||||
},
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
let slice = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
domctl.value.get_page_frame_info.array as *mut u64,
|
||||
domctl.value.get_page_frame_info.num as usize,
|
||||
)
|
||||
};
|
||||
Ok(slice.to_vec())
|
||||
}
|
||||
|
||||
pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} hypercall_init domid={} gmfn={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid,
|
||||
gmfn
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_HYPERCALL_INIT,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue {
|
||||
hypercall_init: HypercallInit { gmfn },
|
||||
},
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn destroy_domain(&self, domid: u32) -> Result<(), XenCallError> {
|
||||
trace!(
|
||||
"domctl fd={} destroy_domain domid={}",
|
||||
self.handle.as_raw_fd(),
|
||||
domid
|
||||
);
|
||||
let mut domctl = DomCtl {
|
||||
cmd: XEN_DOMCTL_DESTROYDOMAIN,
|
||||
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||
domid,
|
||||
value: DomCtlValue { pad: [0; 128] },
|
||||
};
|
||||
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_memory_map(&self, size_of_entry: usize) -> Result<Vec<u8>, XenCallError> {
|
||||
let mut memory_map = MemoryMap {
|
||||
count: 0,
|
||||
buffer: 0,
|
||||
};
|
||||
self.hypercall2(
|
||||
HYPERVISOR_MEMORY_OP,
|
||||
XEN_MEM_MEMORY_MAP as c_ulong,
|
||||
addr_of_mut!(memory_map) as c_ulong,
|
||||
)?;
|
||||
let mut buffer = vec![0u8; memory_map.count as usize * size_of_entry];
|
||||
memory_map.buffer = buffer.as_mut_ptr() as c_ulong;
|
||||
self.hypercall2(
|
||||
HYPERVISOR_MEMORY_OP,
|
||||
XEN_MEM_MEMORY_MAP as c_ulong,
|
||||
addr_of_mut!(memory_map) as c_ulong,
|
||||
)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
pub fn populate_physmap(
|
||||
&self,
|
||||
domid: u32,
|
||||
nr_extents: u64,
|
||||
extent_order: u32,
|
||||
mem_flags: u32,
|
||||
extent_starts: &[u64],
|
||||
) -> Result<Vec<u64>, XenCallError> {
|
||||
trace!("memory fd={} populate_physmap domid={} nr_extents={} extent_order={} mem_flags={} extent_starts={:?}", self.handle.as_raw_fd(), domid, nr_extents, extent_order, mem_flags, extent_starts);
|
||||
let mut extent_starts = extent_starts.to_vec();
|
||||
let ptr = extent_starts.as_mut_ptr();
|
||||
|
||||
let mut reservation = MemoryReservation {
|
||||
extent_start: ptr as c_ulong,
|
||||
nr_extents,
|
||||
extent_order,
|
||||
mem_flags,
|
||||
domid: domid as u16,
|
||||
};
|
||||
|
||||
let calls = &mut [MultiCallEntry {
|
||||
op: HYPERVISOR_MEMORY_OP,
|
||||
result: 0,
|
||||
args: [
|
||||
XEN_MEM_POPULATE_PHYSMAP as c_ulong,
|
||||
addr_of_mut!(reservation) as c_ulong,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
}];
|
||||
self.multicall(calls)?;
|
||||
let code = calls[0].result;
|
||||
if code > !0xfff {
|
||||
return Err(XenCallError::new(
|
||||
format!("failed to populate physmap: {:#x}", code).as_str(),
|
||||
));
|
||||
}
|
||||
if code as usize > extent_starts.len() {
|
||||
return Err(XenCallError::new("failed to populate physmap"));
|
||||
}
|
||||
let extents = extent_starts[0..code as usize].to_vec();
|
||||
Ok(extents)
|
||||
}
|
||||
|
||||
pub fn mmuext(
|
||||
&self,
|
||||
domid: u32,
|
||||
cmd: c_uint,
|
||||
arg1: u64,
|
||||
arg2: u64,
|
||||
) -> Result<(), XenCallError> {
|
||||
let mut ops = MmuExtOp { cmd, arg1, arg2 };
|
||||
|
||||
self.hypercall4(
|
||||
HYPERVISOR_MMUEXT_OP,
|
||||
addr_of_mut!(ops) as c_ulong,
|
||||
1,
|
||||
0,
|
||||
domid as c_ulong,
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[example]]
|
||||
name = "xenclient-simple"
|
||||
path = "examples/simple.rs"
|
||||
|
||||
[[example]]
|
||||
name = "xenclient-boot"
|
||||
path = "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(())
|
||||
}
|
||||
|
@ -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::mem::size_of;
|
||||
use std::slice;
|
||||
use xencall::domctl::DomainControl;
|
||||
use xencall::memory::MemoryControl;
|
||||
use xencall::sys::{VcpuGuestContext, MMUEXT_PIN_L4_TABLE};
|
||||
use xencall::XenCall;
|
||||
|
||||
@ -41,9 +39,8 @@ pub struct BootImageInfo {
|
||||
}
|
||||
|
||||
pub struct BootSetup<'a> {
|
||||
domctl: &'a DomainControl<'a>,
|
||||
memctl: &'a MemoryControl<'a>,
|
||||
phys: PhysicalPages<'a>,
|
||||
call: &'a XenCall,
|
||||
pub phys: PhysicalPages<'a>,
|
||||
domid: u32,
|
||||
virt_alloc_end: u64,
|
||||
pfn_alloc_end: u64,
|
||||
@ -55,7 +52,7 @@ pub struct BootSetup<'a> {
|
||||
pub struct DomainSegment {
|
||||
vstart: u64,
|
||||
_vend: u64,
|
||||
pfn: u64,
|
||||
pub pfn: u64,
|
||||
addr: u64,
|
||||
size: u64,
|
||||
pages: u64,
|
||||
@ -87,15 +84,9 @@ pub struct BootState {
|
||||
}
|
||||
|
||||
impl BootSetup<'_> {
|
||||
pub fn new<'a>(
|
||||
call: &'a XenCall,
|
||||
domctl: &'a DomainControl<'a>,
|
||||
memctl: &'a MemoryControl<'a>,
|
||||
domid: u32,
|
||||
) -> BootSetup<'a> {
|
||||
pub fn new(call: &XenCall, domid: u32) -> BootSetup {
|
||||
BootSetup {
|
||||
domctl,
|
||||
memctl,
|
||||
call,
|
||||
phys: PhysicalPages::new(call, domid),
|
||||
domid,
|
||||
virt_alloc_end: 0,
|
||||
@ -106,7 +97,7 @@ impl BootSetup<'_> {
|
||||
}
|
||||
|
||||
fn initialize_memory(&mut self, total_pages: u64) -> Result<(), XenClientError> {
|
||||
self.domctl.set_address_size(self.domid, 64)?;
|
||||
self.call.set_address_size(self.domid, 64)?;
|
||||
|
||||
let mut vmemranges: Vec<VmemRange> = Vec::new();
|
||||
let stub = VmemRange {
|
||||
@ -162,7 +153,7 @@ impl BootSetup<'_> {
|
||||
}
|
||||
|
||||
let extents_init_slice = extents_init.as_slice();
|
||||
let extents = self.memctl.populate_physmap(
|
||||
let extents = self.call.populate_physmap(
|
||||
self.domid,
|
||||
count,
|
||||
SUPERPAGE_2MB_SHIFT as u32,
|
||||
@ -191,7 +182,7 @@ impl BootSetup<'_> {
|
||||
let p2m_end_idx = p2m_idx + allocsz as usize;
|
||||
let input_extent_starts = &p2m[p2m_idx..p2m_end_idx];
|
||||
let result =
|
||||
self.memctl
|
||||
self.call
|
||||
.populate_physmap(self.domid, allocsz, 0, 0, input_extent_starts)?;
|
||||
|
||||
if result.len() != allocsz as usize {
|
||||
@ -226,7 +217,7 @@ impl BootSetup<'_> {
|
||||
|
||||
let pfn = (image_info.virt_hypercall - image_info.virt_base) >> X86_PAGE_SHIFT;
|
||||
let mfn = self.phys.p2m[pfn as usize];
|
||||
self.domctl.hypercall_init(self.domid, mfn)?;
|
||||
self.call.hypercall_init(self.domid, mfn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -241,8 +232,6 @@ impl BootSetup<'_> {
|
||||
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
|
||||
max_vcpus, mem_mb
|
||||
);
|
||||
self.domctl.set_max_vcpus(self.domid, max_vcpus)?;
|
||||
self.domctl.set_max_mem(self.domid, mem_mb * 1024)?;
|
||||
|
||||
let total_pages = mem_mb << (20 - X86_PAGE_SHIFT);
|
||||
self.initialize_memory(total_pages)?;
|
||||
@ -284,8 +273,8 @@ impl BootSetup<'_> {
|
||||
}
|
||||
|
||||
let initrd_segment = initrd_segment.unwrap();
|
||||
let store_evtchn = self.domctl.call.evtchn_alloc_unbound(self.domid, 0)?;
|
||||
let console_evtchn = self.domctl.call.evtchn_alloc_unbound(self.domid, 0)?;
|
||||
let store_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0)?;
|
||||
let console_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0)?;
|
||||
let state = BootState {
|
||||
kernel_segment,
|
||||
start_info_segment,
|
||||
@ -306,7 +295,7 @@ impl BootSetup<'_> {
|
||||
}
|
||||
|
||||
pub fn boot(&mut self, state: &mut BootState, cmdline: &str) -> Result<(), XenClientError> {
|
||||
let domain_info = self.domctl.get_domain_info(self.domid)?;
|
||||
let domain_info = self.call.get_domain_info(self.domid)?;
|
||||
let shared_info_frame = domain_info.shared_info_frame;
|
||||
state.shared_info_frame = shared_info_frame;
|
||||
self.setup_page_tables(state)?;
|
||||
@ -317,7 +306,7 @@ impl BootSetup<'_> {
|
||||
self.phys.unmap(pg_pfn)?;
|
||||
self.phys.unmap(state.p2m_segment.pfn)?;
|
||||
let pg_mfn = self.phys.p2m[pg_pfn as usize];
|
||||
self.memctl
|
||||
self.call
|
||||
.mmuext(self.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)?;
|
||||
self.setup_shared_info(state.shared_info_frame)?;
|
||||
|
||||
@ -346,7 +335,7 @@ impl BootSetup<'_> {
|
||||
vcpu.kernel_ss = vcpu.user_regs.ss as u64;
|
||||
vcpu.kernel_sp = vcpu.user_regs.rsp;
|
||||
debug!("vcpu context: {:?}", vcpu);
|
||||
self.domctl.set_vcpu_context(self.domid, 0, &vcpu)?;
|
||||
self.call.set_vcpu_context(self.domid, 0, &vcpu)?;
|
||||
self.phys.unmap_all()?;
|
||||
self.gnttab_seed(state)?;
|
||||
Ok(())
|
||||
@ -356,13 +345,10 @@ impl BootSetup<'_> {
|
||||
let console_gfn = self.phys.p2m[state.console_segment.pfn as usize];
|
||||
let xenstore_gfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
|
||||
let addr = self
|
||||
.domctl
|
||||
.call
|
||||
.mmap(0, 1 << XEN_PAGE_SHIFT)
|
||||
.ok_or(XenClientError::new("failed to mmap for resource"))?;
|
||||
self.domctl
|
||||
.call
|
||||
.map_resource(self.domid, 1, 0, 0, 1, addr)?;
|
||||
self.call.map_resource(self.domid, 1, 0, 0, 1, addr)?;
|
||||
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
|
||||
entries[0].flags = 1 << 0;
|
||||
entries[0].domid = 0;
|
||||
|
@ -1,19 +1,27 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct DomainConfig {
|
||||
vm_entries: HashMap<String, String>,
|
||||
domain_entries: HashMap<String, String>,
|
||||
pub max_vcpus: u32,
|
||||
pub mem_mb: u64,
|
||||
pub kernel_path: String,
|
||||
pub initrd_path: String,
|
||||
pub cmdline: String,
|
||||
}
|
||||
|
||||
pub struct PvDomainConfig {
|
||||
pub struct PvDomainStore {
|
||||
kernel: String,
|
||||
ramdisk: Option<String>,
|
||||
cmdline: Option<String>,
|
||||
}
|
||||
|
||||
impl DomainConfig {
|
||||
pub fn new() -> DomainConfig {
|
||||
DomainConfig {
|
||||
pub struct DomainStore {
|
||||
vm_entries: HashMap<String, String>,
|
||||
domain_entries: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl DomainStore {
|
||||
pub fn new() -> DomainStore {
|
||||
DomainStore {
|
||||
vm_entries: HashMap::new(),
|
||||
domain_entries: HashMap::new(),
|
||||
}
|
||||
@ -43,7 +51,7 @@ impl DomainConfig {
|
||||
|
||||
pub fn configure_cpus(&mut self, _maxvcpus: u32) {}
|
||||
|
||||
pub fn configure_pv(&mut self, pv: PvDomainConfig) {
|
||||
pub fn configure_pv(&mut self, pv: PvDomainStore) {
|
||||
self.put_vm_str("image/ostype", "linux");
|
||||
self.put_vm("image/kernel", pv.kernel);
|
||||
|
||||
@ -67,15 +75,15 @@ impl DomainConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DomainConfig {
|
||||
impl Default for DomainStore {
|
||||
fn default() -> Self {
|
||||
DomainConfig::new()
|
||||
DomainStore::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl PvDomainConfig {
|
||||
pub fn new(kernel: String, ramdisk: Option<String>, cmdline: Option<String>) -> PvDomainConfig {
|
||||
PvDomainConfig {
|
||||
impl PvDomainStore {
|
||||
pub fn new(kernel: String, ramdisk: Option<String>, cmdline: Option<String>) -> PvDomainStore {
|
||||
PvDomainStore {
|
||||
kernel,
|
||||
ramdisk,
|
||||
cmdline,
|
||||
|
@ -5,16 +5,19 @@ pub mod mem;
|
||||
pub mod sys;
|
||||
mod x86;
|
||||
|
||||
use crate::boot::BootSetup;
|
||||
use crate::create::DomainConfig;
|
||||
use crate::elfloader::ElfImageLoader;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::fs::read;
|
||||
use std::string::FromUtf8Error;
|
||||
use xencall::domctl::DomainControl;
|
||||
use uuid::Uuid;
|
||||
use xencall::sys::CreateDomain;
|
||||
use xencall::{XenCall, XenCallError};
|
||||
use xenevtchn::EventChannelError;
|
||||
use xenstore::bus::XsdBusError;
|
||||
use xenstore::client::{XsdClient, XsdInterface};
|
||||
use xenstore::client::{XsPermissions, XsdClient, XsdInterface};
|
||||
|
||||
pub struct XenClient {
|
||||
store: XsdClient,
|
||||
@ -83,29 +86,208 @@ impl XenClient {
|
||||
Ok(XenClient { store, call })
|
||||
}
|
||||
|
||||
pub fn create(&mut self, config: DomainConfig) -> Result<(), XenClientError> {
|
||||
let domctl = DomainControl::new(&self.call);
|
||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
||||
let domain = self.store.get_domain_path(domid)?;
|
||||
let vm = self.store.read_string(format!("{}/vm", domain).as_str())?;
|
||||
pub fn create(&mut self, config: DomainConfig) -> Result<u32, XenClientError> {
|
||||
let domain = CreateDomain {
|
||||
max_vcpus: config.max_vcpus,
|
||||
..Default::default()
|
||||
};
|
||||
let domid = self.call.create_domain(domain)?;
|
||||
let dom_path = self.store.get_domain_path(domid)?;
|
||||
let uuid_string = Uuid::from_bytes(domain.handle).to_string();
|
||||
let vm_path = format!("/vm/{}", uuid_string);
|
||||
let libxl_path = format!("/libxl/{}", domid);
|
||||
|
||||
let ro_perm = XsPermissions { id: 0, perms: 0 };
|
||||
|
||||
let rw_perm = XsPermissions { id: 0, perms: 0 };
|
||||
|
||||
let no_perm = XsPermissions { id: 0, perms: 0 };
|
||||
|
||||
{
|
||||
let mut tx = self.store.transaction()?;
|
||||
|
||||
tx.rm(dom_path.as_str())?;
|
||||
tx.mknod(dom_path.as_str(), &ro_perm)?;
|
||||
|
||||
tx.rm(vm_path.as_str())?;
|
||||
tx.mknod(vm_path.as_str(), &ro_perm)?;
|
||||
|
||||
tx.rm(libxl_path.as_str())?;
|
||||
tx.mknod(vm_path.as_str(), &no_perm)?;
|
||||
tx.mknod(format!("{}/device", vm_path).as_str(), &no_perm)?;
|
||||
|
||||
tx.write_string(format!("{}/vm", dom_path).as_str(), &vm_path)?;
|
||||
|
||||
tx.mknod(format!("{}/cpu", dom_path).as_str(), &ro_perm)?;
|
||||
tx.mknod(format!("{}/memory", dom_path).as_str(), &ro_perm)?;
|
||||
|
||||
tx.mknod(format!("{}/control", dom_path).as_str(), &ro_perm)?;
|
||||
|
||||
tx.mknod(format!("{}/control/shutdown", dom_path).as_str(), &rw_perm)?;
|
||||
tx.mknod(
|
||||
format!("{}/control/feature-poweroff", dom_path).as_str(),
|
||||
&rw_perm,
|
||||
)?;
|
||||
tx.mknod(
|
||||
format!("{}/control/feature-reboot", dom_path).as_str(),
|
||||
&rw_perm,
|
||||
)?;
|
||||
tx.mknod(
|
||||
format!("{}/control/feature-suspend", dom_path).as_str(),
|
||||
&rw_perm,
|
||||
)?;
|
||||
tx.mknod(format!("{}/control/sysrq", dom_path).as_str(), &rw_perm)?;
|
||||
|
||||
tx.mknod(format!("{}/data", dom_path).as_str(), &rw_perm)?;
|
||||
tx.mknod(format!("{}/drivers", dom_path).as_str(), &rw_perm)?;
|
||||
tx.mknod(format!("{}/feature", dom_path).as_str(), &rw_perm)?;
|
||||
tx.mknod(format!("{}/attr", dom_path).as_str(), &rw_perm)?;
|
||||
tx.mknod(format!("{}/error", dom_path).as_str(), &rw_perm)?;
|
||||
|
||||
tx.write_string(
|
||||
format!("{}/uuid", vm_path).as_str(),
|
||||
&Uuid::from_bytes(domain.handle).to_string(),
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/name", vm_path).as_str(),
|
||||
"mycelium",
|
||||
)?;
|
||||
tx.write_string(format!("{}/type", libxl_path).as_str(), "pv")?;
|
||||
tx.commit()?;
|
||||
}
|
||||
|
||||
self.call.set_max_vcpus(domid, config.max_vcpus)?;
|
||||
self.call.set_max_mem(domid, config.mem_mb * 1024)?;
|
||||
let image_loader = ElfImageLoader::load_file_kernel(config.kernel_path.as_str())?;
|
||||
|
||||
let console_evtchn: u32;
|
||||
let xenstore_evtchn: u32;
|
||||
let console_mfn: u64;
|
||||
let xenstore_mfn: u64;
|
||||
|
||||
{
|
||||
let mut boot = BootSetup::new(&self.call, domid);
|
||||
let initrd = read(config.initrd_path.as_str())?;
|
||||
let mut state = boot.initialize(
|
||||
&image_loader,
|
||||
initrd.as_slice(),
|
||||
config.max_vcpus,
|
||||
config.mem_mb,
|
||||
)?;
|
||||
boot.boot(&mut state, config.cmdline.as_str())?;
|
||||
console_evtchn = state.console_evtchn;
|
||||
xenstore_evtchn = state.store_evtchn;
|
||||
console_mfn = boot.phys.p2m[state.console_segment.pfn as usize];
|
||||
xenstore_mfn = boot.phys.p2m[state.xenstore_segment.pfn as usize];
|
||||
}
|
||||
|
||||
{
|
||||
let mut tx = self.store.transaction()?;
|
||||
tx.write_string(
|
||||
format!("{}/image/os_type", vm_path).as_str(),
|
||||
"linux",
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/image/kernel", vm_path).as_str(),
|
||||
&config.kernel_path,
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/image/ramdisk", vm_path).as_str(),
|
||||
&config.initrd_path,
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/image/cmdline", vm_path).as_str(),
|
||||
&config.cmdline,
|
||||
)?;
|
||||
|
||||
tx.write_string(
|
||||
format!("{}/memory/static-max", dom_path).as_str(),
|
||||
&(config.mem_mb * 1024).to_string(),
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/memory/target", dom_path).as_str(),
|
||||
&(config.mem_mb * 1024).to_string(),
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/memory/videoram", dom_path).as_str(),
|
||||
"0",
|
||||
)?;
|
||||
tx.write_string(format!("{}/domid", dom_path).as_str(), &domid.to_string())?;
|
||||
tx.write_string(
|
||||
format!("{}/store/port", dom_path).as_str(),
|
||||
&xenstore_evtchn.to_string(),
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/store/ring-ref", dom_path).as_str(),
|
||||
&xenstore_mfn.to_string(),
|
||||
)?;
|
||||
for i in 0..config.max_vcpus {
|
||||
tx.write_string(
|
||||
format!("{}/cpu/{}/availability", dom_path, i).as_str(),
|
||||
"online",
|
||||
)?;
|
||||
}
|
||||
tx.commit()?;
|
||||
}
|
||||
|
||||
self.console_device_add(&dom_path.to_string(), domid, console_evtchn, console_mfn)?;
|
||||
self.store
|
||||
.introduce_domain(domid, xenstore_mfn, xenstore_evtchn)?;
|
||||
self.call.unpause_domain(domid)?;
|
||||
|
||||
Ok(domid)
|
||||
}
|
||||
|
||||
fn console_device_add(
|
||||
&mut self,
|
||||
dom_path: &String,
|
||||
domid: u32,
|
||||
port: u32,
|
||||
mfn: u64,
|
||||
) -> Result<(), XenClientError> {
|
||||
let frontend_path = format!("{}/console", dom_path);
|
||||
let backend_path = format!("{}/backend/console/{}/{}", dom_path, domid, 0);
|
||||
let mut tx = self.store.transaction()?;
|
||||
tx.write_string(
|
||||
format!("{}/frontend-id", backend_path).as_str(),
|
||||
&domid.to_string(),
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/online", backend_path).as_str(),
|
||||
"1",
|
||||
)?;
|
||||
tx.write_string(format!("{}/state", backend_path).as_str(), "1")?;
|
||||
tx.write_string(
|
||||
format!("{}/protocol", backend_path).as_str(),
|
||||
"vt100",
|
||||
)?;
|
||||
|
||||
for (key, value) in config.clone_domain_entries() {
|
||||
let path = format!("{}/{}", domain, key);
|
||||
tx.write(path.as_str(), value.into_bytes())?;
|
||||
}
|
||||
|
||||
let domid_path = format!("{}/domid", domain);
|
||||
tx.write(domid_path.as_str(), domid.to_string().into_bytes())?;
|
||||
|
||||
for (key, value) in config.clone_domain_entries() {
|
||||
let path = format!("{}/{}", vm, key);
|
||||
tx.write(path.as_str(), value.into_bytes())?;
|
||||
}
|
||||
|
||||
tx.write_string(
|
||||
format!("{}/backend-id", frontend_path).as_str(),
|
||||
"0",
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/limit", frontend_path).as_str(),
|
||||
"1048576",
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/type", frontend_path).as_str(),
|
||||
"xenconsoled",
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/output", frontend_path).as_str(),
|
||||
"pty",
|
||||
)?;
|
||||
tx.write_string(format!("{}/tty", frontend_path).as_str(), "")?;
|
||||
tx.write_string(
|
||||
format!("{}/port", frontend_path).as_str(),
|
||||
&port.to_string(),
|
||||
)?;
|
||||
tx.write_string(
|
||||
format!("{}/ring-ref", frontend_path).as_str(),
|
||||
&mfn.to_string(),
|
||||
)?;
|
||||
tx.commit()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::sys::{XsdMessageHeader, XSD_ERROR};
|
||||
use std::error::Error;
|
||||
use std::ffi::{CString, FromVecWithNulError, NulError};
|
||||
use std::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
|
||||
use std::fs::metadata;
|
||||
use std::io::{Read, Write};
|
||||
use std::mem::size_of;
|
||||
@ -83,6 +83,12 @@ impl From<ParseIntError> for XsdBusError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IntoStringError> for XsdBusError {
|
||||
fn from(_: IntoStringError) -> Self {
|
||||
XsdBusError::new("Unable to coerce data into a string.")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XsdSocket {
|
||||
handle: UnixStream,
|
||||
}
|
||||
@ -95,7 +101,7 @@ pub struct XsdResponse {
|
||||
|
||||
impl XsdResponse {
|
||||
pub fn parse_string(&self) -> Result<String, XsdBusError> {
|
||||
Ok(String::from_utf8(self.payload.clone())?)
|
||||
Ok(CString::from_vec_with_nul(self.payload.clone())?.into_string()?)
|
||||
}
|
||||
|
||||
pub fn parse_string_vec(&self) -> Result<Vec<String>, XsdBusError> {
|
||||
@ -114,8 +120,10 @@ impl XsdResponse {
|
||||
}
|
||||
|
||||
pub fn parse_bool(&self) -> Result<bool, XsdBusError> {
|
||||
if self.payload.len() != 1 {
|
||||
Err(XsdBusError::new("Expected payload to be a single byte."))
|
||||
if self.payload.is_empty() {
|
||||
Err(XsdBusError::new(
|
||||
"Expected bool payload to be at least one byte.",
|
||||
))
|
||||
} else {
|
||||
Ok(self.payload[0] == 0)
|
||||
}
|
||||
|
@ -9,14 +9,23 @@ pub struct XsdClient {
|
||||
pub socket: XsdSocket,
|
||||
}
|
||||
|
||||
pub struct XsPermissions {
|
||||
pub id: u32,
|
||||
pub perms: u32,
|
||||
}
|
||||
|
||||
pub trait XsdInterface {
|
||||
fn list(&mut self, path: &str) -> Result<Vec<String>, XsdBusError>;
|
||||
fn read(&mut self, path: &str) -> Result<Vec<u8>, XsdBusError>;
|
||||
fn read_string(&mut self, path: &str) -> Result<String, XsdBusError>;
|
||||
fn write(&mut self, path: &str, data: Vec<u8>) -> Result<bool, XsdBusError>;
|
||||
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError>;
|
||||
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError>;
|
||||
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError>;
|
||||
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError>;
|
||||
|
||||
fn mknod(&mut self, path: &str, _perm: &XsPermissions) -> Result<bool, XsdBusError> {
|
||||
self.write_string(path, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl XsdClient {
|
||||
@ -53,8 +62,9 @@ impl XsdClient {
|
||||
}
|
||||
|
||||
pub fn transaction(&mut self) -> Result<XsdTransaction, XsdBusError> {
|
||||
let response = self.socket.send(0, XSD_TRANSACTION_START, &[])?;
|
||||
let tx = response.parse_string()?.parse::<u32>()?;
|
||||
let response = self.socket.send_single(0, XSD_TRANSACTION_START, "")?;
|
||||
let str = response.parse_string()?;
|
||||
let tx = str.parse::<u32>()?;
|
||||
Ok(XsdTransaction { client: self, tx })
|
||||
}
|
||||
|
||||
@ -68,7 +78,7 @@ impl XsdClient {
|
||||
pub fn introduce_domain(
|
||||
&mut self,
|
||||
domid: u32,
|
||||
mfn: u32,
|
||||
mfn: u64,
|
||||
eventchn: u32,
|
||||
) -> Result<String, XsdBusError> {
|
||||
let response = self.socket.send_multiple(
|
||||
@ -106,8 +116,8 @@ impl XsdInterface for XsdClient {
|
||||
self.write(0, path, data)
|
||||
}
|
||||
|
||||
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError> {
|
||||
self.write(0, path, data.into_bytes())
|
||||
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError> {
|
||||
self.write(0, path, data.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
||||
@ -136,8 +146,8 @@ impl XsdInterface for XsdTransaction<'_> {
|
||||
self.client.write(self.tx, path, data)
|
||||
}
|
||||
|
||||
fn write_string(&mut self, path: &str, data: String) -> Result<bool, XsdBusError> {
|
||||
self.client.write(self.tx, path, data.into_bytes())
|
||||
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError> {
|
||||
self.client.write(self.tx, path, data.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
||||
|
Loading…
Reference in New Issue
Block a user