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 32718e255fSPaolo Bonzini pub mod c_str; 335a5110d2SManos Pitsidianakis pub mod definitions; 345a5110d2SManos Pitsidianakis pub mod device_class; 35*f3518400SJunjie Mao pub mod offset_of; 360a65e412SManos Pitsidianakis pub mod vmstate; 376e50bde1SPaolo Bonzini pub mod zeroable; 385a5110d2SManos Pitsidianakis 399f7d4520SPaolo Bonzini use std::{ 409f7d4520SPaolo Bonzini alloc::{GlobalAlloc, Layout}, 419f7d4520SPaolo Bonzini os::raw::c_void, 429f7d4520SPaolo Bonzini }; 435a5110d2SManos Pitsidianakis 445a5110d2SManos Pitsidianakis #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)] 455a5110d2SManos Pitsidianakis extern "C" { g_aligned_alloc0( n_blocks: bindings::gsize, n_block_bytes: bindings::gsize, alignment: bindings::gsize, ) -> bindings::gpointer465a5110d2SManos Pitsidianakis fn g_aligned_alloc0( 475a5110d2SManos Pitsidianakis n_blocks: bindings::gsize, 485a5110d2SManos Pitsidianakis n_block_bytes: bindings::gsize, 495a5110d2SManos Pitsidianakis alignment: bindings::gsize, 505a5110d2SManos Pitsidianakis ) -> bindings::gpointer; g_aligned_free(mem: bindings::gpointer)515a5110d2SManos Pitsidianakis fn g_aligned_free(mem: bindings::gpointer); 525a5110d2SManos Pitsidianakis } 535a5110d2SManos Pitsidianakis 545a5110d2SManos Pitsidianakis #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))] 555a5110d2SManos Pitsidianakis extern "C" { qemu_memalign(alignment: usize, size: usize) -> *mut c_void569f7d4520SPaolo Bonzini fn qemu_memalign(alignment: usize, size: usize) -> *mut c_void; qemu_vfree(ptr: *mut c_void)579f7d4520SPaolo Bonzini fn qemu_vfree(ptr: *mut c_void); 585a5110d2SManos Pitsidianakis } 595a5110d2SManos Pitsidianakis 605a5110d2SManos Pitsidianakis extern "C" { g_malloc0(n_bytes: bindings::gsize) -> bindings::gpointer615a5110d2SManos Pitsidianakis fn g_malloc0(n_bytes: bindings::gsize) -> bindings::gpointer; g_free(mem: bindings::gpointer)625a5110d2SManos Pitsidianakis fn g_free(mem: bindings::gpointer); 635a5110d2SManos Pitsidianakis } 645a5110d2SManos Pitsidianakis 655a5110d2SManos Pitsidianakis /// An allocator that uses the same allocator as QEMU in C. 665a5110d2SManos Pitsidianakis /// 675a5110d2SManos Pitsidianakis /// It is enabled by default with the `allocator` feature. 685a5110d2SManos Pitsidianakis /// 695a5110d2SManos Pitsidianakis /// To set it up manually as a global allocator in your crate: 705a5110d2SManos Pitsidianakis /// 715a5110d2SManos Pitsidianakis /// ```ignore 725a5110d2SManos Pitsidianakis /// use qemu_api::QemuAllocator; 735a5110d2SManos Pitsidianakis /// 745a5110d2SManos Pitsidianakis /// #[global_allocator] 755a5110d2SManos Pitsidianakis /// static GLOBAL: QemuAllocator = QemuAllocator::new(); 765a5110d2SManos Pitsidianakis /// ``` 775a5110d2SManos Pitsidianakis #[derive(Clone, Copy, Debug)] 785a5110d2SManos Pitsidianakis #[repr(C)] 795a5110d2SManos Pitsidianakis pub struct QemuAllocator { 805a5110d2SManos Pitsidianakis _unused: [u8; 0], 815a5110d2SManos Pitsidianakis } 825a5110d2SManos Pitsidianakis 835a5110d2SManos Pitsidianakis #[cfg_attr(all(feature = "allocator", not(test)), global_allocator)] 845a5110d2SManos Pitsidianakis pub static GLOBAL: QemuAllocator = QemuAllocator::new(); 855a5110d2SManos Pitsidianakis 865a5110d2SManos Pitsidianakis impl QemuAllocator { 875a5110d2SManos Pitsidianakis // From the glibc documentation, on GNU systems, malloc guarantees 16-byte 885a5110d2SManos Pitsidianakis // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See 895a5110d2SManos Pitsidianakis // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html. 905a5110d2SManos Pitsidianakis // This alignment guarantee also applies to Windows and Android. On Darwin 915a5110d2SManos Pitsidianakis // and OpenBSD, the alignment is 16 bytes on both 64-bit and 32-bit systems. 925a5110d2SManos Pitsidianakis #[cfg(all( 935a5110d2SManos Pitsidianakis target_pointer_width = "32", 945a5110d2SManos Pitsidianakis not(any(target_os = "macos", target_os = "openbsd")) 955a5110d2SManos Pitsidianakis ))] 965a5110d2SManos Pitsidianakis pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(8); 975a5110d2SManos Pitsidianakis #[cfg(all( 985a5110d2SManos Pitsidianakis target_pointer_width = "64", 995a5110d2SManos Pitsidianakis not(any(target_os = "macos", target_os = "openbsd")) 1005a5110d2SManos Pitsidianakis ))] 1015a5110d2SManos Pitsidianakis pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16); 1025a5110d2SManos Pitsidianakis #[cfg(all( 1035a5110d2SManos Pitsidianakis any(target_pointer_width = "32", target_pointer_width = "64"), 1045a5110d2SManos Pitsidianakis any(target_os = "macos", target_os = "openbsd") 1055a5110d2SManos Pitsidianakis ))] 1065a5110d2SManos Pitsidianakis pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16); 1075a5110d2SManos Pitsidianakis #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] 1085a5110d2SManos Pitsidianakis pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = None; 1095a5110d2SManos Pitsidianakis new() -> Self1105a5110d2SManos Pitsidianakis pub const fn new() -> Self { 1115a5110d2SManos Pitsidianakis Self { _unused: [] } 1125a5110d2SManos Pitsidianakis } 1135a5110d2SManos Pitsidianakis } 1145a5110d2SManos Pitsidianakis 1155a5110d2SManos Pitsidianakis impl Default for QemuAllocator { default() -> Self1165a5110d2SManos Pitsidianakis fn default() -> Self { 1175a5110d2SManos Pitsidianakis Self::new() 1185a5110d2SManos Pitsidianakis } 1195a5110d2SManos Pitsidianakis } 1205a5110d2SManos Pitsidianakis 1215a5110d2SManos Pitsidianakis // Sanity check. 1229f7d4520SPaolo Bonzini const _: [(); 8] = [(); ::core::mem::size_of::<*mut c_void>()]; 1235a5110d2SManos Pitsidianakis 1245a5110d2SManos Pitsidianakis unsafe impl GlobalAlloc for QemuAllocator { alloc(&self, layout: Layout) -> *mut u81255a5110d2SManos Pitsidianakis unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 1265a5110d2SManos Pitsidianakis if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0)) 1275a5110d2SManos Pitsidianakis { 1285a5110d2SManos Pitsidianakis // SAFETY: g_malloc0() is safe to call. 1295a5110d2SManos Pitsidianakis unsafe { g_malloc0(layout.size().try_into().unwrap()).cast::<u8>() } 1305a5110d2SManos Pitsidianakis } else { 1315a5110d2SManos Pitsidianakis #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)] 1325a5110d2SManos Pitsidianakis { 1335a5110d2SManos Pitsidianakis // SAFETY: g_aligned_alloc0() is safe to call. 1345a5110d2SManos Pitsidianakis unsafe { 1355a5110d2SManos Pitsidianakis g_aligned_alloc0( 1365a5110d2SManos Pitsidianakis layout.size().try_into().unwrap(), 1375a5110d2SManos Pitsidianakis 1, 1385a5110d2SManos Pitsidianakis layout.align().try_into().unwrap(), 1395a5110d2SManos Pitsidianakis ) 1405a5110d2SManos Pitsidianakis .cast::<u8>() 1415a5110d2SManos Pitsidianakis } 1425a5110d2SManos Pitsidianakis } 1435a5110d2SManos Pitsidianakis #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))] 1445a5110d2SManos Pitsidianakis { 1455a5110d2SManos Pitsidianakis // SAFETY: qemu_memalign() is safe to call. 1465a5110d2SManos Pitsidianakis unsafe { qemu_memalign(layout.align(), layout.size()).cast::<u8>() } 1475a5110d2SManos Pitsidianakis } 1485a5110d2SManos Pitsidianakis } 1495a5110d2SManos Pitsidianakis } 1505a5110d2SManos Pitsidianakis dealloc(&self, ptr: *mut u8, layout: Layout)1515a5110d2SManos Pitsidianakis unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 1525a5110d2SManos Pitsidianakis if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0)) 1535a5110d2SManos Pitsidianakis { 1545a5110d2SManos Pitsidianakis // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid 1555a5110d2SManos Pitsidianakis // glib-allocated pointer, so `g_free`ing is safe. 1565a5110d2SManos Pitsidianakis unsafe { g_free(ptr.cast::<_>()) } 1575a5110d2SManos Pitsidianakis } else { 1585a5110d2SManos Pitsidianakis #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)] 1595a5110d2SManos Pitsidianakis { 1605a5110d2SManos Pitsidianakis // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned 1615a5110d2SManos Pitsidianakis // glib-allocated pointer, so `g_aligned_free`ing is safe. 1625a5110d2SManos Pitsidianakis unsafe { g_aligned_free(ptr.cast::<_>()) } 1635a5110d2SManos Pitsidianakis } 1645a5110d2SManos Pitsidianakis #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))] 1655a5110d2SManos Pitsidianakis { 1665a5110d2SManos Pitsidianakis // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned 1675a5110d2SManos Pitsidianakis // glib-allocated pointer, so `qemu_vfree`ing is safe. 1685a5110d2SManos Pitsidianakis unsafe { qemu_vfree(ptr.cast::<_>()) } 1695a5110d2SManos Pitsidianakis } 1705a5110d2SManos Pitsidianakis } 1715a5110d2SManos Pitsidianakis } 1725a5110d2SManos Pitsidianakis } 173*f3518400SJunjie Mao 174*f3518400SJunjie Mao #[cfg(has_offset_of)] 175*f3518400SJunjie Mao pub use core::mem::offset_of; 176