| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| crate::{ok, AsHandleRef, Handle, HandleBased, HandleRef, Port, Resource, Status, Vmar}, |
| fuchsia_zircon_sys as sys, |
| }; |
| |
| /// Wrapper type for guest physical addresses. |
| #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] |
| #[repr(transparent)] |
| pub struct GPAddr(pub usize); |
| |
| /// An object representing a Zircon guest |
| /// |
| /// As essentially a subtype of `Handle`, it can be freely interconverted. |
| #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] |
| #[repr(transparent)] |
| pub struct Guest(Handle); |
| impl_handle_based!(Guest); |
| |
| impl Guest { |
| /// Create a normal guest, that is used to run normal virtual machines. |
| pub fn normal(hypervisor: &Resource) -> Result<(Guest, Vmar), Status> { |
| Self::create(hypervisor, sys::ZX_GUEST_OPT_NORMAL) |
| } |
| |
| fn create( |
| hypervisor: &Resource, |
| options: sys::zx_guest_option_t, |
| ) -> Result<(Guest, Vmar), Status> { |
| unsafe { |
| let mut guest_handle = 0; |
| let mut vmar_handle = 0; |
| ok(sys::zx_guest_create( |
| hypervisor.raw_handle(), |
| options, |
| &mut guest_handle, |
| &mut vmar_handle, |
| ))?; |
| Ok(( |
| Self::from(Handle::from_raw(guest_handle)), |
| Vmar::from(Handle::from_raw(vmar_handle)), |
| )) |
| } |
| } |
| |
| /// Set a bell trap for the given guest physical address range that will be delivered on the specified `Port`. |
| pub fn set_trap_bell( |
| &self, |
| addr: GPAddr, |
| size: usize, |
| port: &Port, |
| key: u64, |
| ) -> Result<(), Status> { |
| ok(unsafe { |
| sys::zx_guest_set_trap( |
| self.raw_handle(), |
| sys::ZX_GUEST_TRAP_BELL, |
| addr.0, |
| size, |
| port.raw_handle(), |
| key, |
| ) |
| }) |
| } |
| |
| /// Set a memory trap for the given guest physical address range. |
| /// |
| /// The trap will be delivered through calls to `Resume` on the guests `Vcpu`. |
| pub fn set_mem_trap(&self, addr: GPAddr, size: usize, key: u64) -> Result<(), Status> { |
| ok(unsafe { |
| sys::zx_guest_set_trap( |
| self.raw_handle(), |
| sys::ZX_GUEST_TRAP_MEM, |
| addr.0, |
| size, |
| sys::ZX_HANDLE_INVALID, |
| key, |
| ) |
| }) |
| } |
| |
| /// Set an IO trap for the given port range in the guest. |
| /// |
| /// The trap will be delivered through calls to `Resume` on the guests `Vcpu`. |
| pub fn set_io_trap(&self, addr: u16, size: u16, key: u64) -> Result<(), Status> { |
| ok(unsafe { |
| sys::zx_guest_set_trap( |
| self.raw_handle(), |
| sys::ZX_GUEST_TRAP_IO, |
| addr.into(), |
| size.into(), |
| sys::ZX_HANDLE_INVALID, |
| key, |
| ) |
| }) |
| } |
| } |
| |
| // Below are types and implementations for parts of guest trap packets that allow the type safe |
| // wrappers to provide constrained values. |
| |
| /// Represents the default operand size as specified by the CS descriptor. |
| #[derive(Debug, Clone, Copy)] |
| pub enum CSDefaultOperandSize { |
| Bits16 = 2, |
| Bits32 = 4, |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| pub enum MemAccessSize { |
| Bits8 = 1, |
| Bits16 = 2, |
| Bits32 = 4, |
| Bits64 = 8, |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| pub enum MemData { |
| Data8(u8), |
| Data16(u16), |
| Data32(u32), |
| Data64(u64), |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| pub enum PortAccessSize { |
| Bits8 = 1, |
| Bits16 = 2, |
| Bits32 = 4, |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| pub enum AccessType { |
| Read, |
| Write, |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| pub enum PortData { |
| Data8(u8), |
| Data16(u16), |
| Data32(u32), |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use { |
| super::*, fidl_fuchsia_kernel as fkernel, fuchsia_component::client::connect_to_protocol, |
| fuchsia_zircon::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 guest_normal_create() { |
| let hypervisor = get_hypervisor().await; |
| match Guest::normal(&hypervisor) { |
| Err(Status::NOT_SUPPORTED) => { |
| println!("Hypervisor not supported"); |
| return; |
| } |
| result => result.unwrap(), |
| }; |
| } |
| } |