aboutsummaryrefslogtreecommitdiff
path: root/rust/hw/char/pl011/src/device_class.rs
blob: 7f3ca8950716986f62c386172baa13de0efcca7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright 2024, Linaro Limited
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later

use core::ptr::NonNull;
use std::os::raw::{c_int, c_void};

use qemu_api::{
    bindings::*, c_str, vmstate_clock, vmstate_fields, vmstate_subsections, vmstate_uint32,
    vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
};

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_str!("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
        }
    }
}

pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
    name: c_str!("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_uint32!(read_pos, PL011State),
        vmstate_uint32!(read_count, PL011State),
        vmstate_uint32!(read_trigger, PL011State),
    },
    subsections: vmstate_subsections! {
        VMSTATE_PL011_CLOCK
    },
    ..Zeroable::ZERO
};

qemu_api::declare_properties! {
    PL011_PROPERTIES,
    qemu_api::define_property!(
        c_str!("chardev"),
        PL011State,
        char_backend,
        unsafe { &qdev_prop_chr },
        CharBackend
    ),
    qemu_api::define_property!(
        c_str!("migrate-clk"),
        PL011State,
        migrate_clock,
        unsafe { &qdev_prop_bool },
        bool,
        default = true
    ),
}