1 // Copyright (C) 2025 Intel Corporation. 2 // Author(s): Zhao Liu <zhai1.liu@intel.com> 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 use std::{ffi::CStr, mem::size_of, slice}; 6 7 use qemu_api::{ 8 bindings::{vmstate_info_int8, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags}, 9 c_str, 10 vmstate::{VMStateDescription, VMStateField}, 11 vmstate_fields, vmstate_of, vmstate_unused, 12 zeroable::Zeroable, 13 }; 14 15 const FOO_ARRAY_MAX: usize = 3; 16 17 // =========================== Test VMSTATE_FOOA =========================== 18 // Test the use cases of the vmstate macro, corresponding to the following C 19 // macro variants: 20 // * VMSTATE_FOOA: 21 // - VMSTATE_U16 22 // - VMSTATE_UNUSED 23 // - VMSTATE_VARRAY_UINT16_UNSAFE 24 // - VMSTATE_VARRAY_MULTIPLY 25 #[repr(C)] 26 #[derive(qemu_api_macros::offsets)] 27 struct FooA { 28 arr: [u8; FOO_ARRAY_MAX], 29 num: u16, 30 arr_mul: [i8; FOO_ARRAY_MAX], 31 num_mul: u32, 32 elem: i8, 33 } 34 35 static VMSTATE_FOOA: VMStateDescription = VMStateDescription { 36 name: c_str!("foo_a").as_ptr(), 37 version_id: 1, 38 minimum_version_id: 1, 39 fields: vmstate_fields! { 40 vmstate_of!(FooA, elem), 41 vmstate_unused!(size_of::<i64>()), 42 vmstate_of!(FooA, arr[0 .. num]).with_version_id(0), 43 vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]), 44 }, 45 ..Zeroable::ZERO 46 }; 47 48 #[test] 49 fn test_vmstate_uint16() { 50 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 51 52 // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16) 53 assert_eq!( 54 unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 55 b"elem\0" 56 ); 57 assert_eq!(foo_fields[0].offset, 16); 58 assert_eq!(foo_fields[0].num_offset, 0); 59 assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 }); 60 assert_eq!(foo_fields[0].version_id, 0); 61 assert_eq!(foo_fields[0].size, 1); 62 assert_eq!(foo_fields[0].num, 0); 63 assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE); 64 assert!(foo_fields[0].vmsd.is_null()); 65 assert!(foo_fields[0].field_exists.is_none()); 66 } 67 68 #[test] 69 fn test_vmstate_unused() { 70 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 71 72 // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED) 73 assert_eq!( 74 unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), 75 b"unused\0" 76 ); 77 assert_eq!(foo_fields[1].offset, 0); 78 assert_eq!(foo_fields[1].num_offset, 0); 79 assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer }); 80 assert_eq!(foo_fields[1].version_id, 0); 81 assert_eq!(foo_fields[1].size, 8); 82 assert_eq!(foo_fields[1].num, 0); 83 assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER); 84 assert!(foo_fields[1].vmsd.is_null()); 85 assert!(foo_fields[1].field_exists.is_none()); 86 } 87 88 #[test] 89 fn test_vmstate_varray_uint16_unsafe() { 90 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 91 92 // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to 93 // VMSTATE_VARRAY_UINT16_UNSAFE) 94 assert_eq!( 95 unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 96 b"arr\0" 97 ); 98 assert_eq!(foo_fields[2].offset, 0); 99 assert_eq!(foo_fields[2].num_offset, 4); 100 assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 }); 101 assert_eq!(foo_fields[2].version_id, 0); 102 assert_eq!(foo_fields[2].size, 1); 103 assert_eq!(foo_fields[2].num, 0); 104 assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16); 105 assert!(foo_fields[2].vmsd.is_null()); 106 assert!(foo_fields[2].field_exists.is_none()); 107 } 108 109 #[test] 110 fn test_vmstate_varray_multiply() { 111 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 112 113 // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to 114 // VMSTATE_VARRAY_MULTIPLY) 115 assert_eq!( 116 unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), 117 b"arr_mul\0" 118 ); 119 assert_eq!(foo_fields[3].offset, 6); 120 assert_eq!(foo_fields[3].num_offset, 12); 121 assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 }); 122 assert_eq!(foo_fields[3].version_id, 0); 123 assert_eq!(foo_fields[3].size, 1); 124 assert_eq!(foo_fields[3].num, 16); 125 assert_eq!( 126 foo_fields[3].flags.0, 127 VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 128 ); 129 assert!(foo_fields[3].vmsd.is_null()); 130 assert!(foo_fields[3].field_exists.is_none()); 131 132 // The last VMStateField in VMSTATE_FOOA. 133 assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END); 134 } 135