multiboot2.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. use core::hint::spin_loop;
  2. use acpi::rsdp::Rsdp;
  3. use alloc::string::{String, ToString};
  4. use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType, RsdpV1Tag};
  5. use system_error::SystemError;
  6. use crate::{
  7. arch::mm::x86_64_set_kernel_load_base_paddr,
  8. driver::{
  9. serial::serial8250::send_to_default_serial8250_port,
  10. video::fbdev::{
  11. base::{BootTimeScreenInfo, BootTimeVideoType},
  12. vesafb::vesafb_early_map,
  13. },
  14. },
  15. init::{
  16. boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg},
  17. boot_params,
  18. },
  19. libs::lazy_init::Lazy,
  20. mm::{memblock::mem_block_manager, PhysAddr},
  21. };
  22. pub(super) const MULTIBOOT2_ENTRY_MAGIC: u32 = multiboot2::MAGIC;
  23. static MB2_INFO: Lazy<BootInformation> = Lazy::new();
  24. const MB2_RAW_INFO_MAX_SIZE: usize = 4096;
  25. static mut MB2_RAW_INFO: [u8; MB2_RAW_INFO_MAX_SIZE] = [0u8; MB2_RAW_INFO_MAX_SIZE];
  26. fn mb2_rsdp_v1_tag_to_rsdp_struct(tag: &RsdpV1Tag) -> Rsdp {
  27. Rsdp {
  28. signature: tag.signature,
  29. checksum: tag.checksum,
  30. oem_id: tag.oem_id,
  31. revision: tag.revision,
  32. rsdt_address: tag.rsdt_address,
  33. length: 0,
  34. xsdt_address: 0,
  35. ext_checksum: 0,
  36. reserved: [0u8; 3],
  37. }
  38. }
  39. fn mb2_rsdp_v2_tag_to_rsdp_struct(tag: &multiboot2::RsdpV2Tag) -> Rsdp {
  40. Rsdp {
  41. signature: tag.signature,
  42. checksum: tag.checksum,
  43. oem_id: tag.oem_id,
  44. revision: tag.revision,
  45. rsdt_address: tag.rsdt_address,
  46. length: tag.length,
  47. xsdt_address: tag.xsdt_address,
  48. ext_checksum: tag.ext_checksum,
  49. reserved: tag._reserved,
  50. }
  51. }
  52. struct Mb2Callback;
  53. impl BootCallbacks for Mb2Callback {
  54. fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
  55. let name = MB2_INFO
  56. .get()
  57. .boot_loader_name_tag()
  58. .expect("MB2: Bootloader name tag not found!")
  59. .name()
  60. .expect("Failed to parse bootloader name!")
  61. .to_string();
  62. Ok(Some(name))
  63. }
  64. fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
  65. if let Some(v1_tag) = MB2_INFO.get().rsdp_v1_tag() {
  66. Ok(BootloaderAcpiArg::Rsdt(mb2_rsdp_v1_tag_to_rsdp_struct(
  67. v1_tag,
  68. )))
  69. } else if let Some(v2_tag) = MB2_INFO.get().rsdp_v2_tag() {
  70. Ok(BootloaderAcpiArg::Xsdt(mb2_rsdp_v2_tag_to_rsdp_struct(
  71. v2_tag,
  72. )))
  73. } else {
  74. Ok(BootloaderAcpiArg::NotProvided)
  75. }
  76. }
  77. fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
  78. let cmdline = MB2_INFO
  79. .get()
  80. .command_line_tag()
  81. .expect("Mb2: Command line tag not found!")
  82. .cmdline()
  83. .expect("Mb2: Failed to parse command line!");
  84. boot_params()
  85. .write_irqsave()
  86. .boot_cmdline_append(cmdline.as_bytes());
  87. Ok(())
  88. }
  89. fn early_init_framebuffer_info(
  90. &self,
  91. scinfo: &mut BootTimeScreenInfo,
  92. ) -> Result<(), SystemError> {
  93. let Some(Ok(fb_tag)) = MB2_INFO.get().framebuffer_tag() else {
  94. return Err(SystemError::ENODEV);
  95. };
  96. let width = fb_tag.width();
  97. let height = fb_tag.height();
  98. scinfo.is_vga = true;
  99. scinfo.lfb_base = PhysAddr::new(fb_tag.address() as usize);
  100. let fb_type = fb_tag.buffer_type().unwrap();
  101. match fb_type {
  102. multiboot2::FramebufferType::Indexed { palette: _ } => todo!(),
  103. multiboot2::FramebufferType::RGB { red, green, blue } => {
  104. scinfo.lfb_width = width;
  105. scinfo.lfb_height = height;
  106. scinfo.video_type = BootTimeVideoType::Vlfb;
  107. scinfo.lfb_depth = fb_tag.bpp();
  108. scinfo.red_pos = red.position;
  109. scinfo.red_size = red.size;
  110. scinfo.green_pos = green.position;
  111. scinfo.green_size = green.size;
  112. scinfo.blue_pos = blue.position;
  113. scinfo.blue_size = blue.size;
  114. }
  115. multiboot2::FramebufferType::Text => {
  116. scinfo.origin_video_cols = width as u8;
  117. scinfo.origin_video_lines = height as u8;
  118. scinfo.video_type = BootTimeVideoType::Mda;
  119. scinfo.lfb_depth = 8;
  120. }
  121. };
  122. scinfo.lfb_size = (width * height * (scinfo.lfb_depth as u32).div_ceil(8)) as usize;
  123. scinfo.lfb_virt_base = Some(vesafb_early_map(scinfo.lfb_base, scinfo.lfb_size)?);
  124. return Ok(());
  125. }
  126. fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
  127. let mb2_info = MB2_INFO.get();
  128. send_to_default_serial8250_port("init_memory_area_from_multiboot2\n\0".as_bytes());
  129. let mem_regions_tag = mb2_info
  130. .memory_map_tag()
  131. .expect("MB2: Memory map tag not found!");
  132. let mut total_mem_size = 0usize;
  133. let mut usable_mem_size = 0usize;
  134. for region in mem_regions_tag.memory_areas() {
  135. let start = PhysAddr::new(region.start_address() as usize);
  136. let size = region.size() as usize;
  137. let area_typ = MemoryAreaType::from(region.typ());
  138. total_mem_size += size;
  139. match area_typ {
  140. MemoryAreaType::Available => {
  141. usable_mem_size += size;
  142. mem_block_manager()
  143. .add_block(start, size)
  144. .unwrap_or_else(|e| {
  145. log::warn!(
  146. "Failed to add memory block: base={:?}, size={:#x}, error={:?}",
  147. start,
  148. size,
  149. e
  150. );
  151. });
  152. }
  153. _ => {
  154. mem_block_manager()
  155. .reserve_block(start, size)
  156. .unwrap_or_else(|e| {
  157. log::warn!(
  158. "Failed to reserve memory block: base={:?}, size={:#x}, error={:?}",
  159. start,
  160. size,
  161. e
  162. );
  163. });
  164. }
  165. }
  166. }
  167. send_to_default_serial8250_port("init_memory_area_from_multiboot2 end\n\0".as_bytes());
  168. log::info!(
  169. "Total memory size: {:#x}, Usable memory size: {:#x}",
  170. total_mem_size,
  171. usable_mem_size
  172. );
  173. // Add the boot module region since Grub does not specify it.
  174. let mb2_module_tag = mb2_info.module_tags();
  175. for module in mb2_module_tag {
  176. let start = PhysAddr::new(module.start_address() as usize);
  177. let size = module.module_size() as usize;
  178. mem_block_manager()
  179. .reserve_block(start, size)
  180. .unwrap_or_else(|e| {
  181. log::warn!(
  182. "Failed to reserve memory block for mb2 modules: base={:?}, size={:#x}, error={:?}",
  183. start,
  184. size,
  185. e
  186. );
  187. });
  188. }
  189. // setup kernel load base
  190. self.setup_kernel_load_base();
  191. Ok(())
  192. }
  193. }
  194. impl Mb2Callback {
  195. fn setup_kernel_load_base(&self) {
  196. let mb2_info = MB2_INFO.get();
  197. let kernel_start = mb2_info
  198. .load_base_addr_tag()
  199. .expect("MB2: Load base address tag not found!")
  200. .load_base_addr();
  201. let loadbase = PhysAddr::new(kernel_start as usize);
  202. x86_64_set_kernel_load_base_paddr(loadbase);
  203. }
  204. }
  205. pub(super) fn early_multiboot2_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError> {
  206. assert_eq!(boot_magic, MULTIBOOT2_ENTRY_MAGIC);
  207. let bi_ptr = boot_info as usize as *const BootInformationHeader;
  208. let bi_size = unsafe { (*bi_ptr).total_size() as usize };
  209. assert!(bi_size <= MB2_RAW_INFO_MAX_SIZE);
  210. unsafe {
  211. core::ptr::copy_nonoverlapping(bi_ptr as *const u8, MB2_RAW_INFO.as_mut_ptr(), bi_size);
  212. }
  213. let boot_info =
  214. unsafe { BootInformation::load(MB2_RAW_INFO.as_mut_ptr() as *const BootInformationHeader) }
  215. .inspect_err(|_| loop {
  216. spin_loop();
  217. })
  218. .unwrap();
  219. MB2_INFO.init(boot_info);
  220. register_boot_callbacks(&Mb2Callback);
  221. return Ok(());
  222. }