119985021SZhao Liu // Copyright (C) 2025 Intel Corporation. 219985021SZhao Liu // Author(s): Zhao Liu <zhai1.liu@intel.com> 319985021SZhao Liu // SPDX-License-Identifier: GPL-2.0-or-later 419985021SZhao Liu 5*e4fb0be1SPaolo Bonzini use std::{ 6*e4fb0be1SPaolo Bonzini ffi::{c_void, CStr}, 7*e4fb0be1SPaolo Bonzini mem::size_of, 8*e4fb0be1SPaolo Bonzini ptr::NonNull, 9*e4fb0be1SPaolo Bonzini slice, 10*e4fb0be1SPaolo Bonzini }; 1119985021SZhao Liu 1219985021SZhao Liu use qemu_api::{ 1357c327f3SZhao Liu bindings::{ 148df1b001SZhao Liu vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8, 158df1b001SZhao Liu vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags, 1657c327f3SZhao Liu }, 1719985021SZhao Liu c_str, 188df1b001SZhao Liu cell::{BqlCell, Opaque}, 198df1b001SZhao Liu impl_vmstate_forward, 2019985021SZhao Liu vmstate::{VMStateDescription, VMStateField}, 219bd7e6f7SZhao Liu vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate, 2219985021SZhao Liu zeroable::Zeroable, 2319985021SZhao Liu }; 2419985021SZhao Liu 2519985021SZhao Liu const FOO_ARRAY_MAX: usize = 3; 2619985021SZhao Liu 2719985021SZhao Liu // =========================== Test VMSTATE_FOOA =========================== 2819985021SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C 2919985021SZhao Liu // macro variants: 3019985021SZhao Liu // * VMSTATE_FOOA: 3119985021SZhao Liu // - VMSTATE_U16 3219985021SZhao Liu // - VMSTATE_UNUSED 3319985021SZhao Liu // - VMSTATE_VARRAY_UINT16_UNSAFE 3419985021SZhao Liu // - VMSTATE_VARRAY_MULTIPLY 3519985021SZhao Liu #[repr(C)] 36cff1ec67SZhao Liu #[derive(Default, qemu_api_macros::offsets)] 3719985021SZhao Liu struct FooA { 3819985021SZhao Liu arr: [u8; FOO_ARRAY_MAX], 3919985021SZhao Liu num: u16, 4019985021SZhao Liu arr_mul: [i8; FOO_ARRAY_MAX], 4119985021SZhao Liu num_mul: u32, 4219985021SZhao Liu elem: i8, 4319985021SZhao Liu } 4419985021SZhao Liu 4519985021SZhao Liu static VMSTATE_FOOA: VMStateDescription = VMStateDescription { 4619985021SZhao Liu name: c_str!("foo_a").as_ptr(), 4719985021SZhao Liu version_id: 1, 4819985021SZhao Liu minimum_version_id: 1, 4919985021SZhao Liu fields: vmstate_fields! { 5019985021SZhao Liu vmstate_of!(FooA, elem), 5119985021SZhao Liu vmstate_unused!(size_of::<i64>()), 5219985021SZhao Liu vmstate_of!(FooA, arr[0 .. num]).with_version_id(0), 5319985021SZhao Liu vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]), 5419985021SZhao Liu }, 5519985021SZhao Liu ..Zeroable::ZERO 5619985021SZhao Liu }; 5719985021SZhao Liu 5819985021SZhao Liu #[test] 5919985021SZhao Liu fn test_vmstate_uint16() { 6019985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 6119985021SZhao Liu 6219985021SZhao Liu // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16) 6319985021SZhao Liu assert_eq!( 6419985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 6519985021SZhao Liu b"elem\0" 6619985021SZhao Liu ); 6719985021SZhao Liu assert_eq!(foo_fields[0].offset, 16); 6819985021SZhao Liu assert_eq!(foo_fields[0].num_offset, 0); 6919985021SZhao Liu assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 }); 7019985021SZhao Liu assert_eq!(foo_fields[0].version_id, 0); 7119985021SZhao Liu assert_eq!(foo_fields[0].size, 1); 7219985021SZhao Liu assert_eq!(foo_fields[0].num, 0); 7319985021SZhao Liu assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE); 7419985021SZhao Liu assert!(foo_fields[0].vmsd.is_null()); 7519985021SZhao Liu assert!(foo_fields[0].field_exists.is_none()); 7619985021SZhao Liu } 7719985021SZhao Liu 7819985021SZhao Liu #[test] 7919985021SZhao Liu fn test_vmstate_unused() { 8019985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 8119985021SZhao Liu 8219985021SZhao Liu // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED) 8319985021SZhao Liu assert_eq!( 8419985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), 8519985021SZhao Liu b"unused\0" 8619985021SZhao Liu ); 8719985021SZhao Liu assert_eq!(foo_fields[1].offset, 0); 8819985021SZhao Liu assert_eq!(foo_fields[1].num_offset, 0); 8919985021SZhao Liu assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer }); 9019985021SZhao Liu assert_eq!(foo_fields[1].version_id, 0); 9119985021SZhao Liu assert_eq!(foo_fields[1].size, 8); 9219985021SZhao Liu assert_eq!(foo_fields[1].num, 0); 9319985021SZhao Liu assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER); 9419985021SZhao Liu assert!(foo_fields[1].vmsd.is_null()); 9519985021SZhao Liu assert!(foo_fields[1].field_exists.is_none()); 9619985021SZhao Liu } 9719985021SZhao Liu 9819985021SZhao Liu #[test] 9919985021SZhao Liu fn test_vmstate_varray_uint16_unsafe() { 10019985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 10119985021SZhao Liu 10219985021SZhao Liu // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to 10319985021SZhao Liu // VMSTATE_VARRAY_UINT16_UNSAFE) 10419985021SZhao Liu assert_eq!( 10519985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 10619985021SZhao Liu b"arr\0" 10719985021SZhao Liu ); 10819985021SZhao Liu assert_eq!(foo_fields[2].offset, 0); 10919985021SZhao Liu assert_eq!(foo_fields[2].num_offset, 4); 11019985021SZhao Liu assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 }); 11119985021SZhao Liu assert_eq!(foo_fields[2].version_id, 0); 11219985021SZhao Liu assert_eq!(foo_fields[2].size, 1); 11319985021SZhao Liu assert_eq!(foo_fields[2].num, 0); 11419985021SZhao Liu assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16); 11519985021SZhao Liu assert!(foo_fields[2].vmsd.is_null()); 11619985021SZhao Liu assert!(foo_fields[2].field_exists.is_none()); 11719985021SZhao Liu } 11819985021SZhao Liu 11919985021SZhao Liu #[test] 12019985021SZhao Liu fn test_vmstate_varray_multiply() { 12119985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 12219985021SZhao Liu 12319985021SZhao Liu // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to 12419985021SZhao Liu // VMSTATE_VARRAY_MULTIPLY) 12519985021SZhao Liu assert_eq!( 12619985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), 12719985021SZhao Liu b"arr_mul\0" 12819985021SZhao Liu ); 12919985021SZhao Liu assert_eq!(foo_fields[3].offset, 6); 13019985021SZhao Liu assert_eq!(foo_fields[3].num_offset, 12); 13119985021SZhao Liu assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 }); 13219985021SZhao Liu assert_eq!(foo_fields[3].version_id, 0); 13319985021SZhao Liu assert_eq!(foo_fields[3].size, 1); 13419985021SZhao Liu assert_eq!(foo_fields[3].num, 16); 13519985021SZhao Liu assert_eq!( 13619985021SZhao Liu foo_fields[3].flags.0, 13719985021SZhao Liu VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 13819985021SZhao Liu ); 13919985021SZhao Liu assert!(foo_fields[3].vmsd.is_null()); 14019985021SZhao Liu assert!(foo_fields[3].field_exists.is_none()); 14119985021SZhao Liu 14219985021SZhao Liu // The last VMStateField in VMSTATE_FOOA. 14319985021SZhao Liu assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END); 14419985021SZhao Liu } 14557c327f3SZhao Liu 14657c327f3SZhao Liu // =========================== Test VMSTATE_FOOB =========================== 14757c327f3SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C 14857c327f3SZhao Liu // macro variants: 14957c327f3SZhao Liu // * VMSTATE_FOOB: 15057c327f3SZhao Liu // - VMSTATE_BOOL_V 15157c327f3SZhao Liu // - VMSTATE_U64 15257c327f3SZhao Liu // - VMSTATE_STRUCT_VARRAY_UINT8 15357c327f3SZhao Liu // - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32 15457c327f3SZhao Liu // - VMSTATE_ARRAY 155cff1ec67SZhao Liu // - VMSTATE_STRUCT_VARRAY_UINT8 with BqlCell wrapper & test_fn 15657c327f3SZhao Liu #[repr(C)] 157cff1ec67SZhao Liu #[derive(Default, qemu_api_macros::offsets)] 15857c327f3SZhao Liu struct FooB { 15957c327f3SZhao Liu arr_a: [FooA; FOO_ARRAY_MAX], 16057c327f3SZhao Liu num_a: u8, 16157c327f3SZhao Liu arr_a_mul: [FooA; FOO_ARRAY_MAX], 16257c327f3SZhao Liu num_a_mul: u32, 16357c327f3SZhao Liu wrap: BqlCell<u64>, 16457c327f3SZhao Liu val: bool, 16557c327f3SZhao Liu // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test. 16657c327f3SZhao Liu arr_i64: [i64; FOO_ARRAY_MAX], 167cff1ec67SZhao Liu arr_a_wrap: [FooA; FOO_ARRAY_MAX], 168cff1ec67SZhao Liu num_a_wrap: BqlCell<u32>, 169cff1ec67SZhao Liu } 170cff1ec67SZhao Liu 171cff1ec67SZhao Liu fn validate_foob(_state: &FooB, _version_id: u8) -> bool { 172cff1ec67SZhao Liu true 17357c327f3SZhao Liu } 17457c327f3SZhao Liu 17557c327f3SZhao Liu static VMSTATE_FOOB: VMStateDescription = VMStateDescription { 17657c327f3SZhao Liu name: c_str!("foo_b").as_ptr(), 17757c327f3SZhao Liu version_id: 2, 17857c327f3SZhao Liu minimum_version_id: 1, 17957c327f3SZhao Liu fields: vmstate_fields! { 18057c327f3SZhao Liu vmstate_of!(FooB, val).with_version_id(2), 18157c327f3SZhao Liu vmstate_of!(FooB, wrap), 18257c327f3SZhao Liu vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1), 18357c327f3SZhao Liu vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2), 18457c327f3SZhao Liu vmstate_of!(FooB, arr_i64), 185cff1ec67SZhao Liu vmstate_struct!(FooB, arr_a_wrap[0 .. num_a_wrap], &VMSTATE_FOOA, FooA, validate_foob), 18657c327f3SZhao Liu }, 18757c327f3SZhao Liu ..Zeroable::ZERO 18857c327f3SZhao Liu }; 18957c327f3SZhao Liu 19057c327f3SZhao Liu #[test] 19157c327f3SZhao Liu fn test_vmstate_bool_v() { 192cff1ec67SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; 19357c327f3SZhao Liu 19457c327f3SZhao Liu // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V) 19557c327f3SZhao Liu assert_eq!( 19657c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 19757c327f3SZhao Liu b"val\0" 19857c327f3SZhao Liu ); 19957c327f3SZhao Liu assert_eq!(foo_fields[0].offset, 136); 20057c327f3SZhao Liu assert_eq!(foo_fields[0].num_offset, 0); 20157c327f3SZhao Liu assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool }); 20257c327f3SZhao Liu assert_eq!(foo_fields[0].version_id, 2); 20357c327f3SZhao Liu assert_eq!(foo_fields[0].size, 1); 20457c327f3SZhao Liu assert_eq!(foo_fields[0].num, 0); 20557c327f3SZhao Liu assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE); 20657c327f3SZhao Liu assert!(foo_fields[0].vmsd.is_null()); 20757c327f3SZhao Liu assert!(foo_fields[0].field_exists.is_none()); 20857c327f3SZhao Liu } 20957c327f3SZhao Liu 21057c327f3SZhao Liu #[test] 21157c327f3SZhao Liu fn test_vmstate_uint64() { 212cff1ec67SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; 21357c327f3SZhao Liu 21457c327f3SZhao Liu // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64) 21557c327f3SZhao Liu assert_eq!( 21657c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), 21757c327f3SZhao Liu b"wrap\0" 21857c327f3SZhao Liu ); 21957c327f3SZhao Liu assert_eq!(foo_fields[1].offset, 128); 22057c327f3SZhao Liu assert_eq!(foo_fields[1].num_offset, 0); 22157c327f3SZhao Liu assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 }); 22257c327f3SZhao Liu assert_eq!(foo_fields[1].version_id, 0); 22357c327f3SZhao Liu assert_eq!(foo_fields[1].size, 8); 22457c327f3SZhao Liu assert_eq!(foo_fields[1].num, 0); 22557c327f3SZhao Liu assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE); 22657c327f3SZhao Liu assert!(foo_fields[1].vmsd.is_null()); 22757c327f3SZhao Liu assert!(foo_fields[1].field_exists.is_none()); 22857c327f3SZhao Liu } 22957c327f3SZhao Liu 23057c327f3SZhao Liu #[test] 23157c327f3SZhao Liu fn test_vmstate_struct_varray_uint8() { 232cff1ec67SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; 23357c327f3SZhao Liu 23457c327f3SZhao Liu // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to 23557c327f3SZhao Liu // VMSTATE_STRUCT_VARRAY_UINT8) 23657c327f3SZhao Liu assert_eq!( 23757c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 23857c327f3SZhao Liu b"arr_a\0" 23957c327f3SZhao Liu ); 24057c327f3SZhao Liu assert_eq!(foo_fields[2].offset, 0); 24157c327f3SZhao Liu assert_eq!(foo_fields[2].num_offset, 60); 24257c327f3SZhao Liu assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field. 24357c327f3SZhao Liu assert_eq!(foo_fields[2].version_id, 1); 24457c327f3SZhao Liu assert_eq!(foo_fields[2].size, 20); 24557c327f3SZhao Liu assert_eq!(foo_fields[2].num, 0); 24657c327f3SZhao Liu assert_eq!( 24757c327f3SZhao Liu foo_fields[2].flags.0, 24857c327f3SZhao Liu VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0 24957c327f3SZhao Liu ); 25057c327f3SZhao Liu assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA); 25157c327f3SZhao Liu assert!(foo_fields[2].field_exists.is_none()); 25257c327f3SZhao Liu } 25357c327f3SZhao Liu 25457c327f3SZhao Liu #[test] 25557c327f3SZhao Liu fn test_vmstate_struct_varray_uint32_multiply() { 256cff1ec67SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; 25757c327f3SZhao Liu 25857c327f3SZhao Liu // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to 25957c327f3SZhao Liu // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32) 26057c327f3SZhao Liu assert_eq!( 26157c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), 26257c327f3SZhao Liu b"arr_a_mul\0" 26357c327f3SZhao Liu ); 26457c327f3SZhao Liu assert_eq!(foo_fields[3].offset, 64); 26557c327f3SZhao Liu assert_eq!(foo_fields[3].num_offset, 124); 26657c327f3SZhao Liu assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field. 26757c327f3SZhao Liu assert_eq!(foo_fields[3].version_id, 2); 26857c327f3SZhao Liu assert_eq!(foo_fields[3].size, 20); 26957c327f3SZhao Liu assert_eq!(foo_fields[3].num, 32); 27057c327f3SZhao Liu assert_eq!( 27157c327f3SZhao Liu foo_fields[3].flags.0, 27257c327f3SZhao Liu VMStateFlags::VMS_STRUCT.0 27357c327f3SZhao Liu | VMStateFlags::VMS_VARRAY_UINT32.0 27457c327f3SZhao Liu | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 27557c327f3SZhao Liu ); 27657c327f3SZhao Liu assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA); 27757c327f3SZhao Liu assert!(foo_fields[3].field_exists.is_none()); 27857c327f3SZhao Liu } 27957c327f3SZhao Liu 28057c327f3SZhao Liu #[test] 28157c327f3SZhao Liu fn test_vmstate_macro_array() { 282cff1ec67SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; 28357c327f3SZhao Liu 28457c327f3SZhao Liu // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to 28557c327f3SZhao Liu // VMSTATE_ARRAY) 28657c327f3SZhao Liu assert_eq!( 28757c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(), 28857c327f3SZhao Liu b"arr_i64\0" 28957c327f3SZhao Liu ); 29057c327f3SZhao Liu assert_eq!(foo_fields[4].offset, 144); 29157c327f3SZhao Liu assert_eq!(foo_fields[4].num_offset, 0); 29257c327f3SZhao Liu assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 }); 29357c327f3SZhao Liu assert_eq!(foo_fields[4].version_id, 0); 29457c327f3SZhao Liu assert_eq!(foo_fields[4].size, 8); 29557c327f3SZhao Liu assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32); 29657c327f3SZhao Liu assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY); 29757c327f3SZhao Liu assert!(foo_fields[4].vmsd.is_null()); 29857c327f3SZhao Liu assert!(foo_fields[4].field_exists.is_none()); 299cff1ec67SZhao Liu } 300cff1ec67SZhao Liu 301cff1ec67SZhao Liu #[test] 302cff1ec67SZhao Liu fn test_vmstate_struct_varray_uint8_wrapper() { 303cff1ec67SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; 304cff1ec67SZhao Liu let mut foo_b: FooB = Default::default(); 305cff1ec67SZhao Liu let foo_b_p = std::ptr::addr_of_mut!(foo_b).cast::<c_void>(); 306cff1ec67SZhao Liu 307cff1ec67SZhao Liu // 6th VMStateField ("arr_a_wrap") in VMSTATE_FOOB (corresponding to 308cff1ec67SZhao Liu // VMSTATE_STRUCT_VARRAY_UINT8). Other fields are checked in 309cff1ec67SZhao Liu // test_vmstate_struct_varray_uint8. 310cff1ec67SZhao Liu assert_eq!( 311cff1ec67SZhao Liu unsafe { CStr::from_ptr(foo_fields[5].name) }.to_bytes_with_nul(), 312cff1ec67SZhao Liu b"arr_a_wrap\0" 313cff1ec67SZhao Liu ); 314cff1ec67SZhao Liu assert_eq!(foo_fields[5].num_offset, 228); 315cff1ec67SZhao Liu assert!(unsafe { foo_fields[5].field_exists.unwrap()(foo_b_p, 0) }); 31657c327f3SZhao Liu 31757c327f3SZhao Liu // The last VMStateField in VMSTATE_FOOB. 318cff1ec67SZhao Liu assert_eq!(foo_fields[6].flags, VMStateFlags::VMS_END); 31957c327f3SZhao Liu } 3208df1b001SZhao Liu 3218df1b001SZhao Liu // =========================== Test VMSTATE_FOOC =========================== 3228df1b001SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C 3238df1b001SZhao Liu // macro variants: 3248df1b001SZhao Liu // * VMSTATE_FOOC: 3258df1b001SZhao Liu // - VMSTATE_POINTER 3268df1b001SZhao Liu // - VMSTATE_ARRAY_OF_POINTER 3278df1b001SZhao Liu struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array is almost impossible. 3288df1b001SZhao Liu 3298df1b001SZhao Liu impl_vmstate_forward!(FooCWrapper); 3308df1b001SZhao Liu 3318df1b001SZhao Liu #[repr(C)] 3328df1b001SZhao Liu #[derive(qemu_api_macros::offsets)] 3338df1b001SZhao Liu struct FooC { 3348df1b001SZhao Liu ptr: *const i32, 3358df1b001SZhao Liu ptr_a: NonNull<FooA>, 3368df1b001SZhao Liu arr_ptr: [Box<u8>; FOO_ARRAY_MAX], 3378df1b001SZhao Liu arr_ptr_wrap: FooCWrapper, 3388df1b001SZhao Liu } 3398df1b001SZhao Liu 3408df1b001SZhao Liu static VMSTATE_FOOC: VMStateDescription = VMStateDescription { 3418df1b001SZhao Liu name: c_str!("foo_c").as_ptr(), 3428df1b001SZhao Liu version_id: 3, 3438df1b001SZhao Liu minimum_version_id: 1, 3448df1b001SZhao Liu fields: vmstate_fields! { 3458df1b001SZhao Liu vmstate_of!(FooC, ptr).with_version_id(2), 3468df1b001SZhao Liu // FIXME: Currently vmstate_struct doesn't support the pointer to structure. 3478df1b001SZhao Liu // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>) 3488df1b001SZhao Liu vmstate_unused!(size_of::<NonNull<FooA>>()), 3498df1b001SZhao Liu vmstate_of!(FooC, arr_ptr), 3508df1b001SZhao Liu vmstate_of!(FooC, arr_ptr_wrap), 3518df1b001SZhao Liu }, 3528df1b001SZhao Liu ..Zeroable::ZERO 3538df1b001SZhao Liu }; 3548df1b001SZhao Liu 3558df1b001SZhao Liu const PTR_SIZE: usize = size_of::<*mut ()>(); 3568df1b001SZhao Liu 3578df1b001SZhao Liu #[test] 3588df1b001SZhao Liu fn test_vmstate_pointer() { 3598df1b001SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; 3608df1b001SZhao Liu 3618df1b001SZhao Liu // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER) 3628df1b001SZhao Liu assert_eq!( 3638df1b001SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 3648df1b001SZhao Liu b"ptr\0" 3658df1b001SZhao Liu ); 3668df1b001SZhao Liu assert_eq!(foo_fields[0].offset, 0); 3678df1b001SZhao Liu assert_eq!(foo_fields[0].num_offset, 0); 3688df1b001SZhao Liu assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 }); 3698df1b001SZhao Liu assert_eq!(foo_fields[0].version_id, 2); 3708df1b001SZhao Liu assert_eq!(foo_fields[0].size, 4); 3718df1b001SZhao Liu assert_eq!(foo_fields[0].num, 0); 3728df1b001SZhao Liu assert_eq!( 3738df1b001SZhao Liu foo_fields[0].flags.0, 3748df1b001SZhao Liu VMStateFlags::VMS_SINGLE.0 | VMStateFlags::VMS_POINTER.0 3758df1b001SZhao Liu ); 3768df1b001SZhao Liu assert!(foo_fields[0].vmsd.is_null()); 3778df1b001SZhao Liu assert!(foo_fields[0].field_exists.is_none()); 3788df1b001SZhao Liu } 3798df1b001SZhao Liu 3808df1b001SZhao Liu #[test] 3818df1b001SZhao Liu fn test_vmstate_macro_array_of_pointer() { 3828df1b001SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; 3838df1b001SZhao Liu 3848df1b001SZhao Liu // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to 3858df1b001SZhao Liu // VMSTATE_ARRAY_OF_POINTER) 3868df1b001SZhao Liu assert_eq!( 3878df1b001SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 3888df1b001SZhao Liu b"arr_ptr\0" 3898df1b001SZhao Liu ); 3908df1b001SZhao Liu assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE); 3918df1b001SZhao Liu assert_eq!(foo_fields[2].num_offset, 0); 3928df1b001SZhao Liu assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 }); 3938df1b001SZhao Liu assert_eq!(foo_fields[2].version_id, 0); 3948df1b001SZhao Liu assert_eq!(foo_fields[2].size, PTR_SIZE); 3958df1b001SZhao Liu assert_eq!(foo_fields[2].num, FOO_ARRAY_MAX as i32); 3968df1b001SZhao Liu assert_eq!( 3978df1b001SZhao Liu foo_fields[2].flags.0, 3988df1b001SZhao Liu VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0 3998df1b001SZhao Liu ); 4008df1b001SZhao Liu assert!(foo_fields[2].vmsd.is_null()); 4018df1b001SZhao Liu assert!(foo_fields[2].field_exists.is_none()); 4028df1b001SZhao Liu } 4038df1b001SZhao Liu 4048df1b001SZhao Liu #[test] 4058df1b001SZhao Liu fn test_vmstate_macro_array_of_pointer_wrapped() { 4068df1b001SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; 4078df1b001SZhao Liu 4088df1b001SZhao Liu // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to 4098df1b001SZhao Liu // VMSTATE_ARRAY_OF_POINTER) 4108df1b001SZhao Liu assert_eq!( 4118df1b001SZhao Liu unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), 4128df1b001SZhao Liu b"arr_ptr_wrap\0" 4138df1b001SZhao Liu ); 4148df1b001SZhao Liu assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE); 4158df1b001SZhao Liu assert_eq!(foo_fields[3].num_offset, 0); 416d031d2faSZhao Liu assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_uint8 }); 4178df1b001SZhao Liu assert_eq!(foo_fields[3].version_id, 0); 4188df1b001SZhao Liu assert_eq!(foo_fields[3].size, PTR_SIZE); 4198df1b001SZhao Liu assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32); 4208df1b001SZhao Liu assert_eq!( 421d031d2faSZhao Liu foo_fields[3].flags.0, 4228df1b001SZhao Liu VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0 4238df1b001SZhao Liu ); 4248df1b001SZhao Liu assert!(foo_fields[3].vmsd.is_null()); 4258df1b001SZhao Liu assert!(foo_fields[3].field_exists.is_none()); 4268df1b001SZhao Liu 4278df1b001SZhao Liu // The last VMStateField in VMSTATE_FOOC. 4288df1b001SZhao Liu assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END); 4298df1b001SZhao Liu } 4309bd7e6f7SZhao Liu 4319bd7e6f7SZhao Liu // =========================== Test VMSTATE_FOOD =========================== 4329bd7e6f7SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C 4339bd7e6f7SZhao Liu // macro variants: 4349bd7e6f7SZhao Liu // * VMSTATE_FOOD: 4359bd7e6f7SZhao Liu // - VMSTATE_VALIDATE 4369bd7e6f7SZhao Liu 4379bd7e6f7SZhao Liu // Add more member fields when vmstate_of/vmstate_struct support "test" 4389bd7e6f7SZhao Liu // parameter. 4399bd7e6f7SZhao Liu struct FooD; 4409bd7e6f7SZhao Liu 4419bd7e6f7SZhao Liu impl FooD { 4429bd7e6f7SZhao Liu fn validate_food_0(&self, _version_id: u8) -> bool { 4439bd7e6f7SZhao Liu true 4449bd7e6f7SZhao Liu } 4459bd7e6f7SZhao Liu 4469bd7e6f7SZhao Liu fn validate_food_1(_state: &FooD, _version_id: u8) -> bool { 4479bd7e6f7SZhao Liu false 4489bd7e6f7SZhao Liu } 4499bd7e6f7SZhao Liu } 4509bd7e6f7SZhao Liu 4519bd7e6f7SZhao Liu fn validate_food_2(_state: &FooD, _version_id: u8) -> bool { 4529bd7e6f7SZhao Liu true 4539bd7e6f7SZhao Liu } 4549bd7e6f7SZhao Liu 4559bd7e6f7SZhao Liu static VMSTATE_FOOD: VMStateDescription = VMStateDescription { 4569bd7e6f7SZhao Liu name: c_str!("foo_d").as_ptr(), 4579bd7e6f7SZhao Liu version_id: 3, 4589bd7e6f7SZhao Liu minimum_version_id: 1, 4599bd7e6f7SZhao Liu fields: vmstate_fields! { 4609bd7e6f7SZhao Liu vmstate_validate!(FooD, c_str!("foo_d_0"), FooD::validate_food_0), 4619bd7e6f7SZhao Liu vmstate_validate!(FooD, c_str!("foo_d_1"), FooD::validate_food_1), 4629bd7e6f7SZhao Liu vmstate_validate!(FooD, c_str!("foo_d_2"), validate_food_2), 4639bd7e6f7SZhao Liu }, 4649bd7e6f7SZhao Liu ..Zeroable::ZERO 4659bd7e6f7SZhao Liu }; 4669bd7e6f7SZhao Liu 4679bd7e6f7SZhao Liu #[test] 4689bd7e6f7SZhao Liu fn test_vmstate_validate() { 4699bd7e6f7SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOD.fields, 4) }; 4709bd7e6f7SZhao Liu let mut foo_d = FooD; 4719bd7e6f7SZhao Liu let foo_d_p = std::ptr::addr_of_mut!(foo_d).cast::<c_void>(); 4729bd7e6f7SZhao Liu 4739bd7e6f7SZhao Liu // 1st VMStateField in VMSTATE_FOOD 4749bd7e6f7SZhao Liu assert_eq!( 4759bd7e6f7SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 4769bd7e6f7SZhao Liu b"foo_d_0\0" 4779bd7e6f7SZhao Liu ); 4789bd7e6f7SZhao Liu assert_eq!(foo_fields[0].offset, 0); 4799bd7e6f7SZhao Liu assert_eq!(foo_fields[0].num_offset, 0); 4809bd7e6f7SZhao Liu assert!(foo_fields[0].info.is_null()); 4819bd7e6f7SZhao Liu assert_eq!(foo_fields[0].version_id, 0); 4829bd7e6f7SZhao Liu assert_eq!(foo_fields[0].size, 0); 4839bd7e6f7SZhao Liu assert_eq!(foo_fields[0].num, 0); 4849bd7e6f7SZhao Liu assert_eq!( 4859bd7e6f7SZhao Liu foo_fields[0].flags.0, 4869bd7e6f7SZhao Liu VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0 4879bd7e6f7SZhao Liu ); 4889bd7e6f7SZhao Liu assert!(foo_fields[0].vmsd.is_null()); 4899bd7e6f7SZhao Liu assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) }); 4909bd7e6f7SZhao Liu 4919bd7e6f7SZhao Liu // 2nd VMStateField in VMSTATE_FOOD 4929bd7e6f7SZhao Liu assert_eq!( 4939bd7e6f7SZhao Liu unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), 4949bd7e6f7SZhao Liu b"foo_d_1\0" 4959bd7e6f7SZhao Liu ); 4969bd7e6f7SZhao Liu assert!(!unsafe { foo_fields[1].field_exists.unwrap()(foo_d_p, 1) }); 4979bd7e6f7SZhao Liu 4989bd7e6f7SZhao Liu // 3rd VMStateField in VMSTATE_FOOD 4999bd7e6f7SZhao Liu assert_eq!( 5009bd7e6f7SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 5019bd7e6f7SZhao Liu b"foo_d_2\0" 5029bd7e6f7SZhao Liu ); 5039bd7e6f7SZhao Liu assert!(unsafe { foo_fields[2].field_exists.unwrap()(foo_d_p, 2) }); 5049bd7e6f7SZhao Liu 5059bd7e6f7SZhao Liu // The last VMStateField in VMSTATE_FOOD. 5069bd7e6f7SZhao Liu assert_eq!(foo_fields[3].flags, VMStateFlags::VMS_END); 5079bd7e6f7SZhao Liu } 508