aboutsummaryrefslogtreecommitdiff
path: root/rust/hw/timer
diff options
context:
space:
mode:
Diffstat (limited to 'rust/hw/timer')
-rw-r--r--rust/hw/timer/hpet/src/device.rs58
1 files changed, 31 insertions, 27 deletions
diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/device.rs
index 735b2fb..acf7251 100644
--- a/rust/hw/timer/hpet/src/device.rs
+++ b/rust/hw/timer/hpet/src/device.rs
@@ -4,6 +4,7 @@
use std::{
ffi::{c_int, c_void, CStr},
+ mem::MaybeUninit,
pin::Pin,
ptr::{addr_of_mut, null_mut, NonNull},
slice::from_ref,
@@ -20,11 +21,12 @@ use qemu_api::{
hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSPECIFIED,
},
prelude::*,
- qdev::{DeviceImpl, DeviceMethods, DeviceState, Property, ResetType, ResettablePhasesImpl},
- qom::{ObjectImpl, ObjectType, ParentField},
+ qdev::{DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl},
+ qom::{ObjectImpl, ObjectType, ParentField, ParentInit},
qom_isa,
sysbus::{SysBusDevice, SysBusDeviceImpl},
timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND},
+ uninit_field_mut,
vmstate::VMStateDescription,
vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmstate_validate,
zeroable::Zeroable,
@@ -212,13 +214,13 @@ pub struct HPETTimer {
}
impl HPETTimer {
- fn init(&mut self, index: u8, state: &HPETState) {
- *self = HPETTimer {
+ fn new(index: u8, state: *const HPETState) -> HPETTimer {
+ 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 HPETState).cast_mut()).unwrap(),
+ state: NonNull::new(state.cast_mut()).unwrap(),
config: 0,
cmp: 0,
fsb: 0,
@@ -226,19 +228,15 @@ impl HPETTimer {
period: 0,
wrap_flag: 0,
last: 0,
- };
+ }
+ }
+ fn init_timer_with_cell(cell: &BqlRefCell<Self>) {
+ let mut timer = cell.borrow_mut();
// 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 as usize],
- )
+ let qemu_timer = unsafe { Pin::new_unchecked(&mut timer.qemu_timer) };
+ qemu_timer.init_full(None, CLOCK_VIRTUAL, Timer::NS, 0, timer_handler, cell);
}
fn get_state(&self) -> &HPETState {
@@ -607,9 +605,18 @@ impl HPETState {
}
}
- fn init_timer(&self) {
- for (index, timer) in self.timers.iter().enumerate() {
- timer.borrow_mut().init(index.try_into().unwrap(), self);
+ fn init_timers(this: &mut MaybeUninit<Self>) {
+ let state = this.as_ptr();
+ for index in 0..HPET_MAX_TIMERS {
+ let mut timer = uninit_field_mut!(*this, timers[index]);
+
+ // Initialize in two steps, to avoid calling Timer::init_full on a
+ // temporary that can be moved.
+ let timer = timer.write(BqlRefCell::new(HPETTimer::new(
+ index.try_into().unwrap(),
+ state,
+ )));
+ HPETTimer::init_timer_with_cell(timer);
}
}
@@ -690,7 +697,7 @@ impl HPETState {
.set(self.counter.get().deposit(shift, len, val));
}
- unsafe fn init(&mut self) {
+ unsafe fn init(mut this: ParentInit<Self>) {
static HPET_RAM_OPS: MemoryRegionOps<HPETState> =
MemoryRegionOpsBuilder::<HPETState>::new()
.read(&HPETState::read)
@@ -700,16 +707,14 @@ impl HPETState {
.impl_sizes(4, 8)
.build();
- // SAFETY:
- // self and self.iomem are guaranteed to be valid at this point since callers
- // must make sure the `self` reference is valid.
MemoryRegion::init_io(
- unsafe { &mut *addr_of_mut!(self.iomem) },
- addr_of_mut!(*self),
+ &mut uninit_field_mut!(*this, iomem),
&HPET_RAM_OPS,
"hpet",
HPET_REG_SPACE_LEN,
);
+
+ Self::init_timers(&mut this);
}
fn post_init(&self) {
@@ -731,7 +736,6 @@ impl HPETState {
self.hpet_id.set(HPETFwConfig::assign_hpet_id()?);
- self.init_timer();
// 64-bit General Capabilities and ID Register; LegacyReplacementRoute.
self.capability.set(
HPET_CAP_REV_ID_VALUE << HPET_CAP_REV_ID_SHIFT |
@@ -767,7 +771,7 @@ impl HPETState {
self.rtc_irq_level.set(0);
}
- fn decode(&self, mut addr: hwaddr, size: u32) -> HPETAddrDecode {
+ 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);
@@ -892,7 +896,7 @@ unsafe impl ObjectType for HPETState {
impl ObjectImpl for HPETState {
type ParentType = SysBusDevice;
- const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = Some(Self::init);
+ const INSTANCE_INIT: Option<unsafe fn(ParentInit<Self>)> = Some(Self::init);
const INSTANCE_POST_INIT: Option<fn(&Self)> = Some(Self::post_init);
const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
}