use crate::{ok, sys, AsHandleRef, Guest, Handle, HandleBased, HandleRef, Packet, Status};
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Vcpu(Handle);
impl_handle_based!(Vcpu);
impl Vcpu {
pub fn create(guest: &Guest, entry: usize) -> Result<Vcpu, Status> {
unsafe {
let mut vcpu_handle = 0;
ok(sys::zx_vcpu_create(guest.raw_handle(), 0, entry, &mut vcpu_handle))?;
Ok(Self::from(Handle::from_raw(vcpu_handle)))
}
}
pub fn enter(&self) -> Result<Packet, Status> {
let mut packet = Default::default();
ok(unsafe { sys::zx_vcpu_enter(self.raw_handle(), &mut packet) })?;
Ok(Packet(packet))
}
pub fn kick(&self) -> Result<(), Status> {
ok(unsafe { sys::zx_vcpu_kick(self.raw_handle()) })
}
pub fn interrupt(&self, vector: u32) -> Result<(), Status> {
ok(unsafe { sys::zx_vcpu_interrupt(self.raw_handle(), vector) })
}
pub fn read_state(&self) -> Result<sys::zx_vcpu_state_t, Status> {
let mut state = sys::zx_vcpu_state_t::default();
let status = unsafe {
sys::zx_vcpu_read_state(
self.raw_handle(),
sys::ZX_VCPU_STATE,
std::ptr::from_mut(&mut state).cast::<u8>(),
std::mem::size_of_val(&state),
)
};
ok(status).map(|_| state)
}
pub fn write_state(&self, state: &sys::zx_vcpu_state_t) -> Result<(), Status> {
let status = unsafe {
sys::zx_vcpu_write_state(
self.raw_handle(),
sys::ZX_VCPU_STATE,
std::ptr::from_ref(state).cast::<u8>(),
std::mem::size_of_val(state),
)
};
ok(status)
}
pub fn write_io(&self, state: &sys::zx_vcpu_io_t) -> Result<(), Status> {
let status = unsafe {
sys::zx_vcpu_write_state(
self.raw_handle(),
sys::ZX_VCPU_IO,
std::ptr::from_ref(state).cast::<u8>(),
std::mem::size_of_val(state),
)
};
ok(status)
}
}
#[derive(Debug, Clone, Copy)]
pub enum VcpuContents {
Interrupt { mask: u64, vector: u8 },
Startup { id: u64, entry: sys::zx_gpaddr_t },
Exit { retcode: i64 },
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Resource;
use fidl_fuchsia_kernel as fkernel;
use fuchsia_component::client::connect_to_protocol;
use zx::HandleBased;
async fn get_hypervisor() -> Resource {
let resource = connect_to_protocol::<fkernel::HypervisorResourceMarker>()
.unwrap()
.get()
.await
.unwrap();
unsafe { Resource::from(Handle::from_raw(resource.into_raw())) }
}
#[fuchsia::test]
async fn vcpu_normal_create() {
let hypervisor = get_hypervisor().await;
let (guest, _vmar) = match Guest::normal(&hypervisor) {
Err(Status::NOT_SUPPORTED) => {
println!("Hypervisor not supported");
return;
}
result => result.unwrap(),
};
let _vcpu = Vcpu::create(&guest, 0).unwrap();
}
#[fuchsia::test]
async fn vcpu_normal_interrupt() {
let hypervisor = get_hypervisor().await;
let (guest, _vmar) = match Guest::normal(&hypervisor) {
Err(Status::NOT_SUPPORTED) => {
println!("Hypervisor not supported");
return;
}
result => result.unwrap(),
};
let vcpu = Vcpu::create(&guest, 0).unwrap();
vcpu.interrupt(0).unwrap();
}
#[fuchsia::test]
async fn vcpu_normal_read_write_state() {
let hypervisor = get_hypervisor().await;
let (guest, _vmar) = match Guest::normal(&hypervisor) {
Err(Status::NOT_SUPPORTED) => {
println!("Hypervisor not supported");
return;
}
result => result.unwrap(),
};
let vcpu = Vcpu::create(&guest, 0).unwrap();
let state = vcpu.read_state().unwrap();
vcpu.write_state(&state).unwrap();
}
}