blob: 1d7861fb03ec0f06c1ca6ad682bb8ee7c868ab48 [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;
19use std::os::fd::FromRawFd;
20use 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::{
26 DiskImage::DiskImage, IVirtualizationService::IVirtualizationService,
27 VirtualMachineConfig::VirtualMachineConfig,
28 VirtualMachineRawConfig::VirtualMachineRawConfig,
29 },
30 binder::{ParcelFileDescriptor, Strong},
31};
Inseob Kim06064252024-12-05 17:52:25 +090032use avf_bindgen::AVirtualMachineStopReason;
33use libc::timespec;
Inseob Kimf3536de2024-11-22 14:00:57 +090034use vmclient::{DeathReason, VirtualizationService, VmInstance};
35
36/// Create a new virtual machine config object with no properties.
37#[no_mangle]
38pub extern "C" fn AVirtualMachineRawConfig_create() -> *mut VirtualMachineRawConfig {
39 let config = Box::new(VirtualMachineRawConfig {
40 platformVersion: "~1.0".to_owned(),
41 ..Default::default()
42 });
43 Box::into_raw(config)
44}
45
46/// Destroy a virtual machine config object.
47///
48/// # Safety
49/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `config` must not be
50/// used after deletion.
51#[no_mangle]
52pub unsafe extern "C" fn AVirtualMachineRawConfig_destroy(config: *mut VirtualMachineRawConfig) {
53 if !config.is_null() {
54 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
55 // AVirtualMachineRawConfig_create. It's the only reference to the object.
56 unsafe {
57 let _ = Box::from_raw(config);
58 }
59 }
60}
61
62/// Set a name of a virtual machine.
63///
64/// # Safety
65/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
66#[no_mangle]
67pub unsafe extern "C" fn AVirtualMachineRawConfig_setName(
68 config: *mut VirtualMachineRawConfig,
69 name: *const c_char,
70) -> c_int {
71 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
72 // AVirtualMachineRawConfig_create. It's the only reference to the object.
73 let config = unsafe { &mut *config };
74 // SAFETY: `name` is assumed to be a pointer to a valid C string.
Inseob Kim06064252024-12-05 17:52:25 +090075 let name = unsafe { CStr::from_ptr(name) };
76 match name.to_str() {
77 Ok(name) => {
78 config.name = name.to_owned();
79 0
80 }
81 Err(_) => -libc::EINVAL,
82 }
Inseob Kimf3536de2024-11-22 14:00:57 +090083}
84
85/// Set an instance ID of a virtual machine.
86///
87/// # Safety
88/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `instanceId` must be a
89/// valid, non-null pointer to 64-byte data.
90#[no_mangle]
91pub unsafe extern "C" fn AVirtualMachineRawConfig_setInstanceId(
92 config: *mut VirtualMachineRawConfig,
93 instance_id: *const u8,
Inseob Kim06064252024-12-05 17:52:25 +090094 instance_id_size: usize,
Inseob Kimf3536de2024-11-22 14:00:57 +090095) -> c_int {
Inseob Kim06064252024-12-05 17:52:25 +090096 if instance_id_size != 64 {
97 return -libc::EINVAL;
98 }
99
Inseob Kimf3536de2024-11-22 14:00:57 +0900100 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
101 // AVirtualMachineRawConfig_create. It's the only reference to the object.
102 let config = unsafe { &mut *config };
103 // SAFETY: `instanceId` is assumed to be a valid pointer to 64 bytes of memory. `config`
104 // is assumed to be a valid object returned by AVirtuaMachineConfig_create.
105 // Both never overlap.
106 unsafe {
Inseob Kim06064252024-12-05 17:52:25 +0900107 ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), instance_id_size);
Inseob Kimf3536de2024-11-22 14:00:57 +0900108 }
109 0
110}
111
112/// Set a kernel image of a virtual machine.
113///
114/// # Safety
115/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
116/// file descriptor or -1. `AVirtualMachineRawConfig_setKernel` takes ownership of `fd` and `fd`
117/// will be closed upon `AVirtualMachineRawConfig_delete`.
118#[no_mangle]
119pub unsafe extern "C" fn AVirtualMachineRawConfig_setKernel(
120 config: *mut VirtualMachineRawConfig,
121 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900122) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900123 let file = get_file_from_fd(fd);
124 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
125 // AVirtualMachineRawConfig_create. It's the only reference to the object.
126 let config = unsafe { &mut *config };
127 config.kernel = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900128}
129
130/// Set an init rd of a virtual machine.
131///
132/// # Safety
133/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
134/// file descriptor or -1. `AVirtualMachineRawConfig_setInitRd` takes ownership of `fd` and `fd`
135/// will be closed upon `AVirtualMachineRawConfig_delete`.
136#[no_mangle]
137pub unsafe extern "C" fn AVirtualMachineRawConfig_setInitRd(
138 config: *mut VirtualMachineRawConfig,
139 fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900140) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900141 let file = get_file_from_fd(fd);
142 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
143 // AVirtualMachineRawConfig_create. It's the only reference to the object.
144 let config = unsafe { &mut *config };
145 config.initrd = file.map(ParcelFileDescriptor::new);
Inseob Kimf3536de2024-11-22 14:00:57 +0900146}
147
148/// Add a disk for a virtual machine.
149///
150/// # Safety
151/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
152/// file descriptor. `AVirtualMachineRawConfig_addDisk` takes ownership of `fd` and `fd` will be
153/// closed upon `AVirtualMachineRawConfig_delete`.
154#[no_mangle]
155pub unsafe extern "C" fn AVirtualMachineRawConfig_addDisk(
156 config: *mut VirtualMachineRawConfig,
157 fd: c_int,
158 writable: bool,
159) -> c_int {
160 let file = get_file_from_fd(fd);
161 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
162 // AVirtualMachineRawConfig_create. It's the only reference to the object.
163 let config = unsafe { &mut *config };
164 match file {
165 // partition not supported yet
166 None => -libc::EINVAL,
167 Some(file) => {
168 config.disks.push(DiskImage {
169 image: Some(ParcelFileDescriptor::new(file)),
170 writable,
171 ..Default::default()
172 });
173 0
174 }
175 }
176}
177
178/// Set how much memory will be given to a virtual machine.
179///
180/// # Safety
181/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
182#[no_mangle]
183pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMib(
184 config: *mut VirtualMachineRawConfig,
185 memory_mib: i32,
Inseob Kim06064252024-12-05 17:52:25 +0900186) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900187 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
188 // AVirtualMachineRawConfig_create. It's the only reference to the object.
189 let config = unsafe { &mut *config };
190 config.memoryMib = memory_mib;
Inseob Kimf3536de2024-11-22 14:00:57 +0900191}
192
193/// Set whether a virtual machine is protected or not.
194///
195/// # Safety
196/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
197#[no_mangle]
198pub unsafe extern "C" fn AVirtualMachineRawConfig_setProtectedVm(
199 config: *mut VirtualMachineRawConfig,
200 protected_vm: bool,
Inseob Kim06064252024-12-05 17:52:25 +0900201) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900202 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
203 // AVirtualMachineRawConfig_create. It's the only reference to the object.
204 let config = unsafe { &mut *config };
205 config.protectedVm = protected_vm;
Inseob Kimf3536de2024-11-22 14:00:57 +0900206}
207
208/// Set whether a virtual machine uses memory ballooning or not.
209///
210/// # Safety
211/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
212#[no_mangle]
213pub unsafe extern "C" fn AVirtualMachineRawConfig_setBalloon(
214 config: *mut VirtualMachineRawConfig,
215 balloon: bool,
Inseob Kim06064252024-12-05 17:52:25 +0900216) {
Inseob Kimf3536de2024-11-22 14:00:57 +0900217 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
218 // AVirtualMachineRawConfig_create. It's the only reference to the object.
219 let config = unsafe { &mut *config };
220 config.noBalloon = !balloon;
Inseob Kimf3536de2024-11-22 14:00:57 +0900221}
222
223/// NOT IMPLEMENTED.
224///
225/// # Returns
226/// It always returns `-ENOTSUP`.
227#[no_mangle]
228pub extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
229 _config: *mut VirtualMachineRawConfig,
230 _enable: bool,
231) -> c_int {
232 -libc::ENOTSUP
233}
234
235/// NOT IMPLEMENTED.
236///
237/// # Returns
238/// It always returns `-ENOTSUP`.
239#[no_mangle]
240pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
241 _config: *mut VirtualMachineRawConfig,
242 _fd: c_int,
Inseob Kim06064252024-12-05 17:52:25 +0900243 _range_start: u64,
244 _range_end: u64,
Inseob Kimf3536de2024-11-22 14:00:57 +0900245) -> c_int {
246 -libc::ENOTSUP
247}
248
249/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
250/// AIDL service, and connect to the child process.
251///
252/// # Safety
253/// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
254#[no_mangle]
255pub unsafe extern "C" fn AVirtualizationService_create(
256 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
257 early: bool,
258) -> c_int {
259 let virtmgr =
260 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
261 let virtmgr = match virtmgr {
262 Ok(virtmgr) => virtmgr,
263 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
264 };
265 match virtmgr.connect() {
266 Ok(service) => {
267 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
268 // pointer. `service` is the only reference here and `config` takes
269 // ownership.
270 unsafe {
271 *service_ptr = Box::into_raw(Box::new(service));
272 }
273 0
274 }
275 Err(_) => -libc::ECONNREFUSED,
276 }
277}
278
279/// Destroy a VirtualizationService object.
280///
281/// # Safety
282/// `service` must be a pointer returned by `AVirtualizationService_create` or
283/// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
284#[no_mangle]
285pub unsafe extern "C" fn AVirtualizationService_destroy(
286 service: *mut Strong<dyn IVirtualizationService>,
287) {
288 if !service.is_null() {
289 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
290 // `AVirtualizationService_create`. It's the only reference to the object.
291 unsafe {
292 let _ = Box::from_raw(service);
293 }
294 }
295}
296
297/// Create a virtual machine with given `config`.
298///
299/// # Safety
300/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
301/// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
302/// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
303/// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
304/// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
305#[no_mangle]
306pub unsafe extern "C" fn AVirtualMachine_createRaw(
307 service: *const Strong<dyn IVirtualizationService>,
308 config: *mut VirtualMachineRawConfig,
309 console_out_fd: c_int,
310 console_in_fd: c_int,
311 log_fd: c_int,
312 vm_ptr: *mut *mut VmInstance,
313) -> c_int {
314 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
315 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
316 // reference to the object.
317 let service = unsafe { &*service };
318
319 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
320 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
321 let config = unsafe { *Box::from_raw(config) };
322 let config = VirtualMachineConfig::RawConfig(config);
323
324 let console_out = get_file_from_fd(console_out_fd);
325 let console_in = get_file_from_fd(console_in_fd);
326 let log = get_file_from_fd(log_fd);
327
328 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None, None) {
329 Ok(vm) => {
330 // SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
331 // `vm` is the only reference here and `vm_ptr` takes ownership.
332 unsafe {
333 *vm_ptr = Box::into_raw(Box::new(vm));
334 }
335 0
336 }
337 Err(_) => -libc::EIO,
338 }
339}
340
341/// Start a virtual machine.
342///
343/// # Safety
344/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
345#[no_mangle]
346pub unsafe extern "C" fn AVirtualMachine_start(vm: *const VmInstance) -> c_int {
347 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
348 // `AVirtualMachine_createRaw`. It's the only reference to the object.
349 let vm = unsafe { &*vm };
350 match vm.start() {
351 Ok(_) => 0,
352 Err(_) => -libc::EIO,
353 }
354}
355
356/// Stop a virtual machine.
357///
358/// # Safety
359/// `vm` must be a pointer returned by `AVirtualMachine_create`.
360#[no_mangle]
361pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
362 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
363 // `AVirtualMachine_createRaw`. It's the only reference to the object.
364 let vm = unsafe { &*vm };
365 match vm.stop() {
366 Ok(_) => 0,
367 Err(_) => -libc::EIO,
368 }
369}
370
Inseob Kim06064252024-12-05 17:52:25 +0900371fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
372 match death_reason {
373 DeathReason::VirtualizationServiceDied => {
374 AVirtualMachineStopReason::AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED
375 }
376 DeathReason::InfrastructureError => {
377 AVirtualMachineStopReason::AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR
378 }
379 DeathReason::Killed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_KILLED,
380 DeathReason::Unknown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNKNOWN,
381 DeathReason::Shutdown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN,
382 DeathReason::StartFailed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_START_FAILED,
383 DeathReason::Reboot => AVirtualMachineStopReason::AVIRTUAL_MACHINE_REBOOT,
384 DeathReason::Crash => AVirtualMachineStopReason::AVIRTUAL_MACHINE_CRASH,
385 DeathReason::PvmFirmwarePublicKeyMismatch => {
386 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH
387 }
388 DeathReason::PvmFirmwareInstanceImageChanged => {
389 AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
390 }
391 DeathReason::Hangup => AVirtualMachineStopReason::AVIRTUAL_MACHINE_HANGUP,
392 _ => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED,
393 }
394}
395
396/// Wait until a virtual machine stops or the timeout elapses.
Inseob Kimf3536de2024-11-22 14:00:57 +0900397///
398/// # Safety
Inseob Kim06064252024-12-05 17:52:25 +0900399/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `timeout` must be a valid
400/// pointer to a `struct timespec` object or null. `reason` must be a valid, non-null pointer to an
401/// AVirtualMachineStopReason object.
Inseob Kimf3536de2024-11-22 14:00:57 +0900402#[no_mangle]
Inseob Kim06064252024-12-05 17:52:25 +0900403pub unsafe extern "C" fn AVirtualMachine_waitForStop(
404 vm: *const VmInstance,
405 timeout: *const timespec,
406 reason: *mut AVirtualMachineStopReason,
407) -> bool {
Inseob Kimf3536de2024-11-22 14:00:57 +0900408 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
409 // AVirtualMachine_create. It's the only reference to the object.
410 let vm = unsafe { &*vm };
Inseob Kim06064252024-12-05 17:52:25 +0900411
412 let death_reason = if timeout.is_null() {
413 vm.wait_for_death()
414 } else {
415 // SAFETY: `timeout` is assumed to be a valid pointer to a `struct timespec` object if
416 // non-null.
417 let timeout = unsafe { &*timeout };
418 let timeout = Duration::new(timeout.tv_sec as u64, timeout.tv_nsec as u32);
419 match vm.wait_for_death_with_timeout(timeout) {
420 Some(death_reason) => death_reason,
421 None => return false,
Inseob Kimf3536de2024-11-22 14:00:57 +0900422 }
Inseob Kim06064252024-12-05 17:52:25 +0900423 };
424
425 // SAFETY: `reason` is assumed to be a valid, non-null pointer to an
426 // AVirtualMachineStopReason object.
427 unsafe { *reason = death_reason_to_stop_reason(death_reason) };
428 true
Inseob Kimf3536de2024-11-22 14:00:57 +0900429}
430
431/// Destroy a virtual machine.
432///
433/// # Safety
434/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
435/// deletion.
436#[no_mangle]
437pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *mut VmInstance) {
438 if !vm.is_null() {
439 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
440 // AVirtualMachine_create. It's the only reference to the object.
441 unsafe {
442 let _ = Box::from_raw(vm);
443 }
444 }
445}
446
447fn get_file_from_fd(fd: i32) -> Option<File> {
448 if fd == -1 {
449 None
450 } else {
451 // SAFETY: transferring ownership of `fd` from the caller
452 Some(unsafe { File::from_raw_fd(fd) })
453 }
454}