multiboot2/
efi.rs

1//! All tags related to (U)EFI with the exception of EFI memory tags:
2//!
3//! - [`EFISdt32Tag`]
4//! - [`EFISdt64Tag`]
5//! - [`EFIImageHandle32Tag`]
6//! - [`EFIImageHandle64Tag`]
7//! - [`EFIBootServicesNotExitedTag`]
8
9use crate::TagType;
10use crate::tag::TagHeader;
11use core::mem::size_of;
12use multiboot2_common::{MaybeDynSized, Tag};
13
14/// EFI system table in 32 bit mode tag.
15#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[repr(C, align(8))]
17pub struct EFISdt32Tag {
18    header: TagHeader,
19    pointer: u32,
20}
21
22impl EFISdt32Tag {
23    const BASE_SIZE: usize = size_of::<TagHeader>() + size_of::<u32>();
24
25    /// Create a new tag to pass the EFI32 System Table pointer.
26    #[must_use]
27    pub fn new(pointer: u32) -> Self {
28        Self {
29            header: TagHeader::new(Self::ID, Self::BASE_SIZE as u32),
30            pointer,
31        }
32    }
33
34    /// The physical address of a i386 EFI system table.
35    #[must_use]
36    pub const fn sdt_address(&self) -> usize {
37        self.pointer as usize
38    }
39}
40
41impl MaybeDynSized for EFISdt32Tag {
42    type Header = TagHeader;
43
44    const BASE_SIZE: usize = size_of::<Self>();
45
46    fn dst_len(_: &TagHeader) {}
47}
48
49impl Tag for EFISdt32Tag {
50    type IDType = TagType;
51
52    const ID: TagType = TagType::Efi32;
53}
54
55/// EFI system table in 64 bit mode tag.
56#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
57#[repr(C, align(8))]
58pub struct EFISdt64Tag {
59    header: TagHeader,
60    pointer: u64,
61}
62
63impl EFISdt64Tag {
64    /// Create a new tag to pass the EFI64 System Table pointer.
65    #[must_use]
66    pub fn new(pointer: u64) -> Self {
67        Self {
68            header: TagHeader::new(Self::ID, size_of::<Self>().try_into().unwrap()),
69            pointer,
70        }
71    }
72
73    /// The physical address of a x86_64 EFI system table.
74    #[must_use]
75    pub const fn sdt_address(&self) -> usize {
76        self.pointer as usize
77    }
78}
79
80impl MaybeDynSized for EFISdt64Tag {
81    type Header = TagHeader;
82
83    const BASE_SIZE: usize = size_of::<Self>();
84
85    fn dst_len(_: &TagHeader) {}
86}
87
88impl Tag for EFISdt64Tag {
89    type IDType = TagType;
90
91    const ID: TagType = TagType::Efi64;
92}
93
94/// Tag that contains the pointer to the boot loader's UEFI image handle
95/// (32-bit).
96#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
97#[repr(C, align(8))]
98pub struct EFIImageHandle32Tag {
99    header: TagHeader,
100    pointer: u32,
101}
102
103impl EFIImageHandle32Tag {
104    const BASE_SIZE: usize = size_of::<TagHeader>() + size_of::<u32>();
105
106    /// Constructs a new tag.
107    #[must_use]
108    pub fn new(pointer: u32) -> Self {
109        Self {
110            header: TagHeader::new(Self::ID, Self::BASE_SIZE as u32),
111            pointer,
112        }
113    }
114
115    /// Returns the physical address of the EFI image handle.
116    #[must_use]
117    pub const fn image_handle(&self) -> usize {
118        self.pointer as usize
119    }
120}
121
122impl MaybeDynSized for EFIImageHandle32Tag {
123    type Header = TagHeader;
124
125    const BASE_SIZE: usize = size_of::<Self>();
126
127    fn dst_len(_: &TagHeader) {}
128}
129
130impl Tag for EFIImageHandle32Tag {
131    type IDType = TagType;
132
133    const ID: TagType = TagType::Efi32Ih;
134}
135
136/// Tag that contains the pointer to the boot loader's UEFI image handle
137/// (64-bit).
138#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
139#[repr(C, align(8))]
140pub struct EFIImageHandle64Tag {
141    header: TagHeader,
142    pointer: u64,
143}
144
145impl EFIImageHandle64Tag {
146    /// Constructs a new tag.
147    #[must_use]
148    pub fn new(pointer: u64) -> Self {
149        Self {
150            header: TagHeader::new(Self::ID, size_of::<Self>().try_into().unwrap()),
151            pointer,
152        }
153    }
154
155    /// Returns the physical address of the EFI image handle.
156    #[must_use]
157    pub const fn image_handle(&self) -> usize {
158        self.pointer as usize
159    }
160}
161
162impl MaybeDynSized for EFIImageHandle64Tag {
163    type Header = TagHeader;
164
165    const BASE_SIZE: usize = size_of::<Self>();
166
167    fn dst_len(_: &TagHeader) {}
168}
169
170impl Tag for EFIImageHandle64Tag {
171    type IDType = TagType;
172
173    const ID: TagType = TagType::Efi64Ih;
174}
175
176/// EFI ExitBootServices was not called tag. This tag has no payload and is
177/// just a marker.
178#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
179#[repr(C, align(8))]
180pub struct EFIBootServicesNotExitedTag {
181    header: TagHeader,
182}
183
184impl EFIBootServicesNotExitedTag {
185    /// Constructs a new tag.
186    #[must_use]
187    pub fn new() -> Self {
188        Self::default()
189    }
190}
191
192impl Default for EFIBootServicesNotExitedTag {
193    fn default() -> Self {
194        Self {
195            header: TagHeader::new(Self::ID, size_of::<Self>().try_into().unwrap()),
196        }
197    }
198}
199
200impl MaybeDynSized for EFIBootServicesNotExitedTag {
201    type Header = TagHeader;
202
203    const BASE_SIZE: usize = size_of::<Self>();
204
205    fn dst_len(_: &TagHeader) {}
206}
207
208impl Tag for EFIBootServicesNotExitedTag {
209    type IDType = TagType;
210
211    const ID: TagType = TagType::EfiBs;
212}
213
214#[cfg(all(test, feature = "builder"))]
215mod tests {
216    use super::{EFIImageHandle32Tag, EFIImageHandle64Tag, EFISdt32Tag, EFISdt64Tag};
217    use crate::{EFIMemoryDesc, EFIMemoryMapTag};
218    use uefi_raw::table::boot::{MemoryAttribute, MemoryType};
219
220    const ADDR: usize = 0xABCDEF;
221
222    #[test]
223    fn test_build_eftsdt32() {
224        let tag = EFISdt32Tag::new(ADDR.try_into().unwrap());
225        assert_eq!(tag.sdt_address(), ADDR);
226    }
227
228    #[test]
229    fn test_build_eftsdt64() {
230        let tag = EFISdt64Tag::new(ADDR.try_into().unwrap());
231        assert_eq!(tag.sdt_address(), ADDR);
232    }
233
234    #[test]
235    fn test_build_eftih32() {
236        let tag = EFIImageHandle32Tag::new(ADDR.try_into().unwrap());
237        assert_eq!(tag.image_handle(), ADDR);
238    }
239
240    #[test]
241    fn test_build_eftih64() {
242        let tag = EFIImageHandle64Tag::new(ADDR.try_into().unwrap());
243        assert_eq!(tag.image_handle(), ADDR);
244    }
245
246    #[test]
247    fn test_construct_efi_mmap_tag() {
248        let tag = EFIMemoryMapTag::new_from_descs(&[
249            EFIMemoryDesc {
250                ty: MemoryType::BOOT_SERVICES_CODE,
251                phys_start: 0x1000,
252                virt_start: 0x1000,
253                page_count: 1,
254                att: MemoryAttribute::WRITE_COMBINE,
255            },
256            EFIMemoryDesc {
257                ty: MemoryType::LOADER_DATA,
258                phys_start: 0x2000,
259                virt_start: 0x2000,
260                page_count: 2,
261                att: MemoryAttribute::NON_VOLATILE,
262            },
263        ]);
264        // Test for Miri
265        dbg!(tag);
266    }
267}