1 // Copyright 2024, Linaro Limited
2 // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4
5 use std::{
6 ffi::{c_int, c_void},
7 ptr::NonNull,
8 };
9
10 use qemu_api::{
11 bindings::{qdev_prop_bool, qdev_prop_chr},
12 prelude::*,
13 vmstate::VMStateDescription,
14 vmstate_clock, vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmstate_unused,
15 zeroable::Zeroable,
16 };
17
18 use crate::device::{PL011Registers, PL011State};
19
pl011_clock_needed(opaque: *mut c_void) -> bool20 extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
21 let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
22 unsafe { state.as_ref().migrate_clock }
23 }
24
25 /// Migration subsection for [`PL011State`] clock.
26 static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
27 name: c"pl011/clock".as_ptr(),
28 version_id: 1,
29 minimum_version_id: 1,
30 needed: Some(pl011_clock_needed),
31 fields: vmstate_fields! {
32 vmstate_clock!(PL011State, clock),
33 },
34 ..Zeroable::ZERO
35 };
36
pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int37 extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
38 let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
39 let result = unsafe { state.as_ref().post_load(version_id as u32) };
40 if result.is_err() {
41 -1
42 } else {
43 0
44 }
45 }
46
47 static VMSTATE_PL011_REGS: VMStateDescription = VMStateDescription {
48 name: c"pl011/regs".as_ptr(),
49 version_id: 2,
50 minimum_version_id: 2,
51 fields: vmstate_fields! {
52 vmstate_of!(PL011Registers, flags),
53 vmstate_of!(PL011Registers, line_control),
54 vmstate_of!(PL011Registers, receive_status_error_clear),
55 vmstate_of!(PL011Registers, control),
56 vmstate_of!(PL011Registers, dmacr),
57 vmstate_of!(PL011Registers, int_enabled),
58 vmstate_of!(PL011Registers, int_level),
59 vmstate_of!(PL011Registers, read_fifo),
60 vmstate_of!(PL011Registers, ilpr),
61 vmstate_of!(PL011Registers, ibrd),
62 vmstate_of!(PL011Registers, fbrd),
63 vmstate_of!(PL011Registers, ifl),
64 vmstate_of!(PL011Registers, read_pos),
65 vmstate_of!(PL011Registers, read_count),
66 vmstate_of!(PL011Registers, read_trigger),
67 },
68 ..Zeroable::ZERO
69 };
70
71 pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
72 name: c"pl011".as_ptr(),
73 version_id: 2,
74 minimum_version_id: 2,
75 post_load: Some(pl011_post_load),
76 fields: vmstate_fields! {
77 vmstate_unused!(core::mem::size_of::<u32>()),
78 vmstate_struct!(PL011State, regs, &VMSTATE_PL011_REGS, BqlRefCell<PL011Registers>),
79 },
80 subsections: vmstate_subsections! {
81 VMSTATE_PL011_CLOCK
82 },
83 ..Zeroable::ZERO
84 };
85
86 qemu_api::declare_properties! {
87 PL011_PROPERTIES,
88 qemu_api::define_property!(
89 c"chardev",
90 PL011State,
91 char_backend,
92 unsafe { &qdev_prop_chr },
93 CharBackend
94 ),
95 qemu_api::define_property!(
96 c"migrate-clk",
97 PL011State,
98 migrate_clock,
99 unsafe { &qdev_prop_bool },
100 bool,
101 default = true
102 ),
103 }
104