xref: /DragonOS/kernel/src/arch/x86_64/init/multiboot2.rs (revision 2b7818e80e00fcfe4d03533f587cc125ea5e4bec)
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