vmstate_tests.rs 4.6 KB

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