1use crate::{ok, sys, AsHandleRef, Guest, Handle, HandleBased, HandleRef, Packet, Status};
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 Exit { retcode: i64 },
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use crate::Resource;
91 use fidl_fuchsia_kernel as fkernel;
92 use fuchsia_component::client::connect_to_protocol;
93 use zx::HandleBased;
94
95 async fn get_hypervisor() -> Resource {
96 let resource = connect_to_protocol::<fkernel::HypervisorResourceMarker>()
97 .unwrap()
98 .get()
99 .await
100 .unwrap();
101 unsafe { Resource::from(Handle::from_raw(resource.into_raw())) }
102 }
103
104 #[fuchsia::test]
105 async fn vcpu_normal_create() {
106 let hypervisor = get_hypervisor().await;
107 let (guest, _vmar) = match Guest::normal(&hypervisor) {
108 Err(Status::NOT_SUPPORTED) => {
109 println!("Hypervisor not supported");
110 return;
111 }
112 result => result.unwrap(),
113 };
114 let _vcpu = Vcpu::create(&guest, 0).unwrap();
115 }
116
117 #[fuchsia::test]
118 async fn vcpu_normal_interrupt() {
119 let hypervisor = get_hypervisor().await;
120 let (guest, _vmar) = match Guest::normal(&hypervisor) {
121 Err(Status::NOT_SUPPORTED) => {
122 println!("Hypervisor not supported");
123 return;
124 }
125 result => result.unwrap(),
126 };
127 let vcpu = Vcpu::create(&guest, 0).unwrap();
128
129 vcpu.interrupt(0).unwrap();
130 }
131
132 #[fuchsia::test]
133 async fn vcpu_normal_read_write_state() {
134 let hypervisor = get_hypervisor().await;
135 let (guest, _vmar) = match Guest::normal(&hypervisor) {
136 Err(Status::NOT_SUPPORTED) => {
137 println!("Hypervisor not supported");
138 return;
139 }
140 result => result.unwrap(),
141 };
142 let vcpu = Vcpu::create(&guest, 0).unwrap();
143
144 let state = vcpu.read_state().unwrap();
145 vcpu.write_state(&state).unwrap();
146 }
147}