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 // 保留内核的内存 79 if let Some(info) = efi_manager().inner.read().dragonstub_load_info.clone() { 80 mem_block_manager() 81 .reserve_block( 82 PhysAddr::new(info.paddr as usize), 83 page_align_up(info.size as usize), 84 ) 85 .expect("Failed to reserve kernel itself memory"); 86 } 87 88 // todo: Initialize screen info 89 90 kinfo!("UEFI init done!"); 91 } 92 93 #[inline(never)] 94 fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> { 95 // 定义错误处理函数 96 97 // 错误处理:取消systable的映射 98 let err_unmap_systable = |st_vaddr: VirtAddr| { 99 EarlyIoRemap::unmap(st_vaddr) 100 .map_err(|e| { 101 kerror!("Failed to unmap system table: {e:?}"); 102 }) 103 .ok(); 104 }; 105 106 // 映射system table 107 108 let st_size = size_of::<uefi_raw::table::system::SystemTable>(); 109 110 let st_vaddr = EarlyIoRemap::map_not_aligned(system_table, st_size, true).map_err(|e| { 111 kwarn!("Unable to map EFI system table, e:{e:?}"); 112 e 113 })?; 114 115 efi_manager() 116 .inner 117 .write() 118 .init_flags 119 .set(EFIInitFlags::BOOT, true); 120 121 efi_manager() 122 .inner 123 .write() 124 .init_flags 125 .set(EFIInitFlags::EFI_64BIT, true); 126 127 if st_vaddr.is_null() { 128 return Err(SystemError::EINVAL); 129 } 130 131 // 解析system table 132 let st_ptr = st_vaddr.data() as *const uefi_raw::table::system::SystemTable; 133 efi_manager() 134 .check_system_table_header(unsafe { &st_ptr.as_ref().unwrap().header }, 2) 135 .map_err(|e| { 136 err_unmap_systable(st_vaddr); 137 e 138 })?; 139 140 let st_ref = unsafe { st_ptr.as_ref().unwrap() }; 141 142 let runtime_service_paddr = efi_vaddr_2_paddr(st_ref.runtime_services as usize); 143 let mut inner_write_guard = efi_manager().inner.write(); 144 inner_write_guard.runtime_paddr = Some(runtime_service_paddr); 145 inner_write_guard.runtime_service_version = Some(st_ref.header.revision); 146 147 drop(inner_write_guard); 148 efi_manager().report_systable_header( 149 &st_ref.header, 150 efi_vaddr_2_paddr(st_ref.firmware_vendor as usize), 151 ); 152 153 { 154 // 映射configuration table 155 let table_size = st_ref.number_of_configuration_table_entries 156 * size_of::<uefi_raw::table::configuration::ConfigurationTable>(); 157 let config_table_vaddr = EarlyIoRemap::map_not_aligned( 158 efi_vaddr_2_paddr(st_ref.configuration_table as usize), 159 table_size, 160 true, 161 ) 162 .map_err(|e| { 163 kwarn!("Unable to map EFI configuration table, e:{e:?}"); 164 err_unmap_systable(st_vaddr); 165 e 166 })?; 167 let cfg_tables = unsafe { 168 core::slice::from_raw_parts( 169 config_table_vaddr.data() 170 as *const uefi_raw::table::configuration::ConfigurationTable, 171 st_ref.number_of_configuration_table_entries, 172 ) 173 }; 174 // 解析configuration table 175 let r = efi_manager().parse_config_tables(cfg_tables); 176 177 EarlyIoRemap::unmap(config_table_vaddr).expect("Failed to unmap EFI config table"); 178 return r; 179 } 180 } 181 182 /// 把EFI固件提供的虚拟地址转换为物理地址。 183 /// 184 /// 因为在调用SetVirtualAddressMap()之后,`EFI SystemTable` 的一些数据成员会被虚拟重映射 185 /// 186 /// ## 锁 187 /// 188 /// 在进入该函数前,请不要持有`efi_manager().inner`的写锁 189 fn efi_vaddr_2_paddr(efi_vaddr: usize) -> PhysAddr { 190 let guard = efi_manager().inner.read(); 191 let mmap = &guard.mmap; 192 193 let efi_vaddr: u64 = efi_vaddr as u64; 194 for md in mmap.iter() { 195 if !md.att.contains(MemoryAttribute::RUNTIME) { 196 continue; 197 } 198 199 if md.virt_start == 0 { 200 // no virtual mapping has been installed by the DragonStub 201 break; 202 } 203 204 if md.virt_start <= efi_vaddr 205 && ((efi_vaddr - md.virt_start) < (md.page_count << (MMArch::PAGE_SHIFT as u64))) 206 { 207 return PhysAddr::new((md.phys_start + (efi_vaddr - md.virt_start)) as usize); 208 } 209 } 210 211 return PhysAddr::new(efi_vaddr as usize); 212 } 213 214 /// 根据UEFI提供的内存描述符的信息,填写内存区域信息 215 fn reserve_memory_regions() { 216 // 忽略之前已经发现的任何内存块。因为之前发现的内存块来自平坦设备树, 217 // 但是UEFI有自己的内存映射表,我们以UEFI提供的为准 218 mem_block_manager() 219 .remove_block(PhysAddr::new(0), PhysAddr::MAX.data()) 220 .expect("Failed to remove all memblocks!"); 221 222 let inner_guard = efi_manager().inner.read_irqsave(); 223 for md in inner_guard.mmap.iter() { 224 let page_count = (PhysPageFrame::new(PhysAddr::new(page_align_up( 225 (md.phys_start + (md.page_count << (MMArch::PAGE_SHIFT as u64))) as usize, 226 ))) 227 .ppn() 228 - PhysPageFrame::new(PhysAddr::new(page_align_down(md.phys_start as usize))).ppn()) 229 as u64; 230 let phys_start = page_align_down(md.phys_start as usize); 231 let size = (page_count << (MMArch::PAGE_SHIFT as u64)) as usize; 232 233 // 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); 234 if md.is_memory() { 235 open_firmware_fdt_driver().early_init_dt_add_memory(phys_start as u64, size as u64); 236 if !md.is_usable_memory() { 237 mem_block_manager() 238 .mark_nomap(PhysAddr::new(phys_start), size) 239 .unwrap(); 240 } 241 242 // keep ACPI reclaim memory intact for kexec etc. 243 if md.ty == MemoryType::ACPI_RECLAIM { 244 mem_block_manager() 245 .reserve_block(PhysAddr::new(phys_start), size) 246 .unwrap(); 247 } 248 } 249 } 250 } 251