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