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*9bd7e6f7SZhao Liu use std::{ffi::CStr, mem::size_of, os::raw::c_void, ptr::NonNull, slice};
619985021SZhao Liu
719985021SZhao Liu use qemu_api::{
857c327f3SZhao Liu bindings::{
98df1b001SZhao Liu vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8,
108df1b001SZhao Liu vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
1157c327f3SZhao Liu },
1219985021SZhao Liu c_str,
138df1b001SZhao Liu cell::{BqlCell, Opaque},
148df1b001SZhao Liu impl_vmstate_forward,
1519985021SZhao Liu vmstate::{VMStateDescription, VMStateField},
16*9bd7e6f7SZhao Liu vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate,
1719985021SZhao Liu zeroable::Zeroable,
1819985021SZhao Liu };
1919985021SZhao Liu
2019985021SZhao Liu const FOO_ARRAY_MAX: usize = 3;
2119985021SZhao Liu
2219985021SZhao Liu // =========================== Test VMSTATE_FOOA ===========================
2319985021SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C
2419985021SZhao Liu // macro variants:
2519985021SZhao Liu // * VMSTATE_FOOA:
2619985021SZhao Liu // - VMSTATE_U16
2719985021SZhao Liu // - VMSTATE_UNUSED
2819985021SZhao Liu // - VMSTATE_VARRAY_UINT16_UNSAFE
2919985021SZhao Liu // - VMSTATE_VARRAY_MULTIPLY
3019985021SZhao Liu #[repr(C)]
3119985021SZhao Liu #[derive(qemu_api_macros::offsets)]
3219985021SZhao Liu struct FooA {
3319985021SZhao Liu arr: [u8; FOO_ARRAY_MAX],
3419985021SZhao Liu num: u16,
3519985021SZhao Liu arr_mul: [i8; FOO_ARRAY_MAX],
3619985021SZhao Liu num_mul: u32,
3719985021SZhao Liu elem: i8,
3819985021SZhao Liu }
3919985021SZhao Liu
4019985021SZhao Liu static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
4119985021SZhao Liu name: c_str!("foo_a").as_ptr(),
4219985021SZhao Liu version_id: 1,
4319985021SZhao Liu minimum_version_id: 1,
4419985021SZhao Liu fields: vmstate_fields! {
4519985021SZhao Liu vmstate_of!(FooA, elem),
4619985021SZhao Liu vmstate_unused!(size_of::<i64>()),
4719985021SZhao Liu vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
4819985021SZhao Liu vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
4919985021SZhao Liu },
5019985021SZhao Liu ..Zeroable::ZERO
5119985021SZhao Liu };
5219985021SZhao Liu
5319985021SZhao Liu #[test]
test_vmstate_uint16()5419985021SZhao Liu fn test_vmstate_uint16() {
5519985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
5619985021SZhao Liu
5719985021SZhao Liu // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
5819985021SZhao Liu assert_eq!(
5919985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
6019985021SZhao Liu b"elem\0"
6119985021SZhao Liu );
6219985021SZhao Liu assert_eq!(foo_fields[0].offset, 16);
6319985021SZhao Liu assert_eq!(foo_fields[0].num_offset, 0);
6419985021SZhao Liu assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
6519985021SZhao Liu assert_eq!(foo_fields[0].version_id, 0);
6619985021SZhao Liu assert_eq!(foo_fields[0].size, 1);
6719985021SZhao Liu assert_eq!(foo_fields[0].num, 0);
6819985021SZhao Liu assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
6919985021SZhao Liu assert!(foo_fields[0].vmsd.is_null());
7019985021SZhao Liu assert!(foo_fields[0].field_exists.is_none());
7119985021SZhao Liu }
7219985021SZhao Liu
7319985021SZhao Liu #[test]
test_vmstate_unused()7419985021SZhao Liu fn test_vmstate_unused() {
7519985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
7619985021SZhao Liu
7719985021SZhao Liu // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
7819985021SZhao Liu assert_eq!(
7919985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
8019985021SZhao Liu b"unused\0"
8119985021SZhao Liu );
8219985021SZhao Liu assert_eq!(foo_fields[1].offset, 0);
8319985021SZhao Liu assert_eq!(foo_fields[1].num_offset, 0);
8419985021SZhao Liu assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
8519985021SZhao Liu assert_eq!(foo_fields[1].version_id, 0);
8619985021SZhao Liu assert_eq!(foo_fields[1].size, 8);
8719985021SZhao Liu assert_eq!(foo_fields[1].num, 0);
8819985021SZhao Liu assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
8919985021SZhao Liu assert!(foo_fields[1].vmsd.is_null());
9019985021SZhao Liu assert!(foo_fields[1].field_exists.is_none());
9119985021SZhao Liu }
9219985021SZhao Liu
9319985021SZhao Liu #[test]
test_vmstate_varray_uint16_unsafe()9419985021SZhao Liu fn test_vmstate_varray_uint16_unsafe() {
9519985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
9619985021SZhao Liu
9719985021SZhao Liu // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
9819985021SZhao Liu // VMSTATE_VARRAY_UINT16_UNSAFE)
9919985021SZhao Liu assert_eq!(
10019985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
10119985021SZhao Liu b"arr\0"
10219985021SZhao Liu );
10319985021SZhao Liu assert_eq!(foo_fields[2].offset, 0);
10419985021SZhao Liu assert_eq!(foo_fields[2].num_offset, 4);
10519985021SZhao Liu assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
10619985021SZhao Liu assert_eq!(foo_fields[2].version_id, 0);
10719985021SZhao Liu assert_eq!(foo_fields[2].size, 1);
10819985021SZhao Liu assert_eq!(foo_fields[2].num, 0);
10919985021SZhao Liu assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
11019985021SZhao Liu assert!(foo_fields[2].vmsd.is_null());
11119985021SZhao Liu assert!(foo_fields[2].field_exists.is_none());
11219985021SZhao Liu }
11319985021SZhao Liu
11419985021SZhao Liu #[test]
test_vmstate_varray_multiply()11519985021SZhao Liu fn test_vmstate_varray_multiply() {
11619985021SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
11719985021SZhao Liu
11819985021SZhao Liu // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
11919985021SZhao Liu // VMSTATE_VARRAY_MULTIPLY)
12019985021SZhao Liu assert_eq!(
12119985021SZhao Liu unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
12219985021SZhao Liu b"arr_mul\0"
12319985021SZhao Liu );
12419985021SZhao Liu assert_eq!(foo_fields[3].offset, 6);
12519985021SZhao Liu assert_eq!(foo_fields[3].num_offset, 12);
12619985021SZhao Liu assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
12719985021SZhao Liu assert_eq!(foo_fields[3].version_id, 0);
12819985021SZhao Liu assert_eq!(foo_fields[3].size, 1);
12919985021SZhao Liu assert_eq!(foo_fields[3].num, 16);
13019985021SZhao Liu assert_eq!(
13119985021SZhao Liu foo_fields[3].flags.0,
13219985021SZhao Liu VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
13319985021SZhao Liu );
13419985021SZhao Liu assert!(foo_fields[3].vmsd.is_null());
13519985021SZhao Liu assert!(foo_fields[3].field_exists.is_none());
13619985021SZhao Liu
13719985021SZhao Liu // The last VMStateField in VMSTATE_FOOA.
13819985021SZhao Liu assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
13919985021SZhao Liu }
14057c327f3SZhao Liu
14157c327f3SZhao Liu // =========================== Test VMSTATE_FOOB ===========================
14257c327f3SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C
14357c327f3SZhao Liu // macro variants:
14457c327f3SZhao Liu // * VMSTATE_FOOB:
14557c327f3SZhao Liu // - VMSTATE_BOOL_V
14657c327f3SZhao Liu // - VMSTATE_U64
14757c327f3SZhao Liu // - VMSTATE_STRUCT_VARRAY_UINT8
14857c327f3SZhao Liu // - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
14957c327f3SZhao Liu // - VMSTATE_ARRAY
15057c327f3SZhao Liu #[repr(C)]
15157c327f3SZhao Liu #[derive(qemu_api_macros::offsets)]
15257c327f3SZhao Liu struct FooB {
15357c327f3SZhao Liu arr_a: [FooA; FOO_ARRAY_MAX],
15457c327f3SZhao Liu num_a: u8,
15557c327f3SZhao Liu arr_a_mul: [FooA; FOO_ARRAY_MAX],
15657c327f3SZhao Liu num_a_mul: u32,
15757c327f3SZhao Liu wrap: BqlCell<u64>,
15857c327f3SZhao Liu val: bool,
15957c327f3SZhao Liu // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
16057c327f3SZhao Liu arr_i64: [i64; FOO_ARRAY_MAX],
16157c327f3SZhao Liu }
16257c327f3SZhao Liu
16357c327f3SZhao Liu static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
16457c327f3SZhao Liu name: c_str!("foo_b").as_ptr(),
16557c327f3SZhao Liu version_id: 2,
16657c327f3SZhao Liu minimum_version_id: 1,
16757c327f3SZhao Liu fields: vmstate_fields! {
16857c327f3SZhao Liu vmstate_of!(FooB, val).with_version_id(2),
16957c327f3SZhao Liu vmstate_of!(FooB, wrap),
17057c327f3SZhao Liu vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
17157c327f3SZhao Liu vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
17257c327f3SZhao Liu vmstate_of!(FooB, arr_i64),
17357c327f3SZhao Liu },
17457c327f3SZhao Liu ..Zeroable::ZERO
17557c327f3SZhao Liu };
17657c327f3SZhao Liu
17757c327f3SZhao Liu #[test]
test_vmstate_bool_v()17857c327f3SZhao Liu fn test_vmstate_bool_v() {
17957c327f3SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
18057c327f3SZhao Liu
18157c327f3SZhao Liu // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
18257c327f3SZhao Liu assert_eq!(
18357c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
18457c327f3SZhao Liu b"val\0"
18557c327f3SZhao Liu );
18657c327f3SZhao Liu assert_eq!(foo_fields[0].offset, 136);
18757c327f3SZhao Liu assert_eq!(foo_fields[0].num_offset, 0);
18857c327f3SZhao Liu assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
18957c327f3SZhao Liu assert_eq!(foo_fields[0].version_id, 2);
19057c327f3SZhao Liu assert_eq!(foo_fields[0].size, 1);
19157c327f3SZhao Liu assert_eq!(foo_fields[0].num, 0);
19257c327f3SZhao Liu assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
19357c327f3SZhao Liu assert!(foo_fields[0].vmsd.is_null());
19457c327f3SZhao Liu assert!(foo_fields[0].field_exists.is_none());
19557c327f3SZhao Liu }
19657c327f3SZhao Liu
19757c327f3SZhao Liu #[test]
test_vmstate_uint64()19857c327f3SZhao Liu fn test_vmstate_uint64() {
19957c327f3SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
20057c327f3SZhao Liu
20157c327f3SZhao Liu // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
20257c327f3SZhao Liu assert_eq!(
20357c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
20457c327f3SZhao Liu b"wrap\0"
20557c327f3SZhao Liu );
20657c327f3SZhao Liu assert_eq!(foo_fields[1].offset, 128);
20757c327f3SZhao Liu assert_eq!(foo_fields[1].num_offset, 0);
20857c327f3SZhao Liu assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
20957c327f3SZhao Liu assert_eq!(foo_fields[1].version_id, 0);
21057c327f3SZhao Liu assert_eq!(foo_fields[1].size, 8);
21157c327f3SZhao Liu assert_eq!(foo_fields[1].num, 0);
21257c327f3SZhao Liu assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE);
21357c327f3SZhao Liu assert!(foo_fields[1].vmsd.is_null());
21457c327f3SZhao Liu assert!(foo_fields[1].field_exists.is_none());
21557c327f3SZhao Liu }
21657c327f3SZhao Liu
21757c327f3SZhao Liu #[test]
test_vmstate_struct_varray_uint8()21857c327f3SZhao Liu fn test_vmstate_struct_varray_uint8() {
21957c327f3SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
22057c327f3SZhao Liu
22157c327f3SZhao Liu // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
22257c327f3SZhao Liu // VMSTATE_STRUCT_VARRAY_UINT8)
22357c327f3SZhao Liu assert_eq!(
22457c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
22557c327f3SZhao Liu b"arr_a\0"
22657c327f3SZhao Liu );
22757c327f3SZhao Liu assert_eq!(foo_fields[2].offset, 0);
22857c327f3SZhao Liu assert_eq!(foo_fields[2].num_offset, 60);
22957c327f3SZhao Liu assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
23057c327f3SZhao Liu assert_eq!(foo_fields[2].version_id, 1);
23157c327f3SZhao Liu assert_eq!(foo_fields[2].size, 20);
23257c327f3SZhao Liu assert_eq!(foo_fields[2].num, 0);
23357c327f3SZhao Liu assert_eq!(
23457c327f3SZhao Liu foo_fields[2].flags.0,
23557c327f3SZhao Liu VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
23657c327f3SZhao Liu );
23757c327f3SZhao Liu assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA);
23857c327f3SZhao Liu assert!(foo_fields[2].field_exists.is_none());
23957c327f3SZhao Liu }
24057c327f3SZhao Liu
24157c327f3SZhao Liu #[test]
test_vmstate_struct_varray_uint32_multiply()24257c327f3SZhao Liu fn test_vmstate_struct_varray_uint32_multiply() {
24357c327f3SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
24457c327f3SZhao Liu
24557c327f3SZhao Liu // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
24657c327f3SZhao Liu // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
24757c327f3SZhao Liu assert_eq!(
24857c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
24957c327f3SZhao Liu b"arr_a_mul\0"
25057c327f3SZhao Liu );
25157c327f3SZhao Liu assert_eq!(foo_fields[3].offset, 64);
25257c327f3SZhao Liu assert_eq!(foo_fields[3].num_offset, 124);
25357c327f3SZhao Liu assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
25457c327f3SZhao Liu assert_eq!(foo_fields[3].version_id, 2);
25557c327f3SZhao Liu assert_eq!(foo_fields[3].size, 20);
25657c327f3SZhao Liu assert_eq!(foo_fields[3].num, 32);
25757c327f3SZhao Liu assert_eq!(
25857c327f3SZhao Liu foo_fields[3].flags.0,
25957c327f3SZhao Liu VMStateFlags::VMS_STRUCT.0
26057c327f3SZhao Liu | VMStateFlags::VMS_VARRAY_UINT32.0
26157c327f3SZhao Liu | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
26257c327f3SZhao Liu );
26357c327f3SZhao Liu assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA);
26457c327f3SZhao Liu assert!(foo_fields[3].field_exists.is_none());
26557c327f3SZhao Liu }
26657c327f3SZhao Liu
26757c327f3SZhao Liu #[test]
test_vmstate_macro_array()26857c327f3SZhao Liu fn test_vmstate_macro_array() {
26957c327f3SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
27057c327f3SZhao Liu
27157c327f3SZhao Liu // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
27257c327f3SZhao Liu // VMSTATE_ARRAY)
27357c327f3SZhao Liu assert_eq!(
27457c327f3SZhao Liu unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(),
27557c327f3SZhao Liu b"arr_i64\0"
27657c327f3SZhao Liu );
27757c327f3SZhao Liu assert_eq!(foo_fields[4].offset, 144);
27857c327f3SZhao Liu assert_eq!(foo_fields[4].num_offset, 0);
27957c327f3SZhao Liu assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
28057c327f3SZhao Liu assert_eq!(foo_fields[4].version_id, 0);
28157c327f3SZhao Liu assert_eq!(foo_fields[4].size, 8);
28257c327f3SZhao Liu assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32);
28357c327f3SZhao Liu assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
28457c327f3SZhao Liu assert!(foo_fields[4].vmsd.is_null());
28557c327f3SZhao Liu assert!(foo_fields[4].field_exists.is_none());
28657c327f3SZhao Liu
28757c327f3SZhao Liu // The last VMStateField in VMSTATE_FOOB.
28857c327f3SZhao Liu assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END);
28957c327f3SZhao Liu }
2908df1b001SZhao Liu
2918df1b001SZhao Liu // =========================== Test VMSTATE_FOOC ===========================
2928df1b001SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C
2938df1b001SZhao Liu // macro variants:
2948df1b001SZhao Liu // * VMSTATE_FOOC:
2958df1b001SZhao Liu // - VMSTATE_POINTER
2968df1b001SZhao Liu // - VMSTATE_ARRAY_OF_POINTER
2978df1b001SZhao Liu struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array is almost impossible.
2988df1b001SZhao Liu
2998df1b001SZhao Liu impl_vmstate_forward!(FooCWrapper);
3008df1b001SZhao Liu
3018df1b001SZhao Liu #[repr(C)]
3028df1b001SZhao Liu #[derive(qemu_api_macros::offsets)]
3038df1b001SZhao Liu struct FooC {
3048df1b001SZhao Liu ptr: *const i32,
3058df1b001SZhao Liu ptr_a: NonNull<FooA>,
3068df1b001SZhao Liu arr_ptr: [Box<u8>; FOO_ARRAY_MAX],
3078df1b001SZhao Liu arr_ptr_wrap: FooCWrapper,
3088df1b001SZhao Liu }
3098df1b001SZhao Liu
3108df1b001SZhao Liu static VMSTATE_FOOC: VMStateDescription = VMStateDescription {
3118df1b001SZhao Liu name: c_str!("foo_c").as_ptr(),
3128df1b001SZhao Liu version_id: 3,
3138df1b001SZhao Liu minimum_version_id: 1,
3148df1b001SZhao Liu fields: vmstate_fields! {
3158df1b001SZhao Liu vmstate_of!(FooC, ptr).with_version_id(2),
3168df1b001SZhao Liu // FIXME: Currently vmstate_struct doesn't support the pointer to structure.
3178df1b001SZhao Liu // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>)
3188df1b001SZhao Liu vmstate_unused!(size_of::<NonNull<FooA>>()),
3198df1b001SZhao Liu vmstate_of!(FooC, arr_ptr),
3208df1b001SZhao Liu vmstate_of!(FooC, arr_ptr_wrap),
3218df1b001SZhao Liu },
3228df1b001SZhao Liu ..Zeroable::ZERO
3238df1b001SZhao Liu };
3248df1b001SZhao Liu
3258df1b001SZhao Liu const PTR_SIZE: usize = size_of::<*mut ()>();
3268df1b001SZhao Liu
3278df1b001SZhao Liu #[test]
test_vmstate_pointer()3288df1b001SZhao Liu fn test_vmstate_pointer() {
3298df1b001SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
3308df1b001SZhao Liu
3318df1b001SZhao Liu // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER)
3328df1b001SZhao Liu assert_eq!(
3338df1b001SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
3348df1b001SZhao Liu b"ptr\0"
3358df1b001SZhao Liu );
3368df1b001SZhao Liu assert_eq!(foo_fields[0].offset, 0);
3378df1b001SZhao Liu assert_eq!(foo_fields[0].num_offset, 0);
3388df1b001SZhao Liu assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 });
3398df1b001SZhao Liu assert_eq!(foo_fields[0].version_id, 2);
3408df1b001SZhao Liu assert_eq!(foo_fields[0].size, 4);
3418df1b001SZhao Liu assert_eq!(foo_fields[0].num, 0);
3428df1b001SZhao Liu assert_eq!(
3438df1b001SZhao Liu foo_fields[0].flags.0,
3448df1b001SZhao Liu VMStateFlags::VMS_SINGLE.0 | VMStateFlags::VMS_POINTER.0
3458df1b001SZhao Liu );
3468df1b001SZhao Liu assert!(foo_fields[0].vmsd.is_null());
3478df1b001SZhao Liu assert!(foo_fields[0].field_exists.is_none());
3488df1b001SZhao Liu }
3498df1b001SZhao Liu
3508df1b001SZhao Liu #[test]
test_vmstate_macro_array_of_pointer()3518df1b001SZhao Liu fn test_vmstate_macro_array_of_pointer() {
3528df1b001SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
3538df1b001SZhao Liu
3548df1b001SZhao Liu // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to
3558df1b001SZhao Liu // VMSTATE_ARRAY_OF_POINTER)
3568df1b001SZhao Liu assert_eq!(
3578df1b001SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
3588df1b001SZhao Liu b"arr_ptr\0"
3598df1b001SZhao Liu );
3608df1b001SZhao Liu assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE);
3618df1b001SZhao Liu assert_eq!(foo_fields[2].num_offset, 0);
3628df1b001SZhao Liu assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
3638df1b001SZhao Liu assert_eq!(foo_fields[2].version_id, 0);
3648df1b001SZhao Liu assert_eq!(foo_fields[2].size, PTR_SIZE);
3658df1b001SZhao Liu assert_eq!(foo_fields[2].num, FOO_ARRAY_MAX as i32);
3668df1b001SZhao Liu assert_eq!(
3678df1b001SZhao Liu foo_fields[2].flags.0,
3688df1b001SZhao Liu VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
3698df1b001SZhao Liu );
3708df1b001SZhao Liu assert!(foo_fields[2].vmsd.is_null());
3718df1b001SZhao Liu assert!(foo_fields[2].field_exists.is_none());
3728df1b001SZhao Liu }
3738df1b001SZhao Liu
3748df1b001SZhao Liu #[test]
test_vmstate_macro_array_of_pointer_wrapped()3758df1b001SZhao Liu fn test_vmstate_macro_array_of_pointer_wrapped() {
3768df1b001SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
3778df1b001SZhao Liu
3788df1b001SZhao Liu // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to
3798df1b001SZhao Liu // VMSTATE_ARRAY_OF_POINTER)
3808df1b001SZhao Liu assert_eq!(
3818df1b001SZhao Liu unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
3828df1b001SZhao Liu b"arr_ptr_wrap\0"
3838df1b001SZhao Liu );
3848df1b001SZhao Liu assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE);
3858df1b001SZhao Liu assert_eq!(foo_fields[3].num_offset, 0);
3868df1b001SZhao Liu assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
3878df1b001SZhao Liu assert_eq!(foo_fields[3].version_id, 0);
3888df1b001SZhao Liu assert_eq!(foo_fields[3].size, PTR_SIZE);
3898df1b001SZhao Liu assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32);
3908df1b001SZhao Liu assert_eq!(
3918df1b001SZhao Liu foo_fields[2].flags.0,
3928df1b001SZhao Liu VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
3938df1b001SZhao Liu );
3948df1b001SZhao Liu assert!(foo_fields[3].vmsd.is_null());
3958df1b001SZhao Liu assert!(foo_fields[3].field_exists.is_none());
3968df1b001SZhao Liu
3978df1b001SZhao Liu // The last VMStateField in VMSTATE_FOOC.
3988df1b001SZhao Liu assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
3998df1b001SZhao Liu }
400*9bd7e6f7SZhao Liu
401*9bd7e6f7SZhao Liu // =========================== Test VMSTATE_FOOD ===========================
402*9bd7e6f7SZhao Liu // Test the use cases of the vmstate macro, corresponding to the following C
403*9bd7e6f7SZhao Liu // macro variants:
404*9bd7e6f7SZhao Liu // * VMSTATE_FOOD:
405*9bd7e6f7SZhao Liu // - VMSTATE_VALIDATE
406*9bd7e6f7SZhao Liu
407*9bd7e6f7SZhao Liu // Add more member fields when vmstate_of/vmstate_struct support "test"
408*9bd7e6f7SZhao Liu // parameter.
409*9bd7e6f7SZhao Liu struct FooD;
410*9bd7e6f7SZhao Liu
411*9bd7e6f7SZhao Liu impl FooD {
validate_food_0(&self, _version_id: u8) -> bool412*9bd7e6f7SZhao Liu fn validate_food_0(&self, _version_id: u8) -> bool {
413*9bd7e6f7SZhao Liu true
414*9bd7e6f7SZhao Liu }
415*9bd7e6f7SZhao Liu
validate_food_1(_state: &FooD, _version_id: u8) -> bool416*9bd7e6f7SZhao Liu fn validate_food_1(_state: &FooD, _version_id: u8) -> bool {
417*9bd7e6f7SZhao Liu false
418*9bd7e6f7SZhao Liu }
419*9bd7e6f7SZhao Liu }
420*9bd7e6f7SZhao Liu
validate_food_2(_state: &FooD, _version_id: u8) -> bool421*9bd7e6f7SZhao Liu fn validate_food_2(_state: &FooD, _version_id: u8) -> bool {
422*9bd7e6f7SZhao Liu true
423*9bd7e6f7SZhao Liu }
424*9bd7e6f7SZhao Liu
425*9bd7e6f7SZhao Liu static VMSTATE_FOOD: VMStateDescription = VMStateDescription {
426*9bd7e6f7SZhao Liu name: c_str!("foo_d").as_ptr(),
427*9bd7e6f7SZhao Liu version_id: 3,
428*9bd7e6f7SZhao Liu minimum_version_id: 1,
429*9bd7e6f7SZhao Liu fields: vmstate_fields! {
430*9bd7e6f7SZhao Liu vmstate_validate!(FooD, c_str!("foo_d_0"), FooD::validate_food_0),
431*9bd7e6f7SZhao Liu vmstate_validate!(FooD, c_str!("foo_d_1"), FooD::validate_food_1),
432*9bd7e6f7SZhao Liu vmstate_validate!(FooD, c_str!("foo_d_2"), validate_food_2),
433*9bd7e6f7SZhao Liu },
434*9bd7e6f7SZhao Liu ..Zeroable::ZERO
435*9bd7e6f7SZhao Liu };
436*9bd7e6f7SZhao Liu
437*9bd7e6f7SZhao Liu #[test]
test_vmstate_validate()438*9bd7e6f7SZhao Liu fn test_vmstate_validate() {
439*9bd7e6f7SZhao Liu let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOD.fields, 4) };
440*9bd7e6f7SZhao Liu let mut foo_d = FooD;
441*9bd7e6f7SZhao Liu let foo_d_p = std::ptr::addr_of_mut!(foo_d).cast::<c_void>();
442*9bd7e6f7SZhao Liu
443*9bd7e6f7SZhao Liu // 1st VMStateField in VMSTATE_FOOD
444*9bd7e6f7SZhao Liu assert_eq!(
445*9bd7e6f7SZhao Liu unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
446*9bd7e6f7SZhao Liu b"foo_d_0\0"
447*9bd7e6f7SZhao Liu );
448*9bd7e6f7SZhao Liu assert_eq!(foo_fields[0].offset, 0);
449*9bd7e6f7SZhao Liu assert_eq!(foo_fields[0].num_offset, 0);
450*9bd7e6f7SZhao Liu assert!(foo_fields[0].info.is_null());
451*9bd7e6f7SZhao Liu assert_eq!(foo_fields[0].version_id, 0);
452*9bd7e6f7SZhao Liu assert_eq!(foo_fields[0].size, 0);
453*9bd7e6f7SZhao Liu assert_eq!(foo_fields[0].num, 0);
454*9bd7e6f7SZhao Liu assert_eq!(
455*9bd7e6f7SZhao Liu foo_fields[0].flags.0,
456*9bd7e6f7SZhao Liu VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0
457*9bd7e6f7SZhao Liu );
458*9bd7e6f7SZhao Liu assert!(foo_fields[0].vmsd.is_null());
459*9bd7e6f7SZhao Liu assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) });
460*9bd7e6f7SZhao Liu
461*9bd7e6f7SZhao Liu // 2nd VMStateField in VMSTATE_FOOD
462*9bd7e6f7SZhao Liu assert_eq!(
463*9bd7e6f7SZhao Liu unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
464*9bd7e6f7SZhao Liu b"foo_d_1\0"
465*9bd7e6f7SZhao Liu );
466*9bd7e6f7SZhao Liu assert!(!unsafe { foo_fields[1].field_exists.unwrap()(foo_d_p, 1) });
467*9bd7e6f7SZhao Liu
468*9bd7e6f7SZhao Liu // 3rd VMStateField in VMSTATE_FOOD
469*9bd7e6f7SZhao Liu assert_eq!(
470*9bd7e6f7SZhao Liu unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
471*9bd7e6f7SZhao Liu b"foo_d_2\0"
472*9bd7e6f7SZhao Liu );
473*9bd7e6f7SZhao Liu assert!(unsafe { foo_fields[2].field_exists.unwrap()(foo_d_p, 2) });
474*9bd7e6f7SZhao Liu
475*9bd7e6f7SZhao Liu // The last VMStateField in VMSTATE_FOOD.
476*9bd7e6f7SZhao Liu assert_eq!(foo_fields[3].flags, VMStateFlags::VMS_END);
477*9bd7e6f7SZhao Liu }
478