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