multiboot2_header/
relocatable.rs

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