information_request.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. use crate::HeaderTagType;
  2. use crate::{HeaderTagFlag, MbiTagType};
  3. use core::fmt;
  4. use core::fmt::{Debug, Formatter};
  5. use core::marker::PhantomData;
  6. use core::mem::size_of;
  7. /// Specifies what specific tag types the bootloader should provide
  8. /// inside the mbi.
  9. #[derive(Copy, Clone)]
  10. #[repr(C)]
  11. pub struct InformationRequestHeaderTag<const N: usize> {
  12. typ: HeaderTagType,
  13. flags: HeaderTagFlag,
  14. size: u32,
  15. // Length is determined by size.
  16. // Must be parsed during runtime with unsafe pointer magic and the size field.
  17. requests: [MbiTagType; N],
  18. }
  19. impl<const N: usize> InformationRequestHeaderTag<N> {
  20. /// Creates a new object. The size parameter is the value of the size property.
  21. /// It doesn't have to match with `N` necessarily, because during compile time we
  22. /// can't know the size of the tag in all runtime situations.
  23. pub fn new(flags: HeaderTagFlag, requests: [MbiTagType; N], size: Option<u32>) -> Self {
  24. InformationRequestHeaderTag {
  25. typ: HeaderTagType::InformationRequest,
  26. flags,
  27. size: size.unwrap_or(size_of::<Self>() as u32),
  28. requests,
  29. }
  30. }
  31. pub const fn typ(&self) -> HeaderTagType {
  32. self.typ
  33. }
  34. pub const fn flags(&self) -> HeaderTagFlag {
  35. self.flags
  36. }
  37. pub const fn size(&self) -> u32 {
  38. self.size
  39. }
  40. /// Returns the requests as array. Only works if the number of requests
  41. /// is known at compile time. For safety and correctness during runtime,
  42. /// you should use `req_iter()`.
  43. pub const fn requests(&self) -> [MbiTagType; N] {
  44. // cheap to copy, otherwise difficult with lifetime
  45. self.requests
  46. }
  47. /// Returns the number of [`MbiTagType`]-requests derived
  48. /// from the `size`-property. This method is useful
  49. /// because this struct uses a const generic, but during runtime
  50. /// we don't know the value in almost any case.
  51. pub const fn dynamic_requests_size(&self) -> u32 {
  52. let base_struct_size = size_of::<InformationRequestHeaderTag<0>>();
  53. let size_diff = self.size - base_struct_size as u32;
  54. if size_diff > 0 {
  55. size_diff / size_of::<u32>() as u32
  56. } else {
  57. 0
  58. }
  59. }
  60. /// Returns an [`InformationRequestHeaderTagIter`].
  61. pub fn req_iter(&self) -> InformationRequestHeaderTagIter {
  62. let base_struct_size = size_of::<InformationRequestHeaderTag<0>>();
  63. let count = self.dynamic_requests_size();
  64. let base_ptr = self as *const InformationRequestHeaderTag<N>;
  65. let base_ptr = base_ptr as *const u8;
  66. let base_ptr = unsafe { base_ptr.add(base_struct_size) };
  67. let base_ptr = base_ptr as *const MbiTagType;
  68. InformationRequestHeaderTagIter::new(count, base_ptr)
  69. }
  70. }
  71. impl<const N: usize> Debug for InformationRequestHeaderTag<N> {
  72. fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
  73. f.debug_struct("InformationRequestHeaderTag")
  74. .field("type", &{ self.typ })
  75. .field("flags", &{ self.flags })
  76. .field("size", &{ self.size })
  77. .field("requests", &{ self.req_iter() })
  78. .finish()
  79. }
  80. }
  81. /// Iterates the dynamically sized information request structure and finds all MBI tags
  82. /// that are requested.
  83. #[derive(Copy, Clone)]
  84. pub struct InformationRequestHeaderTagIter<'a> {
  85. base_ptr: *const MbiTagType,
  86. i: u32,
  87. count: u32,
  88. _marker: PhantomData<&'a ()>,
  89. }
  90. impl<'a> InformationRequestHeaderTagIter<'a> {
  91. fn new(count: u32, base_ptr: *const MbiTagType) -> Self {
  92. Self {
  93. i: 0,
  94. count,
  95. base_ptr,
  96. _marker: PhantomData::default(),
  97. }
  98. }
  99. }
  100. impl<'a> Iterator for InformationRequestHeaderTagIter<'a> {
  101. type Item = &'a MbiTagType;
  102. fn next(&mut self) -> Option<Self::Item> {
  103. if self.i < self.count {
  104. let ptr = unsafe { self.base_ptr.offset(self.i as isize) };
  105. self.i += 1;
  106. Some(unsafe { &*ptr })
  107. } else {
  108. None
  109. }
  110. }
  111. }
  112. impl<'a> Debug for InformationRequestHeaderTagIter<'a> {
  113. fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
  114. let mut debug = f.debug_list();
  115. (*self).for_each(|e| {
  116. debug.entry(e);
  117. });
  118. debug.finish()
  119. }
  120. }
  121. #[cfg(test)]
  122. mod tests {
  123. use crate::InformationRequestHeaderTag;
  124. #[test]
  125. #[allow(clippy::erasing_op)]
  126. #[allow(clippy::identity_op)]
  127. fn test_assert_size() {
  128. assert_eq!(
  129. core::mem::size_of::<InformationRequestHeaderTag<0>>(),
  130. 2 + 2 + 4 + 0 * 4
  131. );
  132. assert_eq!(
  133. core::mem::size_of::<InformationRequestHeaderTag<1>>(),
  134. 2 + 2 + 4 + 1 * 4
  135. );
  136. assert_eq!(
  137. core::mem::size_of::<InformationRequestHeaderTag<2>>(),
  138. 2 + 2 + 4 + 2 * 4
  139. );
  140. }
  141. }