xref: /DragonOS/kernel/src/arch/x86_64/init/multiboot.rs (revision db7c782a9aaacb320027167bda4f23751b8f36e1)
1 use core::ffi::CStr;
2 
3 use alloc::string::{String, ToString};
4 
5 use multiboot::MultibootInfo;
6 use system_error::SystemError;
7 
8 use crate::{
9     arch::MMArch,
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, MemoryManagementArch, PhysAddr},
23 };
24 
25 static MB1_INFO: Lazy<MultibootInfo> = Lazy::new();
26 
27 struct Mb1Ops;
28 
29 impl multiboot::MultibootOps for Mb1Ops {
phys_2_virt(&self, paddr: usize) -> usize30     fn phys_2_virt(&self, paddr: usize) -> usize {
31         unsafe { MMArch::phys_2_virt(PhysAddr::new(paddr)).unwrap().data() }
32     }
33 }
34 struct Mb1Callback;
35 
36 impl BootCallbacks for Mb1Callback {
init_bootloader_name(&self) -> Result<Option<String>, SystemError>37     fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
38         let info = MB1_INFO.get();
39         if info.boot_loader_name != 0 {
40             // SAFETY: the bootloader name is C-style zero-terminated string.
41             unsafe {
42                 let cstr_ptr =
43                     MMArch::phys_2_virt(PhysAddr::new(info.boot_loader_name as usize)).unwrap();
44                 let cstr = CStr::from_ptr(cstr_ptr.data() as *const i8);
45 
46                 let result = cstr.to_str().unwrap_or("unknown").to_string();
47                 return Ok(Some(result));
48             }
49         }
50         Ok(None)
51     }
52 
init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError>53     fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
54         // MB1不提供rsdp信息。因此,将来需要让内核支持从UEFI获取RSDP表。
55         Ok(BootloaderAcpiArg::NotProvided)
56     }
57 
init_kernel_cmdline(&self) -> Result<(), SystemError>58     fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
59         let info = MB1_INFO.get();
60 
61         if !info.has_cmdline() {
62             log::debug!("No kernel command line found in multiboot1 info");
63             return Ok(());
64         }
65 
66         if let Some(cmdline) = unsafe { info.cmdline(&Mb1Ops) } {
67             let mut guard = boot_params().write_irqsave();
68             guard.boot_cmdline_append(cmdline.as_bytes());
69 
70             log::info!("Kernel command line: {}\n", cmdline);
71         }
72 
73         Ok(())
74     }
75 
early_init_framebuffer_info( &self, scinfo: &mut BootTimeScreenInfo, ) -> Result<(), SystemError>76     fn early_init_framebuffer_info(
77         &self,
78         scinfo: &mut BootTimeScreenInfo,
79     ) -> Result<(), SystemError> {
80         let info = MB1_INFO.get();
81         let fb_table = info.framebuffer_table;
82         let width = fb_table.width;
83         let height = fb_table.height;
84         scinfo.is_vga = true;
85         scinfo.lfb_base = PhysAddr::new(fb_table.paddr as usize);
86         let fb_type = fb_table.color_info().unwrap();
87 
88         match fb_type {
89             multiboot::ColorInfoType::Palette(_) => todo!(),
90             multiboot::ColorInfoType::Rgb(rgb) => {
91                 scinfo.lfb_width = width;
92                 scinfo.lfb_height = height;
93                 scinfo.video_type = BootTimeVideoType::Vlfb;
94                 scinfo.lfb_depth = fb_table.bpp;
95                 scinfo.red_pos = rgb.red_field_position;
96                 scinfo.red_size = rgb.red_mask_size;
97                 scinfo.green_pos = rgb.green_field_position;
98                 scinfo.green_size = rgb.green_mask_size;
99                 scinfo.blue_pos = rgb.blue_field_position;
100                 scinfo.blue_size = rgb.blue_mask_size;
101             }
102             multiboot::ColorInfoType::Text => {
103                 scinfo.origin_video_cols = width as u8;
104                 scinfo.origin_video_lines = height as u8;
105                 scinfo.video_type = BootTimeVideoType::Mda;
106                 scinfo.lfb_depth = 8;
107             }
108         }
109         scinfo.lfb_size = (width * height * ((scinfo.lfb_depth as u32 + 7) / 8)) as usize;
110 
111         scinfo.lfb_virt_base = Some(vesafb_early_map(scinfo.lfb_base, scinfo.lfb_size)?);
112 
113         return Ok(());
114     }
115 
early_init_memory_blocks(&self) -> Result<(), SystemError>116     fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
117         let info = MB1_INFO.get();
118         let mut total_mem_size = 0usize;
119         let mut usable_mem_size = 0usize;
120         for entry in unsafe { info.memory_map(&Mb1Ops) } {
121             let start = PhysAddr::new(entry.base_addr() as usize);
122             let size = entry.length() as usize;
123             let area_typ = entry.memory_type();
124             total_mem_size += size;
125 
126             match area_typ {
127                 multiboot::MemoryType::Available => {
128                     usable_mem_size += size;
129                     mem_block_manager()
130                         .add_block(start, size)
131                         .unwrap_or_else(|e| {
132                             log::warn!(
133                                 "Failed to add memory block: base={:?}, size={:#x}, error={:?}",
134                                 start,
135                                 size,
136                                 e
137                             );
138                         });
139                 }
140                 _ => {
141                     mem_block_manager()
142                         .reserve_block(start, size)
143                         .unwrap_or_else(|e| {
144                             log::warn!(
145                                 "Failed to reserve memory block: base={:?}, size={:#x}, error={:?}",
146                                 start,
147                                 size,
148                                 e
149                             );
150                         });
151                 }
152             }
153         }
154         send_to_default_serial8250_port("init_memory_area_from_multiboot1 end\n\0".as_bytes());
155         log::info!(
156             "Total memory size: {:#x}, Usable memory size: {:#x}",
157             total_mem_size,
158             usable_mem_size
159         );
160 
161         if let Some(modules_iter) = unsafe { info.modules(&Mb1Ops) } {
162             for m in modules_iter {
163                 let base = PhysAddr::new(m.start() as usize);
164                 let size = m.end() as usize - m.start() as usize;
165                 mem_block_manager()
166                     .reserve_block(base, size)
167                     .unwrap_or_else(|e| {
168                         log::warn!(
169                         "Failed to reserve modules memory block: base={:?}, size={:#x}, error={:?}",
170                         base,
171                         size,
172                         e
173                     );
174                     });
175             }
176         }
177 
178         Ok(())
179     }
180 }
181 
early_multiboot_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError>182 pub(super) fn early_multiboot_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError> {
183     assert_eq!(boot_magic, multiboot::MAGIC);
184     let boot_info = unsafe { MMArch::phys_2_virt(PhysAddr::new(boot_info as usize)).unwrap() };
185     let mb1_info = unsafe { (boot_info.data() as *const MultibootInfo).as_ref().unwrap() };
186     MB1_INFO.init(*mb1_info);
187 
188     register_boot_callbacks(&Mb1Callback);
189 
190     Ok(())
191 }
192