blob: 256803f4049cce8223b7519d6ecbab5ff26a9090 [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;
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +090022use std::sync::Arc;
Inseob Kim06064252024-12-05 17:52:25 +090023use std::time::Duration;
Inseob Kimf3536de2024-11-22 14:00:57 +090024
25use android_system_virtualizationservice::{
26 aidl::android::system::virtualizationservice::{
Jaewan Kimffc007c2024-12-12 22:15:35 +090027 AssignedDevices::AssignedDevices, CpuTopology::CpuTopology, DiskImage::DiskImage,
Frederick Maylecc0eb2b2024-12-11 19:38:16 -080028 IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
Inseob Kimf3536de2024-11-22 14:00:57 +090029 VirtualMachineRawConfig::VirtualMachineRawConfig,
30 },
31 binder::{ParcelFileDescriptor, Strong},
32};
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +090033use avf_bindgen::{AVirtualMachineStopReason, AVirtualMachine_stopCallback};
Inseob Kim06064252024-12-05 17:52:25 +090034use libc::timespec;
Inseob Kim5faf0cb2024-12-16 20:10:11 +090035use log::error;
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +090036use vmclient::{DeathReason, ErrorCode, VirtualizationService, VmCallback, VmInstance};
Inseob Kimf3536de2024-11-22 14:00:57 +090037
38/// Create a new virtual machine config object with no properties.
39#[no_mangle]
40pub extern "C" fn AVirtualMachineRawConfig_create() -> *mut VirtualMachineRawConfig {
41 let config = Box::new(VirtualMachineRawConfig {
42 platformVersion: "~1.0".to_owned(),
43 ..Default::default()
44 });
45 Box::into_raw(config)
46}
47
48/// Destroy a virtual machine config object.
49///
50/// # Safety
51/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `config` must not be
52/// used after deletion.
53#[no_mangle]
54pub unsafe extern "C" fn AVirtualMachineRawConfig_destroy(config: *mut VirtualMachineRawConfig) {
55 if !config.is_null() {
56 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
57 // AVirtualMachineRawConfig_create. It's the only reference to the object.
58 unsafe {
59 let _ = Box::from_raw(config);
60 }
61 }
62}
63
64/// Set a name of a virtual machine.
65///
66/// # Safety
67/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
68#[no_mangle]
69pub unsafe extern "C" fn AVirtualMachineRawConfig_setName(
70 config: *mut VirtualMachineRawConfig,
71 name: *const c_char,
72) -> c_int {
73 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
74 // AVirtualMachineRawConfig_create. It's the only reference to the object.
75 let config = unsafe { &mut *config };
76 // SAFETY: `name` is assumed to be a pointer to a valid C string.
Inseob Kim06064252024-12-05 17:52:25 +090077 let name = unsafe { CStr::from_ptr(name) };
78 match name.to_str() {
79 Ok(name) => {
80 config.name = name.to_owned();
81 0
82 }
83 Err(_) => -libc::EINVAL,
84 }
Inseob Kimf3536de2024-11-22 14:00:57 +090085}
86
87/// Set an instance ID of a virtual machine.
88///
89/// # Safety
90/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `instanceId` must be a
91/// valid, non-null pointer to 64-byte data.
92#[no_mangle]
93pub unsafe extern "C" fn AVirtualMachineRawConfig_setInstanceId(
94 config: *mut VirtualMachineRawConfig,
95 instance_id: *const u8,
Inseob Kim06064252024-12-05 17:52:25 +090096 instance_id_size: usize,
Inseob Kimf3536de2024-11-22 14:00:57 +090097) -> c_int {
Inseob Kim06064252024-12-05 17:52:25 +090098 if instance_id_size != 64 {
99 return -libc::EINVAL;
100 }
101
Inseob Kimf3536de2024-11-22 14:00:57 +0900102 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
103 // AVirtualMachineRawConfig_create. It's the only reference to the object.
104 let config = unsafe { &mut *config };
105 // SAFETY: `instanceId` is assumed to be a valid pointer to 64 bytes of memory. `config`
106 // is assumed to be a valid object returned by AVirtuaMachineConfig_create.
107 // Both never overlap.
108 unsafe {
Inseob Kim06064252024-12-05 17:52:25 +0900109 ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), instance_id_size);
Inseob Kimf3536de2024-11-22 14:00:57 +0900110 }
111 0
112}
113
114/// Set a kernel image of a virtual machine.
115///
116/// # Safety
117/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
118/// file descriptor or -1. `AVirtualMachineRawConfig_setKernel` takes ownership of `fd` and `fd`
119/// will be closed upon `AVirtualMachineRawConfig_delete`.
120#[no_mangle]
121pub unsafe extern "C" fn AVirtualMachineRawConfig_setKernel(
122 config: *mut VirtualMachineRawConfig,
123 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900124) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900125 let file = get_file_from_fd(fd);
126 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
127 // AVirtualMachineRawConfig_create. It's the only reference to the object.
128 let config = unsafe { &mut *config };
129 config.kernel = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900130}
131
132/// Set an init rd of a virtual machine.
133///
134/// # Safety
135/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
136/// file descriptor or -1. `AVirtualMachineRawConfig_setInitRd` takes ownership of `fd` and `fd`
137/// will be closed upon `AVirtualMachineRawConfig_delete`.
138#[no_mangle]
139pub unsafe extern "C" fn AVirtualMachineRawConfig_setInitRd(
140 config: *mut VirtualMachineRawConfig,
141 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900142) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900143 let file = get_file_from_fd(fd);
144 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
145 // AVirtualMachineRawConfig_create. It's the only reference to the object.
146 let config = unsafe { &mut *config };
147 config.initrd = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900148}
149
150/// Add a disk for a virtual machine.
151///
152/// # Safety
153/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
154/// file descriptor. `AVirtualMachineRawConfig_addDisk` takes ownership of `fd` and `fd` will be
155/// closed upon `AVirtualMachineRawConfig_delete`.
156#[no_mangle]
157pub unsafe extern "C" fn AVirtualMachineRawConfig_addDisk(
158 config: *mut VirtualMachineRawConfig,
159 fd: c_int,
160 writable: bool,
161) -> c_int {
162 let file = get_file_from_fd(fd);
163 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
164 // AVirtualMachineRawConfig_create. It's the only reference to the object.
165 let config = unsafe { &mut *config };
166 match file {
167 // partition not supported yet
168 None => -libc::EINVAL,
169 Some(file) => {
170 config.disks.push(DiskImage {
171 image: Some(ParcelFileDescriptor::new(file)),
172 writable,
173 ..Default::default()
174 });
175 0
176 }
177 }
178}
179
180/// Set how much memory will be given to a virtual machine.
181///
182/// # Safety
183/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
184#[no_mangle]
Frederick Mayleb4030cf2024-12-13 15:05:54 -0800185pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMiB(
Inseob Kimf3536de2024-11-22 14:00:57 +0900186 config: *mut VirtualMachineRawConfig,
187 memory_mib: i32,
Inseob Kim06064252024-12-05 17:52:25 +0900188) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900189 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
190 // AVirtualMachineRawConfig_create. It's the only reference to the object.
191 let config = unsafe { &mut *config };
192 config.memoryMib = memory_mib;
Inseob Kimf3536de2024-11-22 14:00:57 +0900193}
194
Frederick Mayle384f5b52024-12-06 16:23:23 -0800195/// Set how much swiotlb will be given to a virtual machine.
196///
197/// # Safety
198/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
199#[no_mangle]
200pub unsafe extern "C" fn AVirtualMachineRawConfig_setSwiotlbMiB(
201 config: *mut VirtualMachineRawConfig,
202 swiotlb_mib: i32,
203) {
204 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
205 // AVirtualMachineRawConfig_create. It's the only reference to the object.
206 let config = unsafe { &mut *config };
207 config.swiotlbMib = swiotlb_mib;
208}
209
Frederick Maylecc0eb2b2024-12-11 19:38:16 -0800210/// Set vCPU count.
211///
212/// # Safety
213/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
214#[no_mangle]
215pub unsafe extern "C" fn AVirtualMachineRawConfig_setVCpuCount(
216 config: *mut VirtualMachineRawConfig,
217 n: i32,
218) {
219 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
220 // AVirtualMachineRawConfig_create. It's the only reference to the object.
221 let config = unsafe { &mut *config };
222 config.cpuTopology = CpuTopology::CUSTOM;
223 config.customVcpuCount = n;
224}
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
258/// NOT IMPLEMENTED.
259///
260/// # Returns
261/// It always returns `-ENOTSUP`.
262#[no_mangle]
263pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
264 _config: *mut VirtualMachineRawConfig,
265 _fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900266 _range_start: u64,
267 _range_end: u64,
Inseob Kimf3536de2024-11-22 14:00:57 +0900268) -> c_int {
269 -libc::ENOTSUP
270}
271
Jaewan Kimffc007c2024-12-12 22:15:35 +0900272/// Add device tree overlay blob
273///
274/// # Safety
275/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
276/// file descriptor or -1. `AVirtualMachineRawConfig_setDeviceTreeOverlay` takes ownership of `fd`
277/// and `fd` will be closed upon `AVirtualMachineRawConfig_delete`.
278#[no_mangle]
279pub unsafe extern "C" fn AVirtualMachineRawConfig_setDeviceTreeOverlay(
280 config: *mut VirtualMachineRawConfig,
281 fd: c_int,
282) {
283 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
284 // AVirtualMachineRawConfig_create. It's the only reference to the object.
285 let config = unsafe { &mut *config };
286
287 match get_file_from_fd(fd) {
288 Some(file) => {
289 let fd = ParcelFileDescriptor::new(file);
290 config.devices = AssignedDevices::Dtbo(Some(fd));
291 }
292 _ => {
293 config.devices = Default::default();
294 }
295 };
296}
297
Inseob Kimf3536de2024-11-22 14:00:57 +0900298/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
299/// AIDL service, and connect to the child process.
300///
301/// # Safety
302/// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
303#[no_mangle]
304pub unsafe extern "C" fn AVirtualizationService_create(
305 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
306 early: bool,
307) -> c_int {
308 let virtmgr =
309 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
310 let virtmgr = match virtmgr {
311 Ok(virtmgr) => virtmgr,
312 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
313 };
314 match virtmgr.connect() {
315 Ok(service) => {
316 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
317 // pointer. `service` is the only reference here and `config` takes
318 // ownership.
319 unsafe {
320 *service_ptr = Box::into_raw(Box::new(service));
321 }
322 0
323 }
324 Err(_) => -libc::ECONNREFUSED,
325 }
326}
327
328/// Destroy a VirtualizationService object.
329///
330/// # Safety
331/// `service` must be a pointer returned by `AVirtualizationService_create` or
332/// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
333#[no_mangle]
334pub unsafe extern "C" fn AVirtualizationService_destroy(
335 service: *mut Strong<dyn IVirtualizationService>,
336) {
337 if !service.is_null() {
338 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
339 // `AVirtualizationService_create`. It's the only reference to the object.
340 unsafe {
341 let _ = Box::from_raw(service);
342 }
343 }
344}
345
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +0900346struct LocalVmInstance {
347 vm: Arc<VmInstance>,
348 callback: AVirtualMachine_stopCallback,
349}
350
351impl VmCallback for LocalVmInstance {
352 fn on_payload_started(&self, _cid: i32) {
353 // Microdroid only. no-op.
354 }
355
356 fn on_payload_ready(&self, _cid: i32) {
357 // Microdroid only. no-op.
358 }
359
360 fn on_payload_finished(&self, _cid: i32, _exit_code: i32) {
361 // Microdroid only. no-op.
362 }
363
364 fn on_error(&self, _cid: i32, _error_code: ErrorCode, _message: &str) {
365 // Microdroid only. no-op.
366 }
367
368 fn on_died(&self, _cid: i32, death_reason: DeathReason) {
369 let Some(callback) = self.callback else {
370 return;
371 };
372 let stop_reason = death_reason_to_stop_reason(death_reason);
373 let vm_ptr: *const VmInstance = Arc::into_raw(Arc::clone(&self.vm));
374
375 // SAFETY: `callback` is assumed to be a valid, non-null function pointer passed by
376 // `AVirtualMachine_start`.
377 unsafe {
378 callback(vm_ptr.cast(), stop_reason);
379 }
380
381 // drop ptr after use.
382 // SAFETY: `vm_ptr` is a valid, non-null pointer casted above.
383 unsafe {
384 let _ = Arc::from_raw(vm_ptr);
385 }
386 }
387}
388
Inseob Kimf3536de2024-11-22 14:00:57 +0900389/// Create a virtual machine with given `config`.
390///
391/// # Safety
392/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
393/// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
394/// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
395/// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
396/// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
397#[no_mangle]
398pub unsafe extern "C" fn AVirtualMachine_createRaw(
399 service: *const Strong<dyn IVirtualizationService>,
400 config: *mut VirtualMachineRawConfig,
401 console_out_fd: c_int,
402 console_in_fd: c_int,
403 log_fd: c_int,
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +0900404 vm_ptr: *mut *const VmInstance,
Inseob Kimf3536de2024-11-22 14:00:57 +0900405) -> c_int {
406 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
407 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
408 // reference to the object.
409 let service = unsafe { &*service };
410
411 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
412 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
413 let config = unsafe { *Box::from_raw(config) };
414 let config = VirtualMachineConfig::RawConfig(config);
415
416 let console_out = get_file_from_fd(console_out_fd);
417 let console_in = get_file_from_fd(console_in_fd);
418 let log = get_file_from_fd(log_fd);
419
Jaewan Kim6dcf3082025-01-10 16:30:27 +0900420 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900421 Ok(vm) => {
422 // SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
Inseob Kimf3536de2024-11-22 14:00:57 +0900423 unsafe {
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +0900424 *vm_ptr = Arc::into_raw(Arc::new(vm));
Inseob Kimf3536de2024-11-22 14:00:57 +0900425 }
426 0
427 }
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900428 Err(e) => {
429 error!("AVirtualMachine_createRaw failed: {e:?}");
430 -libc::EIO
431 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900432 }
433}
434
435/// Start a virtual machine.
436///
437/// # Safety
438/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
439#[no_mangle]
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +0900440pub unsafe extern "C" fn AVirtualMachine_start(
441 vm: *const VmInstance,
442 callback: AVirtualMachine_stopCallback,
443) -> c_int {
Inseob Kimf3536de2024-11-22 14:00:57 +0900444 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
445 // `AVirtualMachine_createRaw`. It's the only reference to the object.
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +0900446 let vm = unsafe { Arc::from_raw(vm) };
447 let callback = callback.map(|_| {
448 let cb: Box<dyn VmCallback + Send + Sync> =
449 Box::new(LocalVmInstance { vm: Arc::clone(&vm), callback });
450 cb
451 });
452
453 match vm.start(callback) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900454 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900455 Err(e) => {
456 error!("AVirtualMachine_start failed: {e:?}");
457 -libc::EIO
458 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900459 }
460}
461
462/// Stop a virtual machine.
463///
464/// # Safety
465/// `vm` must be a pointer returned by `AVirtualMachine_create`.
466#[no_mangle]
467pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
468 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
469 // `AVirtualMachine_createRaw`. It's the only reference to the object.
470 let vm = unsafe { &*vm };
471 match vm.stop() {
472 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900473 Err(e) => {
474 error!("AVirtualMachine_stop failed: {e:?}");
475 -libc::EIO
476 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900477 }
478}
479
Inseob Kim32e299c2024-12-09 15:27:40 +0900480/// Open a vsock connection to the CID of the virtual machine on the given vsock port.
481///
482/// # Safety
483/// `vm` must be a pointer returned by `AVirtualMachine_create`.
484#[no_mangle]
485pub unsafe extern "C" fn AVirtualMachine_connectVsock(vm: *const VmInstance, port: u32) -> c_int {
486 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
487 // `AVirtualMachine_createRaw`. It's the only reference to the object.
488 let vm = unsafe { &*vm };
489 match vm.connect_vsock(port) {
490 Ok(pfd) => pfd.into_raw_fd(),
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900491 Err(e) => {
492 error!("AVirtualMachine_connectVsock failed: {e:?}");
493 -libc::EIO
494 }
Inseob Kim32e299c2024-12-09 15:27:40 +0900495 }
496}
497
Inseob Kim06064252024-12-05 17:52:25 +0900498fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
499 match death_reason {
500 DeathReason::VirtualizationServiceDied => {
501 AVirtualMachineStopReason::AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED
502 }
503 DeathReason::InfrastructureError => {
504 AVirtualMachineStopReason::AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR
505 }
506 DeathReason::Killed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_KILLED,
507 DeathReason::Unknown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNKNOWN,
508 DeathReason::Shutdown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN,
509 DeathReason::StartFailed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_START_FAILED,
510 DeathReason::Reboot => AVirtualMachineStopReason::AVIRTUAL_MACHINE_REBOOT,
511 DeathReason::Crash => AVirtualMachineStopReason::AVIRTUAL_MACHINE_CRASH,
512 DeathReason::PvmFirmwarePublicKeyMismatch => {
513 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH
514 }
515 DeathReason::PvmFirmwareInstanceImageChanged => {
516 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
517 }
518 DeathReason::Hangup => AVirtualMachineStopReason::AVIRTUAL_MACHINE_HANGUP,
519 _ => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED,
520 }
521}
522
523/// Wait until a virtual machine stops or the timeout elapses.
Inseob Kimf3536de2024-11-22 14:00:57 +0900524///
525/// # Safety
Inseob Kim06064252024-12-05 17:52:25 +0900526/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `timeout` must be a valid
527/// pointer to a `struct timespec` object or null. `reason` must be a valid, non-null pointer to an
528/// AVirtualMachineStopReason object.
Inseob Kimf3536de2024-11-22 14:00:57 +0900529#[no_mangle]
Inseob Kim06064252024-12-05 17:52:25 +0900530pub unsafe extern "C" fn AVirtualMachine_waitForStop(
531 vm: *const VmInstance,
532 timeout: *const timespec,
533 reason: *mut AVirtualMachineStopReason,
534) -> bool {
Inseob Kimf3536de2024-11-22 14:00:57 +0900535 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
536 // AVirtualMachine_create. It's the only reference to the object.
537 let vm = unsafe { &*vm };
Inseob Kim06064252024-12-05 17:52:25 +0900538
539 let death_reason = if timeout.is_null() {
540 vm.wait_for_death()
541 } else {
542 // SAFETY: `timeout` is assumed to be a valid pointer to a `struct timespec` object if
543 // non-null.
544 let timeout = unsafe { &*timeout };
545 let timeout = Duration::new(timeout.tv_sec as u64, timeout.tv_nsec as u32);
546 match vm.wait_for_death_with_timeout(timeout) {
547 Some(death_reason) => death_reason,
548 None => return false,
Inseob Kimf3536de2024-11-22 14:00:57 +0900549 }
Inseob Kim06064252024-12-05 17:52:25 +0900550 };
551
552 // SAFETY: `reason` is assumed to be a valid, non-null pointer to an
553 // AVirtualMachineStopReason object.
554 unsafe { *reason = death_reason_to_stop_reason(death_reason) };
555 true
Inseob Kimf3536de2024-11-22 14:00:57 +0900556}
557
558/// Destroy a virtual machine.
559///
560/// # Safety
561/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
562/// deletion.
563#[no_mangle]
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +0900564pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *const VmInstance) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900565 if !vm.is_null() {
566 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
567 // AVirtualMachine_create. It's the only reference to the object.
568 unsafe {
Jaewan Kimf3eaa9e2025-01-13 13:48:31 +0900569 let _ = Arc::from_raw(vm);
Inseob Kimf3536de2024-11-22 14:00:57 +0900570 }
571 }
572}
573
574fn get_file_from_fd(fd: i32) -> Option<File> {
575 if fd == -1 {
576 None
577 } else {
578 // SAFETY: transferring ownership of `fd` from the caller
579 Some(unsafe { File::from_raw_fd(fd) })
580 }
581}