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 core::{ 6 ffi::{c_int, c_void}, 7 ptr::NonNull, 8 }; 9 10 use qemu_api::{ 11 bindings::*, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections, vmstate_uint32, 12 vmstate_uint32_array, vmstate_unused, zeroable::Zeroable, 13 }; 14 15 use crate::device::{PL011State, PL011_FIFO_DEPTH}; 16 17 extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool { 18 unsafe { 19 debug_assert!(!opaque.is_null()); 20 let state = NonNull::new_unchecked(opaque.cast::<PL011State>()); 21 state.as_ref().migrate_clock 22 } 23 } 24 25 /// Migration subsection for [`PL011State`] clock. 26 pub 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!(clock, PL011State), 33 }, 34 ..Zeroable::ZERO 35 }; 36 37 extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int { 38 unsafe { 39 debug_assert!(!opaque.is_null()); 40 let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>()); 41 let result = state.as_mut().post_load(version_id as u32); 42 if result.is_err() { 43 -1 44 } else { 45 0 46 } 47 } 48 } 49 50 pub static VMSTATE_PL011: VMStateDescription = VMStateDescription { 51 name: c"pl011".as_ptr(), 52 version_id: 2, 53 minimum_version_id: 2, 54 post_load: Some(pl011_post_load), 55 fields: vmstate_fields! { 56 vmstate_unused!(core::mem::size_of::<u32>()), 57 vmstate_uint32!(flags, PL011State), 58 vmstate_uint32!(line_control, PL011State), 59 vmstate_uint32!(receive_status_error_clear, PL011State), 60 vmstate_uint32!(control, PL011State), 61 vmstate_uint32!(dmacr, PL011State), 62 vmstate_uint32!(int_enabled, PL011State), 63 vmstate_uint32!(int_level, PL011State), 64 vmstate_uint32_array!(read_fifo, PL011State, PL011_FIFO_DEPTH), 65 vmstate_uint32!(ilpr, PL011State), 66 vmstate_uint32!(ibrd, PL011State), 67 vmstate_uint32!(fbrd, PL011State), 68 vmstate_uint32!(ifl, PL011State), 69 vmstate_int32!(read_pos, PL011State), 70 vmstate_int32!(read_count, PL011State), 71 vmstate_int32!(read_trigger, PL011State), 72 }, 73 subsections: vmstate_subsections! { 74 VMSTATE_PL011_CLOCK 75 }, 76 ..Zeroable::ZERO 77 }; 78 79 qemu_api::declare_properties! { 80 PL011_PROPERTIES, 81 qemu_api::define_property!( 82 c"chardev", 83 PL011State, 84 char_backend, 85 unsafe { &qdev_prop_chr }, 86 CharBackend 87 ), 88 qemu_api::define_property!( 89 c"migrate-clk", 90 PL011State, 91 migrate_clock, 92 unsafe { &qdev_prop_bool }, 93 bool, 94 default = true 95 ), 96 } 97 98 qemu_api::device_class_init! { 99 pl011_class_init, 100 props => PL011_PROPERTIES, 101 realize_fn => Some(pl011_realize), 102 legacy_reset_fn => Some(pl011_reset), 103 vmsd => VMSTATE_PL011, 104 } 105 106 /// # Safety 107 /// 108 /// We expect the FFI user of this function to pass a valid pointer, that has 109 /// the same size as [`PL011State`]. We also expect the device is 110 /// readable/writeable from one thread at any time. 111 pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) { 112 unsafe { 113 assert!(!dev.is_null()); 114 let mut state = NonNull::new_unchecked(dev.cast::<PL011State>()); 115 state.as_mut().realize(); 116 } 117 } 118 119 /// # Safety 120 /// 121 /// We expect the FFI user of this function to pass a valid pointer, that has 122 /// the same size as [`PL011State`]. We also expect the device is 123 /// readable/writeable from one thread at any time. 124 pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) { 125 unsafe { 126 assert!(!dev.is_null()); 127 let mut state = NonNull::new_unchecked(dev.cast::<PL011State>()); 128 state.as_mut().reset(); 129 } 130 } 131