multiboot.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. use core::ffi::CStr;
  2. use alloc::string::{String, ToString};
  3. use multiboot::MultibootInfo;
  4. use system_error::SystemError;
  5. use crate::{
  6. arch::MMArch,
  7. driver::{
  8. serial::serial8250::send_to_default_serial8250_port,
  9. video::fbdev::{
  10. base::{BootTimeScreenInfo, BootTimeVideoType},
  11. vesafb::vesafb_early_map,
  12. },
  13. },
  14. init::{
  15. boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg},
  16. boot_params,
  17. },
  18. libs::lazy_init::Lazy,
  19. mm::{memblock::mem_block_manager, MemoryManagementArch, PhysAddr},
  20. };
  21. static MB1_INFO: Lazy<MultibootInfo> = Lazy::new();
  22. struct Mb1Ops;
  23. impl multiboot::MultibootOps for Mb1Ops {
  24. fn phys_2_virt(&self, paddr: usize) -> usize {
  25. unsafe { MMArch::phys_2_virt(PhysAddr::new(paddr)).unwrap().data() }
  26. }
  27. }
  28. struct Mb1Callback;
  29. impl BootCallbacks for Mb1Callback {
  30. fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
  31. let info = MB1_INFO.get();
  32. if info.boot_loader_name != 0 {
  33. // SAFETY: the bootloader name is C-style zero-terminated string.
  34. unsafe {
  35. let cstr_ptr =
  36. MMArch::phys_2_virt(PhysAddr::new(info.boot_loader_name as usize)).unwrap();
  37. let cstr = CStr::from_ptr(cstr_ptr.data() as *const i8);
  38. let result = cstr.to_str().unwrap_or("unknown").to_string();
  39. return Ok(Some(result));
  40. }
  41. }
  42. Ok(None)
  43. }
  44. fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
  45. // MB1不提供rsdp信息。因此,将来需要让内核支持从UEFI获取RSDP表。
  46. Ok(BootloaderAcpiArg::NotProvided)
  47. }
  48. fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
  49. let info = MB1_INFO.get();
  50. if !info.has_cmdline() {
  51. log::debug!("No kernel command line found in multiboot1 info");
  52. return Ok(());
  53. }
  54. if let Some(cmdline) = unsafe { info.cmdline(&Mb1Ops) } {
  55. let mut guard = boot_params().write_irqsave();
  56. guard.boot_cmdline_append(cmdline.as_bytes());
  57. log::info!("Kernel command line: {}\n", cmdline);
  58. }
  59. Ok(())
  60. }
  61. fn early_init_framebuffer_info(
  62. &self,
  63. scinfo: &mut BootTimeScreenInfo,
  64. ) -> Result<(), SystemError> {
  65. let info = MB1_INFO.get();
  66. let fb_table = info.framebuffer_table;
  67. let width = fb_table.width;
  68. let height = fb_table.height;
  69. scinfo.is_vga = true;
  70. scinfo.lfb_base = PhysAddr::new(fb_table.paddr as usize);
  71. let fb_type = fb_table.color_info().unwrap();
  72. match fb_type {
  73. multiboot::ColorInfoType::Palette(_) => todo!(),
  74. multiboot::ColorInfoType::Rgb(rgb) => {
  75. scinfo.lfb_width = width;
  76. scinfo.lfb_height = height;
  77. scinfo.video_type = BootTimeVideoType::Vlfb;
  78. scinfo.lfb_depth = fb_table.bpp;
  79. scinfo.red_pos = rgb.red_field_position;
  80. scinfo.red_size = rgb.red_mask_size;
  81. scinfo.green_pos = rgb.green_field_position;
  82. scinfo.green_size = rgb.green_mask_size;
  83. scinfo.blue_pos = rgb.blue_field_position;
  84. scinfo.blue_size = rgb.blue_mask_size;
  85. }
  86. multiboot::ColorInfoType::Text => {
  87. scinfo.origin_video_cols = width as u8;
  88. scinfo.origin_video_lines = height as u8;
  89. scinfo.video_type = BootTimeVideoType::Mda;
  90. scinfo.lfb_depth = 8;
  91. }
  92. }
  93. scinfo.lfb_size = (width * height * ((scinfo.lfb_depth as u32 + 7) / 8)) as usize;
  94. scinfo.lfb_virt_base = Some(vesafb_early_map(scinfo.lfb_base, scinfo.lfb_size)?);
  95. return Ok(());
  96. }
  97. fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
  98. let info = MB1_INFO.get();
  99. let mut total_mem_size = 0usize;
  100. let mut usable_mem_size = 0usize;
  101. for entry in unsafe { info.memory_map(&Mb1Ops) } {
  102. let start = PhysAddr::new(entry.base_addr() as usize);
  103. let size = entry.length() as usize;
  104. let area_typ = entry.memory_type();
  105. total_mem_size += size;
  106. match area_typ {
  107. multiboot::MemoryType::Available => {
  108. usable_mem_size += size;
  109. mem_block_manager()
  110. .add_block(start, size)
  111. .unwrap_or_else(|e| {
  112. log::warn!(
  113. "Failed to add memory block: base={:?}, size={:#x}, error={:?}",
  114. start,
  115. size,
  116. e
  117. );
  118. });
  119. }
  120. _ => {
  121. mem_block_manager()
  122. .reserve_block(start, size)
  123. .unwrap_or_else(|e| {
  124. log::warn!(
  125. "Failed to reserve memory block: base={:?}, size={:#x}, error={:?}",
  126. start,
  127. size,
  128. e
  129. );
  130. });
  131. }
  132. }
  133. }
  134. send_to_default_serial8250_port("init_memory_area_from_multiboot1 end\n\0".as_bytes());
  135. log::info!(
  136. "Total memory size: {:#x}, Usable memory size: {:#x}",
  137. total_mem_size,
  138. usable_mem_size
  139. );
  140. if let Some(modules_iter) = unsafe { info.modules(&Mb1Ops) } {
  141. for m in modules_iter {
  142. let base = PhysAddr::new(m.start() as usize);
  143. let size = m.end() as usize - m.start() as usize;
  144. mem_block_manager()
  145. .reserve_block(base, size)
  146. .unwrap_or_else(|e| {
  147. log::warn!(
  148. "Failed to reserve modules memory block: base={:?}, size={:#x}, error={:?}",
  149. base,
  150. size,
  151. e
  152. );
  153. });
  154. }
  155. }
  156. Ok(())
  157. }
  158. }
  159. pub(super) fn early_multiboot_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError> {
  160. assert_eq!(boot_magic, multiboot::MAGIC);
  161. let boot_info = unsafe { MMArch::phys_2_virt(PhysAddr::new(boot_info as usize)).unwrap() };
  162. let mb1_info = unsafe { (boot_info.data() as *const MultibootInfo).as_ref().unwrap() };
  163. MB1_INFO.init(*mb1_info);
  164. register_boot_callbacks(&Mb1Callback);
  165. Ok(())
  166. }