blob: 6532ace502ff135a2706af0060f0e6e3fc8dd151 [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::{
Jaewan Kimffc007c2024-12-12 22:15:35 +090026 AssignedDevices::AssignedDevices, CpuTopology::CpuTopology, DiskImage::DiskImage,
Frederick Maylecc0eb2b2024-12-11 19:38:16 -080027 IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
Inseob Kimf3536de2024-11-22 14:00:57 +090028 VirtualMachineRawConfig::VirtualMachineRawConfig,
29 },
30 binder::{ParcelFileDescriptor, Strong},
31};
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -080032use avf_bindgen::AVirtualMachineStopReason;
Inseob Kim06064252024-12-05 17:52:25 +090033use libc::timespec;
Inseob Kim5faf0cb2024-12-16 20:10:11 +090034use log::error;
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -080035use vmclient::{DeathReason, VirtualizationService, VmInstance};
Inseob Kimf3536de2024-11-22 14:00:57 +090036
37/// Create a new virtual machine config object with no properties.
38#[no_mangle]
39pub extern "C" fn AVirtualMachineRawConfig_create() -> *mut VirtualMachineRawConfig {
40 let config = Box::new(VirtualMachineRawConfig {
41 platformVersion: "~1.0".to_owned(),
42 ..Default::default()
43 });
44 Box::into_raw(config)
45}
46
47/// Destroy a virtual machine config object.
48///
49/// # Safety
50/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `config` must not be
51/// used after deletion.
52#[no_mangle]
53pub unsafe extern "C" fn AVirtualMachineRawConfig_destroy(config: *mut VirtualMachineRawConfig) {
54 if !config.is_null() {
55 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
56 // AVirtualMachineRawConfig_create. It's the only reference to the object.
57 unsafe {
58 let _ = Box::from_raw(config);
59 }
60 }
61}
62
63/// Set a name of a virtual machine.
64///
65/// # Safety
66/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
67#[no_mangle]
68pub unsafe extern "C" fn AVirtualMachineRawConfig_setName(
69 config: *mut VirtualMachineRawConfig,
70 name: *const c_char,
71) -> c_int {
72 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
73 // AVirtualMachineRawConfig_create. It's the only reference to the object.
74 let config = unsafe { &mut *config };
75 // SAFETY: `name` is assumed to be a pointer to a valid C string.
Inseob Kim06064252024-12-05 17:52:25 +090076 let name = unsafe { CStr::from_ptr(name) };
77 match name.to_str() {
78 Ok(name) => {
79 config.name = name.to_owned();
80 0
81 }
82 Err(_) => -libc::EINVAL,
83 }
Inseob Kimf3536de2024-11-22 14:00:57 +090084}
85
86/// Set an instance ID of a virtual machine.
87///
88/// # Safety
89/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `instanceId` must be a
90/// valid, non-null pointer to 64-byte data.
91#[no_mangle]
92pub unsafe extern "C" fn AVirtualMachineRawConfig_setInstanceId(
93 config: *mut VirtualMachineRawConfig,
94 instance_id: *const u8,
Inseob Kim06064252024-12-05 17:52:25 +090095 instance_id_size: usize,
Inseob Kimf3536de2024-11-22 14:00:57 +090096) -> c_int {
Inseob Kim06064252024-12-05 17:52:25 +090097 if instance_id_size != 64 {
98 return -libc::EINVAL;
99 }
100
Inseob Kimf3536de2024-11-22 14:00:57 +0900101 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
102 // AVirtualMachineRawConfig_create. It's the only reference to the object.
103 let config = unsafe { &mut *config };
104 // SAFETY: `instanceId` is assumed to be a valid pointer to 64 bytes of memory. `config`
105 // is assumed to be a valid object returned by AVirtuaMachineConfig_create.
106 // Both never overlap.
107 unsafe {
Inseob Kim06064252024-12-05 17:52:25 +0900108 ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), instance_id_size);
Inseob Kimf3536de2024-11-22 14:00:57 +0900109 }
110 0
111}
112
113/// Set a kernel image of a virtual machine.
114///
115/// # Safety
116/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
117/// file descriptor or -1. `AVirtualMachineRawConfig_setKernel` takes ownership of `fd` and `fd`
118/// will be closed upon `AVirtualMachineRawConfig_delete`.
119#[no_mangle]
120pub unsafe extern "C" fn AVirtualMachineRawConfig_setKernel(
121 config: *mut VirtualMachineRawConfig,
122 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900123) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900124 let file = get_file_from_fd(fd);
125 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
126 // AVirtualMachineRawConfig_create. It's the only reference to the object.
127 let config = unsafe { &mut *config };
128 config.kernel = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900129}
130
131/// Set an init rd of a virtual machine.
132///
133/// # Safety
134/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
135/// file descriptor or -1. `AVirtualMachineRawConfig_setInitRd` takes ownership of `fd` and `fd`
136/// will be closed upon `AVirtualMachineRawConfig_delete`.
137#[no_mangle]
138pub unsafe extern "C" fn AVirtualMachineRawConfig_setInitRd(
139 config: *mut VirtualMachineRawConfig,
140 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900141) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900142 let file = get_file_from_fd(fd);
143 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
144 // AVirtualMachineRawConfig_create. It's the only reference to the object.
145 let config = unsafe { &mut *config };
146 config.initrd = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900147}
148
149/// Add a disk for a virtual machine.
150///
151/// # Safety
152/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
153/// file descriptor. `AVirtualMachineRawConfig_addDisk` takes ownership of `fd` and `fd` will be
154/// closed upon `AVirtualMachineRawConfig_delete`.
155#[no_mangle]
156pub unsafe extern "C" fn AVirtualMachineRawConfig_addDisk(
157 config: *mut VirtualMachineRawConfig,
158 fd: c_int,
159 writable: bool,
160) -> c_int {
161 let file = get_file_from_fd(fd);
162 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
163 // AVirtualMachineRawConfig_create. It's the only reference to the object.
164 let config = unsafe { &mut *config };
165 match file {
166 // partition not supported yet
167 None => -libc::EINVAL,
168 Some(file) => {
169 config.disks.push(DiskImage {
170 image: Some(ParcelFileDescriptor::new(file)),
171 writable,
172 ..Default::default()
173 });
174 0
175 }
176 }
177}
178
179/// Set how much memory will be given to a virtual machine.
180///
181/// # Safety
182/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
183#[no_mangle]
Frederick Mayleb4030cf2024-12-13 15:05:54 -0800184pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMiB(
Inseob Kimf3536de2024-11-22 14:00:57 +0900185 config: *mut VirtualMachineRawConfig,
186 memory_mib: i32,
Inseob Kim06064252024-12-05 17:52:25 +0900187) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900188 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
189 // AVirtualMachineRawConfig_create. It's the only reference to the object.
190 let config = unsafe { &mut *config };
191 config.memoryMib = memory_mib;
Inseob Kimf3536de2024-11-22 14:00:57 +0900192}
193
Frederick Mayle384f5b52024-12-06 16:23:23 -0800194/// Set how much swiotlb will be given to a virtual machine.
195///
196/// # Safety
197/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
198#[no_mangle]
199pub unsafe extern "C" fn AVirtualMachineRawConfig_setSwiotlbMiB(
200 config: *mut VirtualMachineRawConfig,
201 swiotlb_mib: i32,
202) {
203 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
204 // AVirtualMachineRawConfig_create. It's the only reference to the object.
205 let config = unsafe { &mut *config };
206 config.swiotlbMib = swiotlb_mib;
207}
208
Frederick Maylecc0eb2b2024-12-11 19:38:16 -0800209/// Set vCPU count.
210///
211/// # Safety
212/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
213#[no_mangle]
214pub unsafe extern "C" fn AVirtualMachineRawConfig_setVCpuCount(
215 config: *mut VirtualMachineRawConfig,
216 n: i32,
217) {
218 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
219 // AVirtualMachineRawConfig_create. It's the only reference to the object.
220 let config = unsafe { &mut *config };
221 config.cpuTopology = CpuTopology::CUSTOM;
222 config.customVcpuCount = n;
223}
224
Inseob Kimf3536de2024-11-22 14:00:57 +0900225/// Set whether a virtual machine is protected or not.
226///
227/// # Safety
228/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
229#[no_mangle]
230pub unsafe extern "C" fn AVirtualMachineRawConfig_setProtectedVm(
231 config: *mut VirtualMachineRawConfig,
232 protected_vm: bool,
Inseob Kim06064252024-12-05 17:52:25 +0900233) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900234 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
235 // AVirtualMachineRawConfig_create. It's the only reference to the object.
236 let config = unsafe { &mut *config };
237 config.protectedVm = protected_vm;
Inseob Kimf3536de2024-11-22 14:00:57 +0900238}
239
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800240/// Set whether to use an alternate, hypervisor-specific authentication method for protected VMs.
Inseob Kimf3536de2024-11-22 14:00:57 +0900241///
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800242/// # Safety
243/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
Inseob Kimf3536de2024-11-22 14:00:57 +0900244#[no_mangle]
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800245pub unsafe extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
246 config: *mut VirtualMachineRawConfig,
247 enable: bool,
Inseob Kimf3536de2024-11-22 14:00:57 +0900248) -> c_int {
Frederick Mayle196ca2b2024-12-18 15:27:43 -0800249 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
250 // AVirtualMachineRawConfig_create. It's the only reference to the object.
251 let config = unsafe { &mut *config };
252 config.enableHypervisorSpecificAuthMethod = enable;
253 // We don't validate whether this is supported until later, when the VM is started.
254 0
Inseob Kimf3536de2024-11-22 14:00:57 +0900255}
256
257/// NOT IMPLEMENTED.
258///
259/// # Returns
260/// It always returns `-ENOTSUP`.
261#[no_mangle]
262pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
263 _config: *mut VirtualMachineRawConfig,
264 _fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900265 _range_start: u64,
266 _range_end: u64,
Inseob Kimf3536de2024-11-22 14:00:57 +0900267) -> c_int {
268 -libc::ENOTSUP
269}
270
Jaewan Kimffc007c2024-12-12 22:15:35 +0900271/// Add device tree overlay blob
272///
273/// # Safety
274/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
275/// file descriptor or -1. `AVirtualMachineRawConfig_setDeviceTreeOverlay` takes ownership of `fd`
276/// and `fd` will be closed upon `AVirtualMachineRawConfig_delete`.
277#[no_mangle]
278pub unsafe extern "C" fn AVirtualMachineRawConfig_setDeviceTreeOverlay(
279 config: *mut VirtualMachineRawConfig,
280 fd: c_int,
281) {
282 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
283 // AVirtualMachineRawConfig_create. It's the only reference to the object.
284 let config = unsafe { &mut *config };
285
286 match get_file_from_fd(fd) {
287 Some(file) => {
288 let fd = ParcelFileDescriptor::new(file);
289 config.devices = AssignedDevices::Dtbo(Some(fd));
290 }
291 _ => {
292 config.devices = Default::default();
293 }
294 };
295}
296
Inseob Kimf3536de2024-11-22 14:00:57 +0900297/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
298/// AIDL service, and connect to the child process.
299///
300/// # Safety
301/// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
302#[no_mangle]
303pub unsafe extern "C" fn AVirtualizationService_create(
304 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
305 early: bool,
306) -> c_int {
307 let virtmgr =
308 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
309 let virtmgr = match virtmgr {
310 Ok(virtmgr) => virtmgr,
311 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
312 };
313 match virtmgr.connect() {
314 Ok(service) => {
315 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
316 // pointer. `service` is the only reference here and `config` takes
317 // ownership.
318 unsafe {
319 *service_ptr = Box::into_raw(Box::new(service));
320 }
321 0
322 }
323 Err(_) => -libc::ECONNREFUSED,
324 }
325}
326
327/// Destroy a VirtualizationService object.
328///
329/// # Safety
330/// `service` must be a pointer returned by `AVirtualizationService_create` or
331/// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
332#[no_mangle]
333pub unsafe extern "C" fn AVirtualizationService_destroy(
334 service: *mut Strong<dyn IVirtualizationService>,
335) {
336 if !service.is_null() {
337 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
338 // `AVirtualizationService_create`. It's the only reference to the object.
339 unsafe {
340 let _ = Box::from_raw(service);
341 }
342 }
343}
344
345/// Create a virtual machine with given `config`.
346///
347/// # Safety
348/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
349/// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
350/// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
351/// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
352/// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
353#[no_mangle]
354pub unsafe extern "C" fn AVirtualMachine_createRaw(
355 service: *const Strong<dyn IVirtualizationService>,
356 config: *mut VirtualMachineRawConfig,
357 console_out_fd: c_int,
358 console_in_fd: c_int,
359 log_fd: c_int,
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800360 vm_ptr: *mut *mut VmInstance,
Inseob Kimf3536de2024-11-22 14:00:57 +0900361) -> c_int {
362 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
363 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
364 // reference to the object.
365 let service = unsafe { &*service };
366
367 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
368 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
369 let config = unsafe { *Box::from_raw(config) };
370 let config = VirtualMachineConfig::RawConfig(config);
371
372 let console_out = get_file_from_fd(console_out_fd);
373 let console_in = get_file_from_fd(console_in_fd);
374 let log = get_file_from_fd(log_fd);
375
Chaitanya Cheemala (xWF)3da8a162025-01-21 08:57:09 -0800376 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None, None) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900377 Ok(vm) => {
378 // 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 -0800379 // `vm` is the only reference here and `vm_ptr` takes ownership.
Inseob Kimf3536de2024-11-22 14:00:57 +0900380 unsafe {
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800381 *vm_ptr = Box::into_raw(Box::new(vm));
Inseob Kimf3536de2024-11-22 14:00:57 +0900382 }
383 0
384 }
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900385 Err(e) => {
386 error!("AVirtualMachine_createRaw failed: {e:?}");
387 -libc::EIO
388 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900389 }
390}
391
392/// Start a virtual machine.
393///
394/// # Safety
395/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
396#[no_mangle]
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800397pub unsafe extern "C" fn AVirtualMachine_start(vm: *const VmInstance) -> c_int {
Inseob Kimf3536de2024-11-22 14:00:57 +0900398 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
399 // `AVirtualMachine_createRaw`. It's the only reference to the object.
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800400 let vm = unsafe { &*vm };
Chaitanya Cheemala (xWF)3da8a162025-01-21 08:57:09 -0800401 match vm.start() {
Inseob Kimf3536de2024-11-22 14:00:57 +0900402 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900403 Err(e) => {
404 error!("AVirtualMachine_start failed: {e:?}");
405 -libc::EIO
406 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900407 }
408}
409
410/// Stop a virtual machine.
411///
412/// # Safety
413/// `vm` must be a pointer returned by `AVirtualMachine_create`.
414#[no_mangle]
415pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
416 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
417 // `AVirtualMachine_createRaw`. It's the only reference to the object.
418 let vm = unsafe { &*vm };
419 match vm.stop() {
420 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900421 Err(e) => {
422 error!("AVirtualMachine_stop failed: {e:?}");
423 -libc::EIO
424 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900425 }
426}
427
Inseob Kim32e299c2024-12-09 15:27:40 +0900428/// Open a vsock connection to the CID of the virtual machine on the given vsock port.
429///
430/// # Safety
431/// `vm` must be a pointer returned by `AVirtualMachine_create`.
432#[no_mangle]
433pub unsafe extern "C" fn AVirtualMachine_connectVsock(vm: *const VmInstance, port: u32) -> 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.connect_vsock(port) {
438 Ok(pfd) => pfd.into_raw_fd(),
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900439 Err(e) => {
440 error!("AVirtualMachine_connectVsock failed: {e:?}");
441 -libc::EIO
442 }
Inseob Kim32e299c2024-12-09 15:27:40 +0900443 }
444}
445
Inseob Kim06064252024-12-05 17:52:25 +0900446fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
447 match death_reason {
448 DeathReason::VirtualizationServiceDied => {
449 AVirtualMachineStopReason::AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED
450 }
451 DeathReason::InfrastructureError => {
452 AVirtualMachineStopReason::AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR
453 }
454 DeathReason::Killed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_KILLED,
455 DeathReason::Unknown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNKNOWN,
456 DeathReason::Shutdown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN,
457 DeathReason::StartFailed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_START_FAILED,
458 DeathReason::Reboot => AVirtualMachineStopReason::AVIRTUAL_MACHINE_REBOOT,
459 DeathReason::Crash => AVirtualMachineStopReason::AVIRTUAL_MACHINE_CRASH,
460 DeathReason::PvmFirmwarePublicKeyMismatch => {
461 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH
462 }
463 DeathReason::PvmFirmwareInstanceImageChanged => {
464 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
465 }
466 DeathReason::Hangup => AVirtualMachineStopReason::AVIRTUAL_MACHINE_HANGUP,
467 _ => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED,
468 }
469}
470
471/// Wait until a virtual machine stops or the timeout elapses.
Inseob Kimf3536de2024-11-22 14:00:57 +0900472///
473/// # Safety
Inseob Kim06064252024-12-05 17:52:25 +0900474/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `timeout` must be a valid
475/// pointer to a `struct timespec` object or null. `reason` must be a valid, non-null pointer to an
476/// AVirtualMachineStopReason object.
Inseob Kimf3536de2024-11-22 14:00:57 +0900477#[no_mangle]
Inseob Kim06064252024-12-05 17:52:25 +0900478pub unsafe extern "C" fn AVirtualMachine_waitForStop(
479 vm: *const VmInstance,
480 timeout: *const timespec,
481 reason: *mut AVirtualMachineStopReason,
482) -> bool {
Inseob Kimf3536de2024-11-22 14:00:57 +0900483 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
484 // AVirtualMachine_create. It's the only reference to the object.
485 let vm = unsafe { &*vm };
Inseob Kim06064252024-12-05 17:52:25 +0900486
487 let death_reason = if timeout.is_null() {
488 vm.wait_for_death()
489 } else {
490 // SAFETY: `timeout` is assumed to be a valid pointer to a `struct timespec` object if
491 // non-null.
492 let timeout = unsafe { &*timeout };
493 let timeout = Duration::new(timeout.tv_sec as u64, timeout.tv_nsec as u32);
494 match vm.wait_for_death_with_timeout(timeout) {
495 Some(death_reason) => death_reason,
496 None => return false,
Inseob Kimf3536de2024-11-22 14:00:57 +0900497 }
Inseob Kim06064252024-12-05 17:52:25 +0900498 };
499
500 // SAFETY: `reason` is assumed to be a valid, non-null pointer to an
501 // AVirtualMachineStopReason object.
502 unsafe { *reason = death_reason_to_stop_reason(death_reason) };
503 true
Inseob Kimf3536de2024-11-22 14:00:57 +0900504}
505
506/// Destroy a virtual machine.
507///
508/// # Safety
509/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
510/// deletion.
511#[no_mangle]
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800512pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *mut VmInstance) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900513 if !vm.is_null() {
514 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
515 // AVirtualMachine_create. It's the only reference to the object.
516 unsafe {
Chaitanya Cheemala (xWF)5159c622025-01-21 08:57:09 -0800517 let _ = Box::from_raw(vm);
Inseob Kimf3536de2024-11-22 14:00:57 +0900518 }
519 }
520}
521
522fn get_file_from_fd(fd: i32) -> Option<File> {
523 if fd == -1 {
524 None
525 } else {
526 // SAFETY: transferring ownership of `fd` from the caller
527 Some(unsafe { File::from_raw_fd(fd) })
528 }
529}