xref: /openbmc/qemu/rust/qemu-api/src/lib.rs (revision 718e255f)
15a5110d2SManos Pitsidianakis // Copyright 2024, Linaro Limited
25a5110d2SManos Pitsidianakis // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
35a5110d2SManos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later
45a5110d2SManos Pitsidianakis 
55a5110d2SManos Pitsidianakis #![cfg_attr(not(MESON), doc = include_str!("../README.md"))]
65a5110d2SManos Pitsidianakis 
75a5110d2SManos Pitsidianakis #[allow(
85a5110d2SManos Pitsidianakis     dead_code,
95a5110d2SManos Pitsidianakis     improper_ctypes_definitions,
105a5110d2SManos Pitsidianakis     improper_ctypes,
115a5110d2SManos Pitsidianakis     non_camel_case_types,
125a5110d2SManos Pitsidianakis     non_snake_case,
135a5110d2SManos Pitsidianakis     non_upper_case_globals,
145a5110d2SManos Pitsidianakis     unsafe_op_in_unsafe_fn,
155a5110d2SManos Pitsidianakis     clippy::missing_const_for_fn,
165a5110d2SManos Pitsidianakis     clippy::too_many_arguments,
175a5110d2SManos Pitsidianakis     clippy::approx_constant,
185a5110d2SManos Pitsidianakis     clippy::use_self,
195a5110d2SManos Pitsidianakis     clippy::useless_transmute,
205a5110d2SManos Pitsidianakis     clippy::missing_safety_doc,
215a5110d2SManos Pitsidianakis )]
225a5110d2SManos Pitsidianakis #[rustfmt::skip]
235a5110d2SManos Pitsidianakis pub mod bindings;
245a5110d2SManos Pitsidianakis 
255a5110d2SManos Pitsidianakis unsafe impl Send for bindings::Property {}
265a5110d2SManos Pitsidianakis unsafe impl Sync for bindings::Property {}
275a5110d2SManos Pitsidianakis unsafe impl Sync for bindings::TypeInfo {}
285a5110d2SManos Pitsidianakis unsafe impl Sync for bindings::VMStateDescription {}
290a65e412SManos Pitsidianakis unsafe impl Sync for bindings::VMStateField {}
300a65e412SManos Pitsidianakis unsafe impl Sync for bindings::VMStateInfo {}
315a5110d2SManos Pitsidianakis 
32*718e255fSPaolo Bonzini pub mod c_str;
335a5110d2SManos Pitsidianakis pub mod definitions;
345a5110d2SManos Pitsidianakis pub mod device_class;
350a65e412SManos Pitsidianakis pub mod vmstate;
366e50bde1SPaolo Bonzini pub mod zeroable;
375a5110d2SManos Pitsidianakis 
389f7d4520SPaolo Bonzini use std::{
399f7d4520SPaolo Bonzini     alloc::{GlobalAlloc, Layout},
409f7d4520SPaolo Bonzini     os::raw::c_void,
419f7d4520SPaolo Bonzini };
425a5110d2SManos Pitsidianakis 
435a5110d2SManos Pitsidianakis #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
445a5110d2SManos Pitsidianakis extern "C" {
455a5110d2SManos Pitsidianakis     fn g_aligned_alloc0(
465a5110d2SManos Pitsidianakis         n_blocks: bindings::gsize,
475a5110d2SManos Pitsidianakis         n_block_bytes: bindings::gsize,
485a5110d2SManos Pitsidianakis         alignment: bindings::gsize,
495a5110d2SManos Pitsidianakis     ) -> bindings::gpointer;
505a5110d2SManos Pitsidianakis     fn g_aligned_free(mem: bindings::gpointer);
515a5110d2SManos Pitsidianakis }
525a5110d2SManos Pitsidianakis 
535a5110d2SManos Pitsidianakis #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
545a5110d2SManos Pitsidianakis extern "C" {
559f7d4520SPaolo Bonzini     fn qemu_memalign(alignment: usize, size: usize) -> *mut c_void;
569f7d4520SPaolo Bonzini     fn qemu_vfree(ptr: *mut c_void);
575a5110d2SManos Pitsidianakis }
585a5110d2SManos Pitsidianakis 
595a5110d2SManos Pitsidianakis extern "C" {
605a5110d2SManos Pitsidianakis     fn g_malloc0(n_bytes: bindings::gsize) -> bindings::gpointer;
615a5110d2SManos Pitsidianakis     fn g_free(mem: bindings::gpointer);
625a5110d2SManos Pitsidianakis }
635a5110d2SManos Pitsidianakis 
645a5110d2SManos Pitsidianakis /// An allocator that uses the same allocator as QEMU in C.
655a5110d2SManos Pitsidianakis ///
665a5110d2SManos Pitsidianakis /// It is enabled by default with the `allocator` feature.
675a5110d2SManos Pitsidianakis ///
685a5110d2SManos Pitsidianakis /// To set it up manually as a global allocator in your crate:
695a5110d2SManos Pitsidianakis ///
705a5110d2SManos Pitsidianakis /// ```ignore
715a5110d2SManos Pitsidianakis /// use qemu_api::QemuAllocator;
725a5110d2SManos Pitsidianakis ///
735a5110d2SManos Pitsidianakis /// #[global_allocator]
745a5110d2SManos Pitsidianakis /// static GLOBAL: QemuAllocator = QemuAllocator::new();
755a5110d2SManos Pitsidianakis /// ```
765a5110d2SManos Pitsidianakis #[derive(Clone, Copy, Debug)]
775a5110d2SManos Pitsidianakis #[repr(C)]
785a5110d2SManos Pitsidianakis pub struct QemuAllocator {
795a5110d2SManos Pitsidianakis     _unused: [u8; 0],
805a5110d2SManos Pitsidianakis }
815a5110d2SManos Pitsidianakis 
825a5110d2SManos Pitsidianakis #[cfg_attr(all(feature = "allocator", not(test)), global_allocator)]
835a5110d2SManos Pitsidianakis pub static GLOBAL: QemuAllocator = QemuAllocator::new();
845a5110d2SManos Pitsidianakis 
855a5110d2SManos Pitsidianakis impl QemuAllocator {
865a5110d2SManos Pitsidianakis     // From the glibc documentation, on GNU systems, malloc guarantees 16-byte
875a5110d2SManos Pitsidianakis     // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See
885a5110d2SManos Pitsidianakis     // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html.
895a5110d2SManos Pitsidianakis     // This alignment guarantee also applies to Windows and Android. On Darwin
905a5110d2SManos Pitsidianakis     // and OpenBSD, the alignment is 16 bytes on both 64-bit and 32-bit systems.
915a5110d2SManos Pitsidianakis     #[cfg(all(
925a5110d2SManos Pitsidianakis         target_pointer_width = "32",
935a5110d2SManos Pitsidianakis         not(any(target_os = "macos", target_os = "openbsd"))
945a5110d2SManos Pitsidianakis     ))]
955a5110d2SManos Pitsidianakis     pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(8);
965a5110d2SManos Pitsidianakis     #[cfg(all(
975a5110d2SManos Pitsidianakis         target_pointer_width = "64",
985a5110d2SManos Pitsidianakis         not(any(target_os = "macos", target_os = "openbsd"))
995a5110d2SManos Pitsidianakis     ))]
1005a5110d2SManos Pitsidianakis     pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16);
1015a5110d2SManos Pitsidianakis     #[cfg(all(
1025a5110d2SManos Pitsidianakis         any(target_pointer_width = "32", target_pointer_width = "64"),
1035a5110d2SManos Pitsidianakis         any(target_os = "macos", target_os = "openbsd")
1045a5110d2SManos Pitsidianakis     ))]
1055a5110d2SManos Pitsidianakis     pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16);
1065a5110d2SManos Pitsidianakis     #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
1075a5110d2SManos Pitsidianakis     pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = None;
1085a5110d2SManos Pitsidianakis 
1095a5110d2SManos Pitsidianakis     pub const fn new() -> Self {
1105a5110d2SManos Pitsidianakis         Self { _unused: [] }
1115a5110d2SManos Pitsidianakis     }
1125a5110d2SManos Pitsidianakis }
1135a5110d2SManos Pitsidianakis 
1145a5110d2SManos Pitsidianakis impl Default for QemuAllocator {
1155a5110d2SManos Pitsidianakis     fn default() -> Self {
1165a5110d2SManos Pitsidianakis         Self::new()
1175a5110d2SManos Pitsidianakis     }
1185a5110d2SManos Pitsidianakis }
1195a5110d2SManos Pitsidianakis 
1205a5110d2SManos Pitsidianakis // Sanity check.
1219f7d4520SPaolo Bonzini const _: [(); 8] = [(); ::core::mem::size_of::<*mut c_void>()];
1225a5110d2SManos Pitsidianakis 
1235a5110d2SManos Pitsidianakis unsafe impl GlobalAlloc for QemuAllocator {
1245a5110d2SManos Pitsidianakis     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1255a5110d2SManos Pitsidianakis         if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0))
1265a5110d2SManos Pitsidianakis         {
1275a5110d2SManos Pitsidianakis             // SAFETY: g_malloc0() is safe to call.
1285a5110d2SManos Pitsidianakis             unsafe { g_malloc0(layout.size().try_into().unwrap()).cast::<u8>() }
1295a5110d2SManos Pitsidianakis         } else {
1305a5110d2SManos Pitsidianakis             #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
1315a5110d2SManos Pitsidianakis             {
1325a5110d2SManos Pitsidianakis                 // SAFETY: g_aligned_alloc0() is safe to call.
1335a5110d2SManos Pitsidianakis                 unsafe {
1345a5110d2SManos Pitsidianakis                     g_aligned_alloc0(
1355a5110d2SManos Pitsidianakis                         layout.size().try_into().unwrap(),
1365a5110d2SManos Pitsidianakis                         1,
1375a5110d2SManos Pitsidianakis                         layout.align().try_into().unwrap(),
1385a5110d2SManos Pitsidianakis                     )
1395a5110d2SManos Pitsidianakis                     .cast::<u8>()
1405a5110d2SManos Pitsidianakis                 }
1415a5110d2SManos Pitsidianakis             }
1425a5110d2SManos Pitsidianakis             #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
1435a5110d2SManos Pitsidianakis             {
1445a5110d2SManos Pitsidianakis                 // SAFETY: qemu_memalign() is safe to call.
1455a5110d2SManos Pitsidianakis                 unsafe { qemu_memalign(layout.align(), layout.size()).cast::<u8>() }
1465a5110d2SManos Pitsidianakis             }
1475a5110d2SManos Pitsidianakis         }
1485a5110d2SManos Pitsidianakis     }
1495a5110d2SManos Pitsidianakis 
1505a5110d2SManos Pitsidianakis     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
1515a5110d2SManos Pitsidianakis         if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0))
1525a5110d2SManos Pitsidianakis         {
1535a5110d2SManos Pitsidianakis             // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid
1545a5110d2SManos Pitsidianakis             // glib-allocated pointer, so `g_free`ing is safe.
1555a5110d2SManos Pitsidianakis             unsafe { g_free(ptr.cast::<_>()) }
1565a5110d2SManos Pitsidianakis         } else {
1575a5110d2SManos Pitsidianakis             #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
1585a5110d2SManos Pitsidianakis             {
1595a5110d2SManos Pitsidianakis                 // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned
1605a5110d2SManos Pitsidianakis                 // glib-allocated pointer, so `g_aligned_free`ing is safe.
1615a5110d2SManos Pitsidianakis                 unsafe { g_aligned_free(ptr.cast::<_>()) }
1625a5110d2SManos Pitsidianakis             }
1635a5110d2SManos Pitsidianakis             #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
1645a5110d2SManos Pitsidianakis             {
1655a5110d2SManos Pitsidianakis                 // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned
1665a5110d2SManos Pitsidianakis                 // glib-allocated pointer, so `qemu_vfree`ing is safe.
1675a5110d2SManos Pitsidianakis                 unsafe { qemu_vfree(ptr.cast::<_>()) }
1685a5110d2SManos Pitsidianakis             }
1695a5110d2SManos Pitsidianakis         }
1705a5110d2SManos Pitsidianakis     }
1715a5110d2SManos Pitsidianakis }
172