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