1use crate::{AsHandleRef, Guest, Handle, HandleBased, HandleRef, Packet, Status, ok, sys};
6
7#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
8#[repr(transparent)]
9pub struct Vcpu(Handle);
10impl_handle_based!(Vcpu);
11
12impl Vcpu {
13 pub fn create(guest: &Guest, entry: usize) -> Result<Vcpu, Status> {
15 unsafe {
16 let mut vcpu_handle = 0;
17 ok(sys::zx_vcpu_create(guest.raw_handle(), 0, entry, &mut vcpu_handle))?;
18 Ok(Self::from(Handle::from_raw(vcpu_handle)))
19 }
20 }
21
22 pub fn enter(&self) -> Result<Packet, Status> {
24 let mut packet = Default::default();
25 ok(unsafe { sys::zx_vcpu_enter(self.raw_handle(), &mut packet) })?;
26 Ok(Packet(packet))
27 }
28
29 pub fn kick(&self) -> Result<(), Status> {
31 ok(unsafe { sys::zx_vcpu_kick(self.raw_handle()) })
32 }
33
34 pub fn interrupt(&self, vector: u32) -> Result<(), Status> {
36 ok(unsafe { sys::zx_vcpu_interrupt(self.raw_handle(), vector) })
37 }
38
39 pub fn read_state(&self) -> Result<sys::zx_vcpu_state_t, Status> {
41 let mut state = sys::zx_vcpu_state_t::default();
42 let status = unsafe {
43 sys::zx_vcpu_read_state(
44 self.raw_handle(),
45 sys::ZX_VCPU_STATE,
46 std::ptr::from_mut(&mut state).cast::<u8>(),
47 std::mem::size_of_val(&state),
48 )
49 };
50 ok(status).map(|_| state)
51 }
52
53 pub fn write_state(&self, state: &sys::zx_vcpu_state_t) -> Result<(), Status> {
55 let status = unsafe {
56 sys::zx_vcpu_write_state(
57 self.raw_handle(),
58 sys::ZX_VCPU_STATE,
59 std::ptr::from_ref(state).cast::<u8>(),
60 std::mem::size_of_val(state),
61 )
62 };
63 ok(status)
64 }
65
66 pub fn write_io(&self, state: &sys::zx_vcpu_io_t) -> Result<(), Status> {
68 let status = unsafe {
69 sys::zx_vcpu_write_state(
70 self.raw_handle(),
71 sys::ZX_VCPU_IO,
72 std::ptr::from_ref(state).cast::<u8>(),
73 std::mem::size_of_val(state),
74 )
75 };
76 ok(status)
77 }
78}
79
80#[derive(Debug, Clone, Copy)]
81pub enum VcpuContents {
82 Interrupt { mask: u64, vector: u8 },
83 Startup { id: u64, entry: sys::zx_gpaddr_t },
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::Resource;
90 use fidl_fuchsia_kernel as fkernel;
91 use fuchsia_component::client::connect_to_protocol;
92 use zx::HandleBased;
93
94 async fn get_hypervisor() -> Resource {
95 let resource = connect_to_protocol::<fkernel::HypervisorResourceMarker>()
96 .unwrap()
97 .get()
98 .await
99 .unwrap();
100 unsafe { Resource::from(Handle::from_raw(resource.into_raw())) }
101 }
102
103 #[fuchsia::test]
104 async fn vcpu_create() {
105 let hypervisor = get_hypervisor().await;
106 let (guest, _vmar) = match Guest::create(&hypervisor) {
107 Err(Status::NOT_SUPPORTED) => {
108 println!("Hypervisor not supported");
109 return;
110 }
111 result => result.unwrap(),
112 };
113 let _vcpu = Vcpu::create(&guest, 0).unwrap();
114 }
115
116 #[fuchsia::test]
117 async fn vcpu_interrupt() {
118 let hypervisor = get_hypervisor().await;
119 let (guest, _vmar) = match Guest::create(&hypervisor) {
120 Err(Status::NOT_SUPPORTED) => {
121 println!("Hypervisor not supported");
122 return;
123 }
124 result => result.unwrap(),
125 };
126 let vcpu = Vcpu::create(&guest, 0).unwrap();
127
128 vcpu.interrupt(0).unwrap();
129 }
130
131 #[fuchsia::test]
132 async fn vcpu_read_write_state() {
133 let hypervisor = get_hypervisor().await;
134 let (guest, _vmar) = match Guest::create(&hypervisor) {
135 Err(Status::NOT_SUPPORTED) => {
136 println!("Hypervisor not supported");
137 return;
138 }
139 result => result.unwrap(),
140 };
141 let vcpu = Vcpu::create(&guest, 0).unwrap();
142
143 let state = vcpu.read_state().unwrap();
144 vcpu.write_state(&state).unwrap();
145 }
146}