diff options
Diffstat (limited to 'rust/qemu-api')
-rw-r--r-- | rust/qemu-api/Cargo.toml | 2 | ||||
-rw-r--r-- | rust/qemu-api/build.rs | 2 | ||||
-rw-r--r-- | rust/qemu-api/meson.build | 82 | ||||
-rw-r--r-- | rust/qemu-api/src/bindings.rs | 1 | ||||
-rw-r--r-- | rust/qemu-api/src/bitops.rs | 2 | ||||
-rw-r--r-- | rust/qemu-api/src/cell.rs | 22 | ||||
-rw-r--r-- | rust/qemu-api/src/error.rs | 416 | ||||
-rw-r--r-- | rust/qemu-api/src/lib.rs | 5 | ||||
-rw-r--r-- | rust/qemu-api/src/log.rs | 73 | ||||
-rw-r--r-- | rust/qemu-api/src/memory.rs | 12 | ||||
-rw-r--r-- | rust/qemu-api/src/prelude.rs | 2 | ||||
-rw-r--r-- | rust/qemu-api/src/qdev.rs | 61 | ||||
-rw-r--r-- | rust/qemu-api/src/qom.rs | 190 | ||||
-rw-r--r-- | rust/qemu-api/src/timer.rs | 2 | ||||
-rw-r--r-- | rust/qemu-api/src/uninit.rs | 85 | ||||
-rw-r--r-- | rust/qemu-api/src/vmstate.rs | 2 | ||||
-rw-r--r-- | rust/qemu-api/tests/vmstate_tests.rs | 2 | ||||
-rw-r--r-- | rust/qemu-api/wrapper.h | 71 |
18 files changed, 955 insertions, 77 deletions
diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml index c96cf50..db7000d 100644 --- a/rust/qemu-api/Cargo.toml +++ b/rust/qemu-api/Cargo.toml @@ -15,7 +15,9 @@ rust-version.workspace = true [dependencies] qemu_api_macros = { path = "../qemu-api-macros" } +anyhow = "~1.0" libc = "0.2.162" +foreign = "~0.3.1" [features] default = ["debug_cell"] diff --git a/rust/qemu-api/build.rs b/rust/qemu-api/build.rs index 1e72064..7849486 100644 --- a/rust/qemu-api/build.rs +++ b/rust/qemu-api/build.rs @@ -14,7 +14,7 @@ fn main() -> Result<()> { let path = env::var("MESON_BUILD_ROOT") .unwrap_or_else(|_| format!("{}/src", env!("CARGO_MANIFEST_DIR"))); - let file = format!("{path}/bindings.inc.rs"); + let file = format!("{path}/rust/qemu-api/bindings.inc.rs"); let file = Path::new(&file); if !Path::new(&file).exists() { panic!(concat!( diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index 1696df7..a090297 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -2,13 +2,52 @@ _qemu_api_cfg = run_command(rustc_args, '--config-headers', config_host_h, '--features', files('Cargo.toml'), capture: true, check: true).stdout().strip().splitlines() -libc_dep = dependency('libc-0.2-rs') - # _qemu_api_cfg += ['--cfg', 'feature="allocator"'] if get_option('debug_mutex') _qemu_api_cfg += ['--cfg', 'feature="debug_cell"'] endif +c_enums = [ + 'DeviceCategory', + 'GpioPolarity', + 'MachineInitPhase', + 'MemoryDeviceInfoKind', + 'MigrationPolicy', + 'MigrationPriority', + 'QEMUChrEvent', + 'QEMUClockType', + 'ResetType', + 'device_endian', + 'module_init_type', +] +_qemu_api_bindgen_args = [] +foreach enum : c_enums + _qemu_api_bindgen_args += ['--rustified-enum', enum] +endforeach +c_bitfields = [ + 'ClockEvent', + 'VMStateFlags', +] +foreach enum : c_bitfields + _qemu_api_bindgen_args += ['--bitfield-enum', enum] +endforeach + +# TODO: Remove this comment when the clang/libclang mismatch issue is solved. +# +# Rust bindings generation with `bindgen` might fail in some cases where the +# detected `libclang` does not match the expected `clang` version/target. In +# this case you must pass the path to `clang` and `libclang` to your build +# command invocation using the environment variables CLANG_PATH and +# LIBCLANG_PATH +_qemu_api_bindings_inc_rs = rust.bindgen( + input: 'wrapper.h', + dependencies: common_ss.all_dependencies(), + output: 'bindings.inc.rs', + include_directories: bindings_incdir, + bindgen_version: ['>=0.60.0'], + args: bindgen_args_common + _qemu_api_bindgen_args, + ) + _qemu_api_rs = static_library( 'qemu_api', structured_sources( @@ -21,7 +60,9 @@ _qemu_api_rs = static_library( 'src/cell.rs', 'src/chardev.rs', 'src/errno.rs', + 'src/error.rs', 'src/irq.rs', + 'src/log.rs', 'src/memory.rs', 'src/module.rs', 'src/prelude.rs', @@ -29,40 +70,33 @@ _qemu_api_rs = static_library( 'src/qom.rs', 'src/sysbus.rs', 'src/timer.rs', + 'src/uninit.rs', 'src/vmstate.rs', 'src/zeroable.rs', ], - {'.' : bindings_rs}, + {'.' : _qemu_api_bindings_inc_rs}, ), override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_abi: 'rust', rust_args: _qemu_api_cfg, - dependencies: [libc_dep, qemu_api_macros], + dependencies: [anyhow_rs, foreign_rs, libc_rs, qemu_api_macros, qemuutil_rs, + qom, hwcore, chardev, migration], ) rust.test('rust-qemu-api-tests', _qemu_api_rs, suite: ['unit', 'rust']) -qemu_api = declare_dependency(link_with: _qemu_api_rs) +qemu_api = declare_dependency(link_with: [_qemu_api_rs], + dependencies: [qemu_api_macros, qom, hwcore, chardev, migration]) -# Rust executables do not support objects, so add an intermediate step. -rust_qemu_api_objs = static_library( - 'rust_qemu_api_objs', - objects: [libqom.extract_all_objects(recursive: false), - libhwcore.extract_all_objects(recursive: false), - libchardev.extract_all_objects(recursive: false), - libcrypto.extract_all_objects(recursive: false), - libauthz.extract_all_objects(recursive: false), - libio.extract_all_objects(recursive: false), - libmigration.extract_all_objects(recursive: false)]) -rust_qemu_api_deps = declare_dependency( - dependencies: [ - qom_ss.dependencies(), - chardev_ss.dependencies(), - crypto_ss.dependencies(), - authz_ss.dependencies(), - io_ss.dependencies()], - link_whole: [rust_qemu_api_objs, libqemuutil]) +# Doctests are essentially integration tests, so they need the same dependencies. +# Note that running them requires the object files for C code, so place them +# in a separate suite that is run by the "build" CI jobs rather than "check". +rust.doctest('rust-qemu-api-doctests', + _qemu_api_rs, + protocol: 'rust', + dependencies: qemu_api, + suite: ['doc', 'rust']) test('rust-qemu-api-integration', executable( @@ -71,7 +105,7 @@ test('rust-qemu-api-integration', override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_args: ['--test'], install: false, - dependencies: [qemu_api, qemu_api_macros, rust_qemu_api_deps]), + dependencies: [qemu_api]), args: [ '--test', '--test-threads', '1', '--format', 'pretty', diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index 3c1d297..057de4b 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -11,6 +11,7 @@ clippy::restriction, clippy::style, clippy::missing_const_for_fn, + clippy::ptr_offset_with_cast, clippy::useless_transmute, clippy::missing_safety_doc )] diff --git a/rust/qemu-api/src/bitops.rs b/rust/qemu-api/src/bitops.rs index 023ec1a..b1e3a53 100644 --- a/rust/qemu-api/src/bitops.rs +++ b/rust/qemu-api/src/bitops.rs @@ -1,5 +1,5 @@ // Copyright (C) 2024 Intel Corporation. -// Author(s): Zhao Liu <zhai1.liu@intel.com> +// Author(s): Zhao Liu <zhao1.liu@intel.com> // SPDX-License-Identifier: GPL-2.0-or-later //! This module provides bit operation extensions to integer types. diff --git a/rust/qemu-api/src/cell.rs b/rust/qemu-api/src/cell.rs index 05ce09f..27063b0 100644 --- a/rust/qemu-api/src/cell.rs +++ b/rust/qemu-api/src/cell.rs @@ -225,27 +225,23 @@ use crate::bindings; /// An internal function that is used by doctests. pub fn bql_start_test() { - if cfg!(MESON) { - // SAFETY: integration tests are run with --test-threads=1, while - // unit tests and doctests are not multithreaded and do not have - // any BQL-protected data. Just set bql_locked to true. - unsafe { - bindings::rust_bql_mock_lock(); - } + // SAFETY: integration tests are run with --test-threads=1, while + // unit tests and doctests are not multithreaded and do not have + // any BQL-protected data. Just set bql_locked to true. + unsafe { + bindings::rust_bql_mock_lock(); } } pub fn bql_locked() -> bool { // SAFETY: the function does nothing but return a thread-local bool - !cfg!(MESON) || unsafe { bindings::bql_locked() } + unsafe { bindings::bql_locked() } } fn bql_block_unlock(increase: bool) { - if cfg!(MESON) { - // SAFETY: this only adjusts a counter - unsafe { - bindings::bql_block_unlock(increase); - } + // SAFETY: this only adjusts a counter + unsafe { + bindings::bql_block_unlock(increase); } } diff --git a/rust/qemu-api/src/error.rs b/rust/qemu-api/src/error.rs new file mode 100644 index 0000000..e114fc4 --- /dev/null +++ b/rust/qemu-api/src/error.rs @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Error propagation for QEMU Rust code +//! +//! This module contains [`Error`], the bridge between Rust errors and +//! [`Result`](std::result::Result)s and QEMU's C [`Error`](bindings::Error) +//! struct. +//! +//! For FFI code, [`Error`] provides functions to simplify conversion between +//! the Rust ([`Result<>`](std::result::Result)) and C (`Error**`) conventions: +//! +//! * [`ok_or_propagate`](crate::Error::ok_or_propagate), +//! [`bool_or_propagate`](crate::Error::bool_or_propagate), +//! [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to build +//! a C return value while also propagating an error condition +//! +//! * [`err_or_else`](crate::Error::err_or_else) and +//! [`err_or_unit`](crate::Error::err_or_unit) can be used to build a `Result` +//! +//! This module is most commonly used at the boundary between C and Rust code; +//! other code will usually access it through the +//! [`qemu_api::Result`](crate::Result) type alias, and will use the +//! [`std::error::Error`] interface to let C errors participate in Rust's error +//! handling functionality. +//! +//! Rust code can also create use this module to create an error object that +//! will be passed up to C code, though in most cases this will be done +//! transparently through the `?` operator. Errors can be constructed from a +//! simple error string, from an [`anyhow::Error`] to pass any other Rust error +//! type up to C code, or from a combination of the two. +//! +//! The third case, corresponding to [`Error::with_error`], is the only one that +//! requires mentioning [`qemu_api::Error`](crate::Error) explicitly. Similar +//! to how QEMU's C code handles errno values, the string and the +//! `anyhow::Error` object will be concatenated with `:` as the separator. + +use std::{ + borrow::Cow, + ffi::{c_char, c_int, c_void, CStr}, + fmt::{self, Display}, + panic, ptr, +}; + +use foreign::{prelude::*, OwnedPointer}; + +use crate::bindings; + +pub type Result<T> = std::result::Result<T, Error>; + +#[derive(Debug)] +pub struct Error { + msg: Option<Cow<'static, str>>, + /// Appends the print string of the error to the msg if not None + cause: Option<anyhow::Error>, + file: &'static str, + line: u32, +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.cause.as_ref().map(AsRef::as_ref) + } + + #[allow(deprecated)] + fn description(&self) -> &str { + self.msg + .as_deref() + .or_else(|| self.cause.as_deref().map(std::error::Error::description)) + .expect("no message nor cause?") + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut prefix = ""; + if let Some(ref msg) = self.msg { + write!(f, "{msg}")?; + prefix = ": "; + } + if let Some(ref cause) = self.cause { + write!(f, "{prefix}{cause}")?; + } else if prefix.is_empty() { + panic!("no message nor cause?"); + } + Ok(()) + } +} + +impl From<String> for Error { + #[track_caller] + fn from(msg: String) -> Self { + let location = panic::Location::caller(); + Error { + msg: Some(Cow::Owned(msg)), + cause: None, + file: location.file(), + line: location.line(), + } + } +} + +impl From<&'static str> for Error { + #[track_caller] + fn from(msg: &'static str) -> Self { + let location = panic::Location::caller(); + Error { + msg: Some(Cow::Borrowed(msg)), + cause: None, + file: location.file(), + line: location.line(), + } + } +} + +impl From<anyhow::Error> for Error { + #[track_caller] + fn from(error: anyhow::Error) -> Self { + let location = panic::Location::caller(); + Error { + msg: None, + cause: Some(error), + file: location.file(), + line: location.line(), + } + } +} + +impl Error { + /// Create a new error, prepending `msg` to the + /// description of `cause` + #[track_caller] + pub fn with_error(msg: impl Into<Cow<'static, str>>, cause: impl Into<anyhow::Error>) -> Self { + let location = panic::Location::caller(); + Error { + msg: Some(msg.into()), + cause: Some(cause.into()), + file: location.file(), + line: location.line(), + } + } + + /// Consume a result, returning `false` if it is an error and + /// `true` if it is successful. The error is propagated into + /// `errp` like the C API `error_propagate` would do. + /// + /// # Safety + /// + /// `errp` must be a valid argument to `error_propagate`; + /// typically it is received from C code and need not be + /// checked further at the Rust↔C boundary. + pub unsafe fn bool_or_propagate(result: Result<()>, errp: *mut *mut bindings::Error) -> bool { + // SAFETY: caller guarantees errp is valid + unsafe { Self::ok_or_propagate(result, errp) }.is_some() + } + + /// Consume a result, returning a `NULL` pointer if it is an error and + /// a C representation of the contents if it is successful. This is + /// similar to the C API `error_propagate`, but it panics if `*errp` + /// is not `NULL`. + /// + /// # Safety + /// + /// `errp` must be a valid argument to `error_propagate`; + /// typically it is received from C code and need not be + /// checked further at the Rust↔C boundary. + /// + /// See [`propagate`](Error::propagate) for more information. + #[must_use] + pub unsafe fn ptr_or_propagate<T: CloneToForeign>( + result: Result<T>, + errp: *mut *mut bindings::Error, + ) -> *mut T::Foreign { + // SAFETY: caller guarantees errp is valid + unsafe { Self::ok_or_propagate(result, errp) }.clone_to_foreign_ptr() + } + + /// Consume a result in the same way as `self.ok()`, but also propagate + /// a possible error into `errp`. This is similar to the C API + /// `error_propagate`, but it panics if `*errp` is not `NULL`. + /// + /// # Safety + /// + /// `errp` must be a valid argument to `error_propagate`; + /// typically it is received from C code and need not be + /// checked further at the Rust↔C boundary. + /// + /// See [`propagate`](Error::propagate) for more information. + pub unsafe fn ok_or_propagate<T>( + result: Result<T>, + errp: *mut *mut bindings::Error, + ) -> Option<T> { + result.map_err(|err| unsafe { err.propagate(errp) }).ok() + } + + /// Equivalent of the C function `error_propagate`. Fill `*errp` + /// with the information container in `self` if `errp` is not NULL; + /// then consume it. + /// + /// This is similar to the C API `error_propagate`, but it panics if + /// `*errp` is not `NULL`. + /// + /// # Safety + /// + /// `errp` must be a valid argument to `error_propagate`; it can be + /// `NULL` or it can point to any of: + /// * `error_abort` + /// * `error_fatal` + /// * a local variable of (C) type `Error *` + /// + /// Typically `errp` is received from C code and need not be + /// checked further at the Rust↔C boundary. + pub unsafe fn propagate(self, errp: *mut *mut bindings::Error) { + if errp.is_null() { + return; + } + + // SAFETY: caller guarantees that errp and *errp are valid + unsafe { + assert_eq!(*errp, ptr::null_mut()); + bindings::error_propagate(errp, self.clone_to_foreign_ptr()); + } + } + + /// Convert a C `Error*` into a Rust `Result`, using + /// `Ok(())` if `c_error` is NULL. Free the `Error*`. + /// + /// # Safety + /// + /// `c_error` must be `NULL` or valid; typically it was initialized + /// with `ptr::null_mut()` and passed by reference to a C function. + pub unsafe fn err_or_unit(c_error: *mut bindings::Error) -> Result<()> { + // SAFETY: caller guarantees c_error is valid + unsafe { Self::err_or_else(c_error, || ()) } + } + + /// Convert a C `Error*` into a Rust `Result`, calling `f()` to + /// obtain an `Ok` value if `c_error` is NULL. Free the `Error*`. + /// + /// # Safety + /// + /// `c_error` must be `NULL` or point to a valid C [`struct + /// Error`](bindings::Error); typically it was initialized with + /// `ptr::null_mut()` and passed by reference to a C function. + pub unsafe fn err_or_else<T, F: FnOnce() -> T>( + c_error: *mut bindings::Error, + f: F, + ) -> Result<T> { + // SAFETY: caller guarantees c_error is valid + let err = unsafe { Option::<Self>::from_foreign(c_error) }; + match err { + None => Ok(f()), + Some(err) => Err(err), + } + } +} + +impl FreeForeign for Error { + type Foreign = bindings::Error; + + unsafe fn free_foreign(p: *mut bindings::Error) { + // SAFETY: caller guarantees p is valid + unsafe { + bindings::error_free(p); + } + } +} + +impl CloneToForeign for Error { + fn clone_to_foreign(&self) -> OwnedPointer<Self> { + // SAFETY: all arguments are controlled by this function + unsafe { + let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>()); + let err: &mut bindings::Error = &mut *err.cast(); + *err = bindings::Error { + msg: format!("{self}").clone_to_foreign_ptr(), + err_class: bindings::ERROR_CLASS_GENERIC_ERROR, + src_len: self.file.len() as c_int, + src: self.file.as_ptr().cast::<c_char>(), + line: self.line as c_int, + func: ptr::null_mut(), + hint: ptr::null_mut(), + }; + OwnedPointer::new(err) + } + } +} + +impl FromForeign for Error { + unsafe fn cloned_from_foreign(c_error: *const bindings::Error) -> Self { + // SAFETY: caller guarantees c_error is valid + unsafe { + let error = &*c_error; + let file = if error.src_len < 0 { + // NUL-terminated + CStr::from_ptr(error.src).to_str() + } else { + // Can become str::from_utf8 with Rust 1.87.0 + std::str::from_utf8(std::slice::from_raw_parts( + &*error.src.cast::<u8>(), + error.src_len as usize, + )) + }; + + Error { + msg: FromForeign::cloned_from_foreign(error.msg), + cause: None, + file: file.unwrap(), + line: error.line as u32, + } + } + } +} + +#[cfg(test)] +mod tests { + use std::ffi::CStr; + + use anyhow::anyhow; + use foreign::OwnedPointer; + + use super::*; + use crate::{assert_match, bindings}; + + #[track_caller] + fn error_for_test(msg: &CStr) -> OwnedPointer<Error> { + // SAFETY: all arguments are controlled by this function + let location = panic::Location::caller(); + unsafe { + let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>()); + let err: &mut bindings::Error = &mut *err.cast(); + *err = bindings::Error { + msg: msg.clone_to_foreign_ptr(), + err_class: bindings::ERROR_CLASS_GENERIC_ERROR, + src_len: location.file().len() as c_int, + src: location.file().as_ptr().cast::<c_char>(), + line: location.line() as c_int, + func: ptr::null_mut(), + hint: ptr::null_mut(), + }; + OwnedPointer::new(err) + } + } + + unsafe fn error_get_pretty<'a>(local_err: *mut bindings::Error) -> &'a CStr { + unsafe { CStr::from_ptr(bindings::error_get_pretty(local_err)) } + } + + #[test] + #[allow(deprecated)] + fn test_description() { + use std::error::Error; + + assert_eq!(super::Error::from("msg").description(), "msg"); + assert_eq!(super::Error::from("msg".to_owned()).description(), "msg"); + } + + #[test] + fn test_display() { + assert_eq!(&*format!("{}", Error::from("msg")), "msg"); + assert_eq!(&*format!("{}", Error::from("msg".to_owned())), "msg"); + assert_eq!(&*format!("{}", Error::from(anyhow!("msg"))), "msg"); + + assert_eq!( + &*format!("{}", Error::with_error("msg", anyhow!("cause"))), + "msg: cause" + ); + } + + #[test] + fn test_bool_or_propagate() { + unsafe { + let mut local_err: *mut bindings::Error = ptr::null_mut(); + + assert!(Error::bool_or_propagate(Ok(()), &mut local_err)); + assert_eq!(local_err, ptr::null_mut()); + + let my_err = Error::from("msg"); + assert!(!Error::bool_or_propagate(Err(my_err), &mut local_err)); + assert_ne!(local_err, ptr::null_mut()); + assert_eq!(error_get_pretty(local_err), c"msg"); + bindings::error_free(local_err); + } + } + + #[test] + fn test_ptr_or_propagate() { + unsafe { + let mut local_err: *mut bindings::Error = ptr::null_mut(); + + let ret = Error::ptr_or_propagate(Ok("abc".to_owned()), &mut local_err); + assert_eq!(String::from_foreign(ret), "abc"); + assert_eq!(local_err, ptr::null_mut()); + + let my_err = Error::from("msg"); + assert_eq!( + Error::ptr_or_propagate(Err::<String, _>(my_err), &mut local_err), + ptr::null_mut() + ); + assert_ne!(local_err, ptr::null_mut()); + assert_eq!(error_get_pretty(local_err), c"msg"); + bindings::error_free(local_err); + } + } + + #[test] + fn test_err_or_unit() { + unsafe { + let result = Error::err_or_unit(ptr::null_mut()); + assert_match!(result, Ok(())); + + let err = error_for_test(c"msg"); + let err = Error::err_or_unit(err.into_inner()).unwrap_err(); + assert_eq!(&*format!("{err}"), "msg"); + } + } +} diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 234a94e..86dcd8e 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -19,13 +19,16 @@ pub mod callbacks; pub mod cell; pub mod chardev; pub mod errno; +pub mod error; pub mod irq; +pub mod log; pub mod memory; pub mod module; pub mod qdev; pub mod qom; pub mod sysbus; pub mod timer; +pub mod uninit; pub mod vmstate; pub mod zeroable; @@ -34,6 +37,8 @@ use std::{ ffi::c_void, }; +pub use error::{Error, Result}; + #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)] extern "C" { fn g_aligned_alloc0( diff --git a/rust/qemu-api/src/log.rs b/rust/qemu-api/src/log.rs new file mode 100644 index 0000000..d6c3d6c --- /dev/null +++ b/rust/qemu-api/src/log.rs @@ -0,0 +1,73 @@ +// Copyright 2025 Bernhard Beschow <shentey@gmail.com> +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Bindings for QEMU's logging infrastructure + +#[repr(u32)] +/// Represents specific error categories within QEMU's logging system. +/// +/// The `Log` enum provides a Rust abstraction for logging errors, corresponding +/// to a subset of the error categories defined in the C implementation. +pub enum Log { + /// Log invalid access caused by the guest. + /// Corresponds to `LOG_GUEST_ERROR` in the C implementation. + GuestError = crate::bindings::LOG_GUEST_ERROR, + + /// Log guest access of unimplemented functionality. + /// Corresponds to `LOG_UNIMP` in the C implementation. + Unimp = crate::bindings::LOG_UNIMP, +} + +/// A macro to log messages conditionally based on a provided mask. +/// +/// The `log_mask_ln` macro checks whether the given mask matches the current +/// log level and, if so, formats and logs the message. It is the Rust +/// counterpart of the `qemu_log_mask()` macro in the C implementation. +/// +/// # Parameters +/// +/// - `$mask`: A log level mask. This should be a variant of the `Log` enum. +/// - `$fmt`: A format string following the syntax and rules of the `format!` +/// macro. It specifies the structure of the log message. +/// - `$args`: Optional arguments to be interpolated into the format string. +/// +/// # Example +/// +/// ``` +/// use qemu_api::{log::Log, log_mask_ln}; +/// +/// let error_address = 0xbad; +/// log_mask_ln!(Log::GuestError, "Address 0x{error_address:x} out of range"); +/// ``` +/// +/// It is also possible to use printf-style formatting, as well as having a +/// trailing `,`: +/// +/// ``` +/// use qemu_api::{log::Log, log_mask_ln}; +/// +/// let error_address = 0xbad; +/// log_mask_ln!( +/// Log::GuestError, +/// "Address 0x{:x} out of range", +/// error_address, +/// ); +/// ``` +#[macro_export] +macro_rules! log_mask_ln { + ($mask:expr, $fmt:tt $($args:tt)*) => {{ + // Type assertion to enforce type `Log` for $mask + let _: Log = $mask; + + if unsafe { + (::qemu_api::bindings::qemu_loglevel & ($mask as std::os::raw::c_int)) != 0 + } { + let formatted_string = format!("{}\n", format_args!($fmt $($args)*)); + let c_string = std::ffi::CString::new(formatted_string).unwrap(); + + unsafe { + ::qemu_api::bindings::qemu_log(c_string.as_ptr()); + } + } + }}; +} diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs index 9ef2694..e40fad6 100644 --- a/rust/qemu-api/src/memory.rs +++ b/rust/qemu-api/src/memory.rs @@ -16,6 +16,7 @@ use crate::{ callbacks::FnCall, cell::Opaque, prelude::*, + uninit::MaybeUninitField, zeroable::Zeroable, }; @@ -147,7 +148,7 @@ impl MemoryRegion { #[inline(always)] unsafe fn do_init_io( slot: *mut bindings::MemoryRegion, - owner: *mut Object, + owner: *mut bindings::Object, ops: &'static bindings::MemoryRegionOps, name: &'static str, size: u64, @@ -156,7 +157,7 @@ impl MemoryRegion { let cstr = CString::new(name).unwrap(); memory_region_init_io( slot, - owner.cast::<bindings::Object>(), + owner, ops, owner.cast::<c_void>(), cstr.as_ptr(), @@ -166,16 +167,15 @@ impl MemoryRegion { } pub fn init_io<T: IsA<Object>>( - &mut self, - owner: *mut T, + this: &mut MaybeUninitField<'_, T, Self>, ops: &'static MemoryRegionOps<T>, name: &'static str, size: u64, ) { unsafe { Self::do_init_io( - self.0.as_mut_ptr(), - owner.cast::<Object>(), + this.as_mut_ptr().cast(), + MaybeUninitField::parent_mut(this).cast(), &ops.0, name, size, diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 43bfcd5..8f9e23e 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -11,6 +11,8 @@ pub use crate::cell::BqlRefCell; pub use crate::errno; +pub use crate::log_mask_ln; + pub use crate::qdev::DeviceMethods; pub use crate::qom::InterfaceType; diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 1279d7a..36f02fb 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -12,13 +12,14 @@ use std::{ pub use bindings::{ClockEvent, DeviceClass, Property, ResetType}; use crate::{ - bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass}, + bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, ResettableClass}, callbacks::FnCall, cell::{bql_locked, Opaque}, chardev::Chardev, + error::{Error, Result}, irq::InterruptSource, prelude::*, - qom::{ObjectClass, ObjectImpl, Owned}, + qom::{ObjectClass, ObjectImpl, Owned, ParentInit}, vmstate::VMStateDescription, }; @@ -108,7 +109,7 @@ pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> { /// /// If not `None`, the parent class's `realize` method is overridden /// with the function pointed to by `REALIZE`. - const REALIZE: Option<fn(&Self)> = None; + const REALIZE: Option<fn(&Self) -> Result<()>> = None; /// An array providing the properties that the user can set on the /// device. Not a `const` because referencing statics in constants @@ -134,10 +135,13 @@ pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> { /// readable/writeable from one thread at any time. unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>( dev: *mut bindings::DeviceState, - _errp: *mut *mut Error, + errp: *mut *mut bindings::Error, ) { let state = NonNull::new(dev).unwrap().cast::<T>(); - T::REALIZE.unwrap()(unsafe { state.as_ref() }); + let result = T::REALIZE.unwrap()(unsafe { state.as_ref() }); + unsafe { + Error::ok_or_propagate(result, errp); + } } unsafe impl InterfaceType for ResettableClass { @@ -243,15 +247,9 @@ unsafe impl ObjectType for DeviceState { } qom_isa!(DeviceState: Object); -/// Trait for methods exposed by the [`DeviceState`] class. The methods can be -/// called on all objects that have the trait `IsA<DeviceState>`. -/// -/// The trait should only be used through the blanket implementation, -/// which guarantees safety via `IsA`. -pub trait DeviceMethods: ObjectDeref -where - Self::Target: IsA<DeviceState>, -{ +/// Initialization methods take a [`ParentInit`] and can be called as +/// associated functions. +impl DeviceState { /// Add an input clock named `name`. Invoke the callback with /// `self` as the first parameter for the events that are requested. /// @@ -262,12 +260,15 @@ where /// which Rust code has a reference to a child object) it would be /// possible for this function to return a `&Clock` too. #[inline] - fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>( - &self, + pub fn init_clock_in<T: DeviceImpl, F: for<'a> FnCall<(&'a T, ClockEvent)>>( + this: &mut ParentInit<T>, name: &str, _cb: &F, events: ClockEvent, - ) -> Owned<Clock> { + ) -> Owned<Clock> + where + T::ParentType: IsA<DeviceState>, + { fn do_init_clock_in( dev: &DeviceState, name: &str, @@ -283,10 +284,10 @@ where unsafe { let cstr = CString::new(name).unwrap(); let clk = bindings::qdev_init_clock_in( - dev.as_mut_ptr(), + dev.0.as_mut_ptr(), cstr.as_ptr(), cb, - dev.as_void_ptr(), + dev.0.as_void_ptr(), events.0, ); @@ -303,12 +304,12 @@ where // SAFETY: the opaque is "this", which is indeed a pointer to T F::call((unsafe { &*(opaque.cast::<T>()) }, event)) } - Some(rust_clock_cb::<Self::Target, F>) + Some(rust_clock_cb::<T, F>) } else { None }; - do_init_clock_in(self.upcast(), name, cb, events) + do_init_clock_in(unsafe { this.upcast_mut() }, name, cb, events) } /// Add an output clock named `name`. @@ -320,16 +321,30 @@ where /// which Rust code has a reference to a child object) it would be /// possible for this function to return a `&Clock` too. #[inline] - fn init_clock_out(&self, name: &str) -> Owned<Clock> { + pub fn init_clock_out<T: DeviceImpl>(this: &mut ParentInit<T>, name: &str) -> Owned<Clock> + where + T::ParentType: IsA<DeviceState>, + { unsafe { let cstr = CString::new(name).unwrap(); - let clk = bindings::qdev_init_clock_out(self.upcast().as_mut_ptr(), cstr.as_ptr()); + let dev: &mut DeviceState = this.upcast_mut(); + let clk = bindings::qdev_init_clock_out(dev.0.as_mut_ptr(), cstr.as_ptr()); let clk: &Clock = Clock::from_raw(clk); Owned::from(clk) } } +} +/// Trait for methods exposed by the [`DeviceState`] class. The methods can be +/// called on all objects that have the trait `IsA<DeviceState>`. +/// +/// The trait should only be used through the blanket implementation, +/// which guarantees safety via `IsA`. +pub trait DeviceMethods: ObjectDeref +where + Self::Target: IsA<DeviceState>, +{ fn prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>) { assert!(bql_locked()); let c_propname = CString::new(propname).unwrap(); diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 41e5a5e..e20ee01 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -95,7 +95,8 @@ use std::{ ffi::{c_void, CStr}, fmt, - mem::ManuallyDrop, + marker::PhantomData, + mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, ptr::NonNull, }; @@ -206,13 +207,190 @@ impl<T: fmt::Display + ObjectType> fmt::Display for ParentField<T> { } } +/// This struct knows that the superclasses of the object have already been +/// initialized. +/// +/// The declaration of `ParentInit` is.. *"a kind of magic"*. It uses a +/// technique that is found in several crates, the main ones probably being +/// `ghost-cell` (in fact it was introduced by the [`GhostCell` paper](https://plv.mpi-sws.org/rustbelt/ghostcell/)) +/// and `generativity`. +/// +/// The `PhantomData` makes the `ParentInit` type *invariant* with respect to +/// the lifetime argument `'init`. This, together with the `for<'...>` in +/// `[ParentInit::with]`, block any attempt of the compiler to be creative when +/// operating on types of type `ParentInit` and to extend their lifetimes. In +/// particular, it ensures that the `ParentInit` cannot be made to outlive the +/// `rust_instance_init()` function that creates it, and therefore that the +/// `&'init T` reference is valid. +/// +/// This implementation of the same concept, without the QOM baggage, can help +/// understanding the effect: +/// +/// ``` +/// use std::marker::PhantomData; +/// +/// #[derive(PartialEq, Eq)] +/// pub struct Jail<'closure, T: Copy>(&'closure T, PhantomData<fn(&'closure ()) -> &'closure ()>); +/// +/// impl<'closure, T: Copy> Jail<'closure, T> { +/// fn get(&self) -> T { +/// *self.0 +/// } +/// +/// #[inline] +/// fn with<U>(v: T, f: impl for<'id> FnOnce(Jail<'id, T>) -> U) -> U { +/// let parent_init = Jail(&v, PhantomData); +/// f(parent_init) +/// } +/// } +/// ``` +/// +/// It's impossible to escape the `Jail`; `token1` cannot be moved out of the +/// closure: +/// +/// ```ignore +/// let x = 42; +/// let escape = Jail::with(&x, |token1| { +/// println!("{}", token1.get()); +/// // fails to compile... +/// token1 +/// }); +/// // ... so you cannot do this: +/// println!("{}", escape.get()); +/// ``` +/// +/// Likewise, in the QOM case the `ParentInit` cannot be moved out of +/// `instance_init()`. Without this trick it would be possible to stash a +/// `ParentInit` and use it later to access uninitialized memory. +/// +/// Here is another example, showing how separately-created "identities" stay +/// isolated: +/// +/// ```ignore +/// impl<'closure, T: Copy> Clone for Jail<'closure, T> { +/// fn clone(&self) -> Jail<'closure, T> { +/// Jail(self.0, PhantomData) +/// } +/// } +/// +/// fn main() { +/// Jail::with(42, |token1| { +/// // this works and returns true: the clone has the same "identity" +/// println!("{}", token1 == token1.clone()); +/// Jail::with(42, |token2| { +/// // here the outer token remains accessible... +/// println!("{}", token1.get()); +/// // ... but the two are separate: this fails to compile: +/// println!("{}", token1 == token2); +/// }); +/// }); +/// } +/// ``` +pub struct ParentInit<'init, T>( + &'init mut MaybeUninit<T>, + PhantomData<fn(&'init ()) -> &'init ()>, +); + +impl<'init, T> ParentInit<'init, T> { + #[inline] + pub fn with(obj: &'init mut MaybeUninit<T>, f: impl for<'id> FnOnce(ParentInit<'id, T>)) { + let parent_init = ParentInit(obj, PhantomData); + f(parent_init) + } +} + +impl<T: ObjectType> ParentInit<'_, T> { + /// Return the receiver as a mutable raw pointer to Object. + /// + /// # Safety + /// + /// Fields beyond `Object` could be uninitialized and it's your + /// responsibility to avoid that they're used when the pointer is + /// dereferenced, either directly or through a cast. + pub fn as_object_mut_ptr(&self) -> *mut bindings::Object { + self.as_object_ptr().cast_mut() + } + + /// Return the receiver as a mutable raw pointer to Object. + /// + /// # Safety + /// + /// Fields beyond `Object` could be uninitialized and it's your + /// responsibility to avoid that they're used when the pointer is + /// dereferenced, either directly or through a cast. + pub fn as_object_ptr(&self) -> *const bindings::Object { + self.0.as_ptr().cast() + } +} + +impl<'a, T: ObjectImpl> ParentInit<'a, T> { + /// Convert from a derived type to one of its parent types, which + /// have already been initialized. + /// + /// # Safety + /// + /// Structurally this is always a safe operation; the [`IsA`] trait + /// provides static verification trait that `Self` dereferences to `U` or + /// a child of `U`, and only parent types of `T` are allowed. + /// + /// However, while the fields of the resulting reference are initialized, + /// calls might use uninitialized fields of the subclass. It is your + /// responsibility to avoid this. + pub unsafe fn upcast<U: ObjectType>(&self) -> &'a U + where + T::ParentType: IsA<U>, + { + // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait; + // the parent has been initialized before `instance_init `is called + unsafe { &*(self.0.as_ptr().cast::<U>()) } + } + + /// Convert from a derived type to one of its parent types, which + /// have already been initialized. + /// + /// # Safety + /// + /// Structurally this is always a safe operation; the [`IsA`] trait + /// provides static verification trait that `Self` dereferences to `U` or + /// a child of `U`, and only parent types of `T` are allowed. + /// + /// However, while the fields of the resulting reference are initialized, + /// calls might use uninitialized fields of the subclass. It is your + /// responsibility to avoid this. + pub unsafe fn upcast_mut<U: ObjectType>(&mut self) -> &'a mut U + where + T::ParentType: IsA<U>, + { + // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait; + // the parent has been initialized before `instance_init `is called + unsafe { &mut *(self.0.as_mut_ptr().cast::<U>()) } + } +} + +impl<T> Deref for ParentInit<'_, T> { + type Target = MaybeUninit<T>; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +impl<T> DerefMut for ParentInit<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0 + } +} + unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut bindings::Object) { - let mut state = NonNull::new(obj).unwrap().cast::<T>(); + let mut state = NonNull::new(obj).unwrap().cast::<MaybeUninit<T>>(); + // SAFETY: obj is an instance of T, since rust_instance_init<T> // is called from QOM core as the instance_init function // for class T unsafe { - T::INSTANCE_INIT.unwrap()(state.as_mut()); + ParentInit::with(state.as_mut(), |parent_init| { + T::INSTANCE_INIT.unwrap()(parent_init); + }); } } @@ -291,7 +469,7 @@ pub unsafe trait ObjectType: Sized { } /// Return the receiver as a const raw pointer to Object. - /// This is preferrable to `as_object_mut_ptr()` if a C + /// This is preferable to `as_object_mut_ptr()` if a C /// function only needs a `const Object *`. fn as_object_ptr(&self) -> *const bindings::Object { self.as_object().as_ptr() @@ -479,13 +657,13 @@ pub trait ObjectImpl: ObjectType + IsA<Object> { /// /// FIXME: The argument is not really a valid reference. `&mut /// MaybeUninit<Self>` would be a better description. - const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = None; + const INSTANCE_INIT: Option<unsafe fn(ParentInit<Self>)> = None; /// Function that is called to finish initialization of an object, once /// `INSTANCE_INIT` functions have been called. const INSTANCE_POST_INIT: Option<fn(&Self)> = None; - /// Called on descendent classes after all parent class initialization + /// Called on descendant classes after all parent class initialization /// has occurred, but before the class itself is initialized. This /// is only useful if a class is not a leaf, and can be used to undo /// the effects of copying the contents of the parent's class struct diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs index 868bd88..0a2d111 100644 --- a/rust/qemu-api/src/timer.rs +++ b/rust/qemu-api/src/timer.rs @@ -1,5 +1,5 @@ // Copyright (C) 2024 Intel Corporation. -// Author(s): Zhao Liu <zhai1.liu@intel.com> +// Author(s): Zhao Liu <zhao1.liu@intel.com> // SPDX-License-Identifier: GPL-2.0-or-later use std::{ diff --git a/rust/qemu-api/src/uninit.rs b/rust/qemu-api/src/uninit.rs new file mode 100644 index 0000000..04123b4 --- /dev/null +++ b/rust/qemu-api/src/uninit.rs @@ -0,0 +1,85 @@ +//! Access fields of a [`MaybeUninit`] + +use std::{ + mem::MaybeUninit, + ops::{Deref, DerefMut}, +}; + +pub struct MaybeUninitField<'a, T, U> { + parent: &'a mut MaybeUninit<T>, + child: *mut U, +} + +impl<'a, T, U> MaybeUninitField<'a, T, U> { + #[doc(hidden)] + pub fn new(parent: &'a mut MaybeUninit<T>, child: *mut U) -> Self { + MaybeUninitField { parent, child } + } + + /// Return a constant pointer to the containing object of the field. + /// + /// Because the `MaybeUninitField` remembers the containing object, + /// it is possible to use it in foreign APIs that initialize the + /// child. + pub fn parent(f: &Self) -> *const T { + f.parent.as_ptr() + } + + /// Return a mutable pointer to the containing object. + /// + /// Because the `MaybeUninitField` remembers the containing object, + /// it is possible to use it in foreign APIs that initialize the + /// child. + pub fn parent_mut(f: &mut Self) -> *mut T { + f.parent.as_mut_ptr() + } +} + +impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> { + type Target = MaybeUninit<U>; + + fn deref(&self) -> &MaybeUninit<U> { + // SAFETY: self.child was obtained by dereferencing a valid mutable + // reference; the content of the memory may be invalid or uninitialized + // but MaybeUninit<_> makes no assumption on it + unsafe { &*(self.child.cast()) } + } +} + +impl<'a, T, U> DerefMut for MaybeUninitField<'a, T, U> { + fn deref_mut(&mut self) -> &mut MaybeUninit<U> { + // SAFETY: self.child was obtained by dereferencing a valid mutable + // reference; the content of the memory may be invalid or uninitialized + // but MaybeUninit<_> makes no assumption on it + unsafe { &mut *(self.child.cast()) } + } +} + +/// ``` +/// #[derive(Debug)] +/// struct S { +/// x: u32, +/// y: u32, +/// } +/// +/// # use std::mem::MaybeUninit; +/// # use qemu_api::{assert_match, uninit_field_mut}; +/// +/// let mut s: MaybeUninit<S> = MaybeUninit::zeroed(); +/// uninit_field_mut!(s, x).write(5); +/// let s = unsafe { s.assume_init() }; +/// assert_match!(s, S { x: 5, y: 0 }); +/// ``` +#[macro_export] +macro_rules! uninit_field_mut { + ($container:expr, $($field:tt)+) => {{ + let container__: &mut ::std::mem::MaybeUninit<_> = &mut $container; + let container_ptr__ = container__.as_mut_ptr(); + + // SAFETY: the container is not used directly, only through a MaybeUninit<>, + // so the safety is delegated to the caller and to final invocation of + // assume_init() + let target__ = unsafe { std::ptr::addr_of_mut!((*container_ptr__).$($field)+) }; + $crate::uninit::MaybeUninitField::new(container__, target__) + }}; +} diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 9c8b239..812f390 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -9,7 +9,7 @@ //! * [`vmstate_unused!`](crate::vmstate_unused) and //! [`vmstate_of!`](crate::vmstate_of), which are used to express the //! migration format for a struct. This is based on the [`VMState`] trait, -//! which is defined by all migrateable types. +//! which is defined by all migratable types. //! //! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and //! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help with diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vmstate_tests.rs index ad0fc5c..bded836 100644 --- a/rust/qemu-api/tests/vmstate_tests.rs +++ b/rust/qemu-api/tests/vmstate_tests.rs @@ -1,5 +1,5 @@ // Copyright (C) 2025 Intel Corporation. -// Author(s): Zhao Liu <zhai1.liu@intel.com> +// Author(s): Zhao Liu <zhao1.liu@intel.com> // SPDX-License-Identifier: GPL-2.0-or-later use std::{ diff --git a/rust/qemu-api/wrapper.h b/rust/qemu-api/wrapper.h new file mode 100644 index 0000000..15a1b19 --- /dev/null +++ b/rust/qemu-api/wrapper.h @@ -0,0 +1,71 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2024 Linaro Ltd. + * + * Authors: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +/* + * This header file is meant to be used as input to the `bindgen` application + * in order to generate C FFI compatible Rust bindings. + */ + +#ifndef __CLANG_STDATOMIC_H +#define __CLANG_STDATOMIC_H +/* + * Fix potential missing stdatomic.h error in case bindgen does not insert the + * correct libclang header paths on its own. We do not use stdatomic.h symbols + * in QEMU code, so it's fine to declare dummy types instead. + */ +typedef enum memory_order { + memory_order_relaxed, + memory_order_consume, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst, +} memory_order; +#endif /* __CLANG_STDATOMIC_H */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/log-for-trace.h" +#include "qemu/module.h" +#include "qemu-io.h" +#include "system/system.h" +#include "hw/sysbus.h" +#include "system/memory.h" +#include "chardev/char-fe.h" +#include "hw/clock.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/irq.h" +#include "qapi/error.h" +#include "qapi/error-internal.h" +#include "migration/vmstate.h" +#include "chardev/char-serial.h" +#include "exec/memattrs.h" +#include "qemu/timer.h" +#include "system/address-spaces.h" +#include "hw/char/pl011.h" |