rust/pl011: add support for migration

Declare the vmstate description of the PL011 device.

Based on a patch by Manos Pitsidianakis
(https://lore.kernel.org/qemu-devel/20241024-rust-round-2-v1-4-051e7a25b978@linaro.org/).

Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241024-rust-round-2-v1-4-051e7a25b978@linaro.org
This commit is contained in:
Manos Pitsidianakis 2024-10-24 17:03:02 +03:00 committed by Paolo Bonzini
parent 113c668852
commit 93243319db
3 changed files with 95 additions and 6 deletions

View File

@ -20,6 +20,12 @@ use crate::{
static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
/// Integer Baud Rate Divider, `UARTIBRD`
const IBRD_MASK: u32 = 0x3f;
/// Fractional Baud Rate Divider, `UARTFBRD`
const FBRD_MASK: u32 = 0xffff;
const DATA_BREAK: u32 = 1 << 10;
/// QEMU sourced constant.
@ -492,6 +498,27 @@ impl PL011State {
unsafe { qemu_set_irq(*irq, i32::from(flags & i != 0)) };
}
}
pub fn post_load(&mut self, _version_id: u32) -> Result<(), ()> {
/* Sanity-check input state */
if self.read_pos >= self.read_fifo.len() || self.read_count > self.read_fifo.len() {
return Err(());
}
if !self.fifo_enabled() && self.read_count > 0 && self.read_pos > 0 {
// Older versions of PL011 didn't ensure that the single
// character in the FIFO in FIFO-disabled mode is in
// element 0 of the array; convert to follow the current
// code's assumptions.
self.read_fifo[0] = self.read_fifo[self.read_pos];
self.read_pos = 0;
}
self.ibrd &= IBRD_MASK;
self.fbrd &= FBRD_MASK;
Ok(())
}
}
/// Which bits in the interrupt status matter for each outbound IRQ line ?

View File

@ -2,16 +2,77 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
use core::ptr::NonNull;
use core::{
ffi::{c_int, c_void},
ptr::NonNull,
};
use qemu_api::{bindings::*, definitions::ObjectImpl, zeroable::Zeroable};
use qemu_api::{
bindings::*, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections, vmstate_uint32,
vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
};
use crate::device::PL011State;
use crate::device::{PL011State, PL011_FIFO_DEPTH};
extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
unsafe {
debug_assert!(!opaque.is_null());
let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
state.as_ref().migrate_clock
}
}
/// Migration subsection for [`PL011State`] clock.
pub static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
name: c"pl011/clock".as_ptr(),
version_id: 1,
minimum_version_id: 1,
needed: Some(pl011_clock_needed),
fields: vmstate_fields! {
vmstate_clock!(clock, PL011State),
},
..Zeroable::ZERO
};
extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
unsafe {
debug_assert!(!opaque.is_null());
let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
let result = state.as_mut().post_load(version_id as u32);
if result.is_err() {
-1
} else {
0
}
}
}
#[used]
pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
name: PL011State::TYPE_INFO.name,
unmigratable: true,
name: c"pl011".as_ptr(),
version_id: 2,
minimum_version_id: 2,
post_load: Some(pl011_post_load),
fields: vmstate_fields! {
vmstate_unused!(core::mem::size_of::<u32>()),
vmstate_uint32!(flags, PL011State),
vmstate_uint32!(line_control, PL011State),
vmstate_uint32!(receive_status_error_clear, PL011State),
vmstate_uint32!(control, PL011State),
vmstate_uint32!(dmacr, PL011State),
vmstate_uint32!(int_enabled, PL011State),
vmstate_uint32!(int_level, PL011State),
vmstate_uint32_array!(read_fifo, PL011State, PL011_FIFO_DEPTH),
vmstate_uint32!(ilpr, PL011State),
vmstate_uint32!(ibrd, PL011State),
vmstate_uint32!(fbrd, PL011State),
vmstate_uint32!(ifl, PL011State),
vmstate_int32!(read_pos, PL011State),
vmstate_int32!(read_count, PL011State),
vmstate_int32!(read_trigger, PL011State),
},
subsections: vmstate_subsections! {
VMSTATE_PL011_CLOCK
},
..Zeroable::ZERO
};

View File

@ -36,6 +36,7 @@
clippy::cognitive_complexity,
clippy::missing_safety_doc,
)]
#![allow(clippy::result_unit_err)]
extern crate bilge;
extern crate bilge_impl;