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, os::raw::c_void, ptr::NonNull, slice}; 6 7 use qemu_api::{ 8 bindings::{ 9 vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8, 10 vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags, 11 }, 12 c_str, 13 cell::{BqlCell, Opaque}, 14 impl_vmstate_forward, 15 vmstate::{VMStateDescription, VMStateField}, 16 vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate, 17 zeroable::Zeroable, 18 }; 19 20 const FOO_ARRAY_MAX: usize = 3; 21 22 // =========================== Test VMSTATE_FOOA =========================== 23 // Test the use cases of the vmstate macro, corresponding to the following C 24 // macro variants: 25 // * VMSTATE_FOOA: 26 // - VMSTATE_U16 27 // - VMSTATE_UNUSED 28 // - VMSTATE_VARRAY_UINT16_UNSAFE 29 // - VMSTATE_VARRAY_MULTIPLY 30 #[repr(C)] 31 #[derive(qemu_api_macros::offsets)] 32 struct FooA { 33 arr: [u8; FOO_ARRAY_MAX], 34 num: u16, 35 arr_mul: [i8; FOO_ARRAY_MAX], 36 num_mul: u32, 37 elem: i8, 38 } 39 40 static VMSTATE_FOOA: VMStateDescription = VMStateDescription { 41 name: c_str!("foo_a").as_ptr(), 42 version_id: 1, 43 minimum_version_id: 1, 44 fields: vmstate_fields! { 45 vmstate_of!(FooA, elem), 46 vmstate_unused!(size_of::<i64>()), 47 vmstate_of!(FooA, arr[0 .. num]).with_version_id(0), 48 vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]), 49 }, 50 ..Zeroable::ZERO 51 }; 52 53 #[test] 54 fn test_vmstate_uint16() { 55 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 56 57 // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16) 58 assert_eq!( 59 unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 60 b"elem\0" 61 ); 62 assert_eq!(foo_fields[0].offset, 16); 63 assert_eq!(foo_fields[0].num_offset, 0); 64 assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 }); 65 assert_eq!(foo_fields[0].version_id, 0); 66 assert_eq!(foo_fields[0].size, 1); 67 assert_eq!(foo_fields[0].num, 0); 68 assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE); 69 assert!(foo_fields[0].vmsd.is_null()); 70 assert!(foo_fields[0].field_exists.is_none()); 71 } 72 73 #[test] 74 fn test_vmstate_unused() { 75 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 76 77 // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED) 78 assert_eq!( 79 unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), 80 b"unused\0" 81 ); 82 assert_eq!(foo_fields[1].offset, 0); 83 assert_eq!(foo_fields[1].num_offset, 0); 84 assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer }); 85 assert_eq!(foo_fields[1].version_id, 0); 86 assert_eq!(foo_fields[1].size, 8); 87 assert_eq!(foo_fields[1].num, 0); 88 assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER); 89 assert!(foo_fields[1].vmsd.is_null()); 90 assert!(foo_fields[1].field_exists.is_none()); 91 } 92 93 #[test] 94 fn test_vmstate_varray_uint16_unsafe() { 95 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 96 97 // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to 98 // VMSTATE_VARRAY_UINT16_UNSAFE) 99 assert_eq!( 100 unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 101 b"arr\0" 102 ); 103 assert_eq!(foo_fields[2].offset, 0); 104 assert_eq!(foo_fields[2].num_offset, 4); 105 assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 }); 106 assert_eq!(foo_fields[2].version_id, 0); 107 assert_eq!(foo_fields[2].size, 1); 108 assert_eq!(foo_fields[2].num, 0); 109 assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16); 110 assert!(foo_fields[2].vmsd.is_null()); 111 assert!(foo_fields[2].field_exists.is_none()); 112 } 113 114 #[test] 115 fn test_vmstate_varray_multiply() { 116 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) }; 117 118 // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to 119 // VMSTATE_VARRAY_MULTIPLY) 120 assert_eq!( 121 unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), 122 b"arr_mul\0" 123 ); 124 assert_eq!(foo_fields[3].offset, 6); 125 assert_eq!(foo_fields[3].num_offset, 12); 126 assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 }); 127 assert_eq!(foo_fields[3].version_id, 0); 128 assert_eq!(foo_fields[3].size, 1); 129 assert_eq!(foo_fields[3].num, 16); 130 assert_eq!( 131 foo_fields[3].flags.0, 132 VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 133 ); 134 assert!(foo_fields[3].vmsd.is_null()); 135 assert!(foo_fields[3].field_exists.is_none()); 136 137 // The last VMStateField in VMSTATE_FOOA. 138 assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END); 139 } 140 141 // =========================== Test VMSTATE_FOOB =========================== 142 // Test the use cases of the vmstate macro, corresponding to the following C 143 // macro variants: 144 // * VMSTATE_FOOB: 145 // - VMSTATE_BOOL_V 146 // - VMSTATE_U64 147 // - VMSTATE_STRUCT_VARRAY_UINT8 148 // - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32 149 // - VMSTATE_ARRAY 150 #[repr(C)] 151 #[derive(qemu_api_macros::offsets)] 152 struct FooB { 153 arr_a: [FooA; FOO_ARRAY_MAX], 154 num_a: u8, 155 arr_a_mul: [FooA; FOO_ARRAY_MAX], 156 num_a_mul: u32, 157 wrap: BqlCell<u64>, 158 val: bool, 159 // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test. 160 arr_i64: [i64; FOO_ARRAY_MAX], 161 } 162 163 static VMSTATE_FOOB: VMStateDescription = VMStateDescription { 164 name: c_str!("foo_b").as_ptr(), 165 version_id: 2, 166 minimum_version_id: 1, 167 fields: vmstate_fields! { 168 vmstate_of!(FooB, val).with_version_id(2), 169 vmstate_of!(FooB, wrap), 170 vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1), 171 vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2), 172 vmstate_of!(FooB, arr_i64), 173 }, 174 ..Zeroable::ZERO 175 }; 176 177 #[test] 178 fn test_vmstate_bool_v() { 179 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; 180 181 // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V) 182 assert_eq!( 183 unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 184 b"val\0" 185 ); 186 assert_eq!(foo_fields[0].offset, 136); 187 assert_eq!(foo_fields[0].num_offset, 0); 188 assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool }); 189 assert_eq!(foo_fields[0].version_id, 2); 190 assert_eq!(foo_fields[0].size, 1); 191 assert_eq!(foo_fields[0].num, 0); 192 assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE); 193 assert!(foo_fields[0].vmsd.is_null()); 194 assert!(foo_fields[0].field_exists.is_none()); 195 } 196 197 #[test] 198 fn test_vmstate_uint64() { 199 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; 200 201 // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64) 202 assert_eq!( 203 unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), 204 b"wrap\0" 205 ); 206 assert_eq!(foo_fields[1].offset, 128); 207 assert_eq!(foo_fields[1].num_offset, 0); 208 assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 }); 209 assert_eq!(foo_fields[1].version_id, 0); 210 assert_eq!(foo_fields[1].size, 8); 211 assert_eq!(foo_fields[1].num, 0); 212 assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE); 213 assert!(foo_fields[1].vmsd.is_null()); 214 assert!(foo_fields[1].field_exists.is_none()); 215 } 216 217 #[test] 218 fn test_vmstate_struct_varray_uint8() { 219 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; 220 221 // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to 222 // VMSTATE_STRUCT_VARRAY_UINT8) 223 assert_eq!( 224 unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 225 b"arr_a\0" 226 ); 227 assert_eq!(foo_fields[2].offset, 0); 228 assert_eq!(foo_fields[2].num_offset, 60); 229 assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field. 230 assert_eq!(foo_fields[2].version_id, 1); 231 assert_eq!(foo_fields[2].size, 20); 232 assert_eq!(foo_fields[2].num, 0); 233 assert_eq!( 234 foo_fields[2].flags.0, 235 VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0 236 ); 237 assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA); 238 assert!(foo_fields[2].field_exists.is_none()); 239 } 240 241 #[test] 242 fn test_vmstate_struct_varray_uint32_multiply() { 243 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; 244 245 // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to 246 // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32) 247 assert_eq!( 248 unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), 249 b"arr_a_mul\0" 250 ); 251 assert_eq!(foo_fields[3].offset, 64); 252 assert_eq!(foo_fields[3].num_offset, 124); 253 assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field. 254 assert_eq!(foo_fields[3].version_id, 2); 255 assert_eq!(foo_fields[3].size, 20); 256 assert_eq!(foo_fields[3].num, 32); 257 assert_eq!( 258 foo_fields[3].flags.0, 259 VMStateFlags::VMS_STRUCT.0 260 | VMStateFlags::VMS_VARRAY_UINT32.0 261 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 262 ); 263 assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA); 264 assert!(foo_fields[3].field_exists.is_none()); 265 } 266 267 #[test] 268 fn test_vmstate_macro_array() { 269 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; 270 271 // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to 272 // VMSTATE_ARRAY) 273 assert_eq!( 274 unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(), 275 b"arr_i64\0" 276 ); 277 assert_eq!(foo_fields[4].offset, 144); 278 assert_eq!(foo_fields[4].num_offset, 0); 279 assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 }); 280 assert_eq!(foo_fields[4].version_id, 0); 281 assert_eq!(foo_fields[4].size, 8); 282 assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32); 283 assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY); 284 assert!(foo_fields[4].vmsd.is_null()); 285 assert!(foo_fields[4].field_exists.is_none()); 286 287 // The last VMStateField in VMSTATE_FOOB. 288 assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END); 289 } 290 291 // =========================== Test VMSTATE_FOOC =========================== 292 // Test the use cases of the vmstate macro, corresponding to the following C 293 // macro variants: 294 // * VMSTATE_FOOC: 295 // - VMSTATE_POINTER 296 // - VMSTATE_ARRAY_OF_POINTER 297 struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array is almost impossible. 298 299 impl_vmstate_forward!(FooCWrapper); 300 301 #[repr(C)] 302 #[derive(qemu_api_macros::offsets)] 303 struct FooC { 304 ptr: *const i32, 305 ptr_a: NonNull<FooA>, 306 arr_ptr: [Box<u8>; FOO_ARRAY_MAX], 307 arr_ptr_wrap: FooCWrapper, 308 } 309 310 static VMSTATE_FOOC: VMStateDescription = VMStateDescription { 311 name: c_str!("foo_c").as_ptr(), 312 version_id: 3, 313 minimum_version_id: 1, 314 fields: vmstate_fields! { 315 vmstate_of!(FooC, ptr).with_version_id(2), 316 // FIXME: Currently vmstate_struct doesn't support the pointer to structure. 317 // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>) 318 vmstate_unused!(size_of::<NonNull<FooA>>()), 319 vmstate_of!(FooC, arr_ptr), 320 vmstate_of!(FooC, arr_ptr_wrap), 321 }, 322 ..Zeroable::ZERO 323 }; 324 325 const PTR_SIZE: usize = size_of::<*mut ()>(); 326 327 #[test] 328 fn test_vmstate_pointer() { 329 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; 330 331 // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER) 332 assert_eq!( 333 unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 334 b"ptr\0" 335 ); 336 assert_eq!(foo_fields[0].offset, 0); 337 assert_eq!(foo_fields[0].num_offset, 0); 338 assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 }); 339 assert_eq!(foo_fields[0].version_id, 2); 340 assert_eq!(foo_fields[0].size, 4); 341 assert_eq!(foo_fields[0].num, 0); 342 assert_eq!( 343 foo_fields[0].flags.0, 344 VMStateFlags::VMS_SINGLE.0 | VMStateFlags::VMS_POINTER.0 345 ); 346 assert!(foo_fields[0].vmsd.is_null()); 347 assert!(foo_fields[0].field_exists.is_none()); 348 } 349 350 #[test] 351 fn test_vmstate_macro_array_of_pointer() { 352 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; 353 354 // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to 355 // VMSTATE_ARRAY_OF_POINTER) 356 assert_eq!( 357 unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 358 b"arr_ptr\0" 359 ); 360 assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE); 361 assert_eq!(foo_fields[2].num_offset, 0); 362 assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 }); 363 assert_eq!(foo_fields[2].version_id, 0); 364 assert_eq!(foo_fields[2].size, PTR_SIZE); 365 assert_eq!(foo_fields[2].num, FOO_ARRAY_MAX as i32); 366 assert_eq!( 367 foo_fields[2].flags.0, 368 VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0 369 ); 370 assert!(foo_fields[2].vmsd.is_null()); 371 assert!(foo_fields[2].field_exists.is_none()); 372 } 373 374 #[test] 375 fn test_vmstate_macro_array_of_pointer_wrapped() { 376 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) }; 377 378 // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to 379 // VMSTATE_ARRAY_OF_POINTER) 380 assert_eq!( 381 unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), 382 b"arr_ptr_wrap\0" 383 ); 384 assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE); 385 assert_eq!(foo_fields[3].num_offset, 0); 386 assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_uint8 }); 387 assert_eq!(foo_fields[3].version_id, 0); 388 assert_eq!(foo_fields[3].size, PTR_SIZE); 389 assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32); 390 assert_eq!( 391 foo_fields[3].flags.0, 392 VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0 393 ); 394 assert!(foo_fields[3].vmsd.is_null()); 395 assert!(foo_fields[3].field_exists.is_none()); 396 397 // The last VMStateField in VMSTATE_FOOC. 398 assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END); 399 } 400 401 // =========================== Test VMSTATE_FOOD =========================== 402 // Test the use cases of the vmstate macro, corresponding to the following C 403 // macro variants: 404 // * VMSTATE_FOOD: 405 // - VMSTATE_VALIDATE 406 407 // Add more member fields when vmstate_of/vmstate_struct support "test" 408 // parameter. 409 struct FooD; 410 411 impl FooD { 412 fn validate_food_0(&self, _version_id: u8) -> bool { 413 true 414 } 415 416 fn validate_food_1(_state: &FooD, _version_id: u8) -> bool { 417 false 418 } 419 } 420 421 fn validate_food_2(_state: &FooD, _version_id: u8) -> bool { 422 true 423 } 424 425 static VMSTATE_FOOD: VMStateDescription = VMStateDescription { 426 name: c_str!("foo_d").as_ptr(), 427 version_id: 3, 428 minimum_version_id: 1, 429 fields: vmstate_fields! { 430 vmstate_validate!(FooD, c_str!("foo_d_0"), FooD::validate_food_0), 431 vmstate_validate!(FooD, c_str!("foo_d_1"), FooD::validate_food_1), 432 vmstate_validate!(FooD, c_str!("foo_d_2"), validate_food_2), 433 }, 434 ..Zeroable::ZERO 435 }; 436 437 #[test] 438 fn test_vmstate_validate() { 439 let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOD.fields, 4) }; 440 let mut foo_d = FooD; 441 let foo_d_p = std::ptr::addr_of_mut!(foo_d).cast::<c_void>(); 442 443 // 1st VMStateField in VMSTATE_FOOD 444 assert_eq!( 445 unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(), 446 b"foo_d_0\0" 447 ); 448 assert_eq!(foo_fields[0].offset, 0); 449 assert_eq!(foo_fields[0].num_offset, 0); 450 assert!(foo_fields[0].info.is_null()); 451 assert_eq!(foo_fields[0].version_id, 0); 452 assert_eq!(foo_fields[0].size, 0); 453 assert_eq!(foo_fields[0].num, 0); 454 assert_eq!( 455 foo_fields[0].flags.0, 456 VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0 457 ); 458 assert!(foo_fields[0].vmsd.is_null()); 459 assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) }); 460 461 // 2nd VMStateField in VMSTATE_FOOD 462 assert_eq!( 463 unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), 464 b"foo_d_1\0" 465 ); 466 assert!(!unsafe { foo_fields[1].field_exists.unwrap()(foo_d_p, 1) }); 467 468 // 3rd VMStateField in VMSTATE_FOOD 469 assert_eq!( 470 unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(), 471 b"foo_d_2\0" 472 ); 473 assert!(unsafe { foo_fields[2].field_exists.unwrap()(foo_d_p, 2) }); 474 475 // The last VMStateField in VMSTATE_FOOD. 476 assert_eq!(foo_fields[3].flags, VMStateFlags::VMS_END); 477 } 478