blob: 33bd2d744d2d1c4960dff524548b5cdcef8b8e16 [file] [log] [blame]
Inseob Kimf3536de2024-11-22 14:00:57 +09001// Copyright 2024 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Stable C library for AVF.
16
17use std::ffi::CStr;
18use std::fs::File;
Inseob Kim32e299c2024-12-09 15:27:40 +090019use std::os::fd::{FromRawFd, IntoRawFd};
Inseob Kimf3536de2024-11-22 14:00:57 +090020use std::os::raw::{c_char, c_int};
21use std::ptr;
Inseob Kim06064252024-12-05 17:52:25 +090022use std::time::Duration;
Inseob Kimf3536de2024-11-22 14:00:57 +090023
24use android_system_virtualizationservice::{
25 aidl::android::system::virtualizationservice::{
Elie Kheirallahb4b2f242025-01-23 03:38:07 +000026 AssignedDevices::AssignedDevices, CpuOptions::CpuOptions,
Frederick Mayle31cc5b22024-12-19 14:42:43 -080027 CpuOptions::CpuTopology::CpuTopology, CustomMemoryBackingFile::CustomMemoryBackingFile,
28 DiskImage::DiskImage, IVirtualizationService::IVirtualizationService,
29 VirtualMachineConfig::VirtualMachineConfig,
Inseob Kimf3536de2024-11-22 14:00:57 +090030 VirtualMachineRawConfig::VirtualMachineRawConfig,
31 },
32 binder::{ParcelFileDescriptor, Strong},
33};
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -080034use avf_bindgen::AVirtualMachineStopReason;
Inseob Kim06064252024-12-05 17:52:25 +090035use libc::timespec;
Inseob Kim5faf0cb2024-12-16 20:10:11 +090036use log::error;
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -080037use vmclient::{DeathReason, VirtualizationService, VmInstance};
Inseob Kimf3536de2024-11-22 14:00:57 +090038
39/// Create a new virtual machine config object with no properties.
40#[no_mangle]
41pub extern "C" fn AVirtualMachineRawConfig_create() -> *mut VirtualMachineRawConfig {
42 let config = Box::new(VirtualMachineRawConfig {
43 platformVersion: "~1.0".to_owned(),
44 ..Default::default()
45 });
46 Box::into_raw(config)
47}
48
49/// Destroy a virtual machine config object.
50///
51/// # Safety
52/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `config` must not be
53/// used after deletion.
54#[no_mangle]
55pub unsafe extern "C" fn AVirtualMachineRawConfig_destroy(config: *mut VirtualMachineRawConfig) {
56 if !config.is_null() {
57 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
58 // AVirtualMachineRawConfig_create. It's the only reference to the object.
59 unsafe {
60 let _ = Box::from_raw(config);
61 }
62 }
63}
64
65/// Set a name of a virtual machine.
66///
67/// # Safety
68/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
69#[no_mangle]
70pub unsafe extern "C" fn AVirtualMachineRawConfig_setName(
71 config: *mut VirtualMachineRawConfig,
72 name: *const c_char,
73) -> c_int {
74 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
75 // AVirtualMachineRawConfig_create. It's the only reference to the object.
76 let config = unsafe { &mut *config };
77 // SAFETY: `name` is assumed to be a pointer to a valid C string.
Inseob Kim06064252024-12-05 17:52:25 +090078 let name = unsafe { CStr::from_ptr(name) };
79 match name.to_str() {
80 Ok(name) => {
81 config.name = name.to_owned();
82 0
83 }
84 Err(_) => -libc::EINVAL,
85 }
Inseob Kimf3536de2024-11-22 14:00:57 +090086}
87
88/// Set an instance ID of a virtual machine.
89///
90/// # Safety
91/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `instanceId` must be a
92/// valid, non-null pointer to 64-byte data.
93#[no_mangle]
94pub unsafe extern "C" fn AVirtualMachineRawConfig_setInstanceId(
95 config: *mut VirtualMachineRawConfig,
96 instance_id: *const u8,
Inseob Kim06064252024-12-05 17:52:25 +090097 instance_id_size: usize,
Inseob Kimf3536de2024-11-22 14:00:57 +090098) -> c_int {
Inseob Kim06064252024-12-05 17:52:25 +090099 if instance_id_size != 64 {
100 return -libc::EINVAL;
101 }
102
Inseob Kimf3536de2024-11-22 14:00:57 +0900103 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
104 // AVirtualMachineRawConfig_create. It's the only reference to the object.
105 let config = unsafe { &mut *config };
106 // SAFETY: `instanceId` is assumed to be a valid pointer to 64 bytes of memory. `config`
107 // is assumed to be a valid object returned by AVirtuaMachineConfig_create.
108 // Both never overlap.
109 unsafe {
Inseob Kim06064252024-12-05 17:52:25 +0900110 ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), instance_id_size);
Inseob Kimf3536de2024-11-22 14:00:57 +0900111 }
112 0
113}
114
115/// Set a kernel image of a virtual machine.
116///
117/// # Safety
118/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
119/// file descriptor or -1. `AVirtualMachineRawConfig_setKernel` takes ownership of `fd` and `fd`
120/// will be closed upon `AVirtualMachineRawConfig_delete`.
121#[no_mangle]
122pub unsafe extern "C" fn AVirtualMachineRawConfig_setKernel(
123 config: *mut VirtualMachineRawConfig,
124 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900125) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900126 let file = get_file_from_fd(fd);
127 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
128 // AVirtualMachineRawConfig_create. It's the only reference to the object.
129 let config = unsafe { &mut *config };
130 config.kernel = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900131}
132
133/// Set an init rd of a virtual machine.
134///
135/// # Safety
136/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
137/// file descriptor or -1. `AVirtualMachineRawConfig_setInitRd` takes ownership of `fd` and `fd`
138/// will be closed upon `AVirtualMachineRawConfig_delete`.
139#[no_mangle]
140pub unsafe extern "C" fn AVirtualMachineRawConfig_setInitRd(
141 config: *mut VirtualMachineRawConfig,
142 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900143) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900144 let file = get_file_from_fd(fd);
145 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
146 // AVirtualMachineRawConfig_create. It's the only reference to the object.
147 let config = unsafe { &mut *config };
148 config.initrd = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900149}
150
151/// Add a disk for a virtual machine.
152///
153/// # Safety
154/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
155/// file descriptor. `AVirtualMachineRawConfig_addDisk` takes ownership of `fd` and `fd` will be
156/// closed upon `AVirtualMachineRawConfig_delete`.
157#[no_mangle]
158pub unsafe extern "C" fn AVirtualMachineRawConfig_addDisk(
159 config: *mut VirtualMachineRawConfig,
160 fd: c_int,
161 writable: bool,
162) -> c_int {
163 let file = get_file_from_fd(fd);
164 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
165 // AVirtualMachineRawConfig_create. It's the only reference to the object.
166 let config = unsafe { &mut *config };
167 match file {
168 // partition not supported yet
169 None => -libc::EINVAL,
170 Some(file) => {
171 config.disks.push(DiskImage {
172 image: Some(ParcelFileDescriptor::new(file)),
173 writable,
174 ..Default::default()
175 });
176 0
177 }
178 }
179}
180
181/// Set how much memory will be given to a virtual machine.
182///
183/// # Safety
184/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
185#[no_mangle]
Frederick Mayleb4030cf2024-12-13 15:05:54 -0800186pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMiB(
Inseob Kimf3536de2024-11-22 14:00:57 +0900187 config: *mut VirtualMachineRawConfig,
188 memory_mib: i32,
Inseob Kim06064252024-12-05 17:52:25 +0900189) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900190 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
191 // AVirtualMachineRawConfig_create. It's the only reference to the object.
192 let config = unsafe { &mut *config };
193 config.memoryMib = memory_mib;
Inseob Kimf3536de2024-11-22 14:00:57 +0900194}
195
Frederick Mayle384f5b52024-12-06 16:23:23 -0800196/// Set how much swiotlb will be given to a virtual machine.
197///
198/// # Safety
199/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
200#[no_mangle]
201pub unsafe extern "C" fn AVirtualMachineRawConfig_setSwiotlbMiB(
202 config: *mut VirtualMachineRawConfig,
203 swiotlb_mib: i32,
204) {
205 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
206 // AVirtualMachineRawConfig_create. It's the only reference to the object.
207 let config = unsafe { &mut *config };
208 config.swiotlbMib = swiotlb_mib;
209}
210
Frederick Maylecc0eb2b2024-12-11 19:38:16 -0800211/// Set vCPU count.
212///
213/// # Safety
214/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
215#[no_mangle]
216pub unsafe extern "C" fn AVirtualMachineRawConfig_setVCpuCount(
217 config: *mut VirtualMachineRawConfig,
218 n: i32,
219) {
220 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
221 // AVirtualMachineRawConfig_create. It's the only reference to the object.
222 let config = unsafe { &mut *config };
Elie Kheirallahb4b2f242025-01-23 03:38:07 +0000223 config.cpuOptions = CpuOptions { cpuTopology: CpuTopology::CpuCount(n) };
Frederick Maylecc0eb2b2024-12-11 19:38:16 -0800224}
225
Inseob Kimf3536de2024-11-22 14:00:57 +0900226/// Set whether a virtual machine is protected or not.
227///
228/// # Safety
229/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
230#[no_mangle]
231pub unsafe extern "C" fn AVirtualMachineRawConfig_setProtectedVm(
232 config: *mut VirtualMachineRawConfig,
233 protected_vm: bool,
Inseob Kim06064252024-12-05 17:52:25 +0900234) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900235 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
236 // AVirtualMachineRawConfig_create. It's the only reference to the object.
237 let config = unsafe { &mut *config };
238 config.protectedVm = protected_vm;
Inseob Kimf3536de2024-11-22 14:00:57 +0900239}
240
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800241/// Set whether to use an alternate, hypervisor-specific authentication method for protected VMs.
Inseob Kimf3536de2024-11-22 14:00:57 +0900242///
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800243/// # Safety
244/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
Inseob Kimf3536de2024-11-22 14:00:57 +0900245#[no_mangle]
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800246pub unsafe extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
247 config: *mut VirtualMachineRawConfig,
248 enable: bool,
Inseob Kimf3536de2024-11-22 14:00:57 +0900249) -> c_int {
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800250 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
251 // AVirtualMachineRawConfig_create. It's the only reference to the object.
252 let config = unsafe { &mut *config };
253 config.enableHypervisorSpecificAuthMethod = enable;
254 // We don't validate whether this is supported until later, when the VM is started.
255 0
Inseob Kimf3536de2024-11-22 14:00:57 +0900256}
257
Frederick Mayle31cc5b22024-12-19 14:42:43 -0800258/// Use the specified fd as the backing memfd for a range of the guest physical memory.
Inseob Kimf3536de2024-11-22 14:00:57 +0900259///
Frederick Mayle31cc5b22024-12-19 14:42:43 -0800260/// # Safety
261/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
Inseob Kimf3536de2024-11-22 14:00:57 +0900262#[no_mangle]
Frederick Mayle31cc5b22024-12-19 14:42:43 -0800263pub unsafe extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
264 config: *mut VirtualMachineRawConfig,
265 fd: c_int,
266 range_start: u64,
267 range_end: u64,
Inseob Kimf3536de2024-11-22 14:00:57 +0900268) -> c_int {
Frederick Mayle31cc5b22024-12-19 14:42:43 -0800269 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
270 // AVirtualMachineRawConfig_create. It's the only reference to the object.
271 let config = unsafe { &mut *config };
272
273 let Some(file) = get_file_from_fd(fd) else {
274 return -libc::EINVAL;
275 };
276 let Some(size) = range_end.checked_sub(range_start) else {
277 return -libc::EINVAL;
278 };
279 config.customMemoryBackingFiles.push(CustomMemoryBackingFile {
280 file: Some(ParcelFileDescriptor::new(file)),
281 // AIDL doesn't support unsigned ints, so we've got to reinterpret the bytes into a signed
282 // int.
283 rangeStart: range_start as i64,
284 size: size as i64,
285 });
286 0
Inseob Kimf3536de2024-11-22 14:00:57 +0900287}
288
Jaewan Kimffc007c2024-12-12 22:15:35 +0900289/// Add device tree overlay blob
290///
291/// # Safety
292/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
293/// file descriptor or -1. `AVirtualMachineRawConfig_setDeviceTreeOverlay` takes ownership of `fd`
294/// and `fd` will be closed upon `AVirtualMachineRawConfig_delete`.
295#[no_mangle]
296pub unsafe extern "C" fn AVirtualMachineRawConfig_setDeviceTreeOverlay(
297 config: *mut VirtualMachineRawConfig,
298 fd: c_int,
299) {
300 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
301 // AVirtualMachineRawConfig_create. It's the only reference to the object.
302 let config = unsafe { &mut *config };
303
304 match get_file_from_fd(fd) {
305 Some(file) => {
306 let fd = ParcelFileDescriptor::new(file);
307 config.devices = AssignedDevices::Dtbo(Some(fd));
308 }
309 _ => {
310 config.devices = Default::default();
311 }
312 };
313}
314
Inseob Kimf3536de2024-11-22 14:00:57 +0900315/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
316/// AIDL service, and connect to the child process.
317///
318/// # Safety
319/// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
320#[no_mangle]
321pub unsafe extern "C" fn AVirtualizationService_create(
322 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
323 early: bool,
324) -> c_int {
325 let virtmgr =
326 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
327 let virtmgr = match virtmgr {
328 Ok(virtmgr) => virtmgr,
329 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
330 };
331 match virtmgr.connect() {
332 Ok(service) => {
333 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
334 // pointer. `service` is the only reference here and `config` takes
335 // ownership.
336 unsafe {
337 *service_ptr = Box::into_raw(Box::new(service));
338 }
339 0
340 }
341 Err(_) => -libc::ECONNREFUSED,
342 }
343}
344
345/// Destroy a VirtualizationService object.
346///
347/// # Safety
348/// `service` must be a pointer returned by `AVirtualizationService_create` or
349/// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
350#[no_mangle]
351pub unsafe extern "C" fn AVirtualizationService_destroy(
352 service: *mut Strong<dyn IVirtualizationService>,
353) {
354 if !service.is_null() {
355 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
356 // `AVirtualizationService_create`. It's the only reference to the object.
357 unsafe {
358 let _ = Box::from_raw(service);
359 }
360 }
361}
362
363/// Create a virtual machine with given `config`.
364///
365/// # Safety
366/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
367/// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
368/// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
369/// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
370/// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
371#[no_mangle]
372pub unsafe extern "C" fn AVirtualMachine_createRaw(
373 service: *const Strong<dyn IVirtualizationService>,
374 config: *mut VirtualMachineRawConfig,
375 console_out_fd: c_int,
376 console_in_fd: c_int,
377 log_fd: c_int,
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800378 vm_ptr: *mut *mut VmInstance,
Inseob Kimf3536de2024-11-22 14:00:57 +0900379) -> c_int {
380 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
381 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
382 // reference to the object.
383 let service = unsafe { &*service };
384
385 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
386 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
387 let config = unsafe { *Box::from_raw(config) };
388 let config = VirtualMachineConfig::RawConfig(config);
389
390 let console_out = get_file_from_fd(console_out_fd);
391 let console_in = get_file_from_fd(console_in_fd);
392 let log = get_file_from_fd(log_fd);
393
Jaewan Kimfcf98b22025-01-21 23:14:49 -0800394 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900395 Ok(vm) => {
396 // SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800397 // `vm` is the only reference here and `vm_ptr` takes ownership.
Inseob Kimf3536de2024-11-22 14:00:57 +0900398 unsafe {
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800399 *vm_ptr = Box::into_raw(Box::new(vm));
Inseob Kimf3536de2024-11-22 14:00:57 +0900400 }
401 0
402 }
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900403 Err(e) => {
404 error!("AVirtualMachine_createRaw failed: {e:?}");
405 -libc::EIO
406 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900407 }
408}
409
410/// Start a virtual machine.
411///
412/// # Safety
413/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
414#[no_mangle]
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800415pub unsafe extern "C" fn AVirtualMachine_start(vm: *const VmInstance) -> c_int {
Inseob Kimf3536de2024-11-22 14:00:57 +0900416 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
417 // `AVirtualMachine_createRaw`. It's the only reference to the object.
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800418 let vm = unsafe { &*vm };
Jaewan Kimfcf98b22025-01-21 23:14:49 -0800419 match vm.start(None) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900420 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900421 Err(e) => {
422 error!("AVirtualMachine_start failed: {e:?}");
423 -libc::EIO
424 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900425 }
426}
427
428/// Stop a virtual machine.
429///
430/// # Safety
431/// `vm` must be a pointer returned by `AVirtualMachine_create`.
432#[no_mangle]
433pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
434 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
435 // `AVirtualMachine_createRaw`. It's the only reference to the object.
436 let vm = unsafe { &*vm };
437 match vm.stop() {
438 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900439 Err(e) => {
440 error!("AVirtualMachine_stop failed: {e:?}");
441 -libc::EIO
442 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900443 }
444}
445
Inseob Kim32e299c2024-12-09 15:27:40 +0900446/// Open a vsock connection to the CID of the virtual machine on the given vsock port.
447///
448/// # Safety
449/// `vm` must be a pointer returned by `AVirtualMachine_create`.
450#[no_mangle]
451pub unsafe extern "C" fn AVirtualMachine_connectVsock(vm: *const VmInstance, port: u32) -> c_int {
452 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
453 // `AVirtualMachine_createRaw`. It's the only reference to the object.
454 let vm = unsafe { &*vm };
455 match vm.connect_vsock(port) {
456 Ok(pfd) => pfd.into_raw_fd(),
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900457 Err(e) => {
458 error!("AVirtualMachine_connectVsock failed: {e:?}");
459 -libc::EIO
460 }
Inseob Kim32e299c2024-12-09 15:27:40 +0900461 }
462}
463
Inseob Kim06064252024-12-05 17:52:25 +0900464fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
465 match death_reason {
466 DeathReason::VirtualizationServiceDied => {
467 AVirtualMachineStopReason::AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED
468 }
469 DeathReason::InfrastructureError => {
470 AVirtualMachineStopReason::AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR
471 }
472 DeathReason::Killed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_KILLED,
473 DeathReason::Unknown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNKNOWN,
474 DeathReason::Shutdown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN,
475 DeathReason::StartFailed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_START_FAILED,
476 DeathReason::Reboot => AVirtualMachineStopReason::AVIRTUAL_MACHINE_REBOOT,
477 DeathReason::Crash => AVirtualMachineStopReason::AVIRTUAL_MACHINE_CRASH,
478 DeathReason::PvmFirmwarePublicKeyMismatch => {
479 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH
480 }
481 DeathReason::PvmFirmwareInstanceImageChanged => {
482 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
483 }
484 DeathReason::Hangup => AVirtualMachineStopReason::AVIRTUAL_MACHINE_HANGUP,
485 _ => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED,
486 }
487}
488
489/// Wait until a virtual machine stops or the timeout elapses.
Inseob Kimf3536de2024-11-22 14:00:57 +0900490///
491/// # Safety
Inseob Kim06064252024-12-05 17:52:25 +0900492/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `timeout` must be a valid
493/// pointer to a `struct timespec` object or null. `reason` must be a valid, non-null pointer to an
494/// AVirtualMachineStopReason object.
Inseob Kimf3536de2024-11-22 14:00:57 +0900495#[no_mangle]
Inseob Kim06064252024-12-05 17:52:25 +0900496pub unsafe extern "C" fn AVirtualMachine_waitForStop(
497 vm: *const VmInstance,
498 timeout: *const timespec,
499 reason: *mut AVirtualMachineStopReason,
500) -> bool {
Inseob Kimf3536de2024-11-22 14:00:57 +0900501 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
502 // AVirtualMachine_create. It's the only reference to the object.
503 let vm = unsafe { &*vm };
Inseob Kim06064252024-12-05 17:52:25 +0900504
505 let death_reason = if timeout.is_null() {
506 vm.wait_for_death()
507 } else {
508 // SAFETY: `timeout` is assumed to be a valid pointer to a `struct timespec` object if
509 // non-null.
510 let timeout = unsafe { &*timeout };
511 let timeout = Duration::new(timeout.tv_sec as u64, timeout.tv_nsec as u32);
512 match vm.wait_for_death_with_timeout(timeout) {
513 Some(death_reason) => death_reason,
514 None => return false,
Inseob Kimf3536de2024-11-22 14:00:57 +0900515 }
Inseob Kim06064252024-12-05 17:52:25 +0900516 };
517
518 // SAFETY: `reason` is assumed to be a valid, non-null pointer to an
519 // AVirtualMachineStopReason object.
520 unsafe { *reason = death_reason_to_stop_reason(death_reason) };
521 true
Inseob Kimf3536de2024-11-22 14:00:57 +0900522}
523
524/// Destroy a virtual machine.
525///
526/// # Safety
527/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
528/// deletion.
529#[no_mangle]
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800530pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *mut VmInstance) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900531 if !vm.is_null() {
532 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
533 // AVirtualMachine_create. It's the only reference to the object.
534 unsafe {
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800535 let _ = Box::from_raw(vm);
Inseob Kimf3536de2024-11-22 14:00:57 +0900536 }
537 }
538}
539
540fn get_file_from_fd(fd: i32) -> Option<File> {
541 if fd == -1 {
542 None
543 } else {
544 // SAFETY: transferring ownership of `fd` from the caller
545 Some(unsafe { File::from_raw_fd(fd) })
546 }
547}