Import QEMU upstream snapshot d2e570c
Upstream: https://gitlab.com/qemu-project/qemu.git Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
This commit is contained in:
commit
cf256aa081
11315 files changed
+3598369
No files matched your search
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "util"
|
||||
version = "0.1.0"
|
||||
description = "Rust bindings for QEMU/util"
|
||||
resolver = "2"
|
||||
publish = false
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
foreign = { workspace = true }
|
||||
glib-sys = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
common = { path = "../common" }
|
||||
util-sys = { path = "../bindings/util-sys" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,17 @@
|
||||
_util_rs = cargo_ws.package('util').library()
|
||||
cargo_ws.package('util').override_dependency(declare_dependency(link_with: _util_rs))
|
||||
|
||||
util_rs = declare_dependency(link_with: [_util_rs], dependencies: [qemuutil, qom])
|
||||
|
||||
rust.test('rust-util-tests', _util_rs,
|
||||
dependencies: [qemuutil, qom],
|
||||
suite: ['unit', 'rust'])
|
||||
|
||||
# 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-util-rs-doctests',
|
||||
_util_rs,
|
||||
dependencies: util_rs,
|
||||
suite: ['doc', 'rust']
|
||||
)
|
||||
@@ -0,0 +1,462 @@
|
||||
// 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
|
||||
//!
|
||||
//! * [`with_errp`](crate::Error::with_errp) 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
|
||||
//! [`utils::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 [`utils::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},
|
||||
ops::Deref,
|
||||
panic,
|
||||
ptr::{self, addr_of_mut},
|
||||
};
|
||||
|
||||
use foreign::{prelude::*, OwnedPointer};
|
||||
|
||||
use crate::bindings;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
cause: anyhow::Error,
|
||||
file: &'static str,
|
||||
line: u32,
|
||||
}
|
||||
|
||||
impl Deref for Error {
|
||||
type Target = anyhow::Error;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cause
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(&format_args!("{:#}", self.cause), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<E> for Error
|
||||
where
|
||||
anyhow::Error: From<E>,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(src: E) -> Self {
|
||||
Self::new(anyhow::Error::from(src))
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Create a new error from an [`anyhow::Error`].
|
||||
///
|
||||
/// This wraps the error with QEMU's location tracking information.
|
||||
/// Most code should use the `?` operator instead of calling this directly.
|
||||
#[track_caller]
|
||||
pub fn new(cause: anyhow::Error) -> Self {
|
||||
let location = panic::Location::caller();
|
||||
Self {
|
||||
cause,
|
||||
file: location.file(),
|
||||
line: location.line(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new error from a string message.
|
||||
///
|
||||
/// This is a convenience wrapper around [`Error::new`] for simple string
|
||||
/// errors. Most code should use the [`ensure!`](crate::ensure) macro
|
||||
/// instead of calling this directly.
|
||||
#[track_caller]
|
||||
pub fn msg(src: impl Into<Cow<'static, str>>) -> Self {
|
||||
Self::new(anyhow::Error::msg(src.into()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
pub fn format(args: fmt::Arguments) -> Self {
|
||||
// anyhow::Error::msg will allocate anyway, might as well let fmt::format doit.
|
||||
let msg = fmt::format(args);
|
||||
Self::new(anyhow::Error::msg(msg))
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
fn do_with_error(
|
||||
msg: Cow<'static, str>,
|
||||
cause: anyhow::Error,
|
||||
location: &'static panic::Location<'static>,
|
||||
) -> Error {
|
||||
Error {
|
||||
cause: cause.context(msg),
|
||||
file: location.file(),
|
||||
line: location.line(),
|
||||
}
|
||||
}
|
||||
do_with_error(msg.into(), cause.into(), panic::Location::caller())
|
||||
}
|
||||
|
||||
/// 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());
|
||||
}
|
||||
}
|
||||
|
||||
/// Pass a C `Error*` to the closure, and convert the result
|
||||
/// (either the return value of the closure, or the error)
|
||||
/// into a Rust `Result`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// One exit from `f`, `c_error` must be unchanged or point to a
|
||||
/// valid C [`struct Error`](bindings::Error).
|
||||
pub unsafe fn with_errp<T, F: FnOnce(&mut *mut bindings::Error) -> T>(f: F) -> Result<T> {
|
||||
let mut c_error: *mut bindings::Error = ptr::null_mut();
|
||||
|
||||
// SAFETY: guaranteed by the postcondition of `f`
|
||||
match (f(&mut c_error), unsafe { c_error.into_native() }) {
|
||||
(result, None) => Ok(result),
|
||||
(_, Some(err)) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension trait for `std::result::Result`, providing extra
|
||||
/// methods when the error type can be converted into a QEMU
|
||||
/// Error.
|
||||
pub trait ResultExt {
|
||||
/// The success type `T` in `Result<T, E>`.
|
||||
type OkType;
|
||||
|
||||
/// Report a fatal error and exit QEMU, or return the success value.
|
||||
/// Note that, unlike [`unwrap()`](std::result::Result::unwrap), this
|
||||
/// is not an abort and can be used for user errors.
|
||||
fn unwrap_fatal(self) -> Self::OkType;
|
||||
}
|
||||
|
||||
impl<T, E> ResultExt for std::result::Result<T, E>
|
||||
where
|
||||
Error: From<E>,
|
||||
{
|
||||
type OkType = T;
|
||||
|
||||
fn unwrap_fatal(self) -> T {
|
||||
// SAFETY: errp is valid
|
||||
self.map_err(|err| unsafe {
|
||||
Error::from(err).propagate(addr_of_mut!(bindings::error_fatal))
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
cause: anyhow::Error::msg(String::cloned_from_foreign(error.msg)),
|
||||
file: file.unwrap(),
|
||||
line: error.line as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure that a condition is true, returning an error if it is false.
|
||||
///
|
||||
/// This macro is similar to [`anyhow::ensure`] but returns a QEMU [`Result`].
|
||||
/// If the condition evaluates to `false`, the macro returns early with an error
|
||||
/// constructed from the provided message.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use util::{ensure, Result};
|
||||
/// # fn check_positive(x: i32) -> Result<()> {
|
||||
/// ensure!(x > 0, "value must be positive");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use util::{ensure, Result};
|
||||
/// # const MIN: i32 = 123;
|
||||
/// # const MAX: i32 = 456;
|
||||
/// # fn check_range(x: i32) -> Result<()> {
|
||||
/// ensure!(
|
||||
/// x >= MIN && x <= MAX,
|
||||
/// "{} not between {} and {}",
|
||||
/// x,
|
||||
/// MIN,
|
||||
/// MAX
|
||||
/// );
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! ensure {
|
||||
($cond:expr, $fmt:literal, $($arg:tt)*) => {
|
||||
if !$cond {
|
||||
let e = $crate::Error::format(format_args!($fmt, $($arg)*));
|
||||
return $crate::Result::Err(e);
|
||||
}
|
||||
};
|
||||
($cond:expr, $err:expr $(,)?) => {
|
||||
if !$cond {
|
||||
let e = $crate::Error::msg($err);
|
||||
return $crate::Result::Err(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ffi::CStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use common::assert_match;
|
||||
use foreign::OwnedPointer;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[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]
|
||||
fn test_display() {
|
||||
assert_eq!(&*format!("{}", Error::msg("msg")), "msg");
|
||||
assert_eq!(&*format!("{}", Error::msg("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::msg("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::msg("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_with_errp() {
|
||||
unsafe {
|
||||
let result = Error::with_errp(|_errp| true);
|
||||
assert_match!(result, Ok(true));
|
||||
|
||||
let err = Error::with_errp(|errp| {
|
||||
*errp = error_for_test(c"msg").into_inner();
|
||||
false
|
||||
})
|
||||
.unwrap_err();
|
||||
assert_eq!(&*format!("{err}"), "msg");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
pub use util_sys as bindings;
|
||||
|
||||
pub mod error;
|
||||
pub mod log;
|
||||
pub mod module;
|
||||
|
||||
// preserve one-item-per-"use" syntax, it is clearer
|
||||
// for prelude-like modules
|
||||
#[rustfmt::skip]
|
||||
pub mod prelude;
|
||||
pub mod timer;
|
||||
|
||||
pub use error::{Error, Result, ResultExt};
|
||||
@@ -0,0 +1,157 @@
|
||||
// Copyright 2025 Bernhard Beschow <[email protected]>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
//! Bindings for QEMU's logging infrastructure
|
||||
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
use common::errno;
|
||||
|
||||
use crate::bindings;
|
||||
|
||||
#[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 = bindings::LOG_GUEST_ERROR,
|
||||
|
||||
/// Log guest access of unimplemented functionality.
|
||||
/// Corresponds to `LOG_UNIMP` in the C implementation.
|
||||
Unimp = bindings::LOG_UNIMP,
|
||||
}
|
||||
|
||||
/// A RAII guard for QEMU's logging infrastructure. Creating the guard
|
||||
/// locks the log file, and dropping it (letting it go out of scope) unlocks
|
||||
/// the file.
|
||||
///
|
||||
/// As long as the guard lives, it can be written to using [`std::io::Write`].
|
||||
///
|
||||
/// The locking is recursive, therefore owning a guard does not prevent
|
||||
/// using [`log_mask_ln!()`](crate::log_mask_ln).
|
||||
pub struct LogGuard(NonNull<bindings::FILE>);
|
||||
|
||||
impl LogGuard {
|
||||
/// Return a RAII guard that writes to QEMU's logging infrastructure.
|
||||
/// The log file is locked while the guard exists, ensuring that there
|
||||
/// is no tearing of the messages.
|
||||
///
|
||||
/// Return `None` if the log file is closed and could not be opened.
|
||||
/// Do *not* use `unwrap()` on the result; failure can be handled simply
|
||||
/// by not logging anything.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use util::log::LogGuard;
|
||||
/// # use std::io::Write;
|
||||
/// if let Some(mut log) = LogGuard::new() {
|
||||
/// writeln!(log, "test");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn new() -> Option<Self> {
|
||||
let f = unsafe { bindings::qemu_log_trylock() }.cast();
|
||||
NonNull::new(f).map(Self)
|
||||
}
|
||||
|
||||
/// Writes a formatted string into the log, returning any error encountered.
|
||||
///
|
||||
/// This method is primarily used by the
|
||||
/// [`log_mask_ln!()`](crate::log_mask_ln) macro, and it is rare for it
|
||||
/// to be called explicitly. It is public because it is the only way to
|
||||
/// examine the error, which `log_mask_ln!()` ignores
|
||||
///
|
||||
/// Unlike `log_mask_ln!()`, it does *not* append a newline at the end.
|
||||
pub fn log_fmt(args: std::fmt::Arguments) -> io::Result<()> {
|
||||
if let Some(mut log) = Self::new() {
|
||||
log.write_fmt(args)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for LogGuard {
|
||||
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
|
||||
let ret = unsafe {
|
||||
bindings::rust_fwrite(bytes.as_ptr().cast(), 1, bytes.len(), self.0.as_ptr())
|
||||
};
|
||||
errno::into_io_result(ret)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
// Do nothing, dropping the guard takes care of flushing
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LogGuard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
bindings::qemu_log_unlock(self.0.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// Errors from writing to the log are ignored.
|
||||
///
|
||||
/// # 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 util::{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 util::{log::Log, log_mask_ln};
|
||||
///
|
||||
/// let error_address = 0xbad;
|
||||
/// log_mask_ln!(
|
||||
/// Log::GuestError,
|
||||
/// "Address 0x{:x} out of range",
|
||||
/// error_address,
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// The `log_mask_ln` macro must only be used for emitting complete
|
||||
/// log messages. Where it is required to incrementally output string
|
||||
/// fragments to construct a complete message, `LogGuard::new()` must
|
||||
/// be directly used in combination with `writeln()` to avoid output
|
||||
/// races with other QEMU threads.
|
||||
#[macro_export]
|
||||
macro_rules! log_mask_ln {
|
||||
($mask:expr, $fmt:tt $($args:tt)*) => {{
|
||||
// Type assertion to enforce type `Log` for $mask
|
||||
let _: $crate::log::Log = $mask;
|
||||
|
||||
if unsafe {
|
||||
($crate::bindings::qemu_loglevel & ($mask as std::os::raw::c_uint)) != 0
|
||||
} {
|
||||
_ = $crate::log::LogGuard::log_fmt(
|
||||
format_args!("{}\n", format_args!($fmt $($args)*)));
|
||||
}
|
||||
}};
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <[email protected]>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
//! Macro to register blocks of code that run as QEMU starts up.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! module_init {
|
||||
($type:ident => $body:block) => {
|
||||
const _: () = {
|
||||
#[used]
|
||||
#[cfg_attr(
|
||||
not(any(target_vendor = "apple", target_os = "windows")),
|
||||
link_section = ".init_array"
|
||||
)]
|
||||
#[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
|
||||
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
|
||||
pub static LOAD_MODULE: extern "C" fn() = {
|
||||
extern "C" fn init_fn() {
|
||||
$body
|
||||
}
|
||||
|
||||
extern "C" fn ctor_fn() {
|
||||
unsafe {
|
||||
$crate::bindings::register_module_init(
|
||||
Some(init_fn),
|
||||
$crate::bindings::module_init_type::$type,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ctor_fn
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// shortcut because it's quite common that $body needs unsafe {}
|
||||
($type:ident => unsafe $body:block) => {
|
||||
::util::module_init! {
|
||||
$type => { unsafe { $body } }
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
//! Essential types and traits intended for blanket imports.
|
||||
|
||||
pub use crate::error::ResultExt;
|
||||
pub use crate::log::Log;
|
||||
pub use crate::timer::Timer;
|
||||
pub use crate::timer::CLOCK_VIRTUAL;
|
||||
pub use crate::timer::NANOSECONDS_PER_SECOND;
|
||||
|
||||
// Re-export commonly used macros
|
||||
pub use crate::ensure;
|
||||
pub use crate::log_mask_ln;
|
||||
@@ -0,0 +1,141 @@
|
||||
// Copyright (C) 2024 Intel Corporation.
|
||||
// Author(s): Zhao Liu <[email protected]>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::{
|
||||
ffi::{c_int, c_void},
|
||||
pin::Pin,
|
||||
};
|
||||
|
||||
use common::{callbacks::FnCall, Opaque};
|
||||
|
||||
use crate::bindings::{
|
||||
self, qemu_clock_get_ns, timer_del, timer_expire_time_ns, timer_init_full, timer_mod,
|
||||
timer_mod_ns, QEMUClockType,
|
||||
};
|
||||
|
||||
/// A safe wrapper around [`bindings::QEMUTimer`].
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, common::Wrapper)]
|
||||
pub struct Timer(Opaque<bindings::QEMUTimer>);
|
||||
|
||||
unsafe impl Send for Timer {}
|
||||
unsafe impl Sync for Timer {}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(common::Wrapper)]
|
||||
pub struct TimerListGroup(Opaque<bindings::QEMUTimerListGroup>);
|
||||
|
||||
unsafe impl Send for TimerListGroup {}
|
||||
unsafe impl Sync for TimerListGroup {}
|
||||
|
||||
impl Timer {
|
||||
pub const MS: u32 = bindings::SCALE_MS;
|
||||
pub const US: u32 = bindings::SCALE_US;
|
||||
pub const NS: u32 = bindings::SCALE_NS;
|
||||
|
||||
/// Create a `Timer` struct without initializing it.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The timer must be initialized before it is armed with
|
||||
/// [`modify`](Self::modify).
|
||||
pub const unsafe fn new() -> Self {
|
||||
// SAFETY: requirements relayed to callers of Timer::new
|
||||
Self(unsafe { Opaque::zeroed() })
|
||||
}
|
||||
|
||||
/// Create a new timer with the given attributes.
|
||||
pub fn init_full<T, F>(
|
||||
opaque: Pin<&mut T>,
|
||||
timer_list_group: Option<&TimerListGroup>,
|
||||
clk_type: ClockType,
|
||||
scale: u32,
|
||||
attributes: u32,
|
||||
_cb: F,
|
||||
field: impl FnOnce(&mut T) -> &mut Self,
|
||||
) where
|
||||
F: for<'a> FnCall<(&'a T,)>,
|
||||
{
|
||||
const { assert!(F::IS_SOME) };
|
||||
|
||||
/// timer expiration callback
|
||||
unsafe extern "C" fn rust_timer_handler<T, F: for<'a> FnCall<(&'a T,)>>(
|
||||
opaque: *mut c_void,
|
||||
) {
|
||||
// SAFETY: the opaque was passed as a reference to `T`.
|
||||
F::call((unsafe { &*(opaque.cast::<T>()) },))
|
||||
}
|
||||
|
||||
let timer_cb: unsafe extern "C" fn(*mut c_void) = rust_timer_handler::<T, F>;
|
||||
|
||||
// SAFETY: the opaque outlives the timer
|
||||
unsafe {
|
||||
let opaque = Pin::into_inner_unchecked(opaque);
|
||||
let timer = field(opaque).as_mut_ptr();
|
||||
timer_init_full(
|
||||
timer,
|
||||
if let Some(g) = timer_list_group {
|
||||
g as *const TimerListGroup as *mut _
|
||||
} else {
|
||||
::core::ptr::null_mut()
|
||||
},
|
||||
clk_type.id,
|
||||
scale as c_int,
|
||||
attributes as c_int,
|
||||
Some(timer_cb),
|
||||
(opaque as *mut T).cast::<c_void>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expire_time_ns(&self) -> Option<i64> {
|
||||
// SAFETY: the only way to obtain a Timer safely is via methods that
|
||||
// take a Pin<&mut Self>, therefore the timer is pinned
|
||||
let ret = unsafe { timer_expire_time_ns(self.as_ptr()) };
|
||||
i64::try_from(ret).ok()
|
||||
}
|
||||
|
||||
pub fn modify_ns(&self, expire_time: u64) {
|
||||
// SAFETY: the only way to obtain a Timer safely is via methods that
|
||||
// take a Pin<&mut Self>, therefore the timer is pinned
|
||||
unsafe { timer_mod_ns(self.as_mut_ptr(), expire_time.try_into().unwrap()) }
|
||||
}
|
||||
|
||||
pub fn modify(&self, expire_time: u64) {
|
||||
// SAFETY: the only way to obtain a Timer safely is via methods that
|
||||
// take a Pin<&mut Self>, therefore the timer is pinned
|
||||
unsafe { timer_mod(self.as_mut_ptr(), expire_time as i64) }
|
||||
}
|
||||
|
||||
pub fn delete(&self) {
|
||||
// SAFETY: the only way to obtain a Timer safely is via methods that
|
||||
// take a Pin<&mut Self>, therefore the timer is pinned
|
||||
unsafe { timer_del(self.as_mut_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: use something like PinnedDrop from the pinned_init crate
|
||||
impl Drop for Timer {
|
||||
fn drop(&mut self) {
|
||||
self.delete()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClockType {
|
||||
id: QEMUClockType,
|
||||
}
|
||||
|
||||
impl ClockType {
|
||||
pub fn get_ns(&self) -> u64 {
|
||||
// SAFETY: cannot be created outside this module, therefore id
|
||||
// is valid
|
||||
(unsafe { qemu_clock_get_ns(self.id) }) as u64
|
||||
}
|
||||
}
|
||||
|
||||
pub const CLOCK_VIRTUAL: ClockType = ClockType {
|
||||
id: QEMUClockType::QEMU_CLOCK_VIRTUAL,
|
||||
};
|
||||
|
||||
pub const NANOSECONDS_PER_SECOND: u64 = 1000000000;
|
||||
Reference in new issue
Block a user