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