1 use core::{hint::spin_loop, intrinsics::unlikely, mem::size_of};
2
3 use log::{error, info, warn};
4 use system_error::SystemError;
5 use uefi_raw::table::boot::{MemoryAttribute, MemoryType};
6
7 use crate::{
8 arch::MMArch,
9 driver::{
10 firmware::efi::{esrt::efi_esrt_init, EFIInitFlags},
11 open_firmware::fdt::open_firmware_fdt_driver,
12 },
13 libs::align::{page_align_down, page_align_up},
14 mm::{
15 allocator::page_frame::PhysPageFrame, early_ioremap::EarlyIoRemap,
16 memblock::mem_block_manager, MemoryManagementArch, PhysAddr, VirtAddr,
17 },
18 };
19
20 use super::efi_manager;
21
22 #[allow(dead_code)]
23 #[inline(never)]
efi_init()24 pub fn efi_init() {
25 info!("Initializing efi...");
26 let data_from_fdt = efi_manager()
27 .get_fdt_params()
28 .expect("Failed to get fdt params");
29
30 if data_from_fdt.systable.is_none() {
31 error!("Failed to get systable from fdt");
32 return;
33 }
34
35 // debug!("to map memory table");
36
37 // 映射mmap table
38 if efi_manager().memmap_init_early(&data_from_fdt).is_err() {
39 // 如果我们通过UEFI进行引导,
40 // 那么 UEFI memory map 就是我们拥有的关于内存的唯一描述,
41 // 所以如果我们无法访问它,那么继续进行下去就没有什么意义了
42
43 error!("Failed to initialize early memory map");
44 loop {
45 spin_loop();
46 }
47 }
48 // debug!("NNNN");
49 // warn!("BBBB, e:{:?}", SystemError::EINVAL);
50
51 let desc_version = efi_manager().desc_version();
52
53 if unlikely(desc_version != 1) {
54 warn!("Unexpected EFI memory map version: {}", desc_version);
55 }
56
57 let r = uefi_init(PhysAddr::new(data_from_fdt.systable.unwrap() as usize));
58 if let Err(e) = r {
59 error!("Failed to initialize UEFI: {:?}", e);
60 efi_manager().efi_memmap_unmap();
61 return;
62 }
63
64 reserve_memory_regions();
65 // todo: 由于上面的`uefi_init`里面,按照UEFI的数据,初始化了内存块,
66 // 但是UEFI给的数据可能不全,这里Linux会再次从设备树检测可用内存,从而填补完全相应的内存信息
67
68 // 并且,Linux还对EFI BootService提供的Mokvar表进行了检测以及空间保留。
69
70 // todo: 模仿Linux的行为,做好接下来的几步工作:
71 // 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/firmware/efi/efi-init.c#217
72
73 // todo: early_init_dt_check_for_usable_mem_range
74
75 efi_find_mirror();
76 efi_esrt_init();
77
78 // 保留mmap table的内存
79 let base = page_align_down(data_from_fdt.mmap_base.unwrap() as usize);
80 let offset = data_from_fdt.mmap_base.unwrap() as usize - base;
81
82 mem_block_manager()
83 .reserve_block(
84 PhysAddr::new(base),
85 data_from_fdt.mmap_size.unwrap() as usize + offset,
86 )
87 .expect("Failed to reserve memory for EFI mmap table");
88
89 // 保留内核的内存
90 if let Some(info) = efi_manager().inner_read().dragonstub_load_info {
91 mem_block_manager()
92 .reserve_block(
93 PhysAddr::new(info.paddr as usize),
94 page_align_up(info.size as usize),
95 )
96 .expect("Failed to reserve kernel itself memory");
97 }
98
99 // todo: Initialize screen info
100
101 info!("UEFI init done!");
102 }
103
efi_find_mirror()104 fn efi_find_mirror() {
105 let efi_guard = efi_manager().inner_read();
106 let mut total_size = 0;
107 let mut mirror_size = 0;
108 for md in efi_guard.mmap.iter() {
109 let start = PhysAddr::new(md.phys_start as usize);
110 let size = (md.page_count << (MMArch::PAGE_SHIFT as u64)) as usize;
111
112 if md.att.contains(MemoryAttribute::MORE_RELIABLE) {
113 mem_block_manager().mark_mirror(start, size).unwrap();
114 mirror_size += size;
115 }
116
117 total_size += size;
118 }
119
120 if mirror_size > 0 {
121 info!(
122 "Memory: {}M/{}M mirrored memory",
123 mirror_size >> 20,
124 total_size >> 20
125 );
126 }
127 }
128
129 #[inline(never)]
uefi_init(system_table: PhysAddr) -> Result<(), SystemError>130 fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
131 // 定义错误处理函数
132
133 // 错误处理:取消systable的映射
134 let err_unmap_systable = |st_vaddr: VirtAddr| {
135 EarlyIoRemap::unmap(st_vaddr)
136 .map_err(|e| {
137 error!("Failed to unmap system table: {e:?}");
138 })
139 .ok();
140 };
141
142 // 映射system table
143
144 let st_size = size_of::<uefi_raw::table::system::SystemTable>();
145
146 let st_vaddr = EarlyIoRemap::map_not_aligned(system_table, st_size, true).map_err(|e| {
147 warn!("Unable to map EFI system table, e:{e:?}");
148 e
149 })?;
150
151 efi_manager()
152 .inner
153 .write()
154 .init_flags
155 .set(EFIInitFlags::BOOT, true);
156
157 efi_manager()
158 .inner
159 .write()
160 .init_flags
161 .set(EFIInitFlags::EFI_64BIT, true);
162
163 if st_vaddr.is_null() {
164 return Err(SystemError::EINVAL);
165 }
166
167 // 解析system table
168 let st_ptr = st_vaddr.data() as *const uefi_raw::table::system::SystemTable;
169 efi_manager()
170 .check_system_table_header(unsafe { &st_ptr.as_ref().unwrap().header }, 2)
171 .inspect_err(|_| {
172 err_unmap_systable(st_vaddr);
173 })?;
174
175 let st_ref = unsafe { st_ptr.as_ref().unwrap() };
176
177 let runtime_service_paddr = efi_vaddr_2_paddr(st_ref.runtime_services as usize);
178 let mut inner_write_guard = efi_manager().inner_write();
179 inner_write_guard.runtime_paddr = Some(runtime_service_paddr);
180 inner_write_guard.runtime_service_version = Some(st_ref.header.revision);
181
182 drop(inner_write_guard);
183 efi_manager().report_systable_header(
184 &st_ref.header,
185 efi_vaddr_2_paddr(st_ref.firmware_vendor as usize),
186 );
187
188 {
189 // 映射configuration table
190 let table_size = st_ref.number_of_configuration_table_entries
191 * size_of::<uefi_raw::table::configuration::ConfigurationTable>();
192 let config_table_vaddr = EarlyIoRemap::map_not_aligned(
193 efi_vaddr_2_paddr(st_ref.configuration_table as usize),
194 table_size,
195 true,
196 )
197 .map_err(|e| {
198 warn!("Unable to map EFI configuration table, e:{e:?}");
199 err_unmap_systable(st_vaddr);
200 e
201 })?;
202 let cfg_tables = unsafe {
203 core::slice::from_raw_parts(
204 config_table_vaddr.data()
205 as *const uefi_raw::table::configuration::ConfigurationTable,
206 st_ref.number_of_configuration_table_entries,
207 )
208 };
209 // 解析configuration table
210 let r = efi_manager().parse_config_tables(cfg_tables);
211
212 EarlyIoRemap::unmap(config_table_vaddr).expect("Failed to unmap EFI config table");
213 return r;
214 }
215 }
216
217 /// 把EFI固件提供的虚拟地址转换为物理地址。
218 ///
219 /// 因为在调用SetVirtualAddressMap()之后,`EFI SystemTable` 的一些数据成员会被虚拟重映射
220 ///
221 /// ## 锁
222 ///
223 /// 在进入该函数前,请不要持有`efi_manager().inner`的写锁
efi_vaddr_2_paddr(efi_vaddr: usize) -> PhysAddr224 fn efi_vaddr_2_paddr(efi_vaddr: usize) -> PhysAddr {
225 let guard = efi_manager().inner_read();
226 let mmap = &guard.mmap;
227
228 let efi_vaddr: u64 = efi_vaddr as u64;
229 for md in mmap.iter() {
230 if !md.att.contains(MemoryAttribute::RUNTIME) {
231 continue;
232 }
233
234 if md.virt_start == 0 {
235 // no virtual mapping has been installed by the DragonStub
236 break;
237 }
238
239 if md.virt_start <= efi_vaddr
240 && ((efi_vaddr - md.virt_start) < (md.page_count << (MMArch::PAGE_SHIFT as u64)))
241 {
242 return PhysAddr::new((md.phys_start + (efi_vaddr - md.virt_start)) as usize);
243 }
244 }
245
246 return PhysAddr::new(efi_vaddr as usize);
247 }
248
249 /// 根据UEFI提供的内存描述符的信息,填写内存区域信息
reserve_memory_regions()250 fn reserve_memory_regions() {
251 // 忽略之前已经发现的任何内存块。因为之前发现的内存块来自平坦设备树,
252 // 但是UEFI有自己的内存映射表,我们以UEFI提供的为准
253 mem_block_manager()
254 .remove_block(PhysAddr::new(0), PhysAddr::MAX.data())
255 .expect("Failed to remove all memblocks!");
256
257 let inner_guard = efi_manager().inner.read_irqsave();
258 for md in inner_guard.mmap.iter() {
259 let page_count = (PhysPageFrame::new(PhysAddr::new(page_align_up(
260 (md.phys_start + (md.page_count << (MMArch::PAGE_SHIFT as u64))) as usize,
261 )))
262 .ppn()
263 - PhysPageFrame::new(PhysAddr::new(page_align_down(md.phys_start as usize))).ppn())
264 as u64;
265 let phys_start = page_align_down(md.phys_start as usize);
266 let size = (page_count << (MMArch::PAGE_SHIFT as u64)) as usize;
267
268 // debug!("Reserve memory region: {:#x}-{:#x}({:#x}), is_memory: {}, is_usable_memory:{}, type: {:?}, att: {:?}", phys_start, phys_start + size, page_count, md.is_memory(), md.is_usable_memory(), md.ty, md.att);
269 if md.is_memory() {
270 open_firmware_fdt_driver().early_init_dt_add_memory(phys_start as u64, size as u64);
271 if !md.is_usable_memory() {
272 // debug!(
273 // "Marking non-usable memory as nomap: {:#x}-{:#x}",
274 // phys_start,
275 // phys_start + size
276 // );
277 mem_block_manager()
278 .mark_nomap(PhysAddr::new(phys_start), size)
279 .unwrap();
280 }
281
282 // keep ACPI reclaim memory intact for kexec etc.
283 if md.ty == MemoryType::ACPI_RECLAIM {
284 mem_block_manager()
285 .reserve_block(PhysAddr::new(phys_start), size)
286 .unwrap();
287 }
288 }
289 }
290 }
291