lib.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. //! Multiboot v1 library
  2. //!
  3. //! This crate is partitially modified from `https://github.com/gz/rust-multiboot` && asterinas
  4. //!
  5. //! The main structs to interact with are [`Multiboot`] for the Multiboot information
  6. //! passed from the bootloader to the kernel at runtime and [`Header`] for the static
  7. //! information passed from the kernel to the bootloader in the kernel image.
  8. //!
  9. //!
  10. //! # Additional documentation
  11. //! * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
  12. //! * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
  13. //!
  14. //! [`Multiboot`]: information/struct.Multiboot.html
  15. //! [`Header`]: header/struct.Header.html
  16. #![no_std]
  17. use core::ffi::CStr;
  18. pub const MAGIC: u32 = 0x2BADB002;
  19. /// The ‘boot_device’ field.
  20. ///
  21. /// Partition numbers always start from zero. Unused partition
  22. /// bytes must be set to 0xFF. For example, if the disk is partitioned
  23. /// using a simple one-level DOS partitioning scheme, then
  24. /// ‘part’ contains the DOS partition number, and ‘part2’ and ‘part3’
  25. /// are both 0xFF. As another example, if a disk is partitioned first into
  26. /// DOS partitions, and then one of those DOS partitions is subdivided
  27. /// into several BSD partitions using BSD's disklabel strategy, then ‘part1’
  28. /// contains the DOS partition number, ‘part2’ contains the BSD sub-partition
  29. /// within that DOS partition, and ‘part3’ is 0xFF.
  30. ///
  31. #[derive(Debug, Clone, Copy)]
  32. #[repr(C)]
  33. pub struct BootDevice {
  34. /// Contains the bios drive number as understood by
  35. /// the bios INT 0x13 low-level disk interface: e.g. 0x00 for the
  36. /// first floppy disk or 0x80 for the first hard disk.
  37. pub drive: u8,
  38. /// Specifies the top-level partition number.
  39. pub partition1: u8,
  40. /// Specifies a sub-partition in the top-level partition
  41. pub partition2: u8,
  42. /// Specifies a sub-partition in the 2nd-level partition
  43. pub partition3: u8,
  44. }
  45. impl BootDevice {
  46. /// Is partition1 a valid partition?
  47. pub fn partition1_is_valid(&self) -> bool {
  48. self.partition1 != 0xff
  49. }
  50. /// Is partition2 a valid partition?
  51. pub fn partition2_is_valid(&self) -> bool {
  52. self.partition2 != 0xff
  53. }
  54. /// Is partition3 a valid partition?
  55. pub fn partition3_is_valid(&self) -> bool {
  56. self.partition3 != 0xff
  57. }
  58. }
  59. impl Default for BootDevice {
  60. fn default() -> Self {
  61. Self {
  62. drive: 0xff,
  63. partition1: 0xff,
  64. partition2: 0xff,
  65. partition3: 0xff,
  66. }
  67. }
  68. }
  69. /// Representation of Multiboot Information according to specification.
  70. ///
  71. /// Reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
  72. ///
  73. ///```text
  74. /// +-------------------+
  75. /// 0 | flags | (required)
  76. /// +-------------------+
  77. /// 4 | mem_lower | (present if flags[0] is set)
  78. /// 8 | mem_upper | (present if flags[0] is set)
  79. /// +-------------------+
  80. /// 12 | boot_device | (present if flags[1] is set)
  81. /// +-------------------+
  82. /// 16 | cmdline | (present if flags[2] is set)
  83. /// +-------------------+
  84. /// 20 | mods_count | (present if flags[3] is set)
  85. /// 24 | mods_addr | (present if flags[3] is set)
  86. /// +-------------------+
  87. /// 28 - 40 | syms | (present if flags[4] or
  88. /// | | flags[5] is set)
  89. /// +-------------------+
  90. /// 44 | mmap_length | (present if flags[6] is set)
  91. /// 48 | mmap_addr | (present if flags[6] is set)
  92. /// +-------------------+
  93. /// 52 | drives_length | (present if flags[7] is set)
  94. /// 56 | drives_addr | (present if flags[7] is set)
  95. /// +-------------------+
  96. /// 60 | config_table | (present if flags[8] is set)
  97. /// +-------------------+
  98. /// 64 | boot_loader_name | (present if flags[9] is set)
  99. /// +-------------------+
  100. /// 68 | apm_table | (present if flags[10] is set)
  101. /// +-------------------+
  102. /// 72 | vbe_control_info | (present if flags[11] is set)
  103. /// 76 | vbe_mode_info |
  104. /// 80 | vbe_mode |
  105. /// 82 | vbe_interface_seg |
  106. /// 84 | vbe_interface_off |
  107. /// 86 | vbe_interface_len |
  108. /// +-------------------+
  109. /// 88 | framebuffer_addr | (present if flags[12] is set)
  110. /// 96 | framebuffer_pitch |
  111. /// 100 | framebuffer_width |
  112. /// 104 | framebuffer_height|
  113. /// 108 | framebuffer_bpp |
  114. /// 109 | framebuffer_type |
  115. /// 110-115 | color_info |
  116. /// +-------------------+
  117. ///```
  118. ///
  119. #[allow(dead_code)]
  120. #[derive(Debug, Copy, Clone)]
  121. #[repr(C, packed)]
  122. pub struct MultibootInfo {
  123. /// Indicate whether the below field exists.
  124. flags: u32,
  125. /// Physical memory low.
  126. mem_lower: u32,
  127. /// Physical memory high.
  128. mem_upper: u32,
  129. /// Indicates which BIOS disk device the boot loader loaded the OS image from.
  130. boot_device: BootDevice,
  131. /// Command line passed to kernel.
  132. cmdline: u32,
  133. /// Modules count.
  134. pub mods_count: u32,
  135. /// The start address of modules list, each module structure format:
  136. /// ```text
  137. /// +-------------------+
  138. /// 0 | mod_start |
  139. /// 4 | mod_end |
  140. /// +-------------------+
  141. /// 8 | string |
  142. /// +-------------------+
  143. /// 12 | reserved (0) |
  144. /// +-------------------+
  145. /// ```
  146. mods_paddr: u32,
  147. /// If flags[4] = 1, then the field starting at byte 28 are valid:
  148. /// ```text
  149. /// +-------------------+
  150. /// 28 | tabsize |
  151. /// 32 | strsize |
  152. /// 36 | addr |
  153. /// 40 | reserved (0) |
  154. /// +-------------------+
  155. /// ```
  156. /// These indicate where the symbol table from kernel image can be found.
  157. ///
  158. /// If flags[5] = 1, then the field starting at byte 28 are valid:
  159. /// ```text
  160. /// +-------------------+
  161. /// 28 | num |
  162. /// 32 | size |
  163. /// 36 | addr |
  164. /// 40 | shndx |
  165. /// +-------------------+
  166. /// ```
  167. /// These indicate where the section header table from an ELF kernel is,
  168. /// the size of each entry, number of entries, and the string table used as the index of names.
  169. symbols: [u8; 16],
  170. memory_map_len: u32,
  171. memory_map_paddr: u32,
  172. drives_length: u32,
  173. drives_addr: u32,
  174. config_table: u32,
  175. /// bootloader name paddr
  176. pub boot_loader_name: u32,
  177. apm_table: u32,
  178. vbe_table: VbeInfo,
  179. pub framebuffer_table: FramebufferTable,
  180. }
  181. impl MultibootInfo {
  182. /// If true, then the `mem_upper` and `mem_lower` fields are valid.
  183. pub const FLAG_MEMORY_BOUNDS: u32 = 1 << 0;
  184. /// If true, then the `boot_device` field is valid.
  185. pub const FLAG_BOOT_DEVICE: u32 = 1 << 1;
  186. /// If true, then the `cmdline` field is valid.
  187. pub const FLAG_CMDLINE: u32 = 1 << 2;
  188. /// If true, then the `mods_count` and `mods_addr` fields are valid.
  189. pub const FLAG_MODULES: u32 = 1 << 3;
  190. /// If true, then the `symbols` field is valid.
  191. pub const FLAG_SYMBOLS: u32 = 1 << 4;
  192. pub unsafe fn memory_map(&self, ops: &'static dyn MultibootOps) -> MemoryEntryIter {
  193. let mmap_addr = ops.phys_2_virt(self.memory_map_paddr as usize);
  194. let mmap_len = self.memory_map_len as usize;
  195. MemoryEntryIter {
  196. cur_ptr: mmap_addr,
  197. region_end_vaddr: mmap_addr + mmap_len,
  198. }
  199. }
  200. pub unsafe fn modules(&self, ops: &'static dyn MultibootOps) -> Option<ModulesIter> {
  201. if !self.has_modules() {
  202. return None;
  203. }
  204. let mods_addr = ops.phys_2_virt(self.mods_paddr as usize);
  205. let end = mods_addr + (self.mods_count as usize) * core::mem::size_of::<MBModule>();
  206. Some(ModulesIter {
  207. cur_ptr: mods_addr,
  208. region_end_vaddr: end,
  209. })
  210. }
  211. pub unsafe fn cmdline(&self, ops: &'static dyn MultibootOps) -> Option<&str> {
  212. if !self.has_cmdline() {
  213. return None;
  214. }
  215. let cmdline_vaddr = ops.phys_2_virt(self.cmdline as usize);
  216. let cstr = CStr::from_ptr(cmdline_vaddr as *const i8);
  217. cstr.to_str().ok()
  218. }
  219. #[inline]
  220. pub fn has_memory_bounds(&self) -> bool {
  221. self.flags & Self::FLAG_MEMORY_BOUNDS != 0
  222. }
  223. #[inline]
  224. pub fn has_boot_device(&self) -> bool {
  225. self.flags & Self::FLAG_BOOT_DEVICE != 0
  226. }
  227. #[inline]
  228. pub fn has_cmdline(&self) -> bool {
  229. self.flags & Self::FLAG_CMDLINE != 0
  230. }
  231. #[inline]
  232. pub fn has_modules(&self) -> bool {
  233. self.flags & Self::FLAG_MODULES != 0
  234. }
  235. #[inline]
  236. pub fn has_symbols(&self) -> bool {
  237. self.flags & Self::FLAG_SYMBOLS != 0
  238. }
  239. }
  240. pub trait MultibootOps {
  241. fn phys_2_virt(&self, paddr: usize) -> usize;
  242. }
  243. #[derive(Debug, Copy, Clone)]
  244. #[repr(C, packed)]
  245. pub struct VbeInfo {
  246. pub control_info: u32,
  247. pub mode_info: u32,
  248. pub mode: u16,
  249. pub interface_seg: u16,
  250. pub interface_off: u16,
  251. pub interface_len: u16,
  252. }
  253. #[derive(Debug, Copy, Clone)]
  254. #[repr(C, packed)]
  255. pub struct FramebufferTable {
  256. pub paddr: u64,
  257. pub pitch: u32,
  258. pub width: u32,
  259. pub height: u32,
  260. pub bpp: u8,
  261. pub typ: u8,
  262. color_info: ColorInfo,
  263. }
  264. impl FramebufferTable {
  265. /// Get the color info from this table.
  266. pub fn color_info(&self) -> Option<ColorInfoType> {
  267. unsafe {
  268. match self.typ {
  269. 0 => Some(ColorInfoType::Palette(self.color_info.palette)),
  270. 1 => Some(ColorInfoType::Rgb(self.color_info.rgb)),
  271. 2 => Some(ColorInfoType::Text),
  272. _ => None,
  273. }
  274. }
  275. }
  276. }
  277. /// Safe wrapper for `ColorInfo`
  278. #[derive(Debug)]
  279. pub enum ColorInfoType {
  280. Palette(ColorInfoPalette),
  281. Rgb(ColorInfoRgb),
  282. Text,
  283. }
  284. /// Multiboot format for the frambuffer color info
  285. ///
  286. /// According to the spec, if type == 0, it's indexed color and
  287. ///<rawtext>
  288. /// +----------------------------------+
  289. /// 110 | framebuffer_palette_addr |
  290. /// 114 | framebuffer_palette_num_colors |
  291. /// +----------------------------------+
  292. ///</rawtext>
  293. /// The address points to an array of `ColorDescriptor`s.
  294. /// If type == 1, it's RGB and
  295. ///<rawtext>
  296. /// +----------------------------------+
  297. ///110 | framebuffer_red_field_position |
  298. ///111 | framebuffer_red_mask_size |
  299. ///112 | framebuffer_green_field_position |
  300. ///113 | framebuffer_green_mask_size |
  301. ///114 | framebuffer_blue_field_position |
  302. ///115 | framebuffer_blue_mask_size |
  303. /// +----------------------------------+
  304. ///</rawtext>
  305. /// (If type == 2, it's just text.)
  306. #[repr(C)]
  307. #[derive(Clone, Copy)]
  308. union ColorInfo {
  309. palette: ColorInfoPalette,
  310. rgb: ColorInfoRgb,
  311. _union_align: [u32; 2usize],
  312. }
  313. impl core::fmt::Debug for ColorInfo {
  314. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  315. unsafe {
  316. f.debug_struct("ColorInfo")
  317. .field("palette", &self.palette)
  318. .field("rgb", &self.rgb)
  319. .finish()
  320. }
  321. }
  322. }
  323. // default type is 0, so indexed color
  324. impl Default for ColorInfo {
  325. fn default() -> Self {
  326. Self {
  327. palette: ColorInfoPalette {
  328. palette_addr: 0,
  329. palette_num_colors: 0,
  330. },
  331. }
  332. }
  333. }
  334. /// Information for indexed color mode
  335. #[repr(C)]
  336. #[derive(Debug, Clone, Copy)]
  337. pub struct ColorInfoPalette {
  338. palette_addr: u32,
  339. palette_num_colors: u16,
  340. }
  341. /// Information for direct RGB color mode
  342. #[repr(C)]
  343. #[derive(Debug, Clone, Copy)]
  344. pub struct ColorInfoRgb {
  345. pub red_field_position: u8,
  346. pub red_mask_size: u8,
  347. pub green_field_position: u8,
  348. pub green_mask_size: u8,
  349. pub blue_field_position: u8,
  350. pub blue_mask_size: u8,
  351. }
  352. /// Types that define if the memory is usable or not.
  353. #[derive(Debug, PartialEq, Eq)]
  354. pub enum MemoryType {
  355. /// memory, available to OS
  356. Available = 1,
  357. /// reserved, not available (rom, mem map dev)
  358. Reserved = 2,
  359. /// ACPI Reclaim Memory
  360. ACPI = 3,
  361. /// ACPI NVS Memory
  362. NVS = 4,
  363. /// defective RAM modules
  364. Defect = 5,
  365. }
  366. /// A memory entry in the memory map header info region.
  367. ///
  368. /// The memory layout of the entry structure doesn't fit in any scheme
  369. /// provided by Rust:
  370. ///
  371. /// ```text
  372. /// +-------------------+ <- start of the struct pointer
  373. /// -4 | size |
  374. /// +-------------------+
  375. /// 0 | base_addr |
  376. /// 8 | length |
  377. /// 16 | type |
  378. /// +-------------------+
  379. /// ```
  380. ///
  381. /// The start of a entry is not 64-bit aligned. Although the boot
  382. /// protocol may provide the `mmap_addr` 64-bit aligned when added with
  383. /// 4, it is not guaranteed. So we need to use pointer arithmetic to
  384. /// access the fields.
  385. pub struct MemoryEntry {
  386. ptr: usize,
  387. }
  388. impl MemoryEntry {
  389. pub fn size(&self) -> u32 {
  390. // SAFETY: the entry can only be contructed from a valid address.
  391. unsafe { (self.ptr as *const u32).read_unaligned() }
  392. }
  393. pub fn base_addr(&self) -> u64 {
  394. // SAFETY: the entry can only be contructed from a valid address.
  395. unsafe { ((self.ptr + 4) as *const u64).read_unaligned() }
  396. }
  397. pub fn length(&self) -> u64 {
  398. // SAFETY: the entry can only be contructed from a valid address.
  399. unsafe { ((self.ptr + 12) as *const u64).read_unaligned() }
  400. }
  401. pub fn memory_type(&self) -> MemoryType {
  402. let typ_val = unsafe { ((self.ptr + 20) as *const u8).read_unaligned() };
  403. // The meaning of the values are however documented clearly by the manual.
  404. match typ_val {
  405. 1 => MemoryType::Available,
  406. 2 => MemoryType::Reserved,
  407. 3 => MemoryType::ACPI,
  408. 4 => MemoryType::NVS,
  409. 5 => MemoryType::Defect,
  410. _ => MemoryType::Reserved,
  411. }
  412. }
  413. }
  414. /// A memory entry iterator in the memory map header info region.
  415. #[derive(Debug, Copy, Clone)]
  416. pub struct MemoryEntryIter {
  417. cur_ptr: usize,
  418. region_end_vaddr: usize,
  419. }
  420. impl Iterator for MemoryEntryIter {
  421. type Item = MemoryEntry;
  422. fn next(&mut self) -> Option<Self::Item> {
  423. if self.cur_ptr >= self.region_end_vaddr {
  424. return None;
  425. }
  426. let entry = MemoryEntry { ptr: self.cur_ptr };
  427. self.cur_ptr += entry.size() as usize + 4;
  428. Some(entry)
  429. }
  430. }
  431. /// Multiboot format to information about module
  432. #[repr(C)]
  433. pub struct MBModule {
  434. /// Start address of module in memory.
  435. start: u32,
  436. /// End address of module in memory.
  437. end: u32,
  438. /// The `string` field provides an arbitrary string to be associated
  439. /// with that particular boot module.
  440. ///
  441. /// It is a zero-terminated ASCII string, just like the kernel command line.
  442. /// The `string` field may be 0 if there is no string associated with the module.
  443. /// Typically the string might be a command line (e.g. if the operating system
  444. /// treats boot modules as executable programs), or a pathname
  445. /// (e.g. if the operating system treats boot modules as files in a file system),
  446. /// but its exact use is specific to the operating system.
  447. string: u32,
  448. /// Must be zero.
  449. reserved: u32,
  450. }
  451. impl MBModule {
  452. #[inline]
  453. pub fn start(&self) -> u32 {
  454. self.start
  455. }
  456. #[inline]
  457. pub fn end(&self) -> u32 {
  458. self.end
  459. }
  460. pub fn string(&self) -> u32 {
  461. self.string
  462. }
  463. pub fn reserved(&self) -> u32 {
  464. self.reserved
  465. }
  466. }
  467. impl core::fmt::Debug for MBModule {
  468. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  469. write!(
  470. f,
  471. "MBModule {{ start: {}, end: {}, string: {}, reserved: {} }}",
  472. self.start, self.end, self.string, self.reserved
  473. )
  474. }
  475. }
  476. #[derive(Debug, Copy, Clone)]
  477. pub struct ModulesIter {
  478. cur_ptr: usize,
  479. region_end_vaddr: usize,
  480. }
  481. impl Iterator for ModulesIter {
  482. type Item = MBModule;
  483. fn next(&mut self) -> Option<Self::Item> {
  484. if self.cur_ptr >= self.region_end_vaddr {
  485. return None;
  486. }
  487. let mb_module = unsafe { (self.cur_ptr as *const MBModule).read() };
  488. self.cur_ptr += core::mem::size_of::<MBModule>();
  489. Some(mb_module)
  490. }
  491. }