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