multiboot2_header/
relocatable.rs1use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType};
2use core::fmt;
3use core::fmt::{Debug, Formatter};
4use multiboot2_common::{MaybeDynSized, Tag};
5
6multiboot2_common::raw_type! {
7 pub struct RelocatableHeaderTagPreferenceRaw(u32);
12
13 pub enum RelocatableHeaderTagPreference {
18 None = 0,
20 Low = 1,
23 High = 2,
26 }
27}
28
29#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31#[repr(C, align(8))]
32pub struct RelocatableHeaderTag {
33 header: HeaderTagHeader,
34 min_addr: u32,
38 max_addr: u32,
42 align: u32,
44 preference: RelocatableHeaderTagPreferenceRaw,
45}
46
47const _: () = assert!(size_of::<RelocatableHeaderTag>() == 2 + 2 + 4 + 4 + 4 + 4 + 4);
48
49impl RelocatableHeaderTag {
50 #[must_use]
52 pub const fn new(
53 flags: HeaderTagFlag,
54 min_addr: u32,
55 max_addr: u32,
56 align: u32,
57 preference: RelocatableHeaderTagPreference,
58 ) -> Self {
59 let header =
60 HeaderTagHeader::new(HeaderTagType::Relocatable, flags, size_of::<Self>() as u32);
61 Self {
62 header,
63 min_addr,
64 max_addr,
65 align,
66 preference: RelocatableHeaderTagPreferenceRaw::new(preference.val()),
67 }
68 }
69
70 #[must_use]
72 pub const fn typ(&self) -> HeaderTagType {
73 self.header.typ()
74 }
75
76 #[must_use]
78 pub const fn flags(&self) -> HeaderTagFlag {
79 self.header.flags()
80 }
81
82 #[must_use]
84 pub const fn size(&self) -> u32 {
85 self.header.size()
86 }
87
88 #[must_use]
90 pub const fn min_addr(&self) -> u32 {
91 self.min_addr
92 }
93
94 #[must_use]
96 pub const fn max_addr(&self) -> u32 {
97 self.max_addr
98 }
99
100 #[must_use]
102 pub const fn align(&self) -> u32 {
103 self.align
104 }
105
106 #[must_use]
108 pub const fn preference(&self) -> RelocatableHeaderTagPreference {
109 RelocatableHeaderTagPreference::from_val(self.preference.get())
110 }
111}
112
113impl Debug for RelocatableHeaderTag {
114 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
115 f.debug_struct("RelocatableHeaderTag")
116 .field("type", &self.typ())
117 .field("flags", &self.flags())
118 .field("size", &self.size())
119 .field("min_addr", &self.min_addr)
121 .field("max_addr", &self.max_addr)
122 .field("align", &self.align)
123 .field("preference", &self.preference)
124 .finish()
125 }
126}
127
128unsafe impl MaybeDynSized for RelocatableHeaderTag {
131 type Header = HeaderTagHeader;
132
133 const BASE_SIZE: usize = size_of::<Self>();
134}
135
136impl Tag for RelocatableHeaderTag {
137 type IDType = HeaderTagType;
138 const ID: HeaderTagType = HeaderTagType::Relocatable;
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use crate::GenericHeaderTag;
145 use core::borrow::Borrow;
146 use multiboot2_common::test_utils::AlignedBytes;
147
148 #[test]
151 fn unknown_preference_is_not_ub() {
152 #[rustfmt::skip]
153 let bytes = AlignedBytes::new([
154 10, 0,
156 0, 0,
158 24, 0, 0, 0,
160 0, 0, 0, 0,
162 0, 0, 0, 0,
163 0, 0, 0, 0,
164 99, 0, 0, 0,
166 ]);
167 let tag = GenericHeaderTag::ref_from_slice(bytes.borrow())
168 .unwrap()
169 .cast::<RelocatableHeaderTag>();
170
171 assert_eq!(tag.preference(), RelocatableHeaderTagPreference::Custom(99));
172 let debug = format!("{tag:?}");
174 assert!(debug.contains("Custom(99)"));
175 }
176}