1cde3c425SPaolo Bonzini // Copyright 2024, Linaro Limited 2cde3c425SPaolo Bonzini // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> 3cde3c425SPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later 4cde3c425SPaolo Bonzini 5094cd359SPaolo Bonzini use std::{ffi::CStr, ptr::addr_of}; 6cde3c425SPaolo Bonzini 7cde3c425SPaolo Bonzini use qemu_api::{ 8094cd359SPaolo Bonzini bindings::{module_call_init, module_init_type, qdev_prop_bool}, 9c2f41c1bSPaolo Bonzini cell::{self, BqlCell}, 10c2f41c1bSPaolo Bonzini declare_properties, define_property, 11716d89f9SPaolo Bonzini prelude::*, 12567c0c41SPaolo Bonzini qdev::{DeviceImpl, DeviceState, Property, ResettablePhasesImpl}, 13d556226dSPaolo Bonzini qom::{ObjectImpl, ParentField}, 144cb7040dSPaolo Bonzini sysbus::SysBusDevice, 15716d89f9SPaolo Bonzini vmstate::VMStateDescription, 16716d89f9SPaolo Bonzini zeroable::Zeroable, 17cde3c425SPaolo Bonzini }; 18cde3c425SPaolo Bonzini 1919985021SZhao Liu mod vmstate_tests; 2019985021SZhao Liu 21cde3c425SPaolo Bonzini // Test that macros can compile. 220a65e412SManos Pitsidianakis pub static VMSTATE: VMStateDescription = VMStateDescription { 23*f117857bSPaolo Bonzini name: c"name".as_ptr(), 24cde3c425SPaolo Bonzini unmigratable: true, 250a65e412SManos Pitsidianakis ..Zeroable::ZERO 260a65e412SManos Pitsidianakis }; 27cde3c425SPaolo Bonzini 28cde3c425SPaolo Bonzini #[repr(C)] 29cde3c425SPaolo Bonzini #[derive(qemu_api_macros::Object)] 30cde3c425SPaolo Bonzini pub struct DummyState { 31ca0d60a6SPaolo Bonzini parent: ParentField<DeviceState>, 32c2f41c1bSPaolo Bonzini migrate_clock: bool, 33cde3c425SPaolo Bonzini } 34cde3c425SPaolo Bonzini 35f50cd85cSPaolo Bonzini qom_isa!(DummyState: Object, DeviceState); 36f50cd85cSPaolo Bonzini 37d28ece24SZhao Liu pub struct DummyClass { 38d28ece24SZhao Liu parent_class: <DeviceState as ObjectType>::Class, 39d28ece24SZhao Liu } 40d28ece24SZhao Liu 41567c0c41SPaolo Bonzini impl DummyClass { 42567c0c41SPaolo Bonzini pub fn class_init<T: DeviceImpl>(self: &mut DummyClass) { 43d556226dSPaolo Bonzini self.parent_class.class_init::<T>(); 44567c0c41SPaolo Bonzini } 45567c0c41SPaolo Bonzini } 46567c0c41SPaolo Bonzini 47cde3c425SPaolo Bonzini declare_properties! { 48cde3c425SPaolo Bonzini DUMMY_PROPERTIES, 49cde3c425SPaolo Bonzini define_property!( 50*f117857bSPaolo Bonzini c"migrate-clk", 51cde3c425SPaolo Bonzini DummyState, 52cde3c425SPaolo Bonzini migrate_clock, 53cde3c425SPaolo Bonzini unsafe { &qdev_prop_bool }, 54cde3c425SPaolo Bonzini bool 55cde3c425SPaolo Bonzini ), 56cde3c425SPaolo Bonzini } 57cde3c425SPaolo Bonzini 587bd8e3efSPaolo Bonzini unsafe impl ObjectType for DummyState { 59d28ece24SZhao Liu type Class = DummyClass; 60*f117857bSPaolo Bonzini const TYPE_NAME: &'static CStr = c"dummy"; 617bd8e3efSPaolo Bonzini } 627bd8e3efSPaolo Bonzini 637bd8e3efSPaolo Bonzini impl ObjectImpl for DummyState { 64166e8a1fSPaolo Bonzini type ParentType = DeviceState; 657bd8e3efSPaolo Bonzini const ABSTRACT: bool = false; 66567c0c41SPaolo Bonzini const CLASS_INIT: fn(&mut DummyClass) = DummyClass::class_init::<Self>; 67cde3c425SPaolo Bonzini } 68cde3c425SPaolo Bonzini 695472a38cSPaolo Bonzini impl ResettablePhasesImpl for DummyState {} 705472a38cSPaolo Bonzini 718c80c472SPaolo Bonzini impl DeviceImpl for DummyState { 728c80c472SPaolo Bonzini fn properties() -> &'static [Property] { 738c80c472SPaolo Bonzini &DUMMY_PROPERTIES 74cde3c425SPaolo Bonzini } 758c80c472SPaolo Bonzini fn vmsd() -> Option<&'static VMStateDescription> { 768c80c472SPaolo Bonzini Some(&VMSTATE) 778c80c472SPaolo Bonzini } 788c80c472SPaolo Bonzini } 798c80c472SPaolo Bonzini 80d28ece24SZhao Liu #[repr(C)] 81d28ece24SZhao Liu #[derive(qemu_api_macros::Object)] 82d28ece24SZhao Liu pub struct DummyChildState { 83d28ece24SZhao Liu parent: ParentField<DummyState>, 84d28ece24SZhao Liu } 85d28ece24SZhao Liu 86d28ece24SZhao Liu qom_isa!(DummyChildState: Object, DeviceState, DummyState); 87d28ece24SZhao Liu 88d28ece24SZhao Liu pub struct DummyChildClass { 89d28ece24SZhao Liu parent_class: <DummyState as ObjectType>::Class, 90d28ece24SZhao Liu } 91d28ece24SZhao Liu 92d28ece24SZhao Liu unsafe impl ObjectType for DummyChildState { 93d28ece24SZhao Liu type Class = DummyChildClass; 94*f117857bSPaolo Bonzini const TYPE_NAME: &'static CStr = c"dummy_child"; 95d28ece24SZhao Liu } 96d28ece24SZhao Liu 97d28ece24SZhao Liu impl ObjectImpl for DummyChildState { 98d28ece24SZhao Liu type ParentType = DummyState; 99d28ece24SZhao Liu const ABSTRACT: bool = false; 100567c0c41SPaolo Bonzini const CLASS_INIT: fn(&mut DummyChildClass) = DummyChildClass::class_init::<Self>; 101d28ece24SZhao Liu } 102d28ece24SZhao Liu 1035472a38cSPaolo Bonzini impl ResettablePhasesImpl for DummyChildState {} 104d28ece24SZhao Liu impl DeviceImpl for DummyChildState {} 105d28ece24SZhao Liu 106567c0c41SPaolo Bonzini impl DummyChildClass { 107567c0c41SPaolo Bonzini pub fn class_init<T: DeviceImpl>(self: &mut DummyChildClass) { 108567c0c41SPaolo Bonzini self.parent_class.class_init::<T>(); 109d28ece24SZhao Liu } 110d28ece24SZhao Liu } 111d28ece24SZhao Liu 112c2f41c1bSPaolo Bonzini fn init_qom() { 113c2f41c1bSPaolo Bonzini static ONCE: BqlCell<bool> = BqlCell::new(false); 114c2f41c1bSPaolo Bonzini 115c2f41c1bSPaolo Bonzini cell::bql_start_test(); 116c2f41c1bSPaolo Bonzini if !ONCE.get() { 117cde3c425SPaolo Bonzini unsafe { 118cde3c425SPaolo Bonzini module_call_init(module_init_type::MODULE_INIT_QOM); 119c2f41c1bSPaolo Bonzini } 120c2f41c1bSPaolo Bonzini ONCE.set(true); 121c2f41c1bSPaolo Bonzini } 122c2f41c1bSPaolo Bonzini } 123c2f41c1bSPaolo Bonzini 124c2f41c1bSPaolo Bonzini #[test] 125c2f41c1bSPaolo Bonzini /// Create and immediately drop an instance. 126c2f41c1bSPaolo Bonzini fn test_object_new() { 127c2f41c1bSPaolo Bonzini init_qom(); 128ec3eba98SPaolo Bonzini drop(DummyState::new()); 129ec3eba98SPaolo Bonzini drop(DummyChildState::new()); 130cde3c425SPaolo Bonzini } 131f50cd85cSPaolo Bonzini 132ba3b81f3SPaolo Bonzini #[test] 1330fcccf3fSPaolo Bonzini #[allow(clippy::redundant_clone)] 1340fcccf3fSPaolo Bonzini /// Create, clone and then drop an instance. 1350fcccf3fSPaolo Bonzini fn test_clone() { 1360fcccf3fSPaolo Bonzini init_qom(); 137ec3eba98SPaolo Bonzini let p = DummyState::new(); 1380fcccf3fSPaolo Bonzini assert_eq!(p.clone().typename(), "dummy"); 1390fcccf3fSPaolo Bonzini drop(p); 1400fcccf3fSPaolo Bonzini } 1410fcccf3fSPaolo Bonzini 1420fcccf3fSPaolo Bonzini #[test] 143ba3b81f3SPaolo Bonzini /// Try invoking a method on an object. 144ba3b81f3SPaolo Bonzini fn test_typename() { 145ba3b81f3SPaolo Bonzini init_qom(); 146ec3eba98SPaolo Bonzini let p = DummyState::new(); 147ec3eba98SPaolo Bonzini assert_eq!(p.typename(), "dummy"); 148ba3b81f3SPaolo Bonzini } 149ba3b81f3SPaolo Bonzini 150f50cd85cSPaolo Bonzini // a note on all "cast" tests: usually, especially for downcasts the desired 151f50cd85cSPaolo Bonzini // class would be placed on the right, for example: 152f50cd85cSPaolo Bonzini // 153f50cd85cSPaolo Bonzini // let sbd_ref = p.dynamic_cast::<SysBusDevice>(); 154f50cd85cSPaolo Bonzini // 155f50cd85cSPaolo Bonzini // Here I am doing the opposite to check that the resulting type is correct. 156f50cd85cSPaolo Bonzini 157f50cd85cSPaolo Bonzini #[test] 158f50cd85cSPaolo Bonzini #[allow(clippy::shadow_unrelated)] 159f50cd85cSPaolo Bonzini /// Test casts on shared references. 160f50cd85cSPaolo Bonzini fn test_cast() { 161f50cd85cSPaolo Bonzini init_qom(); 162ec3eba98SPaolo Bonzini let p = DummyState::new(); 163ec3eba98SPaolo Bonzini let p_ptr: *mut DummyState = p.as_mut_ptr(); 164ec3eba98SPaolo Bonzini let p_ref: &mut DummyState = unsafe { &mut *p_ptr }; 165f50cd85cSPaolo Bonzini 166f50cd85cSPaolo Bonzini let obj_ref: &Object = p_ref.upcast(); 167ec3eba98SPaolo Bonzini assert_eq!(addr_of!(*obj_ref), p_ptr.cast()); 168f50cd85cSPaolo Bonzini 169f50cd85cSPaolo Bonzini let sbd_ref: Option<&SysBusDevice> = obj_ref.dynamic_cast(); 170f50cd85cSPaolo Bonzini assert!(sbd_ref.is_none()); 171f50cd85cSPaolo Bonzini 172f50cd85cSPaolo Bonzini let dev_ref: Option<&DeviceState> = obj_ref.downcast(); 173ec3eba98SPaolo Bonzini assert_eq!(addr_of!(*dev_ref.unwrap()), p_ptr.cast()); 174f50cd85cSPaolo Bonzini 175f50cd85cSPaolo Bonzini // SAFETY: the cast is wrong, but the value is only used for comparison 176f50cd85cSPaolo Bonzini unsafe { 177f50cd85cSPaolo Bonzini let sbd_ref: &SysBusDevice = obj_ref.unsafe_cast(); 178ec3eba98SPaolo Bonzini assert_eq!(addr_of!(*sbd_ref), p_ptr.cast()); 179f50cd85cSPaolo Bonzini } 180f50cd85cSPaolo Bonzini } 181