zx/
guest.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{
6    AsHandleRef, HandleBased, HandleRef, NullableHandle, Port, Resource, Status, Vmar, ok, sys,
7};
8
9/// Wrapper type for guest physical addresses.
10#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
11#[repr(transparent)]
12pub struct GPAddr(pub usize);
13
14/// An object representing a Zircon guest
15///
16/// As essentially a subtype of `NullableHandle`, it can be freely interconverted.
17#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
18#[repr(transparent)]
19pub struct Guest(NullableHandle);
20impl_handle_based!(Guest);
21
22impl Guest {
23    pub fn create(hypervisor: &Resource) -> Result<(Guest, Vmar), Status> {
24        unsafe {
25            let mut guest_handle = 0;
26            let mut vmar_handle = 0;
27            ok(sys::zx_guest_create(
28                hypervisor.raw_handle(),
29                0,
30                &mut guest_handle,
31                &mut vmar_handle,
32            ))?;
33            Ok((
34                Self::from(NullableHandle::from_raw(guest_handle)),
35                Vmar::from(NullableHandle::from_raw(vmar_handle)),
36            ))
37        }
38    }
39
40    /// Set a bell trap for the given guest physical address range that will be delivered on the specified `Port`.
41    pub fn set_trap_bell(
42        &self,
43        addr: GPAddr,
44        size: usize,
45        port: &Port,
46        key: u64,
47    ) -> Result<(), Status> {
48        ok(unsafe {
49            sys::zx_guest_set_trap(
50                self.raw_handle(),
51                sys::ZX_GUEST_TRAP_BELL,
52                addr.0,
53                size,
54                port.raw_handle(),
55                key,
56            )
57        })
58    }
59
60    /// Set a memory trap for the given guest physical address range.
61    ///
62    /// The trap will be delivered through calls to `Resume` on the guests `Vcpu`.
63    pub fn set_mem_trap(&self, addr: GPAddr, size: usize, key: u64) -> Result<(), Status> {
64        ok(unsafe {
65            sys::zx_guest_set_trap(
66                self.raw_handle(),
67                sys::ZX_GUEST_TRAP_MEM,
68                addr.0,
69                size,
70                sys::ZX_HANDLE_INVALID,
71                key,
72            )
73        })
74    }
75
76    /// Set an IO trap for the given port range in the guest.
77    ///
78    /// The trap will be delivered through calls to `Resume` on the guests `Vcpu`.
79    pub fn set_io_trap(&self, addr: u16, size: u16, key: u64) -> Result<(), Status> {
80        ok(unsafe {
81            sys::zx_guest_set_trap(
82                self.raw_handle(),
83                sys::ZX_GUEST_TRAP_IO,
84                addr.into(),
85                size.into(),
86                sys::ZX_HANDLE_INVALID,
87                key,
88            )
89        })
90    }
91}
92
93// Below are types and implementations for parts of guest trap packets that allow the type safe
94// wrappers to provide constrained values.
95
96/// Represents the default operand size as specified by the CS descriptor.
97#[derive(Debug, Clone, Copy)]
98pub enum CSDefaultOperandSize {
99    Bits16 = 2,
100    Bits32 = 4,
101}
102
103#[derive(Debug, Clone, Copy)]
104pub enum MemAccessSize {
105    Bits8 = 1,
106    Bits16 = 2,
107    Bits32 = 4,
108    Bits64 = 8,
109}
110
111#[derive(Debug, Clone, Copy)]
112pub enum MemData {
113    Data8(u8),
114    Data16(u16),
115    Data32(u32),
116    Data64(u64),
117}
118
119#[derive(Debug, Clone, Copy)]
120pub enum PortAccessSize {
121    Bits8 = 1,
122    Bits16 = 2,
123    Bits32 = 4,
124}
125
126#[derive(Debug, Clone, Copy)]
127pub enum AccessType {
128    Read,
129    Write,
130}
131
132#[derive(Debug, Clone, Copy)]
133pub enum PortData {
134    Data8(u8),
135    Data16(u16),
136    Data32(u32),
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use fidl_fuchsia_kernel as fkernel;
143    use fuchsia_component::client::connect_to_protocol;
144    use zx::HandleBased;
145
146    async fn get_hypervisor() -> Resource {
147        let resource = connect_to_protocol::<fkernel::HypervisorResourceMarker>()
148            .unwrap()
149            .get()
150            .await
151            .unwrap();
152        unsafe { Resource::from(NullableHandle::from_raw(resource.into_raw())) }
153    }
154
155    #[fuchsia::test]
156    async fn guest_create() {
157        let hypervisor = get_hypervisor().await;
158        match Guest::create(&hypervisor) {
159            Err(Status::NOT_SUPPORTED) => {
160                println!("Hypervisor not supported");
161                return;
162            }
163            result => result.unwrap(),
164        };
165    }
166}