blob: 0a8f891ab001992b794ea1c26a60e5a913fccf45 [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;
22
23use android_system_virtualizationservice::{
24 aidl::android::system::virtualizationservice::{
25 DiskImage::DiskImage, IVirtualizationService::IVirtualizationService,
26 VirtualMachineConfig::VirtualMachineConfig,
27 VirtualMachineRawConfig::VirtualMachineRawConfig,
28 },
29 binder::{ParcelFileDescriptor, Strong},
30};
31use avf_bindgen::StopReason;
32use vmclient::{DeathReason, VirtualizationService, VmInstance};
33
34/// Create a new virtual machine config object with no properties.
35#[no_mangle]
36pub extern "C" fn AVirtualMachineRawConfig_create() -> *mut VirtualMachineRawConfig {
37 let config = Box::new(VirtualMachineRawConfig {
38 platformVersion: "~1.0".to_owned(),
39 ..Default::default()
40 });
41 Box::into_raw(config)
42}
43
44/// Destroy a virtual machine config object.
45///
46/// # Safety
47/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `config` must not be
48/// used after deletion.
49#[no_mangle]
50pub unsafe extern "C" fn AVirtualMachineRawConfig_destroy(config: *mut VirtualMachineRawConfig) {
51 if !config.is_null() {
52 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
53 // AVirtualMachineRawConfig_create. It's the only reference to the object.
54 unsafe {
55 let _ = Box::from_raw(config);
56 }
57 }
58}
59
60/// Set a name of a virtual machine.
61///
62/// # Safety
63/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
64#[no_mangle]
65pub unsafe extern "C" fn AVirtualMachineRawConfig_setName(
66 config: *mut VirtualMachineRawConfig,
67 name: *const c_char,
68) -> c_int {
69 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
70 // AVirtualMachineRawConfig_create. It's the only reference to the object.
71 let config = unsafe { &mut *config };
72 // SAFETY: `name` is assumed to be a pointer to a valid C string.
73 config.name = unsafe { CStr::from_ptr(name) }.to_string_lossy().into_owned();
74 0
75}
76
77/// Set an instance ID of a virtual machine.
78///
79/// # Safety
80/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `instanceId` must be a
81/// valid, non-null pointer to 64-byte data.
82#[no_mangle]
83pub unsafe extern "C" fn AVirtualMachineRawConfig_setInstanceId(
84 config: *mut VirtualMachineRawConfig,
85 instance_id: *const u8,
86) -> c_int {
87 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
88 // AVirtualMachineRawConfig_create. It's the only reference to the object.
89 let config = unsafe { &mut *config };
90 // SAFETY: `instanceId` is assumed to be a valid pointer to 64 bytes of memory. `config`
91 // is assumed to be a valid object returned by AVirtuaMachineConfig_create.
92 // Both never overlap.
93 unsafe {
94 ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), 64);
95 }
96 0
97}
98
99/// Set a kernel image of a virtual machine.
100///
101/// # Safety
102/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
103/// file descriptor or -1. `AVirtualMachineRawConfig_setKernel` takes ownership of `fd` and `fd`
104/// will be closed upon `AVirtualMachineRawConfig_delete`.
105#[no_mangle]
106pub unsafe extern "C" fn AVirtualMachineRawConfig_setKernel(
107 config: *mut VirtualMachineRawConfig,
108 fd: c_int,
109) -> c_int {
110 let file = get_file_from_fd(fd);
111 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
112 // AVirtualMachineRawConfig_create. It's the only reference to the object.
113 let config = unsafe { &mut *config };
114 config.kernel = file.map(ParcelFileDescriptor::new);
115 0
116}
117
118/// Set an init rd of a virtual machine.
119///
120/// # Safety
121/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
122/// file descriptor or -1. `AVirtualMachineRawConfig_setInitRd` takes ownership of `fd` and `fd`
123/// will be closed upon `AVirtualMachineRawConfig_delete`.
124#[no_mangle]
125pub unsafe extern "C" fn AVirtualMachineRawConfig_setInitRd(
126 config: *mut VirtualMachineRawConfig,
127 fd: c_int,
128) -> c_int {
129 let file = get_file_from_fd(fd);
130 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
131 // AVirtualMachineRawConfig_create. It's the only reference to the object.
132 let config = unsafe { &mut *config };
133 config.initrd = file.map(ParcelFileDescriptor::new);
134 0
135}
136
137/// Add a disk for a virtual machine.
138///
139/// # Safety
140/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
141/// file descriptor. `AVirtualMachineRawConfig_addDisk` takes ownership of `fd` and `fd` will be
142/// closed upon `AVirtualMachineRawConfig_delete`.
143#[no_mangle]
144pub unsafe extern "C" fn AVirtualMachineRawConfig_addDisk(
145 config: *mut VirtualMachineRawConfig,
146 fd: c_int,
147 writable: bool,
148) -> c_int {
149 let file = get_file_from_fd(fd);
150 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
151 // AVirtualMachineRawConfig_create. It's the only reference to the object.
152 let config = unsafe { &mut *config };
153 match file {
154 // partition not supported yet
155 None => -libc::EINVAL,
156 Some(file) => {
157 config.disks.push(DiskImage {
158 image: Some(ParcelFileDescriptor::new(file)),
159 writable,
160 ..Default::default()
161 });
162 0
163 }
164 }
165}
166
167/// Set how much memory will be given to a virtual machine.
168///
169/// # Safety
170/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
171#[no_mangle]
172pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMib(
173 config: *mut VirtualMachineRawConfig,
174 memory_mib: i32,
175) -> c_int {
176 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
177 // AVirtualMachineRawConfig_create. It's the only reference to the object.
178 let config = unsafe { &mut *config };
179 config.memoryMib = memory_mib;
180 0
181}
182
183/// Set whether a virtual machine is protected or not.
184///
185/// # Safety
186/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
187#[no_mangle]
188pub unsafe extern "C" fn AVirtualMachineRawConfig_setProtectedVm(
189 config: *mut VirtualMachineRawConfig,
190 protected_vm: bool,
191) -> c_int {
192 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
193 // AVirtualMachineRawConfig_create. It's the only reference to the object.
194 let config = unsafe { &mut *config };
195 config.protectedVm = protected_vm;
196 0
197}
198
199/// Set whether a virtual machine uses memory ballooning or not.
200///
201/// # Safety
202/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
203#[no_mangle]
204pub unsafe extern "C" fn AVirtualMachineRawConfig_setBalloon(
205 config: *mut VirtualMachineRawConfig,
206 balloon: bool,
207) -> c_int {
208 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
209 // AVirtualMachineRawConfig_create. It's the only reference to the object.
210 let config = unsafe { &mut *config };
211 config.noBalloon = !balloon;
212 0
213}
214
215/// NOT IMPLEMENTED.
216///
217/// # Returns
218/// It always returns `-ENOTSUP`.
219#[no_mangle]
220pub extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
221 _config: *mut VirtualMachineRawConfig,
222 _enable: bool,
223) -> c_int {
224 -libc::ENOTSUP
225}
226
227/// NOT IMPLEMENTED.
228///
229/// # Returns
230/// It always returns `-ENOTSUP`.
231#[no_mangle]
232pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
233 _config: *mut VirtualMachineRawConfig,
234 _fd: c_int,
235 _range_start: usize,
236 _range_end: usize,
237) -> c_int {
238 -libc::ENOTSUP
239}
240
241/// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
242/// AIDL service, and connect to the child process.
243///
244/// # Safety
245/// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
246#[no_mangle]
247pub unsafe extern "C" fn AVirtualizationService_create(
248 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
249 early: bool,
250) -> c_int {
251 let virtmgr =
252 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
253 let virtmgr = match virtmgr {
254 Ok(virtmgr) => virtmgr,
255 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
256 };
257 match virtmgr.connect() {
258 Ok(service) => {
259 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
260 // pointer. `service` is the only reference here and `config` takes
261 // ownership.
262 unsafe {
263 *service_ptr = Box::into_raw(Box::new(service));
264 }
265 0
266 }
267 Err(_) => -libc::ECONNREFUSED,
268 }
269}
270
271/// Destroy a VirtualizationService object.
272///
273/// # Safety
274/// `service` must be a pointer returned by `AVirtualizationService_create` or
275/// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
276#[no_mangle]
277pub unsafe extern "C" fn AVirtualizationService_destroy(
278 service: *mut Strong<dyn IVirtualizationService>,
279) {
280 if !service.is_null() {
281 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
282 // `AVirtualizationService_create`. It's the only reference to the object.
283 unsafe {
284 let _ = Box::from_raw(service);
285 }
286 }
287}
288
289/// Create a virtual machine with given `config`.
290///
291/// # Safety
292/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
293/// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
294/// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
295/// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
296/// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
297#[no_mangle]
298pub unsafe extern "C" fn AVirtualMachine_createRaw(
299 service: *const Strong<dyn IVirtualizationService>,
300 config: *mut VirtualMachineRawConfig,
301 console_out_fd: c_int,
302 console_in_fd: c_int,
303 log_fd: c_int,
304 vm_ptr: *mut *mut VmInstance,
305) -> c_int {
306 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
307 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
308 // reference to the object.
309 let service = unsafe { &*service };
310
311 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
312 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
313 let config = unsafe { *Box::from_raw(config) };
314 let config = VirtualMachineConfig::RawConfig(config);
315
316 let console_out = get_file_from_fd(console_out_fd);
317 let console_in = get_file_from_fd(console_in_fd);
318 let log = get_file_from_fd(log_fd);
319
320 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None, None) {
321 Ok(vm) => {
322 // SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
323 // `vm` is the only reference here and `vm_ptr` takes ownership.
324 unsafe {
325 *vm_ptr = Box::into_raw(Box::new(vm));
326 }
327 0
328 }
329 Err(_) => -libc::EIO,
330 }
331}
332
333/// Start a virtual machine.
334///
335/// # Safety
336/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
337#[no_mangle]
338pub unsafe extern "C" fn AVirtualMachine_start(vm: *const VmInstance) -> c_int {
339 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
340 // `AVirtualMachine_createRaw`. It's the only reference to the object.
341 let vm = unsafe { &*vm };
342 match vm.start() {
343 Ok(_) => 0,
344 Err(_) => -libc::EIO,
345 }
346}
347
348/// Stop a virtual machine.
349///
350/// # Safety
351/// `vm` must be a pointer returned by `AVirtualMachine_create`.
352#[no_mangle]
353pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
354 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
355 // `AVirtualMachine_createRaw`. It's the only reference to the object.
356 let vm = unsafe { &*vm };
357 match vm.stop() {
358 Ok(_) => 0,
359 Err(_) => -libc::EIO,
360 }
361}
362
363/// Wait until a virtual machine stops.
364///
365/// # Safety
366/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
367#[no_mangle]
368pub unsafe extern "C" fn AVirtualMachine_waitForStop(vm: *const VmInstance) -> StopReason {
369 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
370 // AVirtualMachine_create. It's the only reference to the object.
371 let vm = unsafe { &*vm };
372 match vm.wait_for_death() {
373 DeathReason::VirtualizationServiceDied => StopReason::VIRTUALIZATION_SERVICE_DIED,
374 DeathReason::InfrastructureError => StopReason::INFRASTRUCTURE_ERROR,
375 DeathReason::Killed => StopReason::KILLED,
376 DeathReason::Unknown => StopReason::UNKNOWN,
377 DeathReason::Shutdown => StopReason::SHUTDOWN,
378 DeathReason::StartFailed => StopReason::START_FAILED,
379 DeathReason::Reboot => StopReason::REBOOT,
380 DeathReason::Crash => StopReason::CRASH,
381 DeathReason::PvmFirmwarePublicKeyMismatch => StopReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH,
382 DeathReason::PvmFirmwareInstanceImageChanged => {
383 StopReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
384 }
385 DeathReason::Hangup => StopReason::HANGUP,
386 _ => StopReason::UNRECOGNISED,
387 }
388}
389
390/// Destroy a virtual machine.
391///
392/// # Safety
393/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
394/// deletion.
395#[no_mangle]
396pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *mut VmInstance) {
397 if !vm.is_null() {
398 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
399 // AVirtualMachine_create. It's the only reference to the object.
400 unsafe {
401 let _ = Box::from_raw(vm);
402 }
403 }
404}
405
406fn get_file_from_fd(fd: i32) -> Option<File> {
407 if fd == -1 {
408 None
409 } else {
410 // SAFETY: transferring ownership of `fd` from the caller
411 Some(unsafe { File::from_raw_fd(fd) })
412 }
413}