xref: /DragonOS/kernel/src/arch/x86_64/init/multiboot2.rs (revision db7c782a9aaacb320027167bda4f23751b8f36e1)
12b7818e8SLoGin use core::hint::spin_loop;
22b7818e8SLoGin 
32b7818e8SLoGin use acpi::rsdp::Rsdp;
42b7818e8SLoGin use alloc::string::{String, ToString};
52b7818e8SLoGin use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType, RsdpV1Tag};
62b7818e8SLoGin use system_error::SystemError;
72b7818e8SLoGin 
82b7818e8SLoGin use crate::{
92b7818e8SLoGin     arch::mm::x86_64_set_kernel_load_base_paddr,
102b7818e8SLoGin     driver::{
112b7818e8SLoGin         serial::serial8250::send_to_default_serial8250_port,
122b7818e8SLoGin         video::fbdev::{
132b7818e8SLoGin             base::{BootTimeScreenInfo, BootTimeVideoType},
142b7818e8SLoGin             vesafb::vesafb_early_map,
152b7818e8SLoGin         },
162b7818e8SLoGin     },
172b7818e8SLoGin     init::{
182b7818e8SLoGin         boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg},
192b7818e8SLoGin         boot_params,
202b7818e8SLoGin     },
212b7818e8SLoGin     libs::lazy_init::Lazy,
222b7818e8SLoGin     mm::{memblock::mem_block_manager, PhysAddr},
232b7818e8SLoGin };
242b7818e8SLoGin 
252b7818e8SLoGin pub(super) const MULTIBOOT2_ENTRY_MAGIC: u32 = multiboot2::MAGIC;
262b7818e8SLoGin static MB2_INFO: Lazy<BootInformation> = Lazy::new();
272b7818e8SLoGin const MB2_RAW_INFO_MAX_SIZE: usize = 4096;
282b7818e8SLoGin 
292b7818e8SLoGin static mut MB2_RAW_INFO: [u8; MB2_RAW_INFO_MAX_SIZE] = [0u8; MB2_RAW_INFO_MAX_SIZE];
302b7818e8SLoGin 
mb2_rsdp_v1_tag_to_rsdp_struct(tag: &RsdpV1Tag) -> Rsdp312b7818e8SLoGin fn mb2_rsdp_v1_tag_to_rsdp_struct(tag: &RsdpV1Tag) -> Rsdp {
322b7818e8SLoGin     Rsdp {
332b7818e8SLoGin         signature: tag.signature,
342b7818e8SLoGin         checksum: tag.checksum,
352b7818e8SLoGin         oem_id: tag.oem_id,
362b7818e8SLoGin         revision: tag.revision,
372b7818e8SLoGin         rsdt_address: tag.rsdt_address,
382b7818e8SLoGin         length: 0,
392b7818e8SLoGin         xsdt_address: 0,
402b7818e8SLoGin         ext_checksum: 0,
412b7818e8SLoGin         reserved: [0u8; 3],
422b7818e8SLoGin     }
432b7818e8SLoGin }
442b7818e8SLoGin 
mb2_rsdp_v2_tag_to_rsdp_struct(tag: &multiboot2::RsdpV2Tag) -> Rsdp452b7818e8SLoGin fn mb2_rsdp_v2_tag_to_rsdp_struct(tag: &multiboot2::RsdpV2Tag) -> Rsdp {
462b7818e8SLoGin     Rsdp {
472b7818e8SLoGin         signature: tag.signature,
482b7818e8SLoGin         checksum: tag.checksum,
492b7818e8SLoGin         oem_id: tag.oem_id,
502b7818e8SLoGin         revision: tag.revision,
512b7818e8SLoGin         rsdt_address: tag.rsdt_address,
522b7818e8SLoGin         length: tag.length,
532b7818e8SLoGin         xsdt_address: tag.xsdt_address,
542b7818e8SLoGin         ext_checksum: tag.ext_checksum,
552b7818e8SLoGin         reserved: tag._reserved,
562b7818e8SLoGin     }
572b7818e8SLoGin }
582b7818e8SLoGin struct Mb2Callback;
592b7818e8SLoGin 
602b7818e8SLoGin impl BootCallbacks for Mb2Callback {
init_bootloader_name(&self) -> Result<Option<String>, SystemError>612b7818e8SLoGin     fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
622b7818e8SLoGin         let name = MB2_INFO
632b7818e8SLoGin             .get()
642b7818e8SLoGin             .boot_loader_name_tag()
652b7818e8SLoGin             .expect("MB2: Bootloader name tag not found!")
662b7818e8SLoGin             .name()
672b7818e8SLoGin             .expect("Failed to parse bootloader name!")
682b7818e8SLoGin             .to_string();
692b7818e8SLoGin         Ok(Some(name))
702b7818e8SLoGin     }
712b7818e8SLoGin 
init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError>722b7818e8SLoGin     fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
732b7818e8SLoGin         if let Some(v1_tag) = MB2_INFO.get().rsdp_v1_tag() {
742b7818e8SLoGin             Ok(BootloaderAcpiArg::Rsdt(mb2_rsdp_v1_tag_to_rsdp_struct(
752b7818e8SLoGin                 v1_tag,
762b7818e8SLoGin             )))
772b7818e8SLoGin         } else if let Some(v2_tag) = MB2_INFO.get().rsdp_v2_tag() {
782b7818e8SLoGin             Ok(BootloaderAcpiArg::Xsdt(mb2_rsdp_v2_tag_to_rsdp_struct(
792b7818e8SLoGin                 v2_tag,
802b7818e8SLoGin             )))
812b7818e8SLoGin         } else {
822b7818e8SLoGin             Ok(BootloaderAcpiArg::NotProvided)
832b7818e8SLoGin         }
842b7818e8SLoGin     }
852b7818e8SLoGin 
init_kernel_cmdline(&self) -> Result<(), SystemError>862b7818e8SLoGin     fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
872b7818e8SLoGin         let cmdline = MB2_INFO
882b7818e8SLoGin             .get()
892b7818e8SLoGin             .command_line_tag()
902b7818e8SLoGin             .expect("Mb2: Command line tag not found!")
912b7818e8SLoGin             .cmdline()
922b7818e8SLoGin             .expect("Mb2: Failed to parse command line!");
932b7818e8SLoGin         boot_params()
942b7818e8SLoGin             .write_irqsave()
952b7818e8SLoGin             .boot_cmdline_append(cmdline.as_bytes());
962b7818e8SLoGin         Ok(())
972b7818e8SLoGin     }
982b7818e8SLoGin 
early_init_framebuffer_info( &self, scinfo: &mut BootTimeScreenInfo, ) -> Result<(), SystemError>992b7818e8SLoGin     fn early_init_framebuffer_info(
1002b7818e8SLoGin         &self,
1012b7818e8SLoGin         scinfo: &mut BootTimeScreenInfo,
1022b7818e8SLoGin     ) -> Result<(), SystemError> {
1032b7818e8SLoGin         let Some(Ok(fb_tag)) = MB2_INFO.get().framebuffer_tag() else {
1042b7818e8SLoGin             return Err(SystemError::ENODEV);
1052b7818e8SLoGin         };
1062b7818e8SLoGin         let width = fb_tag.width();
1072b7818e8SLoGin         let height = fb_tag.height();
1082b7818e8SLoGin         scinfo.is_vga = true;
1092b7818e8SLoGin         scinfo.lfb_base = PhysAddr::new(fb_tag.address() as usize);
1102b7818e8SLoGin 
1112b7818e8SLoGin         let fb_type = fb_tag.buffer_type().unwrap();
1122b7818e8SLoGin         match fb_type {
1132b7818e8SLoGin             multiboot2::FramebufferType::Indexed { palette: _ } => todo!(),
1142b7818e8SLoGin             multiboot2::FramebufferType::RGB { red, green, blue } => {
1152b7818e8SLoGin                 scinfo.lfb_width = width;
1162b7818e8SLoGin                 scinfo.lfb_height = height;
1172b7818e8SLoGin                 scinfo.video_type = BootTimeVideoType::Vlfb;
1182b7818e8SLoGin                 scinfo.lfb_depth = fb_tag.bpp();
1192b7818e8SLoGin                 scinfo.red_pos = red.position;
1202b7818e8SLoGin                 scinfo.red_size = red.size;
1212b7818e8SLoGin                 scinfo.green_pos = green.position;
1222b7818e8SLoGin                 scinfo.green_size = green.size;
1232b7818e8SLoGin                 scinfo.blue_pos = blue.position;
1242b7818e8SLoGin                 scinfo.blue_size = blue.size;
1252b7818e8SLoGin             }
1262b7818e8SLoGin             multiboot2::FramebufferType::Text => {
1272b7818e8SLoGin                 scinfo.origin_video_cols = width as u8;
1282b7818e8SLoGin                 scinfo.origin_video_lines = height as u8;
1292b7818e8SLoGin                 scinfo.video_type = BootTimeVideoType::Mda;
1302b7818e8SLoGin                 scinfo.lfb_depth = 8;
1312b7818e8SLoGin             }
1322b7818e8SLoGin         };
1332b7818e8SLoGin 
134*db7c782aSLoGin         scinfo.lfb_size = (width * height * ((scinfo.lfb_depth as u32 + 7) / 8)) as usize;
1352b7818e8SLoGin 
1362b7818e8SLoGin         scinfo.lfb_virt_base = Some(vesafb_early_map(scinfo.lfb_base, scinfo.lfb_size)?);
1372b7818e8SLoGin 
1382b7818e8SLoGin         return Ok(());
1392b7818e8SLoGin     }
1402b7818e8SLoGin 
early_init_memory_blocks(&self) -> Result<(), SystemError>1412b7818e8SLoGin     fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
1422b7818e8SLoGin         let mb2_info = MB2_INFO.get();
1432b7818e8SLoGin         send_to_default_serial8250_port("init_memory_area_from_multiboot2\n\0".as_bytes());
1442b7818e8SLoGin 
1452b7818e8SLoGin         let mem_regions_tag = mb2_info
1462b7818e8SLoGin             .memory_map_tag()
1472b7818e8SLoGin             .expect("MB2: Memory map tag not found!");
1482b7818e8SLoGin         let mut total_mem_size = 0usize;
1492b7818e8SLoGin         let mut usable_mem_size = 0usize;
1502b7818e8SLoGin         for region in mem_regions_tag.memory_areas() {
1512b7818e8SLoGin             let start = PhysAddr::new(region.start_address() as usize);
1522b7818e8SLoGin             let size = region.size() as usize;
1532b7818e8SLoGin             let area_typ = MemoryAreaType::from(region.typ());
1542b7818e8SLoGin             total_mem_size += size;
1552b7818e8SLoGin 
1562b7818e8SLoGin             match area_typ {
1572b7818e8SLoGin                 MemoryAreaType::Available => {
1582b7818e8SLoGin                     usable_mem_size += size;
1592b7818e8SLoGin                     mem_block_manager()
1602b7818e8SLoGin                         .add_block(start, size)
1612b7818e8SLoGin                         .unwrap_or_else(|e| {
1622b7818e8SLoGin                             log::warn!(
1632b7818e8SLoGin                                 "Failed to add memory block: base={:?}, size={:#x}, error={:?}",
1642b7818e8SLoGin                                 start,
1652b7818e8SLoGin                                 size,
1662b7818e8SLoGin                                 e
1672b7818e8SLoGin                             );
1682b7818e8SLoGin                         });
1692b7818e8SLoGin                 }
1702b7818e8SLoGin 
1712b7818e8SLoGin                 _ => {
1722b7818e8SLoGin                     mem_block_manager()
1732b7818e8SLoGin                         .reserve_block(start, size)
1742b7818e8SLoGin                         .unwrap_or_else(|e| {
1752b7818e8SLoGin                             log::warn!(
1762b7818e8SLoGin                                 "Failed to reserve memory block: base={:?}, size={:#x}, error={:?}",
1772b7818e8SLoGin                                 start,
1782b7818e8SLoGin                                 size,
1792b7818e8SLoGin                                 e
1802b7818e8SLoGin                             );
1812b7818e8SLoGin                         });
1822b7818e8SLoGin                 }
1832b7818e8SLoGin             }
1842b7818e8SLoGin         }
1852b7818e8SLoGin         send_to_default_serial8250_port("init_memory_area_from_multiboot2 end\n\0".as_bytes());
1862b7818e8SLoGin         log::info!(
1872b7818e8SLoGin             "Total memory size: {:#x}, Usable memory size: {:#x}",
1882b7818e8SLoGin             total_mem_size,
1892b7818e8SLoGin             usable_mem_size
1902b7818e8SLoGin         );
1912b7818e8SLoGin 
1922b7818e8SLoGin         // Add the boot module region since Grub does not specify it.
1932b7818e8SLoGin         let mb2_module_tag = mb2_info.module_tags();
1942b7818e8SLoGin         for module in mb2_module_tag {
1952b7818e8SLoGin             let start = PhysAddr::new(module.start_address() as usize);
1962b7818e8SLoGin             let size = module.module_size() as usize;
1972b7818e8SLoGin             mem_block_manager()
1982b7818e8SLoGin                 .reserve_block(start, size)
1992b7818e8SLoGin                 .unwrap_or_else(|e| {
2002b7818e8SLoGin                     log::warn!(
2012b7818e8SLoGin                         "Failed to reserve memory block for mb2 modules: base={:?}, size={:#x}, error={:?}",
2022b7818e8SLoGin                         start,
2032b7818e8SLoGin                         size,
2042b7818e8SLoGin                         e
2052b7818e8SLoGin                     );
2062b7818e8SLoGin                 });
2072b7818e8SLoGin         }
2082b7818e8SLoGin 
2092b7818e8SLoGin         // setup kernel load base
2102b7818e8SLoGin         self.setup_kernel_load_base();
2112b7818e8SLoGin 
2122b7818e8SLoGin         Ok(())
2132b7818e8SLoGin     }
2142b7818e8SLoGin }
2152b7818e8SLoGin 
2162b7818e8SLoGin impl Mb2Callback {
setup_kernel_load_base(&self)2172b7818e8SLoGin     fn setup_kernel_load_base(&self) {
2182b7818e8SLoGin         let mb2_info = MB2_INFO.get();
2192b7818e8SLoGin         let kernel_start = mb2_info
2202b7818e8SLoGin             .load_base_addr_tag()
2212b7818e8SLoGin             .expect("MB2: Load base address tag not found!")
2222b7818e8SLoGin             .load_base_addr();
2232b7818e8SLoGin         let loadbase = PhysAddr::new(kernel_start as usize);
2242b7818e8SLoGin         x86_64_set_kernel_load_base_paddr(loadbase);
2252b7818e8SLoGin     }
2262b7818e8SLoGin }
early_multiboot2_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError>2272b7818e8SLoGin pub(super) fn early_multiboot2_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError> {
2282b7818e8SLoGin     assert_eq!(boot_magic, MULTIBOOT2_ENTRY_MAGIC);
2292b7818e8SLoGin     let bi_ptr = boot_info as usize as *const BootInformationHeader;
2302b7818e8SLoGin     let bi_size = unsafe { (*bi_ptr).total_size() as usize };
2312b7818e8SLoGin     assert!(bi_size <= MB2_RAW_INFO_MAX_SIZE);
2322b7818e8SLoGin     unsafe {
2332b7818e8SLoGin         core::ptr::copy_nonoverlapping(bi_ptr as *const u8, MB2_RAW_INFO.as_mut_ptr(), bi_size);
2342b7818e8SLoGin     }
2352b7818e8SLoGin 
2362b7818e8SLoGin     let boot_info =
2372b7818e8SLoGin         unsafe { BootInformation::load(MB2_RAW_INFO.as_mut_ptr() as *const BootInformationHeader) }
2382b7818e8SLoGin             .inspect_err(|_| loop {
2392b7818e8SLoGin                 spin_loop();
2402b7818e8SLoGin             })
2412b7818e8SLoGin             .unwrap();
2422b7818e8SLoGin 
2432b7818e8SLoGin     MB2_INFO.init(boot_info);
2442b7818e8SLoGin 
2452b7818e8SLoGin     register_boot_callbacks(&Mb2Callback);
2462b7818e8SLoGin 
2472b7818e8SLoGin     return Ok(());
2482b7818e8SLoGin }
249