blob: 9ae263572bc618b4fb34646988028a63799f2d9c [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::{
Frederick Maylecc0eb2b2024-12-11 19:38:16 -080026 CpuTopology::CpuTopology, DiskImage::DiskImage,
27 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
266/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
267/// AIDL service, and connect to the child process.
268///
269/// # Safety
270/// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
271#[no_mangle]
272pub unsafe extern "C" fn AVirtualizationService_create(
273 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
274 early: bool,
275) -> c_int {
276 let virtmgr =
277 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
278 let virtmgr = match virtmgr {
279 Ok(virtmgr) => virtmgr,
280 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
281 };
282 match virtmgr.connect() {
283 Ok(service) => {
284 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
285 // pointer. `service` is the only reference here and `config` takes
286 // ownership.
287 unsafe {
288 *service_ptr = Box::into_raw(Box::new(service));
289 }
290 0
291 }
292 Err(_) => -libc::ECONNREFUSED,
293 }
294}
295
296/// Destroy a VirtualizationService object.
297///
298/// # Safety
299/// `service` must be a pointer returned by `AVirtualizationService_create` or
300/// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
301#[no_mangle]
302pub unsafe extern "C" fn AVirtualizationService_destroy(
303 service: *mut Strong<dyn IVirtualizationService>,
304) {
305 if !service.is_null() {
306 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
307 // `AVirtualizationService_create`. It's the only reference to the object.
308 unsafe {
309 let _ = Box::from_raw(service);
310 }
311 }
312}
313
314/// Create a virtual machine with given `config`.
315///
316/// # Safety
317/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
318/// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
319/// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
320/// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
321/// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
322#[no_mangle]
323pub unsafe extern "C" fn AVirtualMachine_createRaw(
324 service: *const Strong<dyn IVirtualizationService>,
325 config: *mut VirtualMachineRawConfig,
326 console_out_fd: c_int,
327 console_in_fd: c_int,
328 log_fd: c_int,
329 vm_ptr: *mut *mut VmInstance,
330) -> c_int {
331 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
332 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
333 // reference to the object.
334 let service = unsafe { &*service };
335
336 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
337 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
338 let config = unsafe { *Box::from_raw(config) };
339 let config = VirtualMachineConfig::RawConfig(config);
340
341 let console_out = get_file_from_fd(console_out_fd);
342 let console_in = get_file_from_fd(console_in_fd);
343 let log = get_file_from_fd(log_fd);
344
345 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None, None) {
346 Ok(vm) => {
347 // SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
348 // `vm` is the only reference here and `vm_ptr` takes ownership.
349 unsafe {
350 *vm_ptr = Box::into_raw(Box::new(vm));
351 }
352 0
353 }
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900354 Err(e) => {
355 error!("AVirtualMachine_createRaw failed: {e:?}");
356 -libc::EIO
357 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900358 }
359}
360
361/// Start a virtual machine.
362///
363/// # Safety
364/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
365#[no_mangle]
366pub unsafe extern "C" fn AVirtualMachine_start(vm: *const VmInstance) -> c_int {
367 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
368 // `AVirtualMachine_createRaw`. It's the only reference to the object.
369 let vm = unsafe { &*vm };
370 match vm.start() {
371 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900372 Err(e) => {
373 error!("AVirtualMachine_start failed: {e:?}");
374 -libc::EIO
375 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900376 }
377}
378
379/// Stop a virtual machine.
380///
381/// # Safety
382/// `vm` must be a pointer returned by `AVirtualMachine_create`.
383#[no_mangle]
384pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
385 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
386 // `AVirtualMachine_createRaw`. It's the only reference to the object.
387 let vm = unsafe { &*vm };
388 match vm.stop() {
389 Ok(_) => 0,
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900390 Err(e) => {
391 error!("AVirtualMachine_stop failed: {e:?}");
392 -libc::EIO
393 }
Inseob Kimf3536de2024-11-22 14:00:57 +0900394 }
395}
396
Inseob Kim32e299c2024-12-09 15:27:40 +0900397/// Open a vsock connection to the CID of the virtual machine on the given vsock port.
398///
399/// # Safety
400/// `vm` must be a pointer returned by `AVirtualMachine_create`.
401#[no_mangle]
402pub unsafe extern "C" fn AVirtualMachine_connectVsock(vm: *const VmInstance, port: u32) -> c_int {
403 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
404 // `AVirtualMachine_createRaw`. It's the only reference to the object.
405 let vm = unsafe { &*vm };
406 match vm.connect_vsock(port) {
407 Ok(pfd) => pfd.into_raw_fd(),
Inseob Kim5faf0cb2024-12-16 20:10:11 +0900408 Err(e) => {
409 error!("AVirtualMachine_connectVsock failed: {e:?}");
410 -libc::EIO
411 }
Inseob Kim32e299c2024-12-09 15:27:40 +0900412 }
413}
414
Inseob Kim06064252024-12-05 17:52:25 +0900415fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
416 match death_reason {
417 DeathReason::VirtualizationServiceDied => {
418 AVirtualMachineStopReason::AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED
419 }
420 DeathReason::InfrastructureError => {
421 AVirtualMachineStopReason::AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR
422 }
423 DeathReason::Killed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_KILLED,
424 DeathReason::Unknown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNKNOWN,
425 DeathReason::Shutdown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN,
426 DeathReason::StartFailed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_START_FAILED,
427 DeathReason::Reboot => AVirtualMachineStopReason::AVIRTUAL_MACHINE_REBOOT,
428 DeathReason::Crash => AVirtualMachineStopReason::AVIRTUAL_MACHINE_CRASH,
429 DeathReason::PvmFirmwarePublicKeyMismatch => {
430 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH
431 }
432 DeathReason::PvmFirmwareInstanceImageChanged => {
433 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
434 }
435 DeathReason::Hangup => AVirtualMachineStopReason::AVIRTUAL_MACHINE_HANGUP,
436 _ => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED,
437 }
438}
439
440/// Wait until a virtual machine stops or the timeout elapses.
Inseob Kimf3536de2024-11-22 14:00:57 +0900441///
442/// # Safety
Inseob Kim06064252024-12-05 17:52:25 +0900443/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `timeout` must be a valid
444/// pointer to a `struct timespec` object or null. `reason` must be a valid, non-null pointer to an
445/// AVirtualMachineStopReason object.
Inseob Kimf3536de2024-11-22 14:00:57 +0900446#[no_mangle]
Inseob Kim06064252024-12-05 17:52:25 +0900447pub unsafe extern "C" fn AVirtualMachine_waitForStop(
448 vm: *const VmInstance,
449 timeout: *const timespec,
450 reason: *mut AVirtualMachineStopReason,
451) -> bool {
Inseob Kimf3536de2024-11-22 14:00:57 +0900452 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
453 // AVirtualMachine_create. It's the only reference to the object.
454 let vm = unsafe { &*vm };
Inseob Kim06064252024-12-05 17:52:25 +0900455
456 let death_reason = if timeout.is_null() {
457 vm.wait_for_death()
458 } else {
459 // SAFETY: `timeout` is assumed to be a valid pointer to a `struct timespec` object if
460 // non-null.
461 let timeout = unsafe { &*timeout };
462 let timeout = Duration::new(timeout.tv_sec as u64, timeout.tv_nsec as u32);
463 match vm.wait_for_death_with_timeout(timeout) {
464 Some(death_reason) => death_reason,
465 None => return false,
Inseob Kimf3536de2024-11-22 14:00:57 +0900466 }
Inseob Kim06064252024-12-05 17:52:25 +0900467 };
468
469 // SAFETY: `reason` is assumed to be a valid, non-null pointer to an
470 // AVirtualMachineStopReason object.
471 unsafe { *reason = death_reason_to_stop_reason(death_reason) };
472 true
Inseob Kimf3536de2024-11-22 14:00:57 +0900473}
474
475/// Destroy a virtual machine.
476///
477/// # Safety
478/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
479/// deletion.
480#[no_mangle]
481pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *mut VmInstance) {
482 if !vm.is_null() {
483 // 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 unsafe {
486 let _ = Box::from_raw(vm);
487 }
488 }
489}
490
491fn get_file_from_fd(fd: i32) -> Option<File> {
492 if fd == -1 {
493 None
494 } else {
495 // SAFETY: transferring ownership of `fd` from the caller
496 Some(unsafe { File::from_raw_fd(fd) })
497 }
498}