lib.rs 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747
  1. #![no_std]
  2. #![cfg_attr(feature = "unstable", feature(error_in_core))]
  3. #![deny(missing_debug_implementations)]
  4. // --- BEGIN STYLE CHECKS ---
  5. // These checks are optional in CI for PRs, as discussed in
  6. // https://github.com/rust-osdev/multiboot2/pull/92
  7. #![deny(clippy::all)]
  8. #![deny(rustdoc::all)]
  9. #![allow(rustdoc::private_doc_tests)]
  10. // --- END STYLE CHECKS ---
  11. //! Library that helps you to parse the multiboot information structure (mbi) from
  12. //! Multiboot2-compliant bootloaders, like GRUB. It supports all tags from the specification
  13. //! including full support for the sections of ELF-64. This library is `no_std` and can be
  14. //! used in a Multiboot2-kernel.
  15. //!
  16. //! The GNU Multiboot(2) specification aims to provide a standardised
  17. //! method of sharing commonly used information about the host machine at
  18. //! boot time and give the payload, i.e. a kernel, a well defined machine
  19. //! state.
  20. //!
  21. //! ## Example
  22. //!
  23. //! ```rust
  24. //! use multiboot2::load;
  25. //! fn kmain(multiboot_info_ptr: u32) {
  26. //! let boot_info = unsafe { load(multiboot_info_ptr as usize).unwrap() };
  27. //! println!("{:?}", boot_info);
  28. //! }
  29. //! ```
  30. //!
  31. //! ## MSRV
  32. //! The MSRV is 1.56.1 stable.
  33. #[cfg(feature = "builder")]
  34. extern crate alloc;
  35. // this crate can use std in tests only
  36. #[cfg_attr(test, macro_use)]
  37. #[cfg(test)]
  38. extern crate std;
  39. use core::fmt;
  40. use derive_more::Display;
  41. // Must be public so that custom tags can be DSTs.
  42. pub use ptr_meta::Pointee;
  43. use crate::framebuffer::UnknownFramebufferType;
  44. pub use boot_loader_name::BootLoaderNameTag;
  45. #[cfg(feature = "builder")]
  46. use builder::traits::StructAsBytes;
  47. pub use command_line::CommandLineTag;
  48. pub use efi::{EFIImageHandle32, EFIImageHandle64, EFISdt32, EFISdt64};
  49. pub use elf_sections::{
  50. ElfSection, ElfSectionFlags, ElfSectionIter, ElfSectionType, ElfSectionsTag,
  51. };
  52. pub use framebuffer::{FramebufferColor, FramebufferField, FramebufferTag, FramebufferType};
  53. pub use image_load_addr::ImageLoadPhysAddr;
  54. pub use memory_map::{
  55. BasicMemoryInfoTag, EFIBootServicesNotExited, EFIMemoryAreaType, EFIMemoryDesc,
  56. EFIMemoryMapTag, MemoryArea, MemoryAreaIter, MemoryAreaType, MemoryMapTag,
  57. };
  58. pub use module::{ModuleIter, ModuleTag};
  59. pub use rsdp::{RsdpV1Tag, RsdpV2Tag};
  60. pub use smbios::SmbiosTag;
  61. use tag_type::TagIter;
  62. pub use tag_type::{EndTag, Tag, TagType, TagTypeId};
  63. pub use vbe_info::{
  64. VBECapabilities, VBEControlInfo, VBEDirectColorAttributes, VBEField, VBEInfoTag,
  65. VBEMemoryModel, VBEModeAttributes, VBEModeInfo, VBEWindowAttributes,
  66. };
  67. #[macro_use]
  68. extern crate bitflags;
  69. mod boot_loader_name;
  70. mod command_line;
  71. mod efi;
  72. mod elf_sections;
  73. mod framebuffer;
  74. mod image_load_addr;
  75. mod memory_map;
  76. mod module;
  77. mod rsdp;
  78. mod smbios;
  79. mod tag_type;
  80. mod vbe_info;
  81. #[cfg(feature = "builder")]
  82. pub mod builder;
  83. /// Magic number that a multiboot2-compliant boot loader will store in `eax` register
  84. /// right before handoff to the payload (the kernel). This value can be used to check,
  85. /// that the kernel was indeed booted via multiboot2.
  86. ///
  87. /// Caution: You might need some assembly code (e.g. GAS or NASM) first, which
  88. /// moves `eax` to another register, like `edi`. Otherwise it probably happens,
  89. /// that the Rust compiler output changes `eax` before you can access it.
  90. pub const MULTIBOOT2_BOOTLOADER_MAGIC: u32 = 0x36d76289;
  91. /// Load the multiboot boot information struct from an address.
  92. ///
  93. /// This is the same as [`load_with_offset`] but the offset is omitted and set
  94. /// to zero.
  95. ///
  96. /// ## Example
  97. ///
  98. /// ```rust
  99. /// use multiboot2::load;
  100. ///
  101. /// fn kmain(multiboot_info_ptr: u32) {
  102. /// let boot_info = unsafe { load(multiboot_info_ptr as usize).unwrap() };
  103. /// println!("{:?}", boot_info);
  104. /// }
  105. /// ```
  106. ///
  107. /// ## Safety
  108. /// * `address` must be valid for reading. Otherwise this function might
  109. /// terminate the program. This can be the case in environments with standard
  110. /// environment (segfault) but also in UEFI-applications, where the referenced
  111. /// memory is not (identity) mapped (UEFI does only identity mapping).
  112. /// * The memory at `address` must not be modified after calling `load` or the
  113. /// program may observe unsynchronized mutation.
  114. pub unsafe fn load(address: usize) -> Result<BootInformation, MbiLoadError> {
  115. load_with_offset(address, 0)
  116. }
  117. /// Load the multiboot boot information struct from an address at an offset.
  118. ///
  119. /// ## Example
  120. ///
  121. /// ```rust,no_run
  122. /// use multiboot2::load_with_offset;
  123. ///
  124. /// let ptr = 0xDEADBEEF as *const u32;
  125. /// let boot_info = unsafe { load_with_offset(ptr as usize, 0xCAFEBABE).unwrap() };
  126. /// println!("{:?}", boot_info);
  127. /// ```
  128. ///
  129. /// ## Safety
  130. /// * `address` must be valid for reading. Otherwise this function might
  131. /// terminate the program. This can be the case in environments with standard
  132. /// environment (segfault) but also in UEFI-applications, where the referenced
  133. /// memory is not (identity) mapped (UEFI does only identity mapping).
  134. /// * The memory at `address` must not be modified after calling `load` or the
  135. /// program may observe unsynchronized mutation.
  136. pub unsafe fn load_with_offset(
  137. address: usize,
  138. offset: usize,
  139. ) -> Result<BootInformation, MbiLoadError> {
  140. let address = address + offset;
  141. let null_ptr = address == 0;
  142. let eight_byte_aligned = address & 0b111 == 0;
  143. if null_ptr || !eight_byte_aligned {
  144. return Err(MbiLoadError::IllegalAddress);
  145. }
  146. let multiboot = &*(address as *const BootInformationInner);
  147. // Check if total size is a multiple of 8.
  148. // See MbiLoadError::IllegalTotalSize for comments
  149. if multiboot.total_size & 0b111 != 0 {
  150. return Err(MbiLoadError::IllegalTotalSize(multiboot.total_size));
  151. }
  152. if !multiboot.has_valid_end_tag() {
  153. return Err(MbiLoadError::NoEndTag);
  154. }
  155. Ok(BootInformation {
  156. inner: multiboot,
  157. offset,
  158. })
  159. }
  160. /// Error type that describes errors while loading/parsing a multiboot2 information structure
  161. /// from a given address.
  162. #[derive(Debug, Display)]
  163. pub enum MbiLoadError {
  164. /// The address is invalid. Make sure that the address is 8-byte aligned,
  165. /// according to the spec.
  166. #[display(fmt = "The address is invalid")]
  167. IllegalAddress,
  168. /// The total size of the multiboot2 information structure must be a multiple of 8.
  169. /// (Not in spec, but it is implicitly the case, because the begin of MBI
  170. /// and all tags are 8-byte aligned and the end tag is exactly 8 byte long).
  171. #[display(fmt = "The size of the MBI is unexpected")]
  172. IllegalTotalSize(u32),
  173. /// End tag missing. Each multiboot2 header requires to have an end tag.
  174. #[display(fmt = "There is no end tag")]
  175. NoEndTag,
  176. }
  177. #[cfg(feature = "unstable")]
  178. impl core::error::Error for MbiLoadError {}
  179. /// A Multiboot 2 Boot Information struct.
  180. pub struct BootInformation {
  181. inner: *const BootInformationInner,
  182. offset: usize,
  183. }
  184. #[derive(Clone, Copy)]
  185. #[repr(C)]
  186. struct BootInformationInner {
  187. total_size: u32,
  188. _reserved: u32,
  189. }
  190. impl BootInformationInner {
  191. #[cfg(feature = "builder")]
  192. fn new(total_size: u32) -> Self {
  193. Self {
  194. total_size,
  195. _reserved: 0,
  196. }
  197. }
  198. }
  199. #[cfg(feature = "builder")]
  200. impl StructAsBytes for BootInformationInner {
  201. fn byte_size(&self) -> usize {
  202. core::mem::size_of::<Self>()
  203. }
  204. }
  205. impl BootInformation {
  206. /// Get the start address of the boot info.
  207. pub fn start_address(&self) -> usize {
  208. self.inner as usize
  209. }
  210. /// Get the end address of the boot info.
  211. ///
  212. /// This is the same as doing:
  213. ///
  214. /// ```rust,no_run
  215. /// # let boot_info = unsafe { multiboot2::load(0xdeadbeef).unwrap() };
  216. /// let end_addr = boot_info.start_address() + boot_info.total_size();
  217. /// ```
  218. pub fn end_address(&self) -> usize {
  219. self.start_address() + self.total_size()
  220. }
  221. /// Get the total size of the boot info struct.
  222. pub fn total_size(&self) -> usize {
  223. self.get().total_size as usize
  224. }
  225. /// Search for the basic memory info tag.
  226. pub fn basic_memory_info_tag(&self) -> Option<&BasicMemoryInfoTag> {
  227. self.get_tag::<BasicMemoryInfoTag, _>(TagType::BasicMeminfo)
  228. }
  229. /// Search for the ELF Sections.
  230. ///
  231. /// # Examples
  232. ///
  233. /// ```rust,no_run
  234. /// # let boot_info = unsafe { multiboot2::load(0xdeadbeef).unwrap() };
  235. /// if let Some(sections) = boot_info.elf_sections() {
  236. /// let mut total = 0;
  237. /// for section in sections {
  238. /// println!("Section: {:?}", section);
  239. /// total += 1;
  240. /// }
  241. /// }
  242. /// ```
  243. pub fn elf_sections(&self) -> Option<ElfSectionIter> {
  244. let tag = self.get_tag::<ElfSectionsTag, _>(TagType::ElfSections);
  245. tag.map(|t| {
  246. assert!((t.entry_size * t.shndx) <= t.size);
  247. t.sections(self.offset)
  248. })
  249. }
  250. /// Search for the Memory map tag.
  251. pub fn memory_map_tag(&self) -> Option<&MemoryMapTag> {
  252. self.get_tag::<MemoryMapTag, _>(TagType::Mmap)
  253. }
  254. /// Get an iterator of all module tags.
  255. pub fn module_tags(&self) -> ModuleIter {
  256. module::module_iter(self.tags())
  257. }
  258. /// Search for the BootLoader name tag.
  259. pub fn boot_loader_name_tag(&self) -> Option<&BootLoaderNameTag> {
  260. self.get_tag::<BootLoaderNameTag, _>(TagType::BootLoaderName)
  261. }
  262. /// Search for the Command line tag.
  263. pub fn command_line_tag(&self) -> Option<&CommandLineTag> {
  264. self.get_tag::<CommandLineTag, _>(TagType::Cmdline)
  265. }
  266. /// Search for the VBE framebuffer tag. The result is `Some(Err(e))`, if the
  267. /// framebuffer type is unknown, while the framebuffer tag is present.
  268. pub fn framebuffer_tag(&self) -> Option<Result<&FramebufferTag, UnknownFramebufferType>> {
  269. self.get_tag::<FramebufferTag, _>(TagType::Framebuffer)
  270. .map(|tag| match tag.buffer_type() {
  271. Ok(_) => Ok(tag),
  272. Err(e) => Err(e),
  273. })
  274. }
  275. /// Search for the EFI 32-bit SDT tag.
  276. pub fn efi_sdt_32_tag(&self) -> Option<&EFISdt32> {
  277. self.get_tag::<EFISdt32, _>(TagType::Efi32)
  278. }
  279. /// Search for the EFI 64-bit SDT tag.
  280. pub fn efi_sdt_64_tag(&self) -> Option<&EFISdt64> {
  281. self.get_tag::<EFISdt64, _>(TagType::Efi64)
  282. }
  283. /// Search for the (ACPI 1.0) RSDP tag.
  284. pub fn rsdp_v1_tag(&self) -> Option<&RsdpV1Tag> {
  285. self.get_tag::<RsdpV1Tag, _>(TagType::AcpiV1)
  286. }
  287. /// Search for the (ACPI 2.0 or later) RSDP tag.
  288. pub fn rsdp_v2_tag(&self) -> Option<&RsdpV2Tag> {
  289. self.get_tag::<RsdpV2Tag, _>(TagType::AcpiV2)
  290. }
  291. /// Search for the EFI Memory map tag, if the boot services were exited.
  292. /// Otherwise, if the [`TagType::EfiBs`] tag is present, this returns `None`
  293. /// as it is strictly recommended to get the memory map from the `uefi`
  294. /// services.
  295. pub fn efi_memory_map_tag(&self) -> Option<&EFIMemoryMapTag> {
  296. // If the EFIBootServicesNotExited is present, then we should not use
  297. // the memory map, as it could still be in use.
  298. match self.get_tag::<Tag, _>(TagType::EfiBs) {
  299. Some(_tag) => None,
  300. None => self.get_tag::<EFIMemoryMapTag, _>(TagType::EfiMmap),
  301. }
  302. }
  303. /// Search for the EFI 32-bit image handle pointer.
  304. pub fn efi_32_ih(&self) -> Option<&EFIImageHandle32> {
  305. self.get_tag::<EFIImageHandle32, _>(TagType::Efi32Ih)
  306. }
  307. /// Search for the EFI 64-bit image handle pointer.
  308. pub fn efi_64_ih(&self) -> Option<&EFIImageHandle64> {
  309. self.get_tag::<EFIImageHandle64, _>(TagType::Efi64Ih)
  310. }
  311. /// Search for the Image Load Base Physical Address.
  312. pub fn load_base_addr(&self) -> Option<&ImageLoadPhysAddr> {
  313. self.get_tag::<ImageLoadPhysAddr, _>(TagType::LoadBaseAddr)
  314. }
  315. /// Search for the VBE information tag.
  316. pub fn vbe_info_tag(&self) -> Option<&VBEInfoTag> {
  317. self.get_tag::<VBEInfoTag, _>(TagType::Vbe)
  318. }
  319. /// Search for the SMBIOS tag.
  320. pub fn smbios_tag(&self) -> Option<&SmbiosTag> {
  321. self.get_tag::<SmbiosTag, _>(TagType::Smbios)
  322. }
  323. fn get(&self) -> &BootInformationInner {
  324. unsafe { &*self.inner }
  325. }
  326. /// Public getter to find any Multiboot tag by its type, including
  327. /// specified and custom ones.
  328. ///
  329. /// The parameter can be of type `u32`, [`TagType`], or [`TagTypeId`].
  330. ///
  331. /// # Specified or Custom Tags
  332. /// The Multiboot2 specification specifies a list of tags, see [`TagType`].
  333. /// However, it doesn't forbid to use custom tags. Because of this, there
  334. /// exists the [`TagType`] abstraction. It is recommended to use this
  335. /// getter only for custom tags. For specified tags, use getters, such as
  336. /// [`Self::efi_64_ih`].
  337. ///
  338. /// ## Use Custom Tags
  339. /// The following example shows how you may use this interface to parse
  340. /// custom tags from the MBI. If they are dynamically sized (DST), a few more
  341. /// special handling is required. This is reflected by code-comments.
  342. ///
  343. /// ```no_run
  344. /// use std::str::Utf8Error;
  345. /// use multiboot2::{Tag, TagTrait, TagTypeId};
  346. ///
  347. /// #[repr(C, align(8))]
  348. /// #[derive(multiboot2::Pointee)] // Only needed for DSTs.
  349. /// struct CustomTag {
  350. /// // new type from the lib: has repr(u32)
  351. /// tag: TagTypeId,
  352. /// size: u32,
  353. /// // begin of inline string
  354. /// name: [u8],
  355. /// }
  356. ///
  357. /// // This implementation is only necessary for tags that are DSTs.
  358. /// impl TagTrait for CustomTag {
  359. /// fn dst_size(base_tag: &Tag) -> usize {
  360. /// // The size of the sized portion of the custom tag.
  361. /// let tag_base_size = 8; // id + size is 8 byte in size
  362. /// assert!(base_tag.size >= 8);
  363. /// base_tag.size as usize - tag_base_size
  364. /// }
  365. /// }
  366. ///
  367. /// impl CustomTag {
  368. /// fn name(&self) -> Result<&str, Utf8Error> {
  369. /// Tag::get_dst_str_slice(&self.name)
  370. /// }
  371. /// }
  372. ///
  373. /// let mbi = unsafe { multiboot2::load(0xdeadbeef).unwrap() };
  374. ///
  375. /// let tag = mbi
  376. /// .get_tag::<CustomTag, _>(0x1337)
  377. /// .unwrap();
  378. /// assert_eq!(tag.name(), Ok("name"));
  379. /// ```
  380. pub fn get_tag<TagT: TagTrait + ?Sized, TagType: Into<TagTypeId>>(
  381. &self,
  382. typ: TagType,
  383. ) -> Option<&TagT> {
  384. let typ = typ.into();
  385. self.tags()
  386. .find(|tag| tag.typ == typ)
  387. .map(|tag| tag.cast_tag::<TagT>())
  388. }
  389. fn tags(&self) -> TagIter {
  390. TagIter::new(unsafe { self.inner.offset(1) } as *const _)
  391. }
  392. }
  393. impl BootInformationInner {
  394. fn has_valid_end_tag(&self) -> bool {
  395. let end_tag_prototype = EndTag::default();
  396. let self_ptr = self as *const _;
  397. let end_tag_addr = self_ptr as usize + (self.total_size - end_tag_prototype.size) as usize;
  398. let end_tag = unsafe { &*(end_tag_addr as *const Tag) };
  399. end_tag.typ == end_tag_prototype.typ && end_tag.size == end_tag_prototype.size
  400. }
  401. }
  402. // SAFETY: BootInformation contains a const ptr to memory that is never mutated.
  403. // Sending this pointer to other threads is sound.
  404. unsafe impl Send for BootInformation {}
  405. impl fmt::Debug for BootInformation {
  406. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  407. /// Limit how many Elf-Sections should be debug-formatted.
  408. /// Can be thousands of sections for a Rust binary => this is useless output.
  409. /// If the user really wants this, they should debug-format the field directly.
  410. const ELF_SECTIONS_LIMIT: usize = 17;
  411. let mut debug = f.debug_struct("Multiboot2 Boot Information");
  412. debug
  413. .field("start_address", &(self.start_address() as *const u64))
  414. .field("end_address", &(self.end_address() as *const u64))
  415. .field("total_size", &(self.total_size() as *const u64))
  416. .field(
  417. "boot_loader_name_tag",
  418. &self
  419. .boot_loader_name_tag()
  420. .and_then(|x| x.name().ok())
  421. .unwrap_or("<unknown>"),
  422. )
  423. .field(
  424. "command_line",
  425. &self
  426. .command_line_tag()
  427. .and_then(|x| x.command_line().ok())
  428. .unwrap_or(""),
  429. )
  430. .field("memory_areas", &self.memory_map_tag())
  431. // so far, I didn't found a nice way to connect the iterator with ".field()" because
  432. // the iterator isn't Debug
  433. .field("module_tags", &self.module_tags());
  434. // usually this is REALLY big (thousands of tags) => skip it here
  435. let elf_sections_tag_entries_count = self.elf_sections().map(|x| x.count()).unwrap_or(0);
  436. if elf_sections_tag_entries_count > ELF_SECTIONS_LIMIT {
  437. debug.field("elf_sections_tags (count)", &elf_sections_tag_entries_count);
  438. } else {
  439. debug.field(
  440. "elf_sections_tags",
  441. &self.elf_sections().unwrap_or_default(),
  442. );
  443. }
  444. debug
  445. .field("efi_32_ih", &self.efi_32_ih())
  446. .field("efi_64_ih", &self.efi_64_ih())
  447. .field("efi_sdt_32_tag", &self.efi_sdt_32_tag())
  448. .field("efi_sdt_64_tag", &self.efi_sdt_64_tag())
  449. .field("efi_memory_map_tag", &self.efi_memory_map_tag())
  450. .finish()
  451. }
  452. }
  453. pub(crate) struct Reader {
  454. pub(crate) ptr: *const u8,
  455. pub(crate) off: usize,
  456. }
  457. impl Reader {
  458. pub(crate) fn new<T>(ptr: *const T) -> Reader {
  459. Reader {
  460. ptr: ptr as *const u8,
  461. off: 0,
  462. }
  463. }
  464. pub(crate) fn read_u8(&mut self) -> u8 {
  465. self.off += 1;
  466. unsafe { *self.ptr.add(self.off - 1) }
  467. }
  468. pub(crate) fn read_u16(&mut self) -> u16 {
  469. self.read_u8() as u16 | (self.read_u8() as u16) << 8
  470. }
  471. pub(crate) fn read_u32(&mut self) -> u32 {
  472. self.read_u16() as u32 | (self.read_u16() as u32) << 16
  473. }
  474. pub(crate) fn read_u64(&mut self) -> u64 {
  475. self.read_u32() as u64 | (self.read_u32() as u64) << 32
  476. }
  477. pub(crate) fn skip(&mut self, n: usize) {
  478. self.off += n;
  479. }
  480. pub(crate) fn current_address(&self) -> usize {
  481. unsafe { self.ptr.add(self.off) as usize }
  482. }
  483. }
  484. /// A trait to abstract over all sized and unsized tags (DSTs). For sized tags,
  485. /// this trait does not much. For DSTs, a `TagTrait::dst_size` implementation
  486. /// must me provided, which returns the right size hint for the dynamically
  487. /// sized portion of the struct.
  488. ///
  489. /// The [`TagTrait::from_base_tag`] method has a default implementation for all
  490. /// tags that are `Sized`.
  491. ///
  492. /// # Trivia
  493. /// This crate uses the [`Pointee`]-abstraction of the [`ptr_meta`] crate to
  494. /// create fat pointers.
  495. pub trait TagTrait: Pointee {
  496. /// Returns
  497. fn dst_size(base_tag: &Tag) -> Self::Metadata;
  498. /// Creates a reference to a (dynamically sized) tag type in a safe way.
  499. /// DST tags need to implement a proper [`Self::dst_size`] implementation.
  500. ///
  501. /// # Safety
  502. /// Callers must be sure that the "size" field of the provided [`Tag`] is
  503. /// sane and the underlying memory valid. The implementation of this trait
  504. /// **must have** a correct [`Self::dst_size`] implementation.
  505. unsafe fn from_base_tag<'a>(tag: &Tag) -> &'a Self {
  506. let ptr = tag as *const _ as *const ();
  507. let ptr = ptr_meta::from_raw_parts(ptr, Self::dst_size(tag));
  508. &*ptr
  509. }
  510. }
  511. // All sized tags automatically have a Pointee implementation where
  512. // Pointee::Metadata is (). Hence, the TagTrait is implemented automatically for
  513. // all tags that are sized.
  514. impl<T: Pointee<Metadata = ()>> TagTrait for T {
  515. #[allow(clippy::unused_unit)]
  516. fn dst_size(_: &Tag) -> Self::Metadata {
  517. ()
  518. }
  519. }
  520. /* TODO doesn't work, missing support in Rust (so far):
  521. https://github.com/rust-lang/rust/issues/20400
  522. fn dst_size(base_tag: &Tag) -> usize {
  523. // The size of the sized portion of the module tag.
  524. let tag_base_size = 16;
  525. assert!(base_tag.size >= 8);
  526. base_tag.size as usize - tag_base_size
  527. }
  528. }
  529. */
  530. #[cfg(test)]
  531. mod tests {
  532. use super::*;
  533. use core::str::Utf8Error;
  534. #[test]
  535. fn no_tags() {
  536. #[repr(C, align(8))]
  537. struct Bytes([u8; 16]);
  538. let bytes: Bytes = Bytes([
  539. 16, 0, 0, 0, // total_size
  540. 0, 0, 0, 0, // reserved
  541. 0, 0, 0, 0, // end tag type
  542. 8, 0, 0, 0, // end tag size
  543. ]);
  544. let addr = bytes.0.as_ptr() as usize;
  545. let bi = unsafe { load(addr) };
  546. let bi = bi.unwrap();
  547. assert_eq!(addr, bi.start_address());
  548. assert_eq!(addr + bytes.0.len(), bi.end_address());
  549. assert_eq!(bytes.0.len(), bi.total_size());
  550. assert!(bi.elf_sections().is_none());
  551. assert!(bi.memory_map_tag().is_none());
  552. assert!(bi.module_tags().next().is_none());
  553. assert!(bi.boot_loader_name_tag().is_none());
  554. assert!(bi.command_line_tag().is_none());
  555. }
  556. #[test]
  557. #[should_panic]
  558. fn invalid_total_size() {
  559. #[repr(C, align(8))]
  560. struct Bytes([u8; 15]);
  561. let bytes: Bytes = Bytes([
  562. 15, 0, 0, 0, // total_size
  563. 0, 0, 0, 0, // reserved
  564. 0, 0, 0, 0, // end tag type
  565. 8, 0, 0, // end tag size
  566. ]);
  567. let addr = bytes.0.as_ptr() as usize;
  568. let bi = unsafe { load(addr) };
  569. let bi = bi.unwrap();
  570. assert_eq!(addr, bi.start_address());
  571. assert_eq!(addr + bytes.0.len(), bi.end_address());
  572. assert_eq!(bytes.0.len(), bi.total_size());
  573. assert!(bi.elf_sections().is_none());
  574. assert!(bi.memory_map_tag().is_none());
  575. assert!(bi.module_tags().next().is_none());
  576. assert!(bi.boot_loader_name_tag().is_none());
  577. assert!(bi.command_line_tag().is_none());
  578. }
  579. #[test]
  580. #[should_panic]
  581. fn invalid_end_tag() {
  582. #[repr(C, align(8))]
  583. struct Bytes([u8; 16]);
  584. let bytes: Bytes = Bytes([
  585. 16, 0, 0, 0, // total_size
  586. 0, 0, 0, 0, // reserved
  587. 0, 0, 0, 0, // end tag type
  588. 9, 0, 0, 0, // end tag size
  589. ]);
  590. let addr = bytes.0.as_ptr() as usize;
  591. let bi = unsafe { load(addr) };
  592. let bi = bi.unwrap();
  593. assert_eq!(addr, bi.start_address());
  594. assert_eq!(addr + bytes.0.len(), bi.end_address());
  595. assert_eq!(bytes.0.len(), bi.total_size());
  596. assert!(bi.elf_sections().is_none());
  597. assert!(bi.memory_map_tag().is_none());
  598. assert!(bi.module_tags().next().is_none());
  599. assert!(bi.boot_loader_name_tag().is_none());
  600. assert!(bi.command_line_tag().is_none());
  601. }
  602. #[test]
  603. fn name_tag() {
  604. #[repr(C, align(8))]
  605. struct Bytes([u8; 32]);
  606. let bytes: Bytes = Bytes([
  607. 32, 0, 0, 0, // total_size
  608. 0, 0, 0, 0, // reserved
  609. 2, 0, 0, 0, // boot loader name tag type
  610. 13, 0, 0, 0, // boot loader name tag size
  611. 110, 97, 109, 101, // boot loader name 'name'
  612. 0, 0, 0, 0, // boot loader name null + padding
  613. 0, 0, 0, 0, // end tag type
  614. 8, 0, 0, 0, // end tag size
  615. ]);
  616. let addr = bytes.0.as_ptr() as usize;
  617. let bi = unsafe { load(addr) };
  618. let bi = bi.unwrap();
  619. assert_eq!(addr, bi.start_address());
  620. assert_eq!(addr + bytes.0.len(), bi.end_address());
  621. assert_eq!(bytes.0.len(), bi.total_size());
  622. assert!(bi.elf_sections().is_none());
  623. assert!(bi.memory_map_tag().is_none());
  624. assert!(bi.module_tags().next().is_none());
  625. assert_eq!(
  626. "name",
  627. bi.boot_loader_name_tag()
  628. .expect("tag must be present")
  629. .name()
  630. .expect("must be valid utf8")
  631. );
  632. assert!(bi.command_line_tag().is_none());
  633. }
  634. #[test]
  635. fn framebuffer_tag_rgb() {
  636. // direct RGB mode test:
  637. // taken from GRUB2 running in QEMU at
  638. // 1280x720 with 32bpp in BGRA format.
  639. #[repr(C, align(8))]
  640. struct Bytes([u8; 56]);
  641. let bytes: Bytes = Bytes([
  642. 56, 0, 0, 0, // total size
  643. 0, 0, 0, 0, // reserved
  644. 8, 0, 0, 0, // framebuffer tag type
  645. 40, 0, 0, 0, // framebuffer tag size
  646. 0, 0, 0, 253, // framebuffer low dword of address
  647. 0, 0, 0, 0, // framebuffer high dword of address
  648. 0, 20, 0, 0, // framebuffer pitch
  649. 0, 5, 0, 0, // framebuffer width
  650. 208, 2, 0, 0, // framebuffer height
  651. 32, 1, 0, 0, // framebuffer bpp, type, reserved word
  652. 16, 8, 8, 8, // framebuffer red pos/size, green pos/size
  653. 0, 8, 0, 0, // framebuffer blue pos/size, padding word
  654. 0, 0, 0, 0, // end tag type
  655. 8, 0, 0, 0, // end tag size
  656. ]);
  657. let addr = bytes.0.as_ptr() as usize;
  658. let bi = unsafe { load(addr) };
  659. let bi = bi.unwrap();
  660. assert_eq!(addr, bi.start_address());
  661. assert_eq!(addr + bytes.0.len(), bi.end_address());
  662. assert_eq!(bytes.0.len(), bi.total_size());
  663. use framebuffer::{FramebufferField, FramebufferType};
  664. assert!(bi.framebuffer_tag().is_some());
  665. let fbi = bi
  666. .framebuffer_tag()
  667. .expect("Framebuffer info should be available")
  668. .expect("Framebuffer info type should be valid");
  669. assert_eq!(fbi.address(), 4244635648);
  670. assert_eq!(fbi.pitch(), 5120);
  671. assert_eq!(fbi.width(), 1280);
  672. assert_eq!(fbi.height(), 720);
  673. assert_eq!(fbi.bpp(), 32);
  674. assert_eq!(
  675. fbi.buffer_type().unwrap(),
  676. FramebufferType::RGB {
  677. red: FramebufferField {
  678. position: 16,
  679. size: 8
  680. },
  681. green: FramebufferField {
  682. position: 8,
  683. size: 8
  684. },
  685. blue: FramebufferField {
  686. position: 0,
  687. size: 8
  688. }
  689. }
  690. );
  691. }
  692. #[test]
  693. fn framebuffer_tag_indexed() {
  694. // indexed mode test:
  695. // this is synthetic, as I can't get QEMU
  696. // to run in indexed color mode.
  697. #[repr(C, align(8))]
  698. struct Bytes([u8; 64]);
  699. let bytes: Bytes = Bytes([
  700. 64, 0, 0, 0, // total size
  701. 0, 0, 0, 0, // reserved
  702. 8, 0, 0, 0, // framebuffer tag type
  703. 48, 0, 0, 0, // framebuffer tag size
  704. 0, 0, 0, 253, // framebuffer low dword of address
  705. 0, 0, 0, 0, // framebuffer high dword of address
  706. 0, 20, 0, 0, // framebuffer pitch
  707. 0, 5, 0, 0, // framebuffer width
  708. 208, 2, 0, 0, // framebuffer height
  709. 32, 0, 0, 0, // framebuffer bpp, type, reserved word
  710. 4, 0, 0, 0, // framebuffer palette length
  711. 255, 0, 0, 0, // framebuffer palette
  712. 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, // end tag type
  713. 8, 0, 0, 0, // end tag size
  714. ]);
  715. let addr = bytes.0.as_ptr() as usize;
  716. let bi = unsafe { load(addr) };
  717. let bi = bi.unwrap();
  718. assert_eq!(addr, bi.start_address());
  719. assert_eq!(addr + bytes.0.len(), bi.end_address());
  720. assert_eq!(bytes.0.len(), bi.total_size());
  721. use framebuffer::{FramebufferColor, FramebufferType};
  722. assert!(bi.framebuffer_tag().is_some());
  723. let fbi = bi
  724. .framebuffer_tag()
  725. .expect("Framebuffer info should be available")
  726. .expect("Framebuffer info type should be valid");
  727. assert_eq!(fbi.address(), 4244635648);
  728. assert_eq!(fbi.pitch(), 5120);
  729. assert_eq!(fbi.width(), 1280);
  730. assert_eq!(fbi.height(), 720);
  731. assert_eq!(fbi.bpp(), 32);
  732. match fbi.buffer_type().unwrap() {
  733. FramebufferType::Indexed { palette } => assert_eq!(
  734. palette,
  735. [
  736. FramebufferColor {
  737. red: 255,
  738. green: 0,
  739. blue: 0
  740. },
  741. FramebufferColor {
  742. red: 0,
  743. green: 255,
  744. blue: 0
  745. },
  746. FramebufferColor {
  747. red: 0,
  748. green: 0,
  749. blue: 255
  750. },
  751. FramebufferColor {
  752. red: 0,
  753. green: 0,
  754. blue: 0
  755. }
  756. ]
  757. ),
  758. _ => panic!("Expected indexed framebuffer type."),
  759. }
  760. }
  761. #[test]
  762. fn vbe_info_tag() {
  763. //Taken from GRUB2 running in QEMU.
  764. #[repr(C, align(8))]
  765. struct Bytes([u8; 800]);
  766. let bytes = Bytes([
  767. 32, 3, 0, 0, // Total size.
  768. 0, 0, 0, 0, // Reserved
  769. 7, 0, 0, 0, // Tag type.
  770. 16, 3, 0, 0, // Tag size.
  771. 122, 65, 255, 255, // VBE mode, protected mode interface segment,
  772. 0, 96, 79, 0, // protected mode interface offset, and length.
  773. 86, 69, 83, 65, // "VESA" signature.
  774. 0, 3, 220, 87, // VBE version, lower half of OEM string ptr,
  775. 0, 192, 1, 0, // upper half of OEM string ptr, lower half of capabilities
  776. 0, 0, 34, 128, // upper half of capabilities, lower half of vide mode ptr,
  777. 0, 96, 0, 1, // upper half of video mode ptr, number of 64kb memory blocks
  778. 0, 0, 240, 87, // OEM software revision, lower half of OEM vendor string ptr,
  779. 0, 192, 3,
  780. 88, // upper half of OEM vendor string ptr, lower half of OEM product string ptr,
  781. 0, 192, 23,
  782. 88, // upper half of OEM product string ptr, lower half of OEM revision string ptr,
  783. 0, 192, 0, 1, // upper half of OEM revision string ptr.
  784. 1, 1, 2, 1, // Reserved data....
  785. 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20, 1,
  786. 21, 1, 22, 1, 23, 1, 24, 1, 25, 1, 26, 1, 27, 1, 28, 1, 29, 1, 30, 1, 31, 1, 64, 1, 65,
  787. 1, 66, 1, 67, 1, 68, 1, 69, 1, 70, 1, 71, 1, 72, 1, 73, 1, 74, 1, 75, 1, 76, 1, 117, 1,
  788. 118, 1, 119, 1, 120, 1, 121, 1, 122, 1, 123, 1, 124, 1, 125, 1, 126, 1, 127, 1, 128, 1,
  789. 129, 1, 130, 1, 131, 1, 132, 1, 133, 1, 134, 1, 135, 1, 136, 1, 137, 1, 138, 1, 139, 1,
  790. 140, 1, 141, 1, 142, 1, 143, 1, 144, 1, 145, 1, 146, 1, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0,
  791. 5, 0, 6, 0, 7, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 106, 0, 255, 255, 0,
  792. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  793. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  794. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  795. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  796. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  797. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  798. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  799. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  800. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  801. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  802. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Until Here
  803. 187, 0, 7, 0, // Mode attributes, window A and B attributes
  804. 64, 0, 64, 0, // Window granularity and size.
  805. 0, 160, 0, 0, // Window A and B segments.
  806. 186, 84, 0, 192, // Window relocation function pointer.
  807. 0, 20, 0, 5, // Pitch, X resolution.
  808. 32, 3, 8, 16, // Y resolution, X char size, Y char size.
  809. 1, 32, 1, 6, // Number of planes, BPP, number of banks, memory model.
  810. 0, 3, 1, 8, // Bank size, number of images, reserved, red mask size.
  811. 16, 8, 8,
  812. 8, // Red mask position, green mask size, green mask position, blue mask size,
  813. 0, 8, 24,
  814. 2, // blue mask position, reserved mask size, reserved mask position, color attributes.
  815. 0, 0, 0, 253, // Frame buffer base address.
  816. 0, 0, 0, 0, // Off screen memory offset.
  817. 0, 0, 0, 20, // Off screen memory size, reserved data...
  818. 0, 0, 8, 16, 8, 8, 8, 0, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  819. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  820. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  821. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  822. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  823. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  824. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  825. 0, 0, // Until here.
  826. 0, 0, 0, 0, // End tag type.
  827. 8, 0, 0, 0, // End tag size.
  828. ]);
  829. let addr = bytes.0.as_ptr() as usize;
  830. let bi = unsafe { load(addr) };
  831. let bi = bi.unwrap();
  832. assert_eq!(addr, bi.start_address());
  833. assert_eq!(addr + bytes.0.len(), bi.end_address());
  834. assert_eq!(bytes.0.len(), bi.total_size());
  835. assert!(bi.vbe_info_tag().is_some());
  836. let vbe = bi.vbe_info_tag().unwrap();
  837. use vbe_info::*;
  838. assert_eq!({ vbe.mode }, 16762);
  839. assert_eq!({ vbe.interface_segment }, 65535);
  840. assert_eq!({ vbe.interface_offset }, 24576);
  841. assert_eq!({ vbe.interface_length }, 79);
  842. assert_eq!({ vbe.control_info.signature }, [86, 69, 83, 65]);
  843. assert_eq!({ vbe.control_info.version }, 768);
  844. assert_eq!({ vbe.control_info.oem_string_ptr }, 3221247964);
  845. assert_eq!(
  846. { vbe.control_info.capabilities },
  847. VBECapabilities::SWITCHABLE_DAC
  848. );
  849. assert_eq!({ vbe.control_info.mode_list_ptr }, 1610645538);
  850. assert_eq!({ vbe.control_info.total_memory }, 256);
  851. assert_eq!({ vbe.control_info.oem_software_revision }, 0);
  852. assert_eq!({ vbe.control_info.oem_vendor_name_ptr }, 3221247984);
  853. assert_eq!({ vbe.control_info.oem_product_name_ptr }, 3221248003);
  854. assert_eq!({ vbe.control_info.oem_product_revision_ptr }, 3221248023);
  855. assert!({ vbe.mode_info.mode_attributes }.contains(
  856. VBEModeAttributes::SUPPORTED
  857. | VBEModeAttributes::COLOR
  858. | VBEModeAttributes::GRAPHICS
  859. | VBEModeAttributes::NOT_VGA_COMPATIBLE
  860. | VBEModeAttributes::LINEAR_FRAMEBUFFER
  861. ));
  862. assert!(vbe.mode_info.window_a_attributes.contains(
  863. VBEWindowAttributes::RELOCATABLE
  864. | VBEWindowAttributes::READABLE
  865. | VBEWindowAttributes::WRITEABLE
  866. ));
  867. assert_eq!({ vbe.mode_info.window_granularity }, 64);
  868. assert_eq!({ vbe.mode_info.window_size }, 64);
  869. assert_eq!({ vbe.mode_info.window_a_segment }, 40960);
  870. assert_eq!({ vbe.mode_info.window_function_ptr }, 3221247162);
  871. assert_eq!({ vbe.mode_info.pitch }, 5120);
  872. assert_eq!({ vbe.mode_info.resolution }, (1280, 800));
  873. assert_eq!(vbe.mode_info.character_size, (8, 16));
  874. assert_eq!(vbe.mode_info.number_of_planes, 1);
  875. assert_eq!(vbe.mode_info.bpp, 32);
  876. assert_eq!(vbe.mode_info.number_of_banks, 1);
  877. assert_eq!(vbe.mode_info.memory_model, VBEMemoryModel::DirectColor);
  878. assert_eq!(vbe.mode_info.bank_size, 0);
  879. assert_eq!(vbe.mode_info.number_of_image_pages, 3);
  880. assert_eq!(
  881. vbe.mode_info.red_field,
  882. VBEField {
  883. position: 16,
  884. size: 8
  885. }
  886. );
  887. assert_eq!(
  888. vbe.mode_info.green_field,
  889. VBEField {
  890. position: 8,
  891. size: 8
  892. }
  893. );
  894. assert_eq!(
  895. vbe.mode_info.blue_field,
  896. VBEField {
  897. position: 0,
  898. size: 8
  899. }
  900. );
  901. assert_eq!(
  902. vbe.mode_info.reserved_field,
  903. VBEField {
  904. position: 24,
  905. size: 8
  906. }
  907. );
  908. assert_eq!(
  909. vbe.mode_info.direct_color_attributes,
  910. VBEDirectColorAttributes::RESERVED_USABLE
  911. );
  912. assert_eq!({ vbe.mode_info.framebuffer_base_ptr }, 4244635648);
  913. assert_eq!({ vbe.mode_info.offscreen_memory_offset }, 0);
  914. assert_eq!({ vbe.mode_info.offscreen_memory_size }, 0);
  915. }
  916. #[test]
  917. /// Compile time test for [`VBEInfoTag`].
  918. fn vbe_info_tag_size() {
  919. unsafe {
  920. // 16 for the start + 512 from `VBEControlInfo` + 256 from `VBEModeInfo`.
  921. core::mem::transmute::<[u8; 784], VBEInfoTag>([0u8; 784]);
  922. }
  923. }
  924. #[test]
  925. fn grub2() {
  926. #[repr(C, align(8))]
  927. struct Bytes([u8; 960]);
  928. let mut bytes: Bytes = Bytes([
  929. 192, 3, 0, 0, // total_size
  930. 0, 0, 0, 0, // reserved
  931. 1, 0, 0, 0, // boot command tag type
  932. 9, 0, 0, 0, // boot command tag size
  933. 0, 0, 0, 0, // boot command null + padding
  934. 0, 0, 0, 0, // boot command padding
  935. 2, 0, 0, 0, // boot loader name tag type
  936. 26, 0, 0, 0, // boot loader name tag size
  937. 71, 82, 85, 66, // boot loader name
  938. 32, 50, 46, 48, // boot loader name
  939. 50, 126, 98, 101, // boot loader name
  940. 116, 97, 51, 45, // boot loader name
  941. 53, 0, 0, 0, // boot loader name null + padding
  942. 0, 0, 0, 0, // boot loader name padding
  943. 10, 0, 0, 0, // APM tag type
  944. 28, 0, 0, 0, // APM tag size
  945. 2, 1, 0, 240, // APM version, cseg
  946. 207, 212, 0, 0, // APM offset
  947. 0, 240, 0, 240, // APM cseg_16, dseg
  948. 3, 0, 240, 255, // APM flags, cseg_len
  949. 240, 255, 240, 255, // APM cseg_16_len, dseg_len
  950. 0, 0, 0, 0, // APM padding
  951. 6, 0, 0, 0, // memory map tag type
  952. 160, 0, 0, 0, // memory map tag size
  953. 24, 0, 0, 0, // memory map entry_size
  954. 0, 0, 0, 0, // memory map entry_version
  955. 0, 0, 0, 0, // memory map entry 0 base_addr
  956. 0, 0, 0, 0, // memory map entry 0 base_addr
  957. 0, 252, 9, 0, // memory map entry 0 length
  958. 0, 0, 0, 0, // memory map entry 0 length
  959. 1, 0, 0, 0, // memory map entry 0 type
  960. 0, 0, 0, 0, // memory map entry 0 reserved
  961. 0, 252, 9, 0, // memory map entry 1 base_addr
  962. 0, 0, 0, 0, // memory map entry 1 base_addr
  963. 0, 4, 0, 0, // memory map entry 1 length
  964. 0, 0, 0, 0, // memory map entry 1 length
  965. 2, 0, 0, 0, // memory map entry 1 type
  966. 0, 0, 0, 0, // memory map entry 1 reserved
  967. 0, 0, 15, 0, // memory map entry 2 base_addr
  968. 0, 0, 0, 0, // memory map entry 2 base_addr
  969. 0, 0, 1, 0, // memory map entry 2 length
  970. 0, 0, 0, 0, // memory map entry 2 length
  971. 2, 0, 0, 0, // memory map entry 2 type
  972. 0, 0, 0, 0, // memory map entry 2 reserved
  973. 0, 0, 16, 0, // memory map entry 3 base_addr
  974. 0, 0, 0, 0, // memory map entry 3 base_addr
  975. 0, 0, 238, 7, // memory map entry 3 length
  976. 0, 0, 0, 0, // memory map entry 3 length
  977. 1, 0, 0, 0, // memory map entry 3 type
  978. 0, 0, 0, 0, // memory map entry 3 reserved
  979. 0, 0, 254, 7, // memory map entry 4 base_addr
  980. 0, 0, 0, 0, // memory map entry 4 base_addr
  981. 0, 0, 2, 0, // memory map entry 4 length
  982. 0, 0, 0, 0, // memory map entry 4 length
  983. 2, 0, 0, 0, // memory map entry 4 type
  984. 0, 0, 0, 0, // memory map entry 4 reserved
  985. 0, 0, 252, 255, // memory map entry 5 base_addr
  986. 0, 0, 0, 0, // memory map entry 5 base_addr
  987. 0, 0, 4, 0, // memory map entry 5 length
  988. 0, 0, 0, 0, // memory map entry 5 length
  989. 2, 0, 0, 0, // memory map entry 5 type
  990. 0, 0, 0, 0, // memory map entry 5 reserved
  991. 9, 0, 0, 0, // elf symbols tag type
  992. 84, 2, 0, 0, // elf symbols tag size
  993. 9, 0, 0, 0, // elf symbols num
  994. 64, 0, 0, 0, // elf symbols entsize
  995. 8, 0, 0, 0, // elf symbols shndx
  996. 0, 0, 0, 0, // elf symbols entry 0 name
  997. 0, 0, 0, 0, // elf symbols entry 0 type
  998. 0, 0, 0, 0, // elf symbols entry 0 flags
  999. 0, 0, 0, 0, // elf symbols entry 0 flags
  1000. 0, 0, 0, 0, // elf symbols entry 0 addr
  1001. 0, 0, 0, 0, // elf symbols entry 0 addr
  1002. 0, 0, 0, 0, // elf symbols entry 0 offset
  1003. 0, 0, 0, 0, // elf symbols entry 0 offset
  1004. 0, 0, 0, 0, // elf symbols entry 0 size
  1005. 0, 0, 0, 0, // elf symbols entry 0 size
  1006. 0, 0, 0, 0, // elf symbols entry 0 link
  1007. 0, 0, 0, 0, // elf symbols entry 0 info
  1008. 0, 0, 0, 0, // elf symbols entry 0 addralign
  1009. 0, 0, 0, 0, // elf symbols entry 0 addralign
  1010. 0, 0, 0, 0, // elf symbols entry 0 entsize
  1011. 0, 0, 0, 0, // elf symbols entry 0 entsize
  1012. 27, 0, 0, 0, // elf symbols entry 1 name
  1013. 1, 0, 0, 0, // elf symbols entry 1 type
  1014. 2, 0, 0, 0, // elf symbols entry 1 flags
  1015. 0, 0, 0, 0, // elf symbols entry 1 flags
  1016. 0, 0, 16, 0, // elf symbols entry 1 addr
  1017. 0, 128, 255, 255, // elf symbols entry 1 addr
  1018. 0, 16, 0, 0, // elf symbols entry 1 offset
  1019. 0, 0, 0, 0, // elf symbols entry 1 offset
  1020. 0, 48, 0, 0, // elf symbols entry 1 size
  1021. 0, 0, 0, 0, // elf symbols entry 1 size
  1022. 0, 0, 0, 0, // elf symbols entry 1 link
  1023. 0, 0, 0, 0, // elf symbols entry 1 info
  1024. 16, 0, 0, 0, // elf symbols entry 1 addralign
  1025. 0, 0, 0, 0, // elf symbols entry 1 addralign
  1026. 0, 0, 0, 0, // elf symbols entry 1 entsize
  1027. 0, 0, 0, 0, // elf symbols entry 1 entsize
  1028. 35, 0, 0, 0, // elf symbols entry 2 name
  1029. 1, 0, 0, 0, // elf symbols entry 2 type
  1030. 6, 0, 0, 0, // elf symbols entry 2 flags
  1031. 0, 0, 0, 0, // elf symbols entry 2 flags
  1032. 0, 48, 16, 0, // elf symbols entry 2 addr
  1033. 0, 128, 255, 255, // elf symbols entry 2 addr
  1034. 0, 64, 0, 0, // elf symbols entry 2 offset
  1035. 0, 0, 0, 0, // elf symbols entry 2 offset
  1036. 0, 144, 0, 0, // elf symbols entry 2 size
  1037. 0, 0, 0, 0, // elf symbols entry 2 size
  1038. 0, 0, 0, 0, // elf symbols entry 2 link
  1039. 0, 0, 0, 0, // elf symbols entry 2 info
  1040. 16, 0, 0, 0, // elf symbols entry 2 addralign
  1041. 0, 0, 0, 0, // elf symbols entry 2 addralign
  1042. 0, 0, 0, 0, // elf symbols entry 2 entsize
  1043. 0, 0, 0, 0, // elf symbols entry 2 entsize
  1044. 41, 0, 0, 0, // elf symbols entry 3 name
  1045. 1, 0, 0, 0, // elf symbols entry 3 type
  1046. 3, 0, 0, 0, // elf symbols entry 3 flags
  1047. 0, 0, 0, 0, // elf symbols entry 3 flags
  1048. 0, 192, 16, 0, // elf symbols entry 3 addr
  1049. 0, 128, 255, 255, // elf symbols entry 3 addr
  1050. 0, 208, 0, 0, // elf symbols entry 3 offset
  1051. 0, 0, 0, 0, // elf symbols entry 3 offset
  1052. 0, 32, 0, 0, // elf symbols entry 3 size
  1053. 0, 0, 0, 0, // elf symbols entry 3 size
  1054. 0, 0, 0, 0, // elf symbols entry 3 link
  1055. 0, 0, 0, 0, // elf symbols entry 3 info
  1056. 8, 0, 0, 0, // elf symbols entry 3 addralign
  1057. 0, 0, 0, 0, // elf symbols entry 3 addralign
  1058. 0, 0, 0, 0, // elf symbols entry 3 entsize
  1059. 0, 0, 0, 0, // elf symbols entry 3 entsize
  1060. 47, 0, 0, 0, // elf symbols entry 4 name
  1061. 8, 0, 0, 0, // elf symbols entry 4 type
  1062. 3, 0, 0, 0, // elf symbols entry 4 flags
  1063. 0, 0, 0, 0, // elf symbols entry 4 flags
  1064. 0, 224, 16, 0, // elf symbols entry 4 addr
  1065. 0, 128, 255, 255, // elf symbols entry 4 addr
  1066. 0, 240, 0, 0, // elf symbols entry 4 offset
  1067. 0, 0, 0, 0, // elf symbols entry 4 offset
  1068. 0, 80, 0, 0, // elf symbols entry 4 size
  1069. 0, 0, 0, 0, // elf symbols entry 4 size
  1070. 0, 0, 0, 0, // elf symbols entry 4 link
  1071. 0, 0, 0, 0, // elf symbols entry 4 info
  1072. 0, 16, 0, 0, // elf symbols entry 4 addralign
  1073. 0, 0, 0, 0, // elf symbols entry 4 addralign
  1074. 0, 0, 0, 0, // elf symbols entry 4 entsize
  1075. 0, 0, 0, 0, // elf symbols entry 4 entsize
  1076. 52, 0, 0, 0, // elf symbols entry 5 name
  1077. 1, 0, 0, 0, // elf symbols entry 5 type
  1078. 3, 0, 0, 0, // elf symbols entry 5 flags
  1079. 0, 0, 0, 0, // elf symbols entry 5 flags
  1080. 0, 48, 17, 0, // elf symbols entry 5 addr
  1081. 0, 128, 255, 255, // elf symbols entry 5 addr
  1082. 0, 240, 0, 0, // elf symbols entry 5 offset
  1083. 0, 0, 0, 0, // elf symbols entry 5 offset
  1084. 0, 0, 0, 0, // elf symbols entry 5 size
  1085. 0, 0, 0, 0, // elf symbols entry 5 size
  1086. 0, 0, 0, 0, // elf symbols entry 5 link
  1087. 0, 0, 0, 0, // elf symbols entry 5 info
  1088. 1, 0, 0, 0, // elf symbols entry 5 addralign
  1089. 0, 0, 0, 0, // elf symbols entry 5 addralign
  1090. 0, 0, 0, 0, // elf symbols entry 5 entsize
  1091. 0, 0, 0, 0, // elf symbols entry 5 entsize
  1092. 1, 0, 0, 0, // elf symbols entry 6 name
  1093. 2, 0, 0, 0, // elf symbols entry 6 type
  1094. 0, 0, 0, 0, // elf symbols entry 6 flags
  1095. 0, 0, 0, 0, // elf symbols entry 6 flags
  1096. 0, 48, 17, 0, // elf symbols entry 6 addr
  1097. 0, 0, 0, 0, // elf symbols entry 6 addr
  1098. 0, 240, 0, 0, // elf symbols entry 6 offset
  1099. 0, 0, 0, 0, // elf symbols entry 6 offset
  1100. 224, 43, 0, 0, // elf symbols entry 6 size
  1101. 0, 0, 0, 0, // elf symbols entry 6 size
  1102. 7, 0, 0, 0, // elf symbols entry 6 link
  1103. 102, 1, 0, 0, // elf symbols entry 6 info
  1104. 8, 0, 0, 0, // elf symbols entry 6 addralign
  1105. 0, 0, 0, 0, // elf symbols entry 6 addralign
  1106. 24, 0, 0, 0, // elf symbols entry 6 entsize
  1107. 0, 0, 0, 0, // elf symbols entry 6 entsize
  1108. 9, 0, 0, 0, // elf symbols entry 7 name
  1109. 3, 0, 0, 0, // elf symbols entry 7 type
  1110. 0, 0, 0, 0, // elf symbols entry 7 flags
  1111. 0, 0, 0, 0, // elf symbols entry 7 flags
  1112. 224, 91, 17, 0, // elf symbols entry 7 addr
  1113. 0, 0, 0, 0, // elf symbols entry 7 addr
  1114. 224, 27, 1, 0, // elf symbols entry 7 offset
  1115. 0, 0, 0, 0, // elf symbols entry 7 offset
  1116. 145, 55, 0, 0, // elf symbols entry 7 size
  1117. 0, 0, 0, 0, // elf symbols entry 7 size
  1118. 0, 0, 0, 0, // elf symbols entry 7 link
  1119. 0, 0, 0, 0, // elf symbols entry 7 info
  1120. 1, 0, 0, 0, // elf symbols entry 7 addralign
  1121. 0, 0, 0, 0, // elf symbols entry 7 addralign
  1122. 0, 0, 0, 0, // elf symbols entry 7 entsize
  1123. 0, 0, 0, 0, // elf symbols entry 7 entsize
  1124. 17, 0, 0, 0, // elf symbols entry 8 name
  1125. 3, 0, 0, 0, // elf symbols entry 8 type
  1126. 0, 0, 0, 0, // elf symbols entry 8 flags
  1127. 0, 0, 0, 0, // elf symbols entry 8 flags
  1128. 113, 147, 17, 0, // elf symbols entry 8 addr
  1129. 0, 0, 0, 0, // elf symbols entry 8 addr
  1130. 113, 83, 1, 0, // elf symbols entry 8 offset
  1131. 0, 0, 0, 0, // elf symbols entry 8 offset
  1132. 65, 0, 0, 0, // elf symbols entry 8 size
  1133. 0, 0, 0, 0, // elf symbols entry 8 size
  1134. 0, 0, 0, 0, // elf symbols entry 8 link
  1135. 0, 0, 0, 0, // elf symbols entry 8 info
  1136. 1, 0, 0, 0, // elf symbols entry 8 addralign
  1137. 0, 0, 0, 0, // elf symbols entry 8 addralign
  1138. 0, 0, 0, 0, // elf symbols entry 8 entsize
  1139. 0, 0, 0, 0, // elf symbols entry 8 entsize
  1140. 0, 0, 0, 0, // elf symbols padding
  1141. 4, 0, 0, 0, // basic memory tag type
  1142. 16, 0, 0, 0, // basic memory tag size
  1143. 127, 2, 0, 0, // basic memory mem_lower
  1144. 128, 251, 1, 0, // basic memory mem_upper
  1145. 5, 0, 0, 0, // BIOS boot device tag type
  1146. 20, 0, 0, 0, // BIOS boot device tag size
  1147. 224, 0, 0, 0, // BIOS boot device biosdev
  1148. 255, 255, 255, 255, // BIOS boot device partition
  1149. 255, 255, 255, 255, // BIOS boot device subpartition
  1150. 0, 0, 0, 0, // BIOS boot device padding
  1151. 8, 0, 0, 0, // framebuffer info tag type
  1152. 32, 0, 0, 0, // framebuffer info tag size
  1153. 0, 128, 11, 0, // framebuffer info framebuffer_addr
  1154. 0, 0, 0, 0, // framebuffer info framebuffer_addr
  1155. 160, 0, 0, 0, // framebuffer info framebuffer_pitch
  1156. 80, 0, 0, 0, // framebuffer info framebuffer_width
  1157. 25, 0, 0, 0, // framebuffer info framebuffer_height
  1158. 16, 2, 0, 0, // framebuffer info framebuffer_[bpp,type], reserved, color_info
  1159. 14, 0, 0, 0, // ACPI old tag type
  1160. 28, 0, 0, 0, // ACPI old tag size
  1161. 82, 83, 68, 32, // ACPI old
  1162. 80, 84, 82, 32, // ACPI old
  1163. 89, 66, 79, 67, // ACPI old
  1164. 72, 83, 32, 0, // ACPI old
  1165. 220, 24, 254, 7, // ACPI old
  1166. 0, 0, 0, 0, // ACPI old padding
  1167. 0, 0, 0, 0, // end tag type
  1168. 8, 0, 0, 0, // end tag size
  1169. ]);
  1170. #[repr(C, align(8))]
  1171. struct StringBytes([u8; 65]);
  1172. let string_bytes: StringBytes = StringBytes([
  1173. 0, 46, 115, 121, 109, 116, 97, 98, 0, 46, 115, 116, 114, 116, 97, 98, 0, 46, 115, 104,
  1174. 115, 116, 114, 116, 97, 98, 0, 46, 114, 111, 100, 97, 116, 97, 0, 46, 116, 101, 120,
  1175. 116, 0, 46, 100, 97, 116, 97, 0, 46, 98, 115, 115, 0, 46, 100, 97, 116, 97, 46, 114,
  1176. 101, 108, 46, 114, 111, 0,
  1177. ]);
  1178. let string_addr = string_bytes.0.as_ptr() as u64;
  1179. for i in 0..8 {
  1180. bytes.0[796 + i] = (string_addr >> (i * 8)) as u8;
  1181. }
  1182. let addr = bytes.0.as_ptr() as usize;
  1183. let bi = unsafe { load(addr) };
  1184. let bi = bi.unwrap();
  1185. test_grub2_boot_info(bi, addr, string_addr, &bytes.0, &string_bytes.0);
  1186. let bi = unsafe { load_with_offset(addr, 0) };
  1187. let bi = bi.unwrap();
  1188. test_grub2_boot_info(bi, addr, string_addr, &bytes.0, &string_bytes.0);
  1189. let offset = 8usize;
  1190. for i in 0..8 {
  1191. bytes.0[796 + i] = ((string_addr - offset as u64) >> (i * 8)) as u8;
  1192. }
  1193. let bi = unsafe { load_with_offset(addr - offset, offset) };
  1194. let bi = bi.unwrap();
  1195. test_grub2_boot_info(
  1196. bi,
  1197. addr,
  1198. string_addr - offset as u64,
  1199. &bytes.0,
  1200. &string_bytes.0,
  1201. );
  1202. }
  1203. fn test_grub2_boot_info(
  1204. bi: BootInformation,
  1205. addr: usize,
  1206. string_addr: u64,
  1207. bytes: &[u8],
  1208. string_bytes: &[u8],
  1209. ) {
  1210. assert_eq!(addr, bi.start_address());
  1211. assert_eq!(addr + bytes.len(), bi.end_address());
  1212. assert_eq!(bytes.len(), bi.total_size());
  1213. let mut es = bi.elf_sections().unwrap();
  1214. let s1 = es.next().expect("Should have one more section");
  1215. assert_eq!(".rodata", s1.name().expect("Should be valid utf-8"));
  1216. assert_eq!(0xFFFF_8000_0010_0000, s1.start_address());
  1217. assert_eq!(0xFFFF_8000_0010_3000, s1.end_address());
  1218. assert_eq!(0x0000_0000_0000_3000, s1.size());
  1219. assert_eq!(ElfSectionFlags::ALLOCATED, s1.flags());
  1220. assert_eq!(ElfSectionType::ProgramSection, s1.section_type());
  1221. let s2 = es.next().expect("Should have one more section");
  1222. assert_eq!(".text", s2.name().expect("Should be valid utf-8"));
  1223. assert_eq!(0xFFFF_8000_0010_3000, s2.start_address());
  1224. assert_eq!(0xFFFF_8000_0010_C000, s2.end_address());
  1225. assert_eq!(0x0000_0000_0000_9000, s2.size());
  1226. assert_eq!(
  1227. ElfSectionFlags::EXECUTABLE | ElfSectionFlags::ALLOCATED,
  1228. s2.flags()
  1229. );
  1230. assert_eq!(ElfSectionType::ProgramSection, s2.section_type());
  1231. let s3 = es.next().expect("Should have one more section");
  1232. assert_eq!(".data", s3.name().expect("Should be valid utf-8"));
  1233. assert_eq!(0xFFFF_8000_0010_C000, s3.start_address());
  1234. assert_eq!(0xFFFF_8000_0010_E000, s3.end_address());
  1235. assert_eq!(0x0000_0000_0000_2000, s3.size());
  1236. assert_eq!(
  1237. ElfSectionFlags::ALLOCATED | ElfSectionFlags::WRITABLE,
  1238. s3.flags()
  1239. );
  1240. assert_eq!(ElfSectionType::ProgramSection, s3.section_type());
  1241. let s4 = es.next().expect("Should have one more section");
  1242. assert_eq!(".bss", s4.name().expect("Should be valid utf-8"));
  1243. assert_eq!(0xFFFF_8000_0010_E000, s4.start_address());
  1244. assert_eq!(0xFFFF_8000_0011_3000, s4.end_address());
  1245. assert_eq!(0x0000_0000_0000_5000, s4.size());
  1246. assert_eq!(
  1247. ElfSectionFlags::ALLOCATED | ElfSectionFlags::WRITABLE,
  1248. s4.flags()
  1249. );
  1250. assert_eq!(ElfSectionType::Uninitialized, s4.section_type());
  1251. let s5 = es.next().expect("Should have one more section");
  1252. assert_eq!(".data.rel.ro", s5.name().expect("Should be valid utf-8"));
  1253. assert_eq!(0xFFFF_8000_0011_3000, s5.start_address());
  1254. assert_eq!(0xFFFF_8000_0011_3000, s5.end_address());
  1255. assert_eq!(0x0000_0000_0000_0000, s5.size());
  1256. assert_eq!(
  1257. ElfSectionFlags::ALLOCATED | ElfSectionFlags::WRITABLE,
  1258. s5.flags()
  1259. );
  1260. assert_eq!(ElfSectionType::ProgramSection, s5.section_type());
  1261. let s6 = es.next().expect("Should have one more section");
  1262. assert_eq!(".symtab", s6.name().expect("Should be valid utf-8"));
  1263. assert_eq!(0x0000_0000_0011_3000, s6.start_address());
  1264. assert_eq!(0x0000_0000_0011_5BE0, s6.end_address());
  1265. assert_eq!(0x0000_0000_0000_2BE0, s6.size());
  1266. assert_eq!(ElfSectionFlags::empty(), s6.flags());
  1267. assert_eq!(ElfSectionType::LinkerSymbolTable, s6.section_type());
  1268. let s7 = es.next().expect("Should have one more section");
  1269. assert_eq!(".strtab", s7.name().expect("Should be valid utf-8"));
  1270. assert_eq!(0x0000_0000_0011_5BE0, s7.start_address());
  1271. assert_eq!(0x0000_0000_0011_9371, s7.end_address());
  1272. assert_eq!(0x0000_0000_0000_3791, s7.size());
  1273. assert_eq!(ElfSectionFlags::empty(), s7.flags());
  1274. assert_eq!(ElfSectionType::StringTable, s7.section_type());
  1275. let s8 = es.next().expect("Should have one more section");
  1276. assert_eq!(".shstrtab", s8.name().expect("Should be valid utf-8"));
  1277. assert_eq!(string_addr, s8.start_address());
  1278. assert_eq!(string_addr + string_bytes.len() as u64, s8.end_address());
  1279. assert_eq!(string_bytes.len() as u64, s8.size());
  1280. assert_eq!(ElfSectionFlags::empty(), s8.flags());
  1281. assert_eq!(ElfSectionType::StringTable, s8.section_type());
  1282. assert!(es.next().is_none());
  1283. let mut mm = bi.memory_map_tag().unwrap().available_memory_areas();
  1284. let mm1 = mm.next().unwrap();
  1285. assert_eq!(0x00000000, mm1.start_address());
  1286. assert_eq!(0x009_FC00, mm1.end_address());
  1287. assert_eq!(0x009_FC00, mm1.size());
  1288. assert_eq!(MemoryAreaType::Available, mm1.typ());
  1289. let mm2 = mm.next().unwrap();
  1290. assert_eq!(0x010_0000, mm2.start_address());
  1291. assert_eq!(0x7FE_0000, mm2.end_address());
  1292. assert_eq!(0x7EE_0000, mm2.size());
  1293. assert_eq!(MemoryAreaType::Available, mm2.typ());
  1294. assert!(mm.next().is_none());
  1295. // Test the RSDP tag
  1296. let rsdp_old = bi.rsdp_v1_tag().unwrap();
  1297. assert_eq!("RSD PTR ", rsdp_old.signature().unwrap());
  1298. assert!(rsdp_old.checksum_is_valid());
  1299. assert_eq!("BOCHS ", rsdp_old.oem_id().unwrap());
  1300. assert_eq!(0, rsdp_old.revision());
  1301. assert_eq!(0x7FE18DC, rsdp_old.rsdt_address());
  1302. assert!(bi.module_tags().next().is_none());
  1303. assert_eq!(
  1304. "GRUB 2.02~beta3-5",
  1305. bi.boot_loader_name_tag()
  1306. .expect("tag must be present")
  1307. .name()
  1308. .expect("must be valid utf-8")
  1309. );
  1310. assert_eq!(
  1311. "",
  1312. bi.command_line_tag()
  1313. .expect("tag must present")
  1314. .command_line()
  1315. .expect("must be valid utf-8")
  1316. );
  1317. // Test the Framebuffer tag
  1318. let fbi = bi
  1319. .framebuffer_tag()
  1320. .expect("Framebuffer info should be available")
  1321. .expect("Framebuffer info type should be valid");
  1322. assert_eq!(fbi.address(), 753664);
  1323. assert_eq!(fbi.pitch(), 160);
  1324. assert_eq!(fbi.width(), 80);
  1325. assert_eq!(fbi.height(), 25);
  1326. assert_eq!(fbi.bpp(), 16);
  1327. assert_eq!(fbi.buffer_type(), Ok(FramebufferType::Text));
  1328. }
  1329. #[test]
  1330. fn elf_sections() {
  1331. #[repr(C, align(8))]
  1332. struct Bytes([u8; 168]);
  1333. let mut bytes: Bytes = Bytes([
  1334. 168, 0, 0, 0, // total_size
  1335. 0, 0, 0, 0, // reserved
  1336. 9, 0, 0, 0, // elf symbols tag type
  1337. 20, 2, 0, 0, // elf symbols tag size
  1338. 2, 0, 0, 0, // elf symbols num
  1339. 64, 0, 0, 0, // elf symbols entsize
  1340. 1, 0, 0, 0, // elf symbols shndx
  1341. 0, 0, 0, 0, // elf symbols entry 0 name
  1342. 0, 0, 0, 0, // elf symbols entry 0 type
  1343. 0, 0, 0, 0, // elf symbols entry 0 flags
  1344. 0, 0, 0, 0, // elf symbols entry 0 flags
  1345. 0, 0, 0, 0, // elf symbols entry 0 addr
  1346. 0, 0, 0, 0, // elf symbols entry 0 addr
  1347. 0, 0, 0, 0, // elf symbols entry 0 offset
  1348. 0, 0, 0, 0, // elf symbols entry 0 offset
  1349. 0, 0, 0, 0, // elf symbols entry 0 size
  1350. 0, 0, 0, 0, // elf symbols entry 0 size
  1351. 0, 0, 0, 0, // elf symbols entry 0 link
  1352. 0, 0, 0, 0, // elf symbols entry 0 info
  1353. 0, 0, 0, 0, // elf symbols entry 0 addralign
  1354. 0, 0, 0, 0, // elf symbols entry 0 addralign
  1355. 0, 0, 0, 0, // elf symbols entry 0 entsize
  1356. 0, 0, 0, 0, // elf symbols entry 0 entsize
  1357. 1, 0, 0, 0, // elf symbols entry 1 name
  1358. 3, 0, 0, 0, // elf symbols entry 1 type
  1359. 0, 0, 0, 0, // elf symbols entry 1 flags
  1360. 0, 0, 0, 0, // elf symbols entry 1 flags
  1361. 255, 255, 255, 255, // elf symbols entry 1 addr
  1362. 255, 255, 255, 255, // elf symbols entry 1 addr
  1363. 113, 83, 1, 0, // elf symbols entry 1 offset
  1364. 0, 0, 0, 0, // elf symbols entry 1 offset
  1365. 11, 0, 0, 0, // elf symbols entry 1 size
  1366. 0, 0, 0, 0, // elf symbols entry 1 size
  1367. 0, 0, 0, 0, // elf symbols entry 1 link
  1368. 0, 0, 0, 0, // elf symbols entry 1 info
  1369. 1, 0, 0, 0, // elf symbols entry 1 addralign
  1370. 0, 0, 0, 0, // elf symbols entry 1 addralign
  1371. 0, 0, 0, 0, // elf symbols entry 1 entsize
  1372. 0, 0, 0, 0, // elf symbols entry 1 entsize
  1373. 0, 0, 0, 0, // elf symbols padding
  1374. 0, 0, 0, 0, // end tag type
  1375. 8, 0, 0, 0, // end tag size
  1376. ]);
  1377. #[repr(C, align(8))]
  1378. struct StringBytes([u8; 11]);
  1379. let string_bytes: StringBytes =
  1380. StringBytes([0, 46, 115, 104, 115, 116, 114, 116, 97, 98, 0]);
  1381. let string_addr = string_bytes.0.as_ptr() as u64;
  1382. for i in 0..8 {
  1383. let offset = 108;
  1384. assert_eq!(255, bytes.0[offset + i]);
  1385. bytes.0[offset + i] = (string_addr >> (i * 8)) as u8;
  1386. }
  1387. let addr = bytes.0.as_ptr() as usize;
  1388. let bi = unsafe { load(addr) };
  1389. let bi = bi.unwrap();
  1390. assert_eq!(addr, bi.start_address());
  1391. assert_eq!(addr + bytes.0.len(), bi.end_address());
  1392. assert_eq!(bytes.0.len(), bi.total_size());
  1393. let mut es = bi.elf_sections().unwrap();
  1394. let s1 = es.next().expect("Should have one more section");
  1395. assert_eq!(".shstrtab", s1.name().expect("Should be valid utf-8"));
  1396. assert_eq!(string_addr, s1.start_address());
  1397. assert_eq!(string_addr + string_bytes.0.len() as u64, s1.end_address());
  1398. assert_eq!(string_bytes.0.len() as u64, s1.size());
  1399. assert_eq!(ElfSectionFlags::empty(), s1.flags());
  1400. assert_eq!(ElfSectionType::StringTable, s1.section_type());
  1401. assert!(es.next().is_none());
  1402. }
  1403. #[test]
  1404. fn efi_memory_map() {
  1405. use memory_map::EFIMemoryAreaType;
  1406. #[repr(C, align(8))]
  1407. struct Bytes([u8; 72]);
  1408. // test that the EFI memory map is detected.
  1409. let bytes: Bytes = Bytes([
  1410. 72, 0, 0, 0, // size
  1411. 0, 0, 0, 0, // reserved
  1412. 17, 0, 0, 0, // EFI memory map type
  1413. 56, 0, 0, 0, // EFI memory map size
  1414. 48, 0, 0, 0, // EFI descriptor size
  1415. 1, 0, 0, 0, // EFI descriptor version, don't think this matters.
  1416. 7, 0, 0, 0, // Type: EfiConventionalMemory
  1417. 0, 0, 0, 0, // Padding
  1418. 0, 0, 16, 0, // Physical Address: should be 0x100000
  1419. 0, 0, 0, 0, // Extension of physical address.
  1420. 0, 0, 16, 0, // Virtual Address: should be 0x100000
  1421. 0, 0, 0, 0, // Extension of virtual address.
  1422. 4, 0, 0, 0, // 4 KiB Pages: 16 KiB
  1423. 0, 0, 0, 0, // Extension of pages
  1424. 0, 0, 0, 0, // Attributes of this memory range.
  1425. 0, 0, 0, 0, // Extension of attributes
  1426. 0, 0, 0, 0, // end tag type.
  1427. 8, 0, 0, 0, // end tag size.
  1428. ]);
  1429. let addr = bytes.0.as_ptr() as usize;
  1430. let bi = unsafe { load(addr) };
  1431. let bi = bi.unwrap();
  1432. assert_eq!(addr, bi.start_address());
  1433. assert_eq!(addr + bytes.0.len(), bi.end_address());
  1434. assert_eq!(bytes.0.len(), bi.total_size());
  1435. let efi_memory_map = bi.efi_memory_map_tag().unwrap();
  1436. let mut efi_mmap_iter = efi_memory_map.memory_areas();
  1437. let desc = efi_mmap_iter.next().unwrap();
  1438. assert_eq!(desc.physical_address(), 0x100000);
  1439. assert_eq!(desc.size(), 16384);
  1440. assert_eq!(desc.typ(), EFIMemoryAreaType::EfiConventionalMemory);
  1441. // test that the EFI memory map is not detected if the boot services
  1442. // are not exited.
  1443. struct Bytes2([u8; 80]);
  1444. let bytes2: Bytes2 = Bytes2([
  1445. 80, 0, 0, 0, // size
  1446. 0, 0, 0, 0, // reserved
  1447. 17, 0, 0, 0, // EFI memory map type
  1448. 56, 0, 0, 0, // EFI memory map size
  1449. 48, 0, 0, 0, // EFI descriptor size
  1450. 1, 0, 0, 0, // EFI descriptor version, don't think this matters.
  1451. 7, 0, 0, 0, // Type: EfiConventionalMemory
  1452. 0, 0, 0, 0, // Padding
  1453. 0, 0, 16, 0, // Physical Address: should be 0x100000
  1454. 0, 0, 0, 0, // Extension of physical address.
  1455. 0, 0, 16, 0, // Virtual Address: should be 0x100000
  1456. 0, 0, 0, 0, // Extension of virtual address.
  1457. 4, 0, 0, 0, // 4 KiB Pages: 16 KiB
  1458. 0, 0, 0, 0, // Extension of pages
  1459. 0, 0, 0, 0, // Attributes of this memory range.
  1460. 0, 0, 0, 0, // Extension of attributes
  1461. 18, 0, 0, 0, // Tag ExitBootServices not terminated.
  1462. 8, 0, 0, 0, // Tag ExitBootServices size.
  1463. 0, 0, 0, 0, // end tag type.
  1464. 8, 0, 0, 0, // end tag size.
  1465. ]);
  1466. let bi = unsafe { load(bytes2.0.as_ptr() as usize) };
  1467. let bi = bi.unwrap();
  1468. let efi_mmap = bi.efi_memory_map_tag();
  1469. assert!(efi_mmap.is_none());
  1470. }
  1471. #[test]
  1472. #[cfg(feature = "unstable")]
  1473. /// This test succeeds if it compiles.
  1474. fn mbi_load_error_implements_error() {
  1475. fn consumer<E: core::error::Error>(_e: E) {}
  1476. consumer(MbiLoadError::IllegalAddress)
  1477. }
  1478. /// Example for a custom tag.
  1479. #[test]
  1480. fn get_custom_tag_from_mbi() {
  1481. const CUSTOM_TAG_ID: u32 = 0x1337;
  1482. #[repr(C, align(8))]
  1483. struct CustomTag {
  1484. tag: TagTypeId,
  1485. size: u32,
  1486. foo: u32,
  1487. }
  1488. #[repr(C, align(8))]
  1489. struct AlignedBytes([u8; 32]);
  1490. // Raw bytes of a MBI that only contains the custom tag.
  1491. let bytes: AlignedBytes = AlignedBytes([
  1492. 32,
  1493. 0,
  1494. 0,
  1495. 0, // end: total size
  1496. 0,
  1497. 0,
  1498. 0,
  1499. 0, // end: padding; end of multiboot2 boot information begin
  1500. CUSTOM_TAG_ID.to_ne_bytes()[0],
  1501. CUSTOM_TAG_ID.to_ne_bytes()[1],
  1502. CUSTOM_TAG_ID.to_ne_bytes()[2],
  1503. CUSTOM_TAG_ID.to_ne_bytes()[3], // end: my custom tag id
  1504. 12,
  1505. 0,
  1506. 0,
  1507. 0, // end: tag size
  1508. 42,
  1509. 0,
  1510. 0,
  1511. 0,
  1512. 0,
  1513. 0,
  1514. 0,
  1515. 0, // 8 byte padding
  1516. 0,
  1517. 0,
  1518. 0,
  1519. 0, // end: end tag type
  1520. 8,
  1521. 0,
  1522. 0,
  1523. 0, // end: end tag size
  1524. ]);
  1525. let addr = bytes.0.as_ptr() as usize;
  1526. let bi = unsafe { load(addr) };
  1527. let bi = bi.unwrap();
  1528. assert_eq!(addr, bi.start_address());
  1529. assert_eq!(addr + bytes.0.len(), bi.end_address());
  1530. assert_eq!(bytes.0.len(), bi.total_size());
  1531. let tag = bi.get_tag::<CustomTag, _>(CUSTOM_TAG_ID).unwrap();
  1532. assert_eq!(tag.foo, 42);
  1533. }
  1534. /// Example for a custom DST tag.
  1535. #[test]
  1536. fn get_custom_dst_tag_from_mbi() {
  1537. const CUSTOM_TAG_ID: u32 = 0x1337;
  1538. #[repr(C, align(8))]
  1539. #[derive(crate::Pointee)]
  1540. struct CustomTag {
  1541. tag: TagTypeId,
  1542. size: u32,
  1543. name: [u8],
  1544. }
  1545. impl CustomTag {
  1546. fn name(&self) -> Result<&str, Utf8Error> {
  1547. Tag::get_dst_str_slice(&self.name)
  1548. }
  1549. }
  1550. impl TagTrait for CustomTag {
  1551. fn dst_size(base_tag: &Tag) -> usize {
  1552. // The size of the sized portion of the command line tag.
  1553. let tag_base_size = 8;
  1554. assert!(base_tag.size >= 8);
  1555. base_tag.size as usize - tag_base_size
  1556. }
  1557. }
  1558. #[repr(C, align(8))]
  1559. struct AlignedBytes([u8; 32]);
  1560. // Raw bytes of a MBI that only contains the custom tag.
  1561. let bytes: AlignedBytes = AlignedBytes([
  1562. 32,
  1563. 0,
  1564. 0,
  1565. 0, // end: total size
  1566. 0,
  1567. 0,
  1568. 0,
  1569. 0, // end: padding; end of multiboot2 boot information begin
  1570. CUSTOM_TAG_ID.to_ne_bytes()[0],
  1571. CUSTOM_TAG_ID.to_ne_bytes()[1],
  1572. CUSTOM_TAG_ID.to_ne_bytes()[2],
  1573. CUSTOM_TAG_ID.to_ne_bytes()[3], // end: my custom tag id
  1574. 14,
  1575. 0,
  1576. 0,
  1577. 0, // end: tag size
  1578. b'h',
  1579. b'e',
  1580. b'l',
  1581. b'l',
  1582. b'o',
  1583. b'\0',
  1584. 0,
  1585. 0, // 2 byte padding
  1586. 0,
  1587. 0,
  1588. 0,
  1589. 0, // end: end tag type
  1590. 8,
  1591. 0,
  1592. 0,
  1593. 0, // end: end tag size
  1594. ]);
  1595. let addr = bytes.0.as_ptr() as usize;
  1596. let bi = unsafe { load(addr) };
  1597. let bi = bi.unwrap();
  1598. assert_eq!(addr, bi.start_address());
  1599. assert_eq!(addr + bytes.0.len(), bi.end_address());
  1600. assert_eq!(bytes.0.len(), bi.total_size());
  1601. let tag = bi.get_tag::<CustomTag, _>(CUSTOM_TAG_ID).unwrap();
  1602. assert_eq!(tag.name(), Ok("hello"));
  1603. }
  1604. /// Tests that `get_tag` can consume multiple types that implement `Into<TagTypeId>`
  1605. #[test]
  1606. fn get_tag_into_variants() {
  1607. #[repr(C, align(8))]
  1608. struct Bytes([u8; 32]);
  1609. let bytes: Bytes = Bytes([
  1610. 32,
  1611. 0,
  1612. 0,
  1613. 0, // total_size
  1614. 0,
  1615. 0,
  1616. 0,
  1617. 0, // reserved
  1618. TagType::Cmdline.val().to_ne_bytes()[0],
  1619. TagType::Cmdline.val().to_ne_bytes()[1],
  1620. TagType::Cmdline.val().to_ne_bytes()[2],
  1621. TagType::Cmdline.val().to_ne_bytes()[3],
  1622. 13,
  1623. 0,
  1624. 0,
  1625. 0, // tag size
  1626. 110,
  1627. 97,
  1628. 109,
  1629. 101, // ASCII string 'name'
  1630. 0,
  1631. 0,
  1632. 0,
  1633. 0, // null byte + padding
  1634. 0,
  1635. 0,
  1636. 0,
  1637. 0, // end tag type
  1638. 8,
  1639. 0,
  1640. 0,
  1641. 0, // end tag size
  1642. ]);
  1643. let addr = bytes.0.as_ptr() as usize;
  1644. let bi = unsafe { load(addr) };
  1645. let bi = bi.unwrap();
  1646. let _tag = bi.get_tag::<CommandLineTag, _>(TagType::Cmdline).unwrap();
  1647. let _tag = bi.get_tag::<CommandLineTag, _>(1).unwrap();
  1648. let _tag = bi.get_tag::<CommandLineTag, _>(TagTypeId::new(1)).unwrap();
  1649. }
  1650. }