Signed-off-by: Paolo Bonzini
---
meson.build | 1 +
rust/hw/char/pl011/src/device.rs | 10 ++-
rust/qemu-api/src/qdev.rs| 111 ---
rust/qemu-api/tests/tests.rs | 5 +-
4 files changed, 99 insertions(+), 28 deletions(-)
diff --git a/meson.build b/meson.build
index 131b2225ab6..32abefb7c48 100644
--- a/meson.build
+++ b/meson.build
@@ -4072,6 +4072,7 @@ if have_rust
'MigrationPriority',
'QEMUChrEvent',
'QEMUClockType',
+'ResetType',
'device_endian',
'module_init_type',
]
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 37936a328b8..1d0390b4fbe 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -18,7 +18,7 @@
c_str, impl_vmstate_forward,
irq::InterruptSource,
prelude::*,
-qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property},
+qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType,
ResettablePhasesImpl},
qom::{ClassInitImpl, ObjectImpl, Owned, ParentField},
sysbus::{SysBusDevice, SysBusDeviceClass},
vmstate::VMStateDescription,
@@ -171,7 +171,10 @@ fn vmsd() -> Option<&'static VMStateDescription> {
Some(&device_class::VMSTATE_PL011)
}
const REALIZE: Option = Some(Self::realize);
-const RESET: Option = Some(Self::reset);
+}
+
+impl ResettablePhasesImpl for PL011State {
+const HOLD: Option = Some(Self::reset_hold);
}
impl PL011Registers {
@@ -622,7 +625,7 @@ pub fn realize(&self) {
}
}
-pub fn reset(&self) {
+pub fn reset_hold(&self, _type: ResetType) {
self.regs.borrow_mut().reset();
}
@@ -737,3 +740,4 @@ impl ObjectImpl for PL011Luminary {
}
impl DeviceImpl for PL011Luminary {}
+impl ResettablePhasesImpl for PL011Luminary {}
diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs
index cb6f12e726c..2ec1ecc8489 100644
--- a/rust/qemu-api/src/qdev.rs
+++ b/rust/qemu-api/src/qdev.rs
@@ -10,10 +10,10 @@
ptr::NonNull,
};
-pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property};
+pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property,
ResetType};
use crate::{
-bindings::{self, Error},
+bindings::{self, Error, ResettableClass},
callbacks::FnCall,
cell::bql_locked,
prelude::*,
@@ -21,8 +21,70 @@
vmstate::VMStateDescription,
};
+/// Trait providing the contents of the `ResettablePhases` struct,
+/// which is part of the QOM `Resettable` interface.
+pub trait ResettablePhasesImpl {
+/// If not None, this is called when the object enters reset. It
+/// can reset local state of the object, but it must not do anything that
+/// has a side-effect on other objects, such as raising or lowering an
+/// [`InterruptSource`](crate::irq::InterruptSource), or reading or
+/// writing guest memory. It takes the reset's type as argument.
+const ENTER: Option = None;
+
+/// If not None, this is called when the object for entry into reset, once
+/// every object in the system which is being reset has had its
+/// `ResettablePhasesImpl::ENTER` method called. At this point devices
+/// can do actions that affect other objects.
+///
+/// If in doubt, implement this method.
+const HOLD: Option = None;
+
+/// If not None, this phase is called when the object leaves the reset
+/// state. Actions affecting other objects are permitted.
+const EXIT: Option = None;
+}
+
+/// # Safety
+///
+/// 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_resettable_enter_fn(
+obj: *mut Object,
+typ: ResetType,
+) {
+let state = NonNull::new(obj).unwrap().cast::();
+T::ENTER.unwrap()(unsafe { state.as_ref() }, typ);
+}
+
+/// # Safety
+///
+/// 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_resettable_hold_fn(
+obj: *mut Object,
+typ: ResetType,
+) {
+let state = NonNull::new(obj).unwrap().cast::();
+T::HOLD.unwrap()(unsafe { state.as_ref() }, typ);
+}
+
+/// # Safety
+///
+/// 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_resettable_exit_fn(
+obj: *mut Object,
+typ: ResetType,
+) {
+let state = NonNull::new(obj).unwrap().cast::();
+T::EXIT.unwrap()(unsafe { state.as_ref() }, typ);
+}
+
/// Trait providing the contents of [`DeviceClass`].
-pub trait DeviceImpl: ObjectImpl {
+pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl {
/// _Realization_ is the s