xref: /DragonOS/kernel/src/driver/firmware/efi/init.rs (revision f79998f626801329580c782fd05e36cb2027f474)
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)]
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 
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)]
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         .map_err(|e| {
172             err_unmap_systable(st_vaddr);
173             e
174         })?;
175 
176     let st_ref = unsafe { st_ptr.as_ref().unwrap() };
177 
178     let runtime_service_paddr = efi_vaddr_2_paddr(st_ref.runtime_services as usize);
179     let mut inner_write_guard = efi_manager().inner_write();
180     inner_write_guard.runtime_paddr = Some(runtime_service_paddr);
181     inner_write_guard.runtime_service_version = Some(st_ref.header.revision);
182 
183     drop(inner_write_guard);
184     efi_manager().report_systable_header(
185         &st_ref.header,
186         efi_vaddr_2_paddr(st_ref.firmware_vendor as usize),
187     );
188 
189     {
190         // 映射configuration table
191         let table_size = st_ref.number_of_configuration_table_entries
192             * size_of::<uefi_raw::table::configuration::ConfigurationTable>();
193         let config_table_vaddr = EarlyIoRemap::map_not_aligned(
194             efi_vaddr_2_paddr(st_ref.configuration_table as usize),
195             table_size,
196             true,
197         )
198         .map_err(|e| {
199             warn!("Unable to map EFI configuration table, e:{e:?}");
200             err_unmap_systable(st_vaddr);
201             e
202         })?;
203         let cfg_tables = unsafe {
204             core::slice::from_raw_parts(
205                 config_table_vaddr.data()
206                     as *const uefi_raw::table::configuration::ConfigurationTable,
207                 st_ref.number_of_configuration_table_entries,
208             )
209         };
210         // 解析configuration table
211         let r = efi_manager().parse_config_tables(cfg_tables);
212 
213         EarlyIoRemap::unmap(config_table_vaddr).expect("Failed to unmap EFI config table");
214         return r;
215     }
216 }
217 
218 /// 把EFI固件提供的虚拟地址转换为物理地址。
219 ///
220 /// 因为在调用SetVirtualAddressMap()之后,`EFI SystemTable` 的一些数据成员会被虚拟重映射
221 ///
222 /// ## 锁
223 ///
224 /// 在进入该函数前,请不要持有`efi_manager().inner`的写锁
225 fn efi_vaddr_2_paddr(efi_vaddr: usize) -> PhysAddr {
226     let guard = efi_manager().inner_read();
227     let mmap = &guard.mmap;
228 
229     let efi_vaddr: u64 = efi_vaddr as u64;
230     for md in mmap.iter() {
231         if !md.att.contains(MemoryAttribute::RUNTIME) {
232             continue;
233         }
234 
235         if md.virt_start == 0 {
236             // no virtual mapping has been installed by the DragonStub
237             break;
238         }
239 
240         if md.virt_start <= efi_vaddr
241             && ((efi_vaddr - md.virt_start) < (md.page_count << (MMArch::PAGE_SHIFT as u64)))
242         {
243             return PhysAddr::new((md.phys_start + (efi_vaddr - md.virt_start)) as usize);
244         }
245     }
246 
247     return PhysAddr::new(efi_vaddr as usize);
248 }
249 
250 /// 根据UEFI提供的内存描述符的信息,填写内存区域信息
251 fn reserve_memory_regions() {
252     // 忽略之前已经发现的任何内存块。因为之前发现的内存块来自平坦设备树,
253     // 但是UEFI有自己的内存映射表,我们以UEFI提供的为准
254     mem_block_manager()
255         .remove_block(PhysAddr::new(0), PhysAddr::MAX.data())
256         .expect("Failed to remove all memblocks!");
257 
258     let inner_guard = efi_manager().inner.read_irqsave();
259     for md in inner_guard.mmap.iter() {
260         let page_count = (PhysPageFrame::new(PhysAddr::new(page_align_up(
261             (md.phys_start + (md.page_count << (MMArch::PAGE_SHIFT as u64))) as usize,
262         )))
263         .ppn()
264             - PhysPageFrame::new(PhysAddr::new(page_align_down(md.phys_start as usize))).ppn())
265             as u64;
266         let phys_start = page_align_down(md.phys_start as usize);
267         let size = (page_count << (MMArch::PAGE_SHIFT as u64)) as usize;
268 
269         // 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);
270         if md.is_memory() {
271             open_firmware_fdt_driver().early_init_dt_add_memory(phys_start as u64, size as u64);
272             if !md.is_usable_memory() {
273                 // debug!(
274                 //     "Marking non-usable memory as nomap: {:#x}-{:#x}",
275                 //     phys_start,
276                 //     phys_start + size
277                 // );
278                 mem_block_manager()
279                     .mark_nomap(PhysAddr::new(phys_start), size)
280                     .unwrap();
281             }
282 
283             //  keep ACPI reclaim memory intact for kexec etc.
284             if md.ty == MemoryType::ACPI_RECLAIM {
285                 mem_block_manager()
286                     .reserve_block(PhysAddr::new(phys_start), size)
287                     .unwrap();
288             }
289         }
290     }
291 }
292