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