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