diff options
author | Manos Pitsidianakis <manos.pitsidianakis@linaro.org> | 2024-10-24 17:03:02 +0300 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2024-11-05 14:18:16 +0100 |
commit | 93243319db276bb424b7f9ad0bdfa8dc4b3368bd (patch) | |
tree | b0d1a5334fc308c34eb241c587fc33a5b0c4c63d | |
parent | 113c66885280bb20296969d780be54fbd42213ad (diff) | |
download | qemu-93243319db276bb424b7f9ad0bdfa8dc4b3368bd.zip qemu-93243319db276bb424b7f9ad0bdfa8dc4b3368bd.tar.gz qemu-93243319db276bb424b7f9ad0bdfa8dc4b3368bd.tar.bz2 |
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
-rw-r--r-- | rust/hw/char/pl011/src/device.rs | 27 | ||||
-rw-r--r-- | rust/hw/char/pl011/src/device_class.rs | 73 | ||||
-rw-r--r-- | rust/hw/char/pl011/src/lib.rs | 1 |
3 files changed, 95 insertions, 6 deletions
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index b3d8bc0..dd91456 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -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 ? diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs index 9282dc4..6a554ad 100644 --- a/rust/hw/char/pl011/src/device_class.rs +++ b/rust/hw/char/pl011/src/device_class.rs @@ -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::*, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections, vmstate_uint32, + vmstate_uint32_array, vmstate_unused, zeroable::Zeroable, +}; + +use crate::device::{PL011State, PL011_FIFO_DEPTH}; -use qemu_api::{bindings::*, definitions::ObjectImpl, zeroable::Zeroable}; +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 + } +} -use crate::device::PL011State; +/// 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 }; diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs index 2939ee5..73474a0 100644 --- a/rust/hw/char/pl011/src/lib.rs +++ b/rust/hw/char/pl011/src/lib.rs @@ -36,6 +36,7 @@ clippy::cognitive_complexity, clippy::missing_safety_doc, )] +#![allow(clippy::result_unit_err)] extern crate bilge; extern crate bilge_impl; |