xref: /DragonOS/kernel/src/driver/firmware/efi/init.rs (revision 0102d69fdd231e472d7bb3d609a41ae56a3799ee)
1 use core::{hint::spin_loop, intrinsics::unlikely, mem::size_of};
2 
3 use system_error::SystemError;
4 use uefi_raw::table::boot::{MemoryAttribute, MemoryType};
5 
6 use crate::{
7     arch::MMArch,
8     driver::{
9         firmware::efi::{esrt::efi_esrt_init, EFIInitFlags},
10         open_firmware::fdt::open_firmware_fdt_driver,
11     },
12     libs::align::{page_align_down, page_align_up},
13     mm::{
14         allocator::page_frame::PhysPageFrame, early_ioremap::EarlyIoRemap,
15         memblock::mem_block_manager, MemoryManagementArch, PhysAddr, VirtAddr,
16     },
17 };
18 
19 use super::efi_manager;
20 
21 #[allow(dead_code)]
22 #[inline(never)]
23 pub fn efi_init() {
24     kinfo!("Initializing efi...");
25     let data_from_fdt = efi_manager()
26         .get_fdt_params()
27         .expect("Failed to get fdt params");
28 
29     if data_from_fdt.systable.is_none() {
30         kerror!("Failed to get systable from fdt");
31         return;
32     }
33 
34     // kdebug!("to map memory table");
35 
36     // 映射mmap table
37     if efi_manager().memmap_init_early(&data_from_fdt).is_err() {
38         // 如果我们通过UEFI进行引导,
39         // 那么 UEFI memory map 就是我们拥有的关于内存的唯一描述,
40         // 所以如果我们无法访问它,那么继续进行下去就没有什么意义了
41 
42         kerror!("Failed to initialize early memory map");
43         loop {
44             spin_loop();
45         }
46     }
47     // kdebug!("NNNN");
48     // kwarn!("BBBB, e:{:?}", SystemError::EINVAL);
49 
50     let desc_version = efi_manager().desc_version();
51 
52     if unlikely(desc_version != 1) {
53         kwarn!("Unexpected EFI memory map version: {}", desc_version);
54     }
55 
56     let r = uefi_init(PhysAddr::new(data_from_fdt.systable.unwrap() as usize));
57     if let Err(e) = r {
58         kerror!("Failed to initialize UEFI: {:?}", e);
59         efi_manager().efi_memmap_unmap();
60         return;
61     }
62 
63     reserve_memory_regions();
64     // todo: 由于上面的`uefi_init`里面,按照UEFI的数据,初始化了内存块,
65     // 但是UEFI给的数据可能不全,这里Linux会再次从设备树检测可用内存,从而填补完全相应的内存信息
66 
67     // 并且,Linux还对EFI BootService提供的Mokvar表进行了检测以及空间保留。
68 
69     // todo: 模仿Linux的行为,做好接下来的几步工作:
70     // 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/firmware/efi/efi-init.c#217
71 
72     // todo: early_init_dt_check_for_usable_mem_range
73 
74     efi_find_mirror();
75     efi_esrt_init();
76 
77     // 保留mmap table的内存
78     let base = page_align_down(data_from_fdt.mmap_base.unwrap() as usize);
79     let offset = data_from_fdt.mmap_base.unwrap() as usize - base;
80 
81     mem_block_manager()
82         .reserve_block(
83             PhysAddr::new(base),
84             data_from_fdt.mmap_size.unwrap() as usize + offset,
85         )
86         .expect("Failed to reserve memory for EFI mmap table");
87 
88     // 保留内核的内存
89     if let Some(info) = efi_manager().inner_read().dragonstub_load_info {
90         mem_block_manager()
91             .reserve_block(
92                 PhysAddr::new(info.paddr as usize),
93                 page_align_up(info.size as usize),
94             )
95             .expect("Failed to reserve kernel itself memory");
96     }
97 
98     // todo: Initialize screen info
99 
100     kinfo!("UEFI init done!");
101 }
102 
103 fn efi_find_mirror() {
104     let efi_guard = efi_manager().inner_read();
105     let mut total_size = 0;
106     let mut mirror_size = 0;
107     for md in efi_guard.mmap.iter() {
108         let start = PhysAddr::new(md.phys_start as usize);
109         let size = (md.page_count << (MMArch::PAGE_SHIFT as u64)) as usize;
110 
111         if md.att.contains(MemoryAttribute::MORE_RELIABLE) {
112             mem_block_manager().mark_mirror(start, size).unwrap();
113             mirror_size += size;
114         }
115 
116         total_size += size;
117     }
118 
119     if mirror_size > 0 {
120         kinfo!(
121             "Memory: {}M/{}M mirrored memory",
122             mirror_size >> 20,
123             total_size >> 20
124         );
125     }
126 }
127 
128 #[inline(never)]
129 fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
130     // 定义错误处理函数
131 
132     // 错误处理:取消systable的映射
133     let err_unmap_systable = |st_vaddr: VirtAddr| {
134         EarlyIoRemap::unmap(st_vaddr)
135             .map_err(|e| {
136                 kerror!("Failed to unmap system table: {e:?}");
137             })
138             .ok();
139     };
140 
141     // 映射system table
142 
143     let st_size = size_of::<uefi_raw::table::system::SystemTable>();
144 
145     let st_vaddr = EarlyIoRemap::map_not_aligned(system_table, st_size, true).map_err(|e| {
146         kwarn!("Unable to map EFI system table, e:{e:?}");
147         e
148     })?;
149 
150     efi_manager()
151         .inner
152         .write()
153         .init_flags
154         .set(EFIInitFlags::BOOT, true);
155 
156     efi_manager()
157         .inner
158         .write()
159         .init_flags
160         .set(EFIInitFlags::EFI_64BIT, true);
161 
162     if st_vaddr.is_null() {
163         return Err(SystemError::EINVAL);
164     }
165 
166     // 解析system table
167     let st_ptr = st_vaddr.data() as *const uefi_raw::table::system::SystemTable;
168     efi_manager()
169         .check_system_table_header(unsafe { &st_ptr.as_ref().unwrap().header }, 2)
170         .map_err(|e| {
171             err_unmap_systable(st_vaddr);
172             e
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             kwarn!("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`的写锁
224 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提供的内存描述符的信息,填写内存区域信息
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         // kdebug!("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                 // kdebug!(
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