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