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