Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging

* scripts: dump stdin on meson-buildoptions error
* rust: introduce qemu_api::cell::Opaque<>
* rust: express pinning requirements for timers
* rust: hpet: decode HPET registers into enums
* rust: cell: add full example of declaring a SysBusDevice
* rust: qom: remove operations on &mut

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmfNbXwUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroNjpwf+ODnG0XzHt7LSag695zs5fVLK353m
# vLAHJ0bsmHoR4V+jEc+eaY7esDx5TLB9SRX/NvDsumJ9xnGYxXVn8Ti5GNHpa/xd
# qSReB6X3E8fqG5e3AffUJGJnxrD8dHJ733RsyJBZqJc9sWkUnSiEBb5lGu7br6oC
# fFyfiGweYboQ4AsiQUDtEN+tQsTWNkdThYEzq+dpnZrDJHNnw5e/rRwmqCUnEsLU
# PfwhrOGJ3OkIUtdgHStuNfiN9sqjXV5DXmZVa9L2We8FEQdkhBzg3TC0ez0gFG/1
# W0P6JwfWk9Z+y/ERxkaycSXmabM0zUiFF1UJNgKEXp5iuPnRFC82OtRSUg==
# =de1b
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 09 Mar 2025 18:29:16 HKT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (25 commits)
  rust: pl011: Allow NULL chardev argument to pl011_create()
  meson.build: default to -gsplit-dwarf for debug info
  rust: qom: remove operations on &mut
  rust: cell: add full example of declaring a SysBusDevice
  rust: hpet: decode HPET registers into enums
  rust: pl011: pass around registers::Data
  rust: pl011: switch to safe chardev operation
  rust: pl011: clean up visibilities of callbacks
  rust: pl011: move register definitions out of lib.rs
  rust: chardev: provide basic bindings to character devices
  rust: bindings: remove more unnecessary Send/Sync impls
  rust: chardev: wrap Chardev with Opaque<>
  rust: memory: wrap MemoryRegion with Opaque<>
  rust: sysbus: wrap SysBusDevice with Opaque<>
  rust: hpet: do not access fields of SysBusDevice
  rust: qdev: wrap Clock and DeviceState with Opaque<>
  rust: qom: wrap Object with Opaque<>
  rust: irq: wrap IRQState with Opaque<>
  rust: timer: wrap QEMUTimer with Opaque<> and express pinning requirements
  rust: hpet: embed Timer without the Option and Box indirection
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi
2025-03-10 13:40:05 +08:00
25 changed files with 1551 additions and 1010 deletions
+28 -8
View File
@@ -296,15 +296,35 @@ of ``&mut self``; access to internal fields must use *interior mutability*
to go from a shared reference to a ``&mut``.
Whenever C code provides you with an opaque ``void *``, avoid converting it
to a Rust mutable reference, and use a shared reference instead. Rust code
will then have to use QEMU's ``BqlRefCell`` and ``BqlCell`` type, which
enforce that locking rules for the "Big QEMU Lock" are respected. These cell
types are also known to the ``vmstate`` crate, which is able to "look inside"
them when building an in-memory representation of a ``struct``'s layout.
Note that the same is not true of a ``RefCell`` or ``Mutex``.
to a Rust mutable reference, and use a shared reference instead. The
``qemu_api::cell`` module provides wrappers that can be used to tell the
Rust compiler about interior mutability, and optionally to enforce locking
rules for the "Big QEMU Lock". In the future, similar cell types might
also be provided for ``AioContext``-based locking as well.
In the future, similar cell types might also be provided for ``AioContext``-based
locking as well.
In particular, device code will usually rely on the ``BqlRefCell`` and
``BqlCell`` type to ensure that data is accessed correctly under the
"Big QEMU Lock". These cell types are also known to the ``vmstate``
crate, which is able to "look inside" them when building an in-memory
representation of a ``struct``'s layout. Note that the same is not true
of a ``RefCell`` or ``Mutex``.
Bindings code instead will usually use the ``Opaque`` type, which hides
the contents of the underlying struct and can be easily converted to
a raw pointer, for use in calls to C functions. It can be used for
example as follows::
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct Object(Opaque<bindings::Object>);
where the special ``derive`` macro provides useful methods such as
``from_raw``, ``as_ptr`, ``as_mut_ptr`` and ``raw_get``. The bindings will
then manually check for the big QEMU lock with assertions, which allows
the wrapper to be declared thread-safe::
unsafe impl Send for Object {}
unsafe impl Sync for Object {}
Writing bindings to C code
''''''''''''''''''''''''''
+7 -8
View File
@@ -601,6 +601,10 @@ if get_option('tsan')
qemu_ldflags = ['-fsanitize=thread'] + qemu_ldflags
endif
if get_option('debug') and get_option('split_debug')
qemu_cflags += '-gsplit-dwarf'
endif
# Detect support for PT_GNU_RELRO + DT_BIND_NOW.
# The combination is known as "full relro", because .got.plt is read-only too.
qemu_ldflags += cc.get_supported_link_arguments('-Wl,-z,relro', '-Wl,-z,now')
@@ -4015,7 +4019,7 @@ libchardev = static_library('chardev', chardev_ss.sources() + genh,
build_by_default: false)
chardev = declare_dependency(objects: libchardev.extract_all_objects(recursive: false),
dependencies: chardev_ss.dependencies())
dependencies: [chardev_ss.dependencies(), io])
hwcore_ss = hwcore_ss.apply({})
libhwcore = static_library('hwcore', sources: hwcore_ss.sources() + genh,
@@ -4100,13 +4104,6 @@ if have_rust
foreach enum : c_bitfields
bindgen_args += ['--bitfield-enum', enum]
endforeach
c_nocopy = [
'QEMUTimer',
]
# Used to customize Drop trait
foreach struct : c_nocopy
bindgen_args += ['--no-copy', struct]
endforeach
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
@@ -4590,6 +4587,8 @@ if have_rust
summary_info += {'bindgen': bindgen.full_path()}
summary_info += {'bindgen version': bindgen.version()}
endif
# option_cflags is purely for the summary display, meson will pass
# -g/-O options directly
option_cflags = (get_option('debug') ? ['-g'] : [])
if get_option('optimization') != 'plain'
option_cflags += ['-O' + get_option('optimization')]
+2
View File
@@ -362,6 +362,8 @@ option('debug_mutex', type: 'boolean', value: false,
description: 'mutex debugging support')
option('debug_stack_usage', type: 'boolean', value: false,
description: 'measure coroutine stack usage')
option('split_debug', type: 'boolean', value: true,
description: 'split debug info from object files')
option('qom_cast_debug', type: 'boolean', value: true,
description: 'cast debugging support')
option('slirp_smbd', type : 'feature', value : 'auto',
+2
View File
@@ -37,6 +37,8 @@ result_unit_err = "allow"
should_implement_trait = "deny"
# can be for a reason, e.g. in callbacks
unused_self = "allow"
# common in device crates
upper_case_acronyms = "allow"
# default-allow lints
as_ptr_cast_mut = "deny"
+46 -109
View File
@@ -2,18 +2,10 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
use std::{
ffi::CStr,
os::raw::{c_int, c_void},
ptr::{addr_of, addr_of_mut, NonNull},
};
use std::{ffi::CStr, ptr::addr_of_mut};
use qemu_api::{
bindings::{
qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers,
qemu_chr_fe_write_all, CharBackend, QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK,
},
chardev::Chardev,
chardev::{CharBackend, Chardev, Event},
impl_vmstate_forward,
irq::{IRQState, InterruptSource},
memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder},
@@ -26,10 +18,13 @@ use qemu_api::{
use crate::{
device_class,
registers::{self, Interrupt},
RegisterOffset,
registers::{self, Interrupt, RegisterOffset},
};
// TODO: You must disable the UART before any of the control registers are
// reprogrammed. When the UART is disabled in the middle of transmission or
// reception, it completes the current character before stopping
/// Integer Baud Rate Divider, `UARTIBRD`
const IBRD_MASK: u32 = 0xffff;
@@ -232,14 +227,14 @@ impl PL011Registers {
&mut self,
offset: RegisterOffset,
value: u32,
char_backend: *mut CharBackend,
char_backend: &CharBackend,
) -> bool {
// eprintln!("write offset {offset} value {value}");
use RegisterOffset::*;
match offset {
DR => {
// interrupts always checked
let _ = self.loopback_tx(value);
let _ = self.loopback_tx(value.into());
self.int_level |= Interrupt::TX.0;
return true;
}
@@ -266,17 +261,9 @@ impl PL011Registers {
self.reset_tx_fifo();
}
let update = (self.line_control.send_break() != new_val.send_break()) && {
let mut break_enable: c_int = new_val.send_break().into();
// SAFETY: self.char_backend is a valid CharBackend instance after it's been
// initialized in realize().
unsafe {
qemu_chr_fe_ioctl(
char_backend,
CHR_IOCTL_SERIAL_SET_BREAK as i32,
addr_of_mut!(break_enable).cast::<c_void>(),
);
}
self.loopback_break(break_enable > 0)
let break_enable = new_val.send_break();
let _ = char_backend.send_break(break_enable);
self.loopback_break(break_enable)
};
self.line_control = new_val;
self.set_read_trigger();
@@ -314,7 +301,7 @@ impl PL011Registers {
#[inline]
#[must_use]
fn loopback_tx(&mut self, value: u32) -> bool {
fn loopback_tx(&mut self, value: registers::Data) -> bool {
// Caveat:
//
// In real hardware, TX loopback happens at the serial-bit level
@@ -383,7 +370,7 @@ impl PL011Registers {
}
fn loopback_break(&mut self, enable: bool) -> bool {
enable && self.loopback_tx(registers::Data::BREAK.into())
enable && self.loopback_tx(registers::Data::BREAK)
}
fn set_read_trigger(&mut self) {
@@ -442,11 +429,11 @@ impl PL011Registers {
}
#[must_use]
pub fn put_fifo(&mut self, value: u32) -> bool {
pub fn put_fifo(&mut self, value: registers::Data) -> bool {
let depth = self.fifo_depth();
assert!(depth > 0);
let slot = (self.read_pos + self.read_count) & (depth - 1);
self.read_fifo[slot] = registers::Data::from(value);
self.read_fifo[slot] = value;
self.read_count += 1;
self.flags.set_receive_fifo_empty(false);
if self.read_count == depth {
@@ -534,7 +521,7 @@ impl PL011State {
}
}
pub fn read(&self, offset: hwaddr, _size: u32) -> u64 {
fn read(&self, offset: hwaddr, _size: u32) -> u64 {
match RegisterOffset::try_from(offset) {
Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => {
let device_id = self.get_class().device_id;
@@ -548,37 +535,30 @@ impl PL011State {
let (update_irq, result) = self.regs.borrow_mut().read(field);
if update_irq {
self.update();
unsafe {
qemu_chr_fe_accept_input(addr_of!(self.char_backend) as *mut _);
}
self.char_backend.accept_input();
}
result.into()
}
}
}
pub fn write(&self, offset: hwaddr, value: u64, _size: u32) {
fn write(&self, offset: hwaddr, value: u64, _size: u32) {
let mut update_irq = false;
if let Ok(field) = RegisterOffset::try_from(offset) {
// qemu_chr_fe_write_all() calls into the can_receive
// callback, so handle writes before entering PL011Registers.
if field == RegisterOffset::DR {
// ??? Check if transmitter is enabled.
let ch: u8 = value as u8;
// SAFETY: char_backend is a valid CharBackend instance after it's been
// initialized in realize().
let ch: [u8; 1] = [value as u8];
// XXX this blocks entire thread. Rewrite to use
// qemu_chr_fe_write and background I/O callbacks
unsafe {
qemu_chr_fe_write_all(addr_of!(self.char_backend) as *mut _, &ch, 1);
}
let _ = self.char_backend.write_all(&ch);
}
update_irq = self.regs.borrow_mut().write(
field,
value as u32,
addr_of!(self.char_backend) as *mut _,
);
update_irq = self
.regs
.borrow_mut()
.write(field, value as u32, &self.char_backend);
} else {
eprintln!("write bad offset {offset} value {value}");
}
@@ -587,15 +567,19 @@ impl PL011State {
}
}
pub fn can_receive(&self) -> bool {
// trace_pl011_can_receive(s->lcr, s->read_count, r);
fn can_receive(&self) -> u32 {
let regs = self.regs.borrow();
regs.read_count < regs.fifo_depth()
// trace_pl011_can_receive(s->lcr, s->read_count, r);
u32::from(regs.read_count < regs.fifo_depth())
}
pub fn receive(&self, ch: u32) {
fn receive(&self, buf: &[u8]) {
if buf.is_empty() {
return;
}
let mut regs = self.regs.borrow_mut();
let update_irq = !regs.loopback_enabled() && regs.put_fifo(ch);
let c: u32 = buf[0].into();
let update_irq = !regs.loopback_enabled() && regs.put_fifo(c.into());
// Release the BqlRefCell before calling self.update()
drop(regs);
@@ -604,11 +588,11 @@ impl PL011State {
}
}
pub fn event(&self, event: QEMUChrEvent) {
fn event(&self, event: Event) {
let mut update_irq = false;
let mut regs = self.regs.borrow_mut();
if event == QEMUChrEvent::CHR_EVENT_BREAK && !regs.loopback_enabled() {
update_irq = regs.put_fifo(registers::Data::BREAK.into());
if event == Event::CHR_EVENT_BREAK && !regs.loopback_enabled() {
update_irq = regs.put_fifo(registers::Data::BREAK);
}
// Release the BqlRefCell before calling self.update()
drop(regs);
@@ -618,28 +602,16 @@ impl PL011State {
}
}
pub fn realize(&self) {
// SAFETY: self.char_backend has the correct size and alignment for a
// CharBackend object, and its callbacks are of the correct types.
unsafe {
qemu_chr_fe_set_handlers(
addr_of!(self.char_backend) as *mut CharBackend,
Some(pl011_can_receive),
Some(pl011_receive),
Some(pl011_event),
None,
addr_of!(*self).cast::<c_void>() as *mut c_void,
core::ptr::null_mut(),
true,
);
}
fn realize(&self) {
self.char_backend
.enable_handlers(self, Self::can_receive, Self::receive, Self::event);
}
pub fn reset_hold(&self, _type: ResetType) {
fn reset_hold(&self, _type: ResetType) {
self.regs.borrow_mut().reset();
}
pub fn update(&self) {
fn update(&self) {
let regs = self.regs.borrow();
let flags = regs.int_level & regs.int_enabled;
for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
@@ -663,43 +635,6 @@ const IRQMASK: [u32; 6] = [
Interrupt::E.0,
];
/// # Safety
///
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
pub unsafe extern "C" fn pl011_can_receive(opaque: *mut c_void) -> c_int {
let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
unsafe { state.as_ref().can_receive().into() }
}
/// # Safety
///
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
///
/// The buffer and size arguments must also be valid.
pub unsafe extern "C" fn pl011_receive(opaque: *mut c_void, buf: *const u8, size: c_int) {
let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
unsafe {
if size > 0 {
debug_assert!(!buf.is_null());
state.as_ref().receive(u32::from(buf.read_volatile()));
}
}
}
/// # Safety
///
/// We expect the FFI user of this function to pass a valid pointer, that has
/// the same size as [`PL011State`]. We also expect the device is
/// readable/writeable from one thread at any time.
pub unsafe extern "C" fn pl011_event(opaque: *mut c_void, event: QEMUChrEvent) {
let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
unsafe { state.as_ref().event(event) }
}
/// # Safety
///
/// We expect the FFI user of this function to pass a valid pointer for `chr`
@@ -713,10 +648,12 @@ pub unsafe extern "C" fn pl011_create(
// SAFETY: The callers promise that they have owned references.
// They do not gift them to pl011_create, so use `Owned::from`.
let irq = unsafe { Owned::<IRQState>::from(&*irq) };
let chr = unsafe { Owned::<Chardev>::from(&*chr) };
let dev = PL011State::new();
dev.prop_set_chr("chardev", &chr);
if !chr.is_null() {
let chr = unsafe { Owned::<Chardev>::from(&*chr) };
dev.prop_set_chr("chardev", &chr);
}
dev.sysbus_realize();
dev.mmio_map(0, addr);
dev.connect_irq(0, &irq);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+152 -139
View File
@@ -4,6 +4,7 @@
use std::{
ffi::CStr,
pin::Pin,
ptr::{addr_of_mut, null_mut, NonNull},
slice::from_ref,
};
@@ -47,8 +48,6 @@ const RTC_ISA_IRQ: usize = 8;
const HPET_CLK_PERIOD: u64 = 10; // 10 ns
const FS_PER_NS: u64 = 1000000; // 1000000 femtoseconds == 1 ns
/// General Capabilities and ID Register
const HPET_CAP_REG: u64 = 0x000;
/// Revision ID (bits 0:7). Revision 1 is implemented (refer to v1.0a spec).
const HPET_CAP_REV_ID_VALUE: u64 = 0x1;
const HPET_CAP_REV_ID_SHIFT: usize = 0;
@@ -64,8 +63,6 @@ const HPET_CAP_VENDER_ID_SHIFT: usize = 16;
/// Main Counter Tick Period (bits 32:63)
const HPET_CAP_CNT_CLK_PERIOD_SHIFT: usize = 32;
/// General Configuration Register
const HPET_CFG_REG: u64 = 0x010;
/// Overall Enable (bit 0)
const HPET_CFG_ENABLE_SHIFT: usize = 0;
/// Legacy Replacement Route (bit 1)
@@ -73,14 +70,6 @@ const HPET_CFG_LEG_RT_SHIFT: usize = 1;
/// Other bits are reserved.
const HPET_CFG_WRITE_MASK: u64 = 0x003;
/// General Interrupt Status Register
const HPET_INT_STATUS_REG: u64 = 0x020;
/// Main Counter Value Register
const HPET_COUNTER_REG: u64 = 0x0f0;
/// Timer N Configuration and Capability Register (masked by 0x18)
const HPET_TN_CFG_REG: u64 = 0x000;
/// bit 0, 7, and bits 16:31 are reserved.
/// bit 4, 5, 15, and bits 32:64 are read-only.
const HPET_TN_CFG_WRITE_MASK: u64 = 0x7f4e;
@@ -108,11 +97,51 @@ const HPET_TN_CFG_FSB_CAP_SHIFT: usize = 15;
/// Timer N Interrupt Routing Capability (bits 32:63)
const HPET_TN_CFG_INT_ROUTE_CAP_SHIFT: usize = 32;
/// Timer N Comparator Value Register (masked by 0x18)
const HPET_TN_CMP_REG: u64 = 0x008;
#[derive(qemu_api_macros::TryInto)]
#[repr(u64)]
#[allow(non_camel_case_types)]
/// Timer registers, masked by 0x18
enum TimerRegister {
/// Timer N Configuration and Capability Register
CFG = 0,
/// Timer N Comparator Value Register
CMP = 8,
/// Timer N FSB Interrupt Route Register
ROUTE = 16,
}
/// Timer N FSB Interrupt Route Register (masked by 0x18)
const HPET_TN_FSB_ROUTE_REG: u64 = 0x010;
#[derive(qemu_api_macros::TryInto)]
#[repr(u64)]
#[allow(non_camel_case_types)]
/// Global registers
enum GlobalRegister {
/// General Capabilities and ID Register
CAP = 0,
/// General Configuration Register
CFG = 0x10,
/// General Interrupt Status Register
INT_STATUS = 0x20,
/// Main Counter Value Register
COUNTER = 0xF0,
}
enum HPETRegister<'a> {
/// Global register in the range from `0` to `0xff`
Global(GlobalRegister),
/// Register in the timer block `0x100`...`0x3ff`
Timer(&'a BqlRefCell<HPETTimer>, TimerRegister),
/// Invalid address
#[allow(dead_code)]
Unknown(hwaddr),
}
struct HPETAddrDecode<'a> {
shift: u32,
len: u32,
reg: HPETRegister<'a>,
}
const fn hpet_next_wrap(cur_tick: u64) -> u64 {
(cur_tick | 0xffffffff) + 1
@@ -151,14 +180,14 @@ fn timer_handler(timer_cell: &BqlRefCell<HPETTimer>) {
/// HPET Timer Abstraction
#[repr(C)]
#[derive(Debug, Default, qemu_api_macros::offsets)]
#[derive(Debug, qemu_api_macros::offsets)]
pub struct HPETTimer {
/// timer N index within the timer block (`HPETState`)
#[doc(alias = "tn")]
index: usize,
qemu_timer: Option<Box<Timer>>,
qemu_timer: Timer,
/// timer block abstraction containing this timer
state: Option<NonNull<HPETState>>,
state: NonNull<HPETState>,
// Memory-mapped, software visible timer registers
/// Timer N Configuration and Capability Register
@@ -181,32 +210,39 @@ pub struct HPETTimer {
}
impl HPETTimer {
fn init(&mut self, index: usize, state_ptr: *mut HPETState) -> &mut Self {
*self = HPETTimer::default();
self.index = index;
self.state = NonNull::new(state_ptr);
self
}
fn init(&mut self, index: usize, state: &HPETState) {
*self = HPETTimer {
index,
// SAFETY: the HPETTimer will only be used after the timer
// is initialized below.
qemu_timer: unsafe { Timer::new() },
state: NonNull::new(state as *const _ as *mut _).unwrap(),
config: 0,
cmp: 0,
fsb: 0,
cmp64: 0,
period: 0,
wrap_flag: 0,
last: 0,
};
fn init_timer_with_state(&mut self) {
self.qemu_timer = Some(Box::new({
let mut t = Timer::new();
t.init_full(
None,
CLOCK_VIRTUAL,
Timer::NS,
0,
timer_handler,
&self.get_state().timers[self.index],
);
t
}));
// SAFETY: HPETTimer is only used as part of HPETState, which is
// always pinned.
let qemu_timer = unsafe { Pin::new_unchecked(&mut self.qemu_timer) };
qemu_timer.init_full(
None,
CLOCK_VIRTUAL,
Timer::NS,
0,
timer_handler,
&state.timers[self.index],
)
}
fn get_state(&self) -> &HPETState {
// SAFETY:
// the pointer is convertible to a reference
unsafe { self.state.unwrap().as_ref() }
unsafe { self.state.as_ref() }
}
fn is_int_active(&self) -> bool {
@@ -330,7 +366,7 @@ impl HPETTimer {
}
self.last = ns;
self.qemu_timer.as_ref().unwrap().modify(self.last);
self.qemu_timer.modify(self.last);
}
fn set_timer(&mut self) {
@@ -353,7 +389,7 @@ impl HPETTimer {
fn del_timer(&mut self) {
// Just remove the timer from the timer_list without destroying
// this timer instance.
self.qemu_timer.as_ref().unwrap().delete();
self.qemu_timer.delete();
if self.is_int_active() {
// For level-triggered interrupt, this leaves interrupt status
@@ -463,33 +499,21 @@ impl HPETTimer {
self.update_irq(true);
}
const fn read(&self, addr: hwaddr, _size: u32) -> u64 {
let shift: u64 = (addr & 4) * 8;
match addr & !4 {
HPET_TN_CFG_REG => self.config >> shift, // including interrupt capabilities
HPET_TN_CMP_REG => self.cmp >> shift, // comparator register
HPET_TN_FSB_ROUTE_REG => self.fsb >> shift,
_ => {
// TODO: Add trace point - trace_hpet_ram_read_invalid()
// Reserved.
0
}
const fn read(&self, reg: TimerRegister) -> u64 {
use TimerRegister::*;
match reg {
CFG => self.config, // including interrupt capabilities
CMP => self.cmp, // comparator register
ROUTE => self.fsb,
}
}
fn write(&mut self, addr: hwaddr, value: u64, size: u32) {
let shift = ((addr & 4) * 8) as u32;
let len = std::cmp::min(size * 8, 64 - shift);
match addr & !4 {
HPET_TN_CFG_REG => self.set_tn_cfg_reg(shift, len, value),
HPET_TN_CMP_REG => self.set_tn_cmp_reg(shift, len, value),
HPET_TN_FSB_ROUTE_REG => self.set_tn_fsb_route_reg(shift, len, value),
_ => {
// TODO: Add trace point - trace_hpet_ram_write_invalid()
// Reserved.
}
fn write(&mut self, reg: TimerRegister, value: u64, shift: u32, len: u32) {
use TimerRegister::*;
match reg {
CFG => self.set_tn_cfg_reg(shift, len, value),
CMP => self.set_tn_cmp_reg(shift, len, value),
ROUTE => self.set_tn_fsb_route_reg(shift, len, value),
}
}
}
@@ -581,13 +605,8 @@ impl HPETState {
}
fn init_timer(&self) {
let raw_ptr: *mut HPETState = self as *const HPETState as *mut HPETState;
for (index, timer) in self.timers.iter().enumerate() {
timer
.borrow_mut()
.init(index, raw_ptr)
.init_timer_with_state();
timer.borrow_mut().init(index, self);
}
}
@@ -727,8 +746,6 @@ impl HPETState {
}
fn reset_hold(&self, _type: ResetType) {
let sbd = self.upcast::<SysBusDevice>();
for timer in self.timers.iter().take(self.num_timers.get()) {
timer.borrow_mut().reset();
}
@@ -741,84 +758,80 @@ impl HPETState {
HPETFwConfig::update_hpet_cfg(
self.hpet_id.get(),
self.capability.get() as u32,
sbd.mmio[0].addr,
self.mmio_addr(0).unwrap(),
);
// to document that the RTC lowers its output on reset as well
self.rtc_irq_level.set(0);
}
fn timer_and_addr(&self, addr: hwaddr) -> Option<(&BqlRefCell<HPETTimer>, hwaddr)> {
let timer_id: usize = ((addr - 0x100) / 0x20) as usize;
// TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
if timer_id > self.num_timers.get() {
// TODO: Add trace point - trace_hpet_timer_id_out_of_range(timer_id)
None
} else {
// Keep the complete address so that HPETTimer's read and write could
// detect the invalid access.
Some((&self.timers[timer_id], addr & 0x1F))
}
}
fn read(&self, addr: hwaddr, size: u32) -> u64 {
let shift: u64 = (addr & 4) * 8;
// address range of all TN regs
// TODO: Add trace point - trace_hpet_ram_read(addr)
if (0x100..=0x3ff).contains(&addr) {
match self.timer_and_addr(addr) {
None => 0, // Reserved,
Some((timer, tn_addr)) => timer.borrow_mut().read(tn_addr, size),
}
} else {
match addr & !4 {
HPET_CAP_REG => self.capability.get() >> shift, /* including HPET_PERIOD 0x004 */
// (CNT_CLK_PERIOD field)
HPET_CFG_REG => self.config.get() >> shift,
HPET_COUNTER_REG => {
let cur_tick: u64 = if self.is_hpet_enabled() {
self.get_ticks()
} else {
self.counter.get()
};
// TODO: Add trace point - trace_hpet_ram_read_reading_counter(addr & 4,
// cur_tick)
cur_tick >> shift
}
HPET_INT_STATUS_REG => self.int_status.get() >> shift,
_ => {
// TODO: Add trace point- trace_hpet_ram_read_invalid()
// Reserved.
0
}
}
}
}
fn write(&self, addr: hwaddr, value: u64, size: u32) {
fn decode(&self, mut addr: hwaddr, size: u32) -> HPETAddrDecode {
let shift = ((addr & 4) * 8) as u32;
let len = std::cmp::min(size * 8, 64 - shift);
// TODO: Add trace point - trace_hpet_ram_write(addr, value)
if (0x100..=0x3ff).contains(&addr) {
match self.timer_and_addr(addr) {
None => (), // Reserved.
Some((timer, tn_addr)) => timer.borrow_mut().write(tn_addr, value, size),
}
addr &= !4;
let reg = if (0..=0xff).contains(&addr) {
GlobalRegister::try_from(addr).map(HPETRegister::Global)
} else {
match addr & !0x4 {
HPET_CAP_REG => {} // General Capabilities and ID Register: Read Only
HPET_CFG_REG => self.set_cfg_reg(shift, len, value),
HPET_INT_STATUS_REG => self.set_int_status_reg(shift, len, value),
HPET_COUNTER_REG => self.set_counter_reg(shift, len, value),
_ => {
// TODO: Add trace point - trace_hpet_ram_write_invalid()
// Reserved.
let timer_id: usize = ((addr - 0x100) / 0x20) as usize;
if timer_id <= self.num_timers.get() {
// TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
TimerRegister::try_from(addr)
.map(|reg| HPETRegister::Timer(&self.timers[timer_id], reg))
} else {
// TODO: Add trace point - trace_hpet_timer_id_out_of_range(timer_id)
Err(addr)
}
};
// reg is now a Result<HPETRegister, hwaddr>
// convert the Err case into HPETRegister as well
let reg = reg.unwrap_or_else(HPETRegister::Unknown);
HPETAddrDecode { shift, len, reg }
}
fn read(&self, addr: hwaddr, size: u32) -> u64 {
// TODO: Add trace point - trace_hpet_ram_read(addr)
let HPETAddrDecode { shift, reg, .. } = self.decode(addr, size);
use GlobalRegister::*;
use HPETRegister::*;
(match reg {
Timer(timer, tn_reg) => timer.borrow_mut().read(tn_reg),
Global(CAP) => self.capability.get(), /* including HPET_PERIOD 0x004 */
Global(CFG) => self.config.get(),
Global(INT_STATUS) => self.int_status.get(),
Global(COUNTER) => {
// TODO: Add trace point
// trace_hpet_ram_read_reading_counter(addr & 4, cur_tick)
if self.is_hpet_enabled() {
self.get_ticks()
} else {
self.counter.get()
}
}
Unknown(_) => {
// TODO: Add trace point- trace_hpet_ram_read_invalid()
0
}
}) >> shift
}
fn write(&self, addr: hwaddr, value: u64, size: u32) {
let HPETAddrDecode { shift, len, reg } = self.decode(addr, size);
// TODO: Add trace point - trace_hpet_ram_write(addr, value)
use GlobalRegister::*;
use HPETRegister::*;
match reg {
Timer(timer, tn_reg) => timer.borrow_mut().write(tn_reg, value, shift, len),
Global(CAP) => {} // General Capabilities and ID Register: Read Only
Global(CFG) => self.set_cfg_reg(shift, len, value),
Global(INT_STATUS) => self.set_int_status_reg(shift, len, value),
Global(COUNTER) => self.set_counter_reg(shift, len, value),
Unknown(_) => {
// TODO: Add trace point - trace_hpet_ram_write_invalid()
}
}
}
}
+89 -1
View File
@@ -6,7 +6,7 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::{
parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma, Data,
DeriveInput, Field, Fields, Ident, Meta, Path, Token, Type, Variant, Visibility,
DeriveInput, Field, Fields, FieldsUnnamed, Ident, Meta, Path, Token, Type, Variant, Visibility,
};
mod utils;
@@ -33,6 +33,35 @@ fn get_fields<'a>(
}
}
fn get_unnamed_field<'a>(input: &'a DeriveInput, msg: &str) -> Result<&'a Field, MacroError> {
if let Data::Struct(s) = &input.data {
let unnamed = match &s.fields {
Fields::Unnamed(FieldsUnnamed {
unnamed: ref fields,
..
}) => fields,
_ => {
return Err(MacroError::Message(
format!("Tuple struct required for {}", msg),
s.fields.span(),
))
}
};
if unnamed.len() != 1 {
return Err(MacroError::Message(
format!("A single field is required for {}", msg),
s.fields.span(),
));
}
Ok(&unnamed[0])
} else {
Err(MacroError::Message(
format!("Struct required for {}", msg),
input.ident.span(),
))
}
}
fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), MacroError> {
let expected = parse_quote! { #[repr(C)] };
@@ -46,6 +75,19 @@ fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), MacroError> {
}
}
fn is_transparent_repr(input: &DeriveInput, msg: &str) -> Result<(), MacroError> {
let expected = parse_quote! { #[repr(transparent)] };
if input.attrs.iter().any(|attr| attr == &expected) {
Ok(())
} else {
Err(MacroError::Message(
format!("#[repr(transparent)] required for {}", msg),
input.ident.span(),
))
}
}
fn derive_object_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
is_c_repr(&input, "#[derive(Object)]")?;
@@ -72,6 +114,52 @@ pub fn derive_object(input: TokenStream) -> TokenStream {
TokenStream::from(expanded)
}
fn derive_opaque_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
is_transparent_repr(&input, "#[derive(Wrapper)]")?;
let name = &input.ident;
let field = &get_unnamed_field(&input, "#[derive(Wrapper)]")?;
let typ = &field.ty;
// TODO: how to add "::qemu_api"? For now, this is only used in the
// qemu_api crate so it's not a problem.
Ok(quote! {
unsafe impl crate::cell::Wrapper for #name {
type Wrapped = <#typ as crate::cell::Wrapper>::Wrapped;
}
impl #name {
pub unsafe fn from_raw<'a>(ptr: *mut <Self as crate::cell::Wrapper>::Wrapped) -> &'a Self {
let ptr = ::std::ptr::NonNull::new(ptr).unwrap().cast::<Self>();
unsafe { ptr.as_ref() }
}
pub const fn as_mut_ptr(&self) -> *mut <Self as crate::cell::Wrapper>::Wrapped {
self.0.as_mut_ptr()
}
pub const fn as_ptr(&self) -> *const <Self as crate::cell::Wrapper>::Wrapped {
self.0.as_ptr()
}
pub const fn as_void_ptr(&self) -> *mut ::core::ffi::c_void {
self.0.as_void_ptr()
}
pub const fn raw_get(slot: *mut Self) -> *mut <Self as crate::cell::Wrapper>::Wrapped {
slot.cast()
}
}
})
}
#[proc_macro_derive(Wrapper)]
pub fn derive_opaque(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let expanded = derive_opaque_or_error(input).unwrap_or_else(Into::into);
TokenStream::from(expanded)
}
#[rustfmt::skip::macros(quote)]
fn derive_offsets_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
is_c_repr(&input, "#[derive(offsets)]")?;
+16 -8
View File
@@ -42,22 +42,31 @@ _qemu_api_rs = static_library(
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
rust_args: _qemu_api_cfg,
dependencies: libc_dep,
dependencies: [libc_dep, qemu_api_macros],
)
rust.test('rust-qemu-api-tests', _qemu_api_rs,
suite: ['unit', 'rust'])
qemu_api = declare_dependency(
link_with: _qemu_api_rs,
dependencies: qemu_api_macros,
)
qemu_api = declare_dependency(link_with: _qemu_api_rs)
# 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)])
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)])
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])
test('rust-qemu-api-integration',
executable(
@@ -66,8 +75,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],
link_whole: [rust_qemu_api_objs, libqemuutil]),
dependencies: [qemu_api, qemu_api_macros, rust_qemu_api_deps]),
args: [
'--test', '--test-threads', '1',
'--format', 'pretty',
+2 -24
View File
@@ -25,33 +25,11 @@ include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs"));
// SAFETY: these are implemented in C; the bindings need to assert that the
// BQL is taken, either directly or via `BqlCell` and `BqlRefCell`.
unsafe impl Send for BusState {}
unsafe impl Sync for BusState {}
// When bindings for character devices are introduced, this can be
// moved to the Opaque<> wrapper in src/chardev.rs.
unsafe impl Send for CharBackend {}
unsafe impl Sync for CharBackend {}
unsafe impl Send for Chardev {}
unsafe impl Sync for Chardev {}
unsafe impl Send for Clock {}
unsafe impl Sync for Clock {}
unsafe impl Send for DeviceState {}
unsafe impl Sync for DeviceState {}
unsafe impl Send for MemoryRegion {}
unsafe impl Sync for MemoryRegion {}
unsafe impl Send for ObjectClass {}
unsafe impl Sync for ObjectClass {}
unsafe impl Send for Object {}
unsafe impl Sync for Object {}
unsafe impl Send for SysBusDevice {}
unsafe impl Sync for SysBusDevice {}
// SAFETY: this is a pure data struct
unsafe impl Send for CoalescedMemoryRange {}
unsafe impl Sync for CoalescedMemoryRange {}
+270 -7
View File
@@ -27,7 +27,7 @@
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//! BQL-protected mutable containers.
//! QEMU-specific mutable containers
//!
//! Rust memory safety is based on this rule: Given an object `T`, it is only
//! possible to have one of the following:
@@ -43,8 +43,10 @@
//! usually have their pointer shared with the "outside world very early in
//! their lifetime", for example when they create their
//! [`MemoryRegion`s](crate::bindings::MemoryRegion). Therefore, individual
//! parts of a device must be made mutable in a controlled manner through the
//! use of cell types.
//! parts of a device must be made mutable in a controlled manner; this module
//! provides the tools to do so.
//!
//! ## Cell types
//!
//! [`BqlCell<T>`] and [`BqlRefCell<T>`] allow doing this via the Big QEMU Lock.
//! While they are essentially the same single-threaded primitives that are
@@ -71,7 +73,35 @@
//! QEMU device implementations is usually incorrect and can lead to
//! thread-safety issues.
//!
//! ## `BqlCell<T>`
//! ### Example
//!
//! ```
//! # use qemu_api::prelude::*;
//! # use qemu_api::{c_str, cell::BqlRefCell, irq::InterruptSource, irq::IRQState};
//! # use qemu_api::{sysbus::SysBusDevice, qom::Owned, qom::ParentField};
//! # const N_GPIOS: usize = 8;
//! # struct PL061Registers { /* ... */ }
//! # unsafe impl ObjectType for PL061State {
//! # type Class = <SysBusDevice as ObjectType>::Class;
//! # const TYPE_NAME: &'static std::ffi::CStr = c_str!("pl061");
//! # }
//! struct PL061State {
//! parent_obj: ParentField<SysBusDevice>,
//!
//! // Configuration is read-only after initialization
//! pullups: u32,
//! pulldowns: u32,
//!
//! // Single values shared with C code use BqlCell, in this case via InterruptSource
//! out: [InterruptSource; N_GPIOS],
//! interrupt: InterruptSource,
//!
//! // Larger state accessed by device methods uses BqlRefCell or Mutex
//! registers: BqlRefCell<PL061Registers>,
//! }
//! ```
//!
//! ### `BqlCell<T>`
//!
//! [`BqlCell<T>`] implements interior mutability by moving values in and out of
//! the cell. That is, an `&mut T` to the inner value can never be obtained as
@@ -91,7 +121,7 @@
//! - [`set`](BqlCell::set): this method replaces the interior value,
//! dropping the replaced value.
//!
//! ## `BqlRefCell<T>`
//! ### `BqlRefCell<T>`
//!
//! [`BqlRefCell<T>`] uses Rust's lifetimes to implement "dynamic borrowing", a
//! process whereby one can claim temporary, exclusive, mutable access to the
@@ -111,13 +141,82 @@
//! Multiple immutable borrows are allowed via [`borrow`](BqlRefCell::borrow),
//! or a single mutable borrow via [`borrow_mut`](BqlRefCell::borrow_mut). The
//! thread will panic if these rules are violated or if the BQL is not held.
//!
//! ## Opaque wrappers
//!
//! The cell types from the previous section are useful at the boundaries
//! of code that requires interior mutability. When writing glue code that
//! interacts directly with C structs, however, it is useful to operate
//! at a lower level.
//!
//! C functions often violate Rust's fundamental assumptions about memory
//! safety by modifying memory even if it is shared. Furthermore, C structs
//! often start their life uninitialized and may be populated lazily.
//!
//! For this reason, this module provides the [`Opaque<T>`] type to opt out
//! of Rust's usual guarantees about the wrapped type. Access to the wrapped
//! value is always through raw pointers, obtained via methods like
//! [`as_mut_ptr()`](Opaque::as_mut_ptr) and [`as_ptr()`](Opaque::as_ptr). These
//! pointers can then be passed to C functions or dereferenced; both actions
//! require `unsafe` blocks, making it clear where safety guarantees must be
//! manually verified. For example
//!
//! ```ignore
//! unsafe {
//! let state = Opaque::<MyStruct>::uninit();
//! qemu_struct_init(state.as_mut_ptr());
//! }
//! ```
//!
//! [`Opaque<T>`] will usually be wrapped one level further, so that
//! bridge methods can be added to the wrapper:
//!
//! ```ignore
//! pub struct MyStruct(Opaque<bindings::MyStruct>);
//!
//! impl MyStruct {
//! fn new() -> Pin<Box<MyStruct>> {
//! let result = Box::pin(unsafe { Opaque::uninit() });
//! unsafe { qemu_struct_init(result.as_mut_ptr()) };
//! result
//! }
//! }
//! ```
//!
//! This pattern of wrapping bindgen-generated types in [`Opaque<T>`] provides
//! several advantages:
//!
//! * The choice of traits to be implemented is not limited by the
//! bindgen-generated code. For example, [`Drop`] can be added without
//! disabling [`Copy`] on the underlying bindgen type
//!
//! * [`Send`] and [`Sync`] implementations can be controlled by the wrapper
//! type rather than being automatically derived from the C struct's layout
//!
//! * Methods can be implemented in a separate crate from the bindgen-generated
//! bindings
//!
//! * [`Debug`](std::fmt::Debug) and [`Display`](std::fmt::Display)
//! implementations can be customized to be more readable than the raw C
//! struct representation
//!
//! The [`Opaque<T>`] type does not include BQL validation; it is possible to
//! assert in the code that the right lock is taken, to use it together
//! with a custom lock guard type, or to let C code take the lock, as
//! appropriate. It is also possible to use it with non-thread-safe
//! types, since by default (unlike [`BqlCell`] and [`BqlRefCell`]
//! it is neither `Sync` nor `Send`.
//!
//! While [`Opaque<T>`] is necessary for C interop, it should be used sparingly
//! and only at FFI boundaries. For QEMU-specific types that need interior
//! mutability, prefer [`BqlCell`] or [`BqlRefCell`].
use std::{
cell::{Cell, UnsafeCell},
cmp::Ordering,
fmt,
marker::PhantomData,
mem,
marker::{PhantomData, PhantomPinned},
mem::{self, MaybeUninit},
ops::{Deref, DerefMut},
ptr::NonNull,
};
@@ -840,3 +939,167 @@ impl<T: fmt::Display> fmt::Display for BqlRefMut<'_, T> {
(**self).fmt(f)
}
}
/// Stores an opaque value that is shared with C code.
///
/// Often, C structs can changed when calling a C function even if they are
/// behind a shared Rust reference, or they can be initialized lazily and have
/// invalid bit patterns (e.g. `3` for a [`bool`]). This goes against Rust's
/// strict aliasing rules, which normally prevent mutation through shared
/// references.
///
/// Wrapping the struct with `Opaque<T>` ensures that the Rust compiler does not
/// assume the usual constraints that Rust structs require, and allows using
/// shared references on the Rust side.
///
/// `Opaque<T>` is `#[repr(transparent)]`, so that it matches the memory layout
/// of `T`.
#[repr(transparent)]
pub struct Opaque<T> {
value: UnsafeCell<MaybeUninit<T>>,
// PhantomPinned also allows multiple references to the `Opaque<T>`, i.e.
// one `&mut Opaque<T>` can coexist with a `&mut T` or any number of `&T`;
// see https://docs.rs/pinned-aliasable/latest/pinned_aliasable/.
_pin: PhantomPinned,
}
impl<T> Opaque<T> {
/// Creates a new shared reference from a C pointer
///
/// # Safety
///
/// The pointer must be valid, though it need not point to a valid value.
pub unsafe fn from_raw<'a>(ptr: *mut T) -> &'a Self {
let ptr = NonNull::new(ptr).unwrap().cast::<Self>();
// SAFETY: Self is a transparent wrapper over T
unsafe { ptr.as_ref() }
}
/// Creates a new opaque object with uninitialized contents.
///
/// # Safety
///
/// Ultimately the pointer to the returned value will be dereferenced
/// in another `unsafe` block, for example when passing it to a C function,
/// but the functions containing the dereference are usually safe. The
/// value returned from `uninit()` must be initialized and pinned before
/// calling them.
#[allow(clippy::missing_const_for_fn)]
pub unsafe fn uninit() -> Self {
Self {
value: UnsafeCell::new(MaybeUninit::uninit()),
_pin: PhantomPinned,
}
}
/// Creates a new opaque object with zeroed contents.
///
/// # Safety
///
/// Ultimately the pointer to the returned value will be dereferenced
/// in another `unsafe` block, for example when passing it to a C function,
/// but the functions containing the dereference are usually safe. The
/// value returned from `uninit()` must be pinned (and possibly initialized)
/// before calling them.
#[allow(clippy::missing_const_for_fn)]
pub unsafe fn zeroed() -> Self {
Self {
value: UnsafeCell::new(MaybeUninit::zeroed()),
_pin: PhantomPinned,
}
}
/// Returns a raw mutable pointer to the opaque data.
pub const fn as_mut_ptr(&self) -> *mut T {
UnsafeCell::get(&self.value).cast()
}
/// Returns a raw pointer to the opaque data.
pub const fn as_ptr(&self) -> *const T {
self.as_mut_ptr() as *const _
}
/// Returns a raw pointer to the opaque data that can be passed to a
/// C function as `void *`.
pub const fn as_void_ptr(&self) -> *mut std::ffi::c_void {
UnsafeCell::get(&self.value).cast()
}
/// Converts a raw pointer to the wrapped type.
pub const fn raw_get(slot: *mut Self) -> *mut T {
// Compare with Linux's raw_get method, which goes through an UnsafeCell
// because it takes a *const Self instead.
slot.cast()
}
}
impl<T> fmt::Debug for Opaque<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut name: String = "Opaque<".to_string();
name += std::any::type_name::<T>();
name += ">";
f.debug_tuple(&name).field(&self.as_ptr()).finish()
}
}
impl<T: Default> Opaque<T> {
/// Creates a new opaque object with default contents.
///
/// # Safety
///
/// Ultimately the pointer to the returned value will be dereferenced
/// in another `unsafe` block, for example when passing it to a C function,
/// but the functions containing the dereference are usually safe. The
/// value returned from `uninit()` must be pinned before calling them.
pub unsafe fn new() -> Self {
Self {
value: UnsafeCell::new(MaybeUninit::new(T::default())),
_pin: PhantomPinned,
}
}
}
/// Annotates [`Self`] as a transparent wrapper for another type.
///
/// Usually defined via the [`qemu_api_macros::Wrapper`] derive macro.
///
/// # Examples
///
/// ```
/// # use std::mem::ManuallyDrop;
/// # use qemu_api::cell::Wrapper;
/// #[repr(transparent)]
/// pub struct Example {
/// inner: ManuallyDrop<String>,
/// }
///
/// unsafe impl Wrapper for Example {
/// type Wrapped = String;
/// }
/// ```
///
/// # Safety
///
/// `Self` must be a `#[repr(transparent)]` wrapper for the `Wrapped` type,
/// whether directly or indirectly.
///
/// # Methods
///
/// By convention, types that implement Wrapper also implement the following
/// methods:
///
/// ```ignore
/// pub const unsafe fn from_raw<'a>(value: *mut Self::Wrapped) -> &'a Self;
/// pub const unsafe fn as_mut_ptr(&self) -> *mut Self::Wrapped;
/// pub const unsafe fn as_ptr(&self) -> *const Self::Wrapped;
/// pub const unsafe fn raw_get(slot: *mut Self) -> *const Self::Wrapped;
/// ```
///
/// They are not defined here to allow them to be `const`.
pub unsafe trait Wrapper {
type Wrapped;
}
unsafe impl<T> Wrapper for Opaque<T> {
type Wrapped = T;
}
+245 -3
View File
@@ -3,13 +3,255 @@
// SPDX-License-Identifier: GPL-2.0-or-later
//! Bindings for character devices
//!
//! Character devices in QEMU can run under the big QEMU lock or in a separate
//! `GMainContext`. Here we only support the former, because the bindings
//! enforce that the BQL is taken whenever the functions in [`CharBackend`] are
//! called.
use std::ffi::CStr;
use std::{
ffi::CStr,
fmt::{self, Debug},
io::{self, ErrorKind, Write},
marker::PhantomPinned,
os::raw::{c_int, c_void},
ptr::addr_of_mut,
slice,
};
use crate::{bindings, prelude::*};
use crate::{
bindings,
callbacks::FnCall,
cell::{BqlRefMut, Opaque},
prelude::*,
};
/// A safe wrapper around [`bindings::Chardev`].
#[repr(transparent)]
#[derive(qemu_api_macros::Wrapper)]
pub struct Chardev(Opaque<bindings::Chardev>);
pub type Chardev = bindings::Chardev;
pub type ChardevClass = bindings::ChardevClass;
pub type Event = bindings::QEMUChrEvent;
/// A safe wrapper around [`bindings::CharBackend`], denoting the character
/// back-end that is used for example by a device. Compared to the
/// underlying C struct it adds BQL protection, and is marked as pinned
/// because the QOM object ([`bindings::Chardev`]) contains a pointer to
/// the `CharBackend`.
pub struct CharBackend {
inner: BqlRefCell<bindings::CharBackend>,
_pin: PhantomPinned,
}
impl Write for BqlRefMut<'_, bindings::CharBackend> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let chr: &mut bindings::CharBackend = self;
let len = buf.len().try_into().unwrap();
let r = unsafe { bindings::qemu_chr_fe_write(addr_of_mut!(*chr), buf.as_ptr(), len) };
errno::into_io_result(r).map(|cnt| cnt as usize)
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
let chr: &mut bindings::CharBackend = self;
let len = buf.len().try_into().unwrap();
let r = unsafe { bindings::qemu_chr_fe_write_all(addr_of_mut!(*chr), buf.as_ptr(), len) };
errno::into_io_result(r).and_then(|cnt| {
if cnt as usize == buf.len() {
Ok(())
} else {
Err(ErrorKind::WriteZero.into())
}
})
}
}
impl Debug for CharBackend {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// SAFETY: accessed just to print the values
let chr = self.inner.as_ptr();
Debug::fmt(unsafe { &*chr }, f)
}
}
// FIXME: use something like PinnedDrop from the pinned_init crate
impl Drop for CharBackend {
fn drop(&mut self) {
self.disable_handlers();
}
}
impl CharBackend {
/// Enable the front-end's character device handlers, if there is an
/// associated `Chardev`.
pub fn enable_handlers<
'chardev,
'owner: 'chardev,
T,
CanReceiveFn: for<'a> FnCall<(&'a T,), u32>,
ReceiveFn: for<'a, 'b> FnCall<(&'a T, &'b [u8])>,
EventFn: for<'a> FnCall<(&'a T, Event)>,
>(
// When "self" is dropped, the handlers are automatically disabled.
// However, this is not necessarily true if the owner is dropped.
// So require the owner to outlive the character device.
&'chardev self,
owner: &'owner T,
_can_receive: CanReceiveFn,
_receive: ReceiveFn,
_event: EventFn,
) {
unsafe extern "C" fn rust_can_receive_cb<T, F: for<'a> FnCall<(&'a T,), u32>>(
opaque: *mut c_void,
) -> c_int {
// SAFETY: the values are safe according to the contract of
// enable_handlers() and qemu_chr_fe_set_handlers()
let owner: &T = unsafe { &*(opaque.cast::<T>()) };
let r = F::call((owner,));
r.try_into().unwrap()
}
unsafe extern "C" fn rust_receive_cb<T, F: for<'a, 'b> FnCall<(&'a T, &'b [u8])>>(
opaque: *mut c_void,
buf: *const u8,
size: c_int,
) {
// SAFETY: the values are safe according to the contract of
// enable_handlers() and qemu_chr_fe_set_handlers()
let owner: &T = unsafe { &*(opaque.cast::<T>()) };
let buf = unsafe { slice::from_raw_parts(buf, size.try_into().unwrap()) };
F::call((owner, buf))
}
unsafe extern "C" fn rust_event_cb<T, F: for<'a> FnCall<(&'a T, Event)>>(
opaque: *mut c_void,
event: Event,
) {
// SAFETY: the values are safe according to the contract of
// enable_handlers() and qemu_chr_fe_set_handlers()
let owner: &T = unsafe { &*(opaque.cast::<T>()) };
F::call((owner, event))
}
let _: () = CanReceiveFn::ASSERT_IS_SOME;
let receive_cb: Option<unsafe extern "C" fn(*mut c_void, *const u8, c_int)> =
if ReceiveFn::is_some() {
Some(rust_receive_cb::<T, ReceiveFn>)
} else {
None
};
let event_cb: Option<unsafe extern "C" fn(*mut c_void, Event)> = if EventFn::is_some() {
Some(rust_event_cb::<T, EventFn>)
} else {
None
};
let mut chr = self.inner.borrow_mut();
// SAFETY: the borrow promises that the BQL is taken
unsafe {
bindings::qemu_chr_fe_set_handlers(
addr_of_mut!(*chr),
Some(rust_can_receive_cb::<T, CanReceiveFn>),
receive_cb,
event_cb,
None,
(owner as *const T as *mut T).cast::<c_void>(),
core::ptr::null_mut(),
true,
);
}
}
/// Disable the front-end's character device handlers.
pub fn disable_handlers(&self) {
let mut chr = self.inner.borrow_mut();
// SAFETY: the borrow promises that the BQL is taken
unsafe {
bindings::qemu_chr_fe_set_handlers(
addr_of_mut!(*chr),
None,
None,
None,
None,
core::ptr::null_mut(),
core::ptr::null_mut(),
true,
);
}
}
/// Notify that the frontend is ready to receive data.
pub fn accept_input(&self) {
let mut chr = self.inner.borrow_mut();
// SAFETY: the borrow promises that the BQL is taken
unsafe { bindings::qemu_chr_fe_accept_input(addr_of_mut!(*chr)) }
}
/// Temporarily borrow the character device, allowing it to be used
/// as an implementor of `Write`. Note that it is not valid to drop
/// the big QEMU lock while the character device is borrowed, as
/// that might cause C code to write to the character device.
pub fn borrow_mut(&self) -> impl Write + '_ {
self.inner.borrow_mut()
}
/// Send a continuous stream of zero bits on the line if `enabled` is
/// true, or a short stream if `enabled` is false.
pub fn send_break(&self, long: bool) -> io::Result<()> {
let mut chr = self.inner.borrow_mut();
let mut duration: c_int = long.into();
// SAFETY: the borrow promises that the BQL is taken
let r = unsafe {
bindings::qemu_chr_fe_ioctl(
addr_of_mut!(*chr),
bindings::CHR_IOCTL_SERIAL_SET_BREAK as i32,
addr_of_mut!(duration).cast::<c_void>(),
)
};
errno::into_io_result(r).map(|_| ())
}
/// Write data to a character backend from the front end. This function
/// will send data from the front end to the back end. Unlike
/// `write`, this function will block if the back end cannot
/// consume all of the data attempted to be written.
///
/// Returns the number of bytes consumed (0 if no associated Chardev) or an
/// error.
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let len = buf.len().try_into().unwrap();
// SAFETY: qemu_chr_fe_write is thread-safe
let r = unsafe { bindings::qemu_chr_fe_write(self.inner.as_ptr(), buf.as_ptr(), len) };
errno::into_io_result(r).map(|cnt| cnt as usize)
}
/// Write data to a character backend from the front end. This function
/// will send data from the front end to the back end. Unlike
/// `write`, this function will block if the back end cannot
/// consume all of the data attempted to be written.
///
/// Returns the number of bytes consumed (0 if no associated Chardev) or an
/// error.
pub fn write_all(&self, buf: &[u8]) -> io::Result<()> {
let len = buf.len().try_into().unwrap();
// SAFETY: qemu_chr_fe_write_all is thread-safe
let r = unsafe { bindings::qemu_chr_fe_write_all(self.inner.as_ptr(), buf.as_ptr(), len) };
errno::into_io_result(r).and_then(|cnt| {
if cnt as usize == buf.len() {
Ok(())
} else {
Err(ErrorKind::WriteZero.into())
}
})
}
}
unsafe impl ObjectType for Chardev {
type Class = ChardevClass;
+10 -5
View File
@@ -8,10 +8,16 @@ use std::{ffi::CStr, marker::PhantomData, os::raw::c_int, ptr};
use crate::{
bindings::{self, qemu_set_irq},
cell::Opaque,
prelude::*,
qom::ObjectClass,
};
/// An opaque wrapper around [`bindings::IRQState`].
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct IRQState(Opaque<bindings::IRQState>);
/// Interrupt sources are used by devices to pass changes to a value (typically
/// a boolean). The interrupt sink is usually an interrupt controller or
/// GPIO controller.
@@ -21,8 +27,7 @@ use crate::{
/// method sends a `true` value to the sink. If the guest has to see a
/// different polarity, that change is performed by the board between the
/// device and the interrupt controller.
pub type IRQState = bindings::IRQState;
///
/// Interrupts are implemented as a pointer to the interrupt "sink", which has
/// type [`IRQState`]. A device exposes its source as a QOM link property using
/// a function such as [`SysBusDeviceMethods::init_irq`], and
@@ -40,7 +45,7 @@ pub struct InterruptSource<T = bool>
where
c_int: From<T>,
{
cell: BqlCell<*mut IRQState>,
cell: BqlCell<*mut bindings::IRQState>,
_marker: PhantomData<T>,
}
@@ -79,11 +84,11 @@ where
}
}
pub(crate) const fn as_ptr(&self) -> *mut *mut IRQState {
pub(crate) const fn as_ptr(&self) -> *mut *mut bindings::IRQState {
self.cell.as_ptr()
}
pub(crate) const fn slice_as_ptr(slice: &[Self]) -> *mut *mut IRQState {
pub(crate) const fn slice_as_ptr(slice: &[Self]) -> *mut *mut bindings::IRQState {
assert!(!slice.is_empty());
slice[0].as_ptr()
}
+17 -15
View File
@@ -6,9 +6,8 @@
use std::{
ffi::{CStr, CString},
marker::{PhantomData, PhantomPinned},
marker::PhantomData,
os::raw::{c_uint, c_void},
ptr::addr_of,
};
pub use bindings::{hwaddr, MemTxAttrs};
@@ -16,6 +15,7 @@ pub use bindings::{hwaddr, MemTxAttrs};
use crate::{
bindings::{self, device_endian, memory_region_init_io},
callbacks::FnCall,
cell::Opaque,
prelude::*,
zeroable::Zeroable,
};
@@ -132,13 +132,13 @@ impl<T> Default for MemoryRegionOpsBuilder<T> {
}
}
/// A safe wrapper around [`bindings::MemoryRegion`]. Compared to the
/// underlying C struct it is marked as pinned because the QOM tree
/// contains a pointer to it.
pub struct MemoryRegion {
inner: bindings::MemoryRegion,
_pin: PhantomPinned,
}
/// A safe wrapper around [`bindings::MemoryRegion`].
#[repr(transparent)]
#[derive(qemu_api_macros::Wrapper)]
pub struct MemoryRegion(Opaque<bindings::MemoryRegion>);
unsafe impl Send for MemoryRegion {}
unsafe impl Sync for MemoryRegion {}
impl MemoryRegion {
// inline to ensure that it is not included in tests, which only
@@ -157,7 +157,7 @@ impl MemoryRegion {
let cstr = CString::new(name).unwrap();
memory_region_init_io(
slot,
owner.cast::<Object>(),
owner.cast::<bindings::Object>(),
ops,
owner.cast::<c_void>(),
cstr.as_ptr(),
@@ -174,13 +174,15 @@ impl MemoryRegion {
size: u64,
) {
unsafe {
Self::do_init_io(&mut self.inner, owner.cast::<Object>(), &ops.0, name, size);
Self::do_init_io(
self.0.as_mut_ptr(),
owner.cast::<Object>(),
&ops.0,
name,
size,
);
}
}
pub(crate) const fn as_mut_ptr(&self) -> *mut bindings::MemoryRegion {
addr_of!(self.inner) as *mut _
}
}
unsafe impl ObjectType for MemoryRegion {
-1
View File
@@ -17,7 +17,6 @@ pub use crate::qom::InterfaceType;
pub use crate::qom::IsA;
pub use crate::qom::Object;
pub use crate::qom::ObjectCast;
pub use crate::qom::ObjectCastMut;
pub use crate::qom::ObjectDeref;
pub use crate::qom::ObjectClassMethods;
pub use crate::qom::ObjectMethods;
+52 -23
View File
@@ -10,12 +10,12 @@ use std::{
ptr::NonNull,
};
pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType};
pub use bindings::{ClockEvent, DeviceClass, Property, ResetType};
use crate::{
bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass},
callbacks::FnCall,
cell::bql_locked,
cell::{bql_locked, Opaque},
chardev::Chardev,
irq::InterruptSource,
prelude::*,
@@ -23,6 +23,22 @@ use crate::{
vmstate::VMStateDescription,
};
/// A safe wrapper around [`bindings::Clock`].
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct Clock(Opaque<bindings::Clock>);
unsafe impl Send for Clock {}
unsafe impl Sync for Clock {}
/// A safe wrapper around [`bindings::DeviceState`].
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct DeviceState(Opaque<bindings::DeviceState>);
unsafe impl Send for DeviceState {}
unsafe impl Sync for DeviceState {}
/// Trait providing the contents of the `ResettablePhases` struct,
/// which is part of the QOM `Resettable` interface.
pub trait ResettablePhasesImpl {
@@ -52,7 +68,7 @@ pub trait ResettablePhasesImpl {
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
obj: *mut Object,
obj: *mut bindings::Object,
typ: ResetType,
) {
let state = NonNull::new(obj).unwrap().cast::<T>();
@@ -65,7 +81,7 @@ unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
obj: *mut Object,
obj: *mut bindings::Object,
typ: ResetType,
) {
let state = NonNull::new(obj).unwrap().cast::<T>();
@@ -78,7 +94,7 @@ unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
obj: *mut Object,
obj: *mut bindings::Object,
typ: ResetType,
) {
let state = NonNull::new(obj).unwrap().cast::<T>();
@@ -117,7 +133,10 @@ pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> {
/// We expect the FFI user of this function to pass a valid pointer that
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(dev: *mut DeviceState, _errp: *mut *mut Error) {
unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(
dev: *mut bindings::DeviceState,
_errp: *mut *mut Error,
) {
let state = NonNull::new(dev).unwrap().cast::<T>();
T::REALIZE.unwrap()(unsafe { state.as_ref() });
}
@@ -251,7 +270,7 @@ where
events: ClockEvent,
) -> Owned<Clock> {
fn do_init_clock_in(
dev: *mut DeviceState,
dev: &DeviceState,
name: &str,
cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>,
events: ClockEvent,
@@ -265,14 +284,15 @@ where
unsafe {
let cstr = CString::new(name).unwrap();
let clk = bindings::qdev_init_clock_in(
dev,
dev.as_mut_ptr(),
cstr.as_ptr(),
cb,
dev.cast::<c_void>(),
dev.as_void_ptr(),
events.0,
);
Owned::from(&*clk)
let clk: &Clock = Clock::from_raw(clk);
Owned::from(clk)
}
}
@@ -289,7 +309,7 @@ where
None
};
do_init_clock_in(self.as_mut_ptr(), name, cb, events)
do_init_clock_in(self.upcast(), name, cb, events)
}
/// Add an output clock named `name`.
@@ -304,17 +324,23 @@ where
fn init_clock_out(&self, name: &str) -> Owned<Clock> {
unsafe {
let cstr = CString::new(name).unwrap();
let clk = bindings::qdev_init_clock_out(self.as_mut_ptr(), cstr.as_ptr());
let clk = bindings::qdev_init_clock_out(self.upcast().as_mut_ptr(), cstr.as_ptr());
Owned::from(&*clk)
let clk: &Clock = Clock::from_raw(clk);
Owned::from(clk)
}
}
fn prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>) {
assert!(bql_locked());
let c_propname = CString::new(propname).unwrap();
let chr: &Chardev = chr;
unsafe {
bindings::qdev_prop_set_chr(self.as_mut_ptr(), c_propname.as_ptr(), chr.as_mut_ptr());
bindings::qdev_prop_set_chr(
self.upcast().as_mut_ptr(),
c_propname.as_ptr(),
chr.as_mut_ptr(),
);
}
}
@@ -323,8 +349,17 @@ where
num_lines: u32,
_cb: F,
) {
let _: () = F::ASSERT_IS_SOME;
fn do_init_gpio_in(
dev: &DeviceState,
num_lines: u32,
gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int),
) {
unsafe {
qdev_init_gpio_in(dev.as_mut_ptr(), Some(gpio_in_cb), num_lines as c_int);
}
}
let _: () = F::ASSERT_IS_SOME;
unsafe extern "C" fn rust_irq_handler<T, F: for<'a> FnCall<(&'a T, u32, u32)>>(
opaque: *mut c_void,
line: c_int,
@@ -337,19 +372,13 @@ where
let gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int) =
rust_irq_handler::<Self::Target, F>;
unsafe {
qdev_init_gpio_in(
self.as_mut_ptr::<DeviceState>(),
Some(gpio_in_cb),
num_lines as c_int,
);
}
do_init_gpio_in(self.upcast(), num_lines, gpio_in_cb);
}
fn init_gpio_out(&self, pins: &[InterruptSource]) {
unsafe {
qdev_init_gpio_out(
self.as_mut_ptr::<DeviceState>(),
self.upcast().as_mut_ptr(),
InterruptSource::slice_as_ptr(pins),
pins.len() as c_int,
);
+22 -96
View File
@@ -101,16 +101,24 @@ use std::{
ptr::NonNull,
};
pub use bindings::{Object, ObjectClass};
pub use bindings::ObjectClass;
use crate::{
bindings::{
self, object_class_dynamic_cast, object_dynamic_cast, object_get_class,
object_get_typename, object_new, object_ref, object_unref, TypeInfo,
},
cell::bql_locked,
cell::{bql_locked, Opaque},
};
/// A safe wrapper around [`bindings::Object`].
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct Object(Opaque<bindings::Object>);
unsafe impl Send for Object {}
unsafe impl Sync for Object {}
/// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct
/// or indirect parent of `Self`).
///
@@ -199,7 +207,7 @@ impl<T: fmt::Display + ObjectType> fmt::Display for ParentField<T> {
}
}
unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) {
unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut bindings::Object) {
let mut state = NonNull::new(obj).unwrap().cast::<T>();
// SAFETY: obj is an instance of T, since rust_instance_init<T>
// is called from QOM core as the instance_init function
@@ -209,7 +217,7 @@ unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) {
}
}
unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut Object) {
unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut bindings::Object) {
let state = NonNull::new(obj).unwrap().cast::<T>();
// SAFETY: obj is an instance of T, since rust_instance_post_init<T>
// is called from QOM core as the instance_post_init function
@@ -230,7 +238,7 @@ unsafe extern "C" fn rust_class_init<T: ObjectType + ObjectImpl>(
<T as ObjectImpl>::CLASS_INIT(unsafe { klass.as_mut() })
}
unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut Object) {
unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut bindings::Object) {
// SAFETY: obj is an instance of T, since drop_object<T> is called
// from the QOM core function object_deinit() as the instance_finalize
// function for class T. Note that while object_deinit() will drop the
@@ -280,14 +288,14 @@ pub unsafe trait ObjectType: Sized {
/// Return the receiver as an Object. This is always safe, even
/// if this type represents an interface.
fn as_object(&self) -> &Object {
unsafe { &*self.as_object_ptr() }
unsafe { &*self.as_ptr().cast() }
}
/// Return the receiver as a const raw pointer to Object.
/// This is preferrable to `as_object_mut_ptr()` if a C
/// function only needs a `const Object *`.
fn as_object_ptr(&self) -> *const Object {
self.as_ptr().cast()
fn as_object_ptr(&self) -> *const bindings::Object {
self.as_object().as_ptr()
}
/// Return the receiver as a mutable raw pointer to Object.
@@ -297,8 +305,8 @@ pub unsafe trait ObjectType: Sized {
/// This cast is always safe, but because the result is mutable
/// and the incoming reference is not, this should only be used
/// for calls to C functions, and only if needed.
unsafe fn as_object_mut_ptr(&self) -> *mut Object {
self.as_object_ptr() as *mut _
unsafe fn as_object_mut_ptr(&self) -> *mut bindings::Object {
self.as_object().as_mut_ptr()
}
}
@@ -455,90 +463,7 @@ where
impl<T: ObjectType> ObjectDeref for &T {}
impl<T: ObjectType> ObjectCast for &T {}
/// Trait for mutable type casting operations in the QOM hierarchy.
///
/// This trait provides the mutable counterparts to [`ObjectCast`]'s conversion
/// functions. Unlike `ObjectCast`, this trait returns `Result` for fallible
/// conversions to preserve the original smart pointer if the cast fails. This
/// is necessary because mutable references cannot be copied, so a failed cast
/// must return ownership of the original reference. For example:
///
/// ```ignore
/// let mut dev = get_device();
/// // If this fails, we need the original `dev` back to try something else
/// match dev.dynamic_cast_mut::<FooDevice>() {
/// Ok(foodev) => /* use foodev */,
/// Err(dev) => /* still have ownership of dev */
/// }
/// ```
pub trait ObjectCastMut: Sized + ObjectDeref + DerefMut
where
Self::Target: ObjectType,
{
/// Safely convert from a derived type to one of its parent types.
///
/// This is always safe; the [`IsA`] trait provides static verification
/// that `Self` dereferences to `U` or a child of `U`.
fn upcast_mut<'a, U: ObjectType>(self) -> &'a mut U
where
Self::Target: IsA<U>,
Self: 'a,
{
// SAFETY: soundness is declared via IsA<U>, which is an unsafe trait
unsafe { self.unsafe_cast_mut::<U>() }
}
/// Attempt to convert to a derived type.
///
/// Returns `Ok(..)` if the object is of type `U`, or `Err(self)` if the
/// object if the conversion failed. This is verified at runtime by
/// checking the object's type information.
fn downcast_mut<'a, U: IsA<Self::Target>>(self) -> Result<&'a mut U, Self>
where
Self: 'a,
{
self.dynamic_cast_mut::<U>()
}
/// Attempt to convert between any two types in the QOM hierarchy.
///
/// Returns `Ok(..)` if the object is of type `U`, or `Err(self)` if the
/// object if the conversion failed. This is verified at runtime by
/// checking the object's type information.
fn dynamic_cast_mut<'a, U: ObjectType>(self) -> Result<&'a mut U, Self>
where
Self: 'a,
{
unsafe {
// SAFETY: upcasting to Object is always valid, and the
// return type is either NULL or the argument itself
let result: *mut U =
object_dynamic_cast(self.as_object_mut_ptr(), U::TYPE_NAME.as_ptr()).cast();
result.as_mut().ok_or(self)
}
}
/// Convert to any QOM type without verification.
///
/// # Safety
///
/// What safety? You need to know yourself that the cast is correct; only
/// use when performance is paramount. It is still better than a raw
/// pointer `cast()`, which does not even check that you remain in the
/// realm of QOM `ObjectType`s.
///
/// `unsafe_cast::<Object>()` is always safe.
unsafe fn unsafe_cast_mut<'a, U: ObjectType>(self) -> &'a mut U
where
Self: 'a,
{
unsafe { &mut *self.as_mut_ptr::<Self::Target>().cast::<U>() }
}
}
impl<T: ObjectType> ObjectDeref for &mut T {}
impl<T: ObjectType> ObjectCastMut for &mut T {}
/// Trait a type must implement to be registered with QEMU.
pub trait ObjectImpl: ObjectType + IsA<Object> {
@@ -621,7 +546,7 @@ pub trait ObjectImpl: ObjectType + IsA<Object> {
/// We expect the FFI user of this function to pass a valid pointer that
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut Object) {
unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut bindings::Object) {
let state = NonNull::new(dev).unwrap().cast::<T>();
T::UNPARENT.unwrap()(unsafe { state.as_ref() });
}
@@ -796,8 +721,9 @@ pub trait ObjectClassMethods: IsA<Object> {
// SAFETY: the object created by object_new is allocated on
// the heap and has a reference count of 1
unsafe {
let obj = &*object_new(Self::TYPE_NAME.as_ptr());
Owned::from_raw(obj.unsafe_cast::<Self>())
let raw_obj = object_new(Self::TYPE_NAME.as_ptr());
let obj = Object::from_raw(raw_obj).unsafe_cast::<Self>();
Owned::from_raw(obj)
}
}
}
+33 -7
View File
@@ -6,11 +6,11 @@
use std::{ffi::CStr, ptr::addr_of_mut};
pub use bindings::{SysBusDevice, SysBusDeviceClass};
pub use bindings::SysBusDeviceClass;
use crate::{
bindings,
cell::bql_locked,
cell::{bql_locked, Opaque},
irq::{IRQState, InterruptSource},
memory::MemoryRegion,
prelude::*,
@@ -18,6 +18,14 @@ use crate::{
qom::Owned,
};
/// A safe wrapper around [`bindings::SysBusDevice`].
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct SysBusDevice(Opaque<bindings::SysBusDevice>);
unsafe impl Send for SysBusDevice {}
unsafe impl Sync for SysBusDevice {}
unsafe impl ObjectType for SysBusDevice {
type Class = SysBusDeviceClass;
const TYPE_NAME: &'static CStr =
@@ -49,7 +57,7 @@ where
fn init_mmio(&self, iomem: &MemoryRegion) {
assert!(bql_locked());
unsafe {
bindings::sysbus_init_mmio(self.as_mut_ptr(), iomem.as_mut_ptr());
bindings::sysbus_init_mmio(self.upcast().as_mut_ptr(), iomem.as_mut_ptr());
}
}
@@ -60,7 +68,21 @@ where
fn init_irq(&self, irq: &InterruptSource) {
assert!(bql_locked());
unsafe {
bindings::sysbus_init_irq(self.as_mut_ptr(), irq.as_ptr());
bindings::sysbus_init_irq(self.upcast().as_mut_ptr(), irq.as_ptr());
}
}
// TODO: do we want a type like GuestAddress here?
fn mmio_addr(&self, id: u32) -> Option<u64> {
assert!(bql_locked());
// SAFETY: the BQL ensures that no one else writes to sbd.mmio[], and
// the SysBusDevice must be initialized to get an IsA<SysBusDevice>.
let sbd = unsafe { *self.upcast().as_ptr() };
let id: usize = id.try_into().unwrap();
if sbd.mmio[id].memory.is_null() {
None
} else {
Some(sbd.mmio[id].addr)
}
}
@@ -69,7 +91,7 @@ where
assert!(bql_locked());
let id: i32 = id.try_into().unwrap();
unsafe {
bindings::sysbus_mmio_map(self.as_mut_ptr(), id, addr);
bindings::sysbus_mmio_map(self.upcast().as_mut_ptr(), id, addr);
}
}
@@ -79,8 +101,9 @@ where
fn connect_irq(&self, id: u32, irq: &Owned<IRQState>) {
assert!(bql_locked());
let id: i32 = id.try_into().unwrap();
let irq: &IRQState = irq;
unsafe {
bindings::sysbus_connect_irq(self.as_mut_ptr(), id, irq.as_mut_ptr());
bindings::sysbus_connect_irq(self.upcast().as_mut_ptr(), id, irq.as_mut_ptr());
}
}
@@ -88,7 +111,10 @@ where
// TODO: return an Error
assert!(bql_locked());
unsafe {
bindings::sysbus_realize(self.as_mut_ptr(), addr_of_mut!(bindings::error_fatal));
bindings::sysbus_realize(
self.upcast().as_mut_ptr(),
addr_of_mut!(bindings::error_fatal),
);
}
}
}
+36 -11
View File
@@ -2,31 +2,51 @@
// Author(s): Zhao Liu <zhai1.liu@intel.com>
// SPDX-License-Identifier: GPL-2.0-or-later
use std::os::raw::{c_int, c_void};
use std::{
os::raw::{c_int, c_void},
pin::Pin,
};
use crate::{
bindings::{self, qemu_clock_get_ns, timer_del, timer_init_full, timer_mod, QEMUClockType},
callbacks::FnCall,
cell::Opaque,
};
pub type Timer = bindings::QEMUTimer;
pub type TimerListGroup = bindings::QEMUTimerListGroup;
/// A safe wrapper around [`bindings::QEMUTimer`].
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct Timer(Opaque<bindings::QEMUTimer>);
unsafe impl Send for Timer {}
unsafe impl Sync for Timer {}
#[repr(transparent)]
#[derive(qemu_api_macros::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;
pub fn new() -> Self {
Default::default()
}
const fn as_mut_ptr(&self) -> *mut Self {
self as *const Timer as *mut _
/// Create a `Timer` struct without initializing it.
///
/// # Safety
///
/// The timer must be initialized before it is armed with
/// [`modify`](Self::modify).
pub 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<'timer, 'opaque: 'timer, T, F>(
&'timer mut self,
self: Pin<&'timer mut Self>,
timer_list_group: Option<&TimerListGroup>,
clk_type: ClockType,
scale: u32,
@@ -51,7 +71,7 @@ impl Timer {
// SAFETY: the opaque outlives the timer
unsafe {
timer_init_full(
self,
self.as_mut_ptr(),
if let Some(g) = timer_list_group {
g as *const TimerListGroup as *mut _
} else {
@@ -67,14 +87,19 @@ impl Timer {
}
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()

Some files were not shown because too many files have changed in this diff Show More