blob: 4f23da44cba24762b6dfde0d5d871197f5887b9c [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};
Inseob Kim06064252024-12-05 17:52:25 +090032use avf_bindgen::AVirtualMachineStopReason;
33use libc::timespec;
Inseob Kim5faf0cb2024-12-16 20:10:11 +090034use log::error;
Inseob Kimf3536de2024-11-22 14:00:57 +090035use vmclient::{DeathReason, VirtualizationService, VmInstance};
36
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
Inseob Kimf3536de2024-11-22 14:00:57 +0900240/// NOT IMPLEMENTED.
241///
242/// # Returns
243/// It always returns `-ENOTSUP`.
244#[no_mangle]
245pub extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
246 _config: *mut VirtualMachineRawConfig,
247 _enable: bool,
248) -> c_int {
249 -libc::ENOTSUP
250}
251
252/// NOT IMPLEMENTED.
253///
254/// # Returns
255/// It always returns `-ENOTSUP`.
256#[no_mangle]
257pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
258 _config: *mut VirtualMachineRawConfig,
259 _fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900260 _range_start: u64,
261 _range_end: u64,
Inseob Kimf3536de2024-11-22 14:00:57 +0900262) -> c_int {
263 -libc::ENOTSUP
264}
265
Jaewan Kimffc007c2024-12-12 22:15:35 +0900266/// Add device tree overlay blob
267///
268/// # Safety
269/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
270/// file descriptor or -1. `AVirtualMachineRawConfig_setDeviceTreeOverlay` takes ownership of `fd`
271/// and `fd` will be closed upon `AVirtualMachineRawConfig_delete`.
272#[no_mangle]
273pub unsafe extern "C" fn AVirtualMachineRawConfig_setDeviceTreeOverlay(
274 config: *mut VirtualMachineRawConfig,
275 fd: c_int,
276) {
277 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
278 // AVirtualMachineRawConfig_create. It's the only reference to the object.
279 let config = unsafe { &mut *config };
280
281 match get_file_from_fd(fd) {
282 Some(file) => {
283 let fd = ParcelFileDescriptor::new(file);
284 config.devices = AssignedDevices::Dtbo(Some(fd));
285 }
286 _ => {
287 config.devices = Default::default();
288 }
289 };
290}
291
Inseob Kimf3536de2024-11-22 14:00:57 +0900292/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
293/// AIDL service, and connect to the child process.
294///
295/// # Safety
296/// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
297#[no_mangle]
298pub unsafe extern "C" fn AVirtualizationService_create(
299 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
300 early: bool,
301) -> c_int {
302 let virtmgr =
303 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
304 let virtmgr = match virtmgr {
305 Ok(virtmgr) => virtmgr,
306 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
307 };
308 match virtmgr.connect() {
309 Ok(service) => {
310 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
311 // pointer. `service` is the only reference here and `config` takes
312 // ownership.
313 unsafe {
314 *service_ptr = Box::into_raw(Box::new(service));
315 }
316 0
317 }
318 Err(_) => -libc::ECONNREFUSED,
319 }
320}
321
322/// Destroy a VirtualizationService object.
323///
324/// # Safety
325/// `service` must be a pointer returned by `AVirtualizationService_create` or
326/// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
327#[no_mangle]
328pub unsafe extern "C" fn AVirtualizationService_destroy(
329 service: *mut Strong<dyn IVirtualizationService>,
330) {
331 if !service.is_null() {
332 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
333 // `AVirtualizationService_create`. It's the only reference to the object.
334 unsafe {
335 let _ = Box::from_raw(service);
336 }
337 }
338}
339
340/// Create a virtual machine with given `config`.
341///
342/// # Safety
343/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
344/// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
345/// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
346/// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
347/// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
348#[no_mangle]
349pub unsafe extern "C" fn AVirtualMachine_createRaw(
350 service: *const Strong<dyn IVirtualizationService>,
351 config: *mut VirtualMachineRawConfig,
352 console_out_fd: c_int,
353 console_in_fd: c_int,
354 log_fd: c_int,
355 vm_ptr: *mut *mut VmInstance,
356) -> c_int {
357 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
358 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
359 // reference to the object.
360 let service = unsafe { &*service };
361
362 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
363 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
364 let config = unsafe { *Box::from_raw(config) };
365 let config = VirtualMachineConfig::RawConfig(config);
366
367 let console_out = get_file_from_fd(console_out_fd);
368 let console_in = get_file_from_fd(console_in_fd);
369 let log = get_file_from_fd(log_fd);
370
371 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None, None) {
372 Ok(vm) => {
373 // SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
374 // `vm` is the only reference here and `vm_ptr` takes ownership.
375 unsafe {
376 *vm_ptr = Box::into_raw(Box::new(vm));
377 }
378 0
379 }
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900380 Err(e) => {
381 error!("AVirtualMachine_createRaw failed: {e:?}");
382 -libc::EIO
383 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900384 }
385}
386
387/// Start a virtual machine.
388///
389/// # Safety
390/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
391#[no_mangle]
392pub unsafe extern "C" fn AVirtualMachine_start(vm: *const VmInstance) -> c_int {
393 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
394 // `AVirtualMachine_createRaw`. It's the only reference to the object.
395 let vm = unsafe { &*vm };
396 match vm.start() {
397 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900398 Err(e) => {
399 error!("AVirtualMachine_start failed: {e:?}");
400 -libc::EIO
401 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900402 }
403}
404
405/// Stop a virtual machine.
406///
407/// # Safety
408/// `vm` must be a pointer returned by `AVirtualMachine_create`.
409#[no_mangle]
410pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
411 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
412 // `AVirtualMachine_createRaw`. It's the only reference to the object.
413 let vm = unsafe { &*vm };
414 match vm.stop() {
415 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900416 Err(e) => {
417 error!("AVirtualMachine_stop failed: {e:?}");
418 -libc::EIO
419 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900420 }
421}
422
Inseob Kim32e299c2024-12-09 15:27:40 +0900423/// Open a vsock connection to the CID of the virtual machine on the given vsock port.
424///
425/// # Safety
426/// `vm` must be a pointer returned by `AVirtualMachine_create`.
427#[no_mangle]
428pub unsafe extern "C" fn AVirtualMachine_connectVsock(vm: *const VmInstance, port: u32) -> c_int {
429 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
430 // `AVirtualMachine_createRaw`. It's the only reference to the object.
431 let vm = unsafe { &*vm };
432 match vm.connect_vsock(port) {
433 Ok(pfd) => pfd.into_raw_fd(),
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900434 Err(e) => {
435 error!("AVirtualMachine_connectVsock failed: {e:?}");
436 -libc::EIO
437 }
Inseob Kim32e299c2024-12-09 15:27:40 +0900438 }
439}
440
Inseob Kim06064252024-12-05 17:52:25 +0900441fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
442 match death_reason {
443 DeathReason::VirtualizationServiceDied => {
444 AVirtualMachineStopReason::AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED
445 }
446 DeathReason::InfrastructureError => {
447 AVirtualMachineStopReason::AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR
448 }
449 DeathReason::Killed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_KILLED,
450 DeathReason::Unknown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNKNOWN,
451 DeathReason::Shutdown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN,
452 DeathReason::StartFailed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_START_FAILED,
453 DeathReason::Reboot => AVirtualMachineStopReason::AVIRTUAL_MACHINE_REBOOT,
454 DeathReason::Crash => AVirtualMachineStopReason::AVIRTUAL_MACHINE_CRASH,
455 DeathReason::PvmFirmwarePublicKeyMismatch => {
456 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH
457 }
458 DeathReason::PvmFirmwareInstanceImageChanged => {
459 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
460 }
461 DeathReason::Hangup => AVirtualMachineStopReason::AVIRTUAL_MACHINE_HANGUP,
462 _ => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED,
463 }
464}
465
466/// Wait until a virtual machine stops or the timeout elapses.
Inseob Kimf3536de2024-11-22 14:00:57 +0900467///
468/// # Safety
Inseob Kim06064252024-12-05 17:52:25 +0900469/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `timeout` must be a valid
470/// pointer to a `struct timespec` object or null. `reason` must be a valid, non-null pointer to an
471/// AVirtualMachineStopReason object.
Inseob Kimf3536de2024-11-22 14:00:57 +0900472#[no_mangle]
Inseob Kim06064252024-12-05 17:52:25 +0900473pub unsafe extern "C" fn AVirtualMachine_waitForStop(
474 vm: *const VmInstance,
475 timeout: *const timespec,
476 reason: *mut AVirtualMachineStopReason,
477) -> bool {
Inseob Kimf3536de2024-11-22 14:00:57 +0900478 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
479 // AVirtualMachine_create. It's the only reference to the object.
480 let vm = unsafe { &*vm };
Inseob Kim06064252024-12-05 17:52:25 +0900481
482 let death_reason = if timeout.is_null() {
483 vm.wait_for_death()
484 } else {
485 // SAFETY: `timeout` is assumed to be a valid pointer to a `struct timespec` object if
486 // non-null.
487 let timeout = unsafe { &*timeout };
488 let timeout = Duration::new(timeout.tv_sec as u64, timeout.tv_nsec as u32);
489 match vm.wait_for_death_with_timeout(timeout) {
490 Some(death_reason) => death_reason,
491 None => return false,
Inseob Kimf3536de2024-11-22 14:00:57 +0900492 }
Inseob Kim06064252024-12-05 17:52:25 +0900493 };
494
495 // SAFETY: `reason` is assumed to be a valid, non-null pointer to an
496 // AVirtualMachineStopReason object.
497 unsafe { *reason = death_reason_to_stop_reason(death_reason) };
498 true
Inseob Kimf3536de2024-11-22 14:00:57 +0900499}
500
501/// Destroy a virtual machine.
502///
503/// # Safety
504/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
505/// deletion.
506#[no_mangle]
507pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *mut VmInstance) {
508 if !vm.is_null() {
509 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
510 // AVirtualMachine_create. It's the only reference to the object.
511 unsafe {
512 let _ = Box::from_raw(vm);
513 }
514 }
515}
516
517fn get_file_from_fd(fd: i32) -> Option<File> {
518 if fd == -1 {
519 None
520 } else {
521 // SAFETY: transferring ownership of `fd` from the caller
522 Some(unsafe { File::from_raw_fd(fd) })
523 }
524}