Skip to main content

multiboot2_header/
relocatable.rs

1use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType};
2use core::fmt;
3use core::fmt::{Debug, Formatter};
4use multiboot2_common::{MaybeDynSized, Tag};
5
6/// Specifies the bootloader's preferred placement for a relocatable image.
7#[repr(u32)]
8#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub enum RelocatableHeaderTagPreference {
10    /// Let the bootloader choose the image location.
11    None = 0,
12    /// Load the image at the lowest possible address that is not below
13    /// `min_addr`.
14    Low = 1,
15    /// Load the image at the highest possible address that does not end above
16    /// `max_addr`.
17    High = 2,
18}
19
20/// This tag indicates that the image is relocatable.
21#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22#[repr(C, align(8))]
23pub struct RelocatableHeaderTag {
24    header: HeaderTagHeader,
25    /// Lowest physical address at which the image may be loaded.
26    ///
27    /// The bootloader cannot load any part of the image below this address.
28    min_addr: u32,
29    /// Highest physical address at which the loaded image may end.
30    ///
31    /// The bootloader cannot load any part of the image above this address.
32    max_addr: u32,
33    /// Image alignment in memory, e.g. 4096.
34    align: u32,
35    preference: RelocatableHeaderTagPreference,
36}
37
38impl RelocatableHeaderTag {
39    /// Constructs a new tag.
40    #[must_use]
41    pub const fn new(
42        flags: HeaderTagFlag,
43        min_addr: u32,
44        max_addr: u32,
45        align: u32,
46        preference: RelocatableHeaderTagPreference,
47    ) -> Self {
48        let header =
49            HeaderTagHeader::new(HeaderTagType::Relocatable, flags, size_of::<Self>() as u32);
50        Self {
51            header,
52            min_addr,
53            max_addr,
54            align,
55            preference,
56        }
57    }
58
59    /// Returns the [`HeaderTagType`].
60    #[must_use]
61    pub const fn typ(&self) -> HeaderTagType {
62        self.header.typ()
63    }
64
65    /// Returns the [`HeaderTagFlag`]s.
66    #[must_use]
67    pub const fn flags(&self) -> HeaderTagFlag {
68        self.header.flags()
69    }
70
71    /// Returns the size.
72    #[must_use]
73    pub const fn size(&self) -> u32 {
74        self.header.size()
75    }
76
77    /// Return the minimum address.
78    #[must_use]
79    pub const fn min_addr(&self) -> u32 {
80        self.min_addr
81    }
82
83    /// Return the maximum address.
84    #[must_use]
85    pub const fn max_addr(&self) -> u32 {
86        self.max_addr
87    }
88
89    /// Return the alignment.
90    #[must_use]
91    pub const fn align(&self) -> u32 {
92        self.align
93    }
94
95    /// Return the preference.
96    #[must_use]
97    pub const fn preference(&self) -> RelocatableHeaderTagPreference {
98        self.preference
99    }
100}
101
102impl Debug for RelocatableHeaderTag {
103    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
104        f.debug_struct("RelocatableHeaderTag")
105            .field("type", &self.typ())
106            .field("flags", &self.flags())
107            .field("size", &self.size())
108            // trick to print this as hexadecimal pointer
109            .field("min_addr", &self.min_addr)
110            .field("max_addr", &self.max_addr)
111            .field("align", &self.align)
112            .field("preference", &self.preference)
113            .finish()
114    }
115}
116
117impl MaybeDynSized for RelocatableHeaderTag {
118    type Header = HeaderTagHeader;
119
120    const BASE_SIZE: usize = size_of::<Self>();
121}
122
123impl Tag for RelocatableHeaderTag {
124    type IDType = HeaderTagType;
125    const ID: HeaderTagType = HeaderTagType::Relocatable;
126}
127
128#[cfg(test)]
129mod tests {
130    use crate::RelocatableHeaderTag;
131
132    #[test]
133    fn test_assert_size() {
134        assert_eq!(size_of::<RelocatableHeaderTag>(), 2 + 2 + 4 + 4 + 4 + 4 + 4);
135    }
136}