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
mb2_rsdp_v1_tag_to_rsdp_struct(tag: &RsdpV1Tag) -> Rsdp31 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
mb2_rsdp_v2_tag_to_rsdp_struct(tag: &multiboot2::RsdpV2Tag) -> Rsdp45 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 {
init_bootloader_name(&self) -> Result<Option<String>, SystemError>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
init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError>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
init_kernel_cmdline(&self) -> Result<(), SystemError>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
early_init_framebuffer_info( &self, scinfo: &mut BootTimeScreenInfo, ) -> Result<(), SystemError>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
early_init_memory_blocks(&self) -> Result<(), SystemError>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 {
setup_kernel_load_base(&self)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 }
early_multiboot2_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError>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