mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 01:03:55 -06:00
rust: qom: change instance_init to take a ParentInit<>
This removes undefined behavior associated to writing to uninitialized fields, and makes it possible to remove "unsafe" from the instance_init implementation. However, the init function itself is still unsafe, because it must promise (as a sort as MaybeUninit::assume_init) that all fields have been initialized. Reviewed-by: Zhao Liu <zhao1.liu@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
8d394f6cf0
commit
345bef46a1
5 changed files with 63 additions and 57 deletions
|
@ -2,7 +2,7 @@
|
|||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::{ffi::CStr, mem::size_of, ptr::addr_of_mut};
|
||||
use std::{ffi::CStr, mem::size_of};
|
||||
|
||||
use qemu_api::{
|
||||
chardev::{CharBackend, Chardev, Event},
|
||||
|
@ -11,9 +11,10 @@ use qemu_api::{
|
|||
memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder},
|
||||
prelude::*,
|
||||
qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl},
|
||||
qom::{ObjectImpl, Owned, ParentField},
|
||||
qom::{ObjectImpl, Owned, ParentField, ParentInit},
|
||||
static_assert,
|
||||
sysbus::{SysBusDevice, SysBusDeviceImpl},
|
||||
uninit_field_mut,
|
||||
vmstate::VMStateDescription,
|
||||
};
|
||||
|
||||
|
@ -163,7 +164,7 @@ impl PL011Impl for PL011State {
|
|||
impl ObjectImpl for PL011State {
|
||||
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>;
|
||||
}
|
||||
|
@ -488,7 +489,7 @@ impl PL011State {
|
|||
/// `PL011State` type. It must not be called more than once on the same
|
||||
/// location/instance. All its fields are expected to hold uninitialized
|
||||
/// values with the sole exception of `parent_obj`.
|
||||
unsafe fn init(&mut self) {
|
||||
unsafe fn init(mut this: ParentInit<Self>) {
|
||||
static PL011_OPS: MemoryRegionOps<PL011State> = MemoryRegionOpsBuilder::<PL011State>::new()
|
||||
.read(&PL011State::read)
|
||||
.write(&PL011State::write)
|
||||
|
@ -496,28 +497,23 @@ impl PL011State {
|
|||
.impl_sizes(4, 4)
|
||||
.build();
|
||||
|
||||
// SAFETY:
|
||||
//
|
||||
// self and self.iomem are guaranteed to be valid at this point since callers
|
||||
// must make sure the `self` reference is valid.
|
||||
// SAFETY: this and this.iomem are guaranteed to be valid at this point
|
||||
MemoryRegion::init_io(
|
||||
unsafe { &mut *addr_of_mut!(self.iomem) },
|
||||
addr_of_mut!(*self),
|
||||
&mut uninit_field_mut!(*this, iomem),
|
||||
&PL011_OPS,
|
||||
"pl011",
|
||||
0x1000,
|
||||
);
|
||||
|
||||
self.regs = Default::default();
|
||||
uninit_field_mut!(*this, regs).write(Default::default());
|
||||
|
||||
// SAFETY:
|
||||
//
|
||||
// self.clock is not initialized at this point; but since `Owned<_>` is
|
||||
// not Drop, we can overwrite the undefined value without side effects;
|
||||
// it's not sound but, because for all PL011State instances are created
|
||||
// by QOM code which calls this function to initialize the fields, at
|
||||
// leastno code is able to access an invalid self.clock value.
|
||||
self.clock = self.init_clock_in("clk", &Self::clock_update, ClockEvent::ClockUpdate);
|
||||
let clock = DeviceState::init_clock_in(
|
||||
&mut this,
|
||||
"clk",
|
||||
&Self::clock_update,
|
||||
ClockEvent::ClockUpdate,
|
||||
);
|
||||
uninit_field_mut!(*this, clock).write(clock);
|
||||
}
|
||||
|
||||
const fn clock_update(&self, _event: ClockEvent) {
|
||||
|
|
|
@ -21,8 +21,8 @@ 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},
|
||||
|
@ -697,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)
|
||||
|
@ -707,18 +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(unsafe { &mut *((self as *mut Self).cast::<MaybeUninit<Self>>()) });
|
||||
Self::init_timers(&mut this);
|
||||
}
|
||||
|
||||
fn post_init(&self) {
|
||||
|
@ -900,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>;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue