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