xref: /DragonOS/kernel/src/driver/firmware/efi/tables.rs (revision 4b0170bd6bb374d0e9699a0076cc23b976ad6db7)
1 use core::{ffi::CStr, mem::size_of};
2 
3 use hashbrown::Equivalent;
4 use system_error::SystemError;
5 use uefi_raw::table::{
6     boot::{MemoryAttribute, MemoryType},
7     configuration::ConfigurationTable,
8 };
9 
10 use crate::{
11     arch::MMArch,
12     driver::firmware::efi::{
13         efi_manager,
14         guid::{DragonStubPayloadEFI, DRAGONSTUB_EFI_PAYLOAD_EFI_GUID},
15     },
16     mm::{
17         early_ioremap::EarlyIoRemap, memblock::mem_block_manager, MemoryManagementArch, PhysAddr,
18         VirtAddr,
19     },
20 };
21 
22 use super::{
23     guid::{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, EFI_MEMRESERVE_TABLE_GUID},
24     EFIManager,
25 };
26 
27 /// 所有的要解析的表格的解析器
28 static TABLE_PARSERS: &[&TableMatcher] = &[
29     &TableMatcher::new(&MatchTableDragonStubPayloadEFI),
30     &TableMatcher::new(&MatchTableMemoryAttributes),
31     &TableMatcher::new(&MatchTableMemReserve),
32 ];
33 
34 impl EFIManager {
35     /// 显示EFI系统表头的信息
36     ///
37     /// ## 参数
38     ///
39     /// - header: system table表头
40     /// - firmware_vendor: firmware vendor字符串的物理地址
41     #[inline(never)]
42     pub fn report_systable_header(
43         &self,
44         header: &uefi_raw::table::Header,
45         firmware_vendor: PhysAddr,
46     ) {
47         const TMPBUF_SIZE: usize = 100;
48 
49         let mut tmp_buf = [0u8; TMPBUF_SIZE];
50 
51         let fw_ptr =
52             EarlyIoRemap::map_not_aligned(firmware_vendor, TMPBUF_SIZE * size_of::<u16>(), true);
53         if let Ok(fw_ptr) = fw_ptr {
54             let slice =
55                 unsafe { core::slice::from_raw_parts(fw_ptr.data() as *const u16, TMPBUF_SIZE) };
56             for i in 0..(TMPBUF_SIZE - 1) {
57                 let val = slice[i];
58 
59                 if (val & 0xff) == 0 {
60                     break;
61                 }
62                 tmp_buf[i] = (val & 0xff) as u8;
63             }
64 
65             EarlyIoRemap::unmap(fw_ptr).map_err(|e|{
66                 kerror!("report systable header: failed to unmap systable header, fw_ptr: {fw_ptr:?}, err: {e:?}");
67                 e
68             }).ok();
69         } else {
70             kwarn!("report systable header: failed to map systable header, err: {fw_ptr:?}");
71         }
72 
73         let s = CStr::from_bytes_with_nul(&tmp_buf)
74             .unwrap_or_else(|_| CStr::from_bytes_with_nul(b"Unknown\0").unwrap());
75         kinfo!("EFI version: {:?}, vendor: {:?}", header.revision, s);
76     }
77 
78     /// 解析EFI config table
79     pub fn parse_config_tables(&self, tables: &[ConfigurationTable]) -> Result<(), SystemError> {
80         for table in tables {
81             let mut flag = false;
82             'parser_loop: for parser in TABLE_PARSERS {
83                 if let Some(r) = parser.match_table(table) {
84                     // 有匹配结果
85                     if let Err(e) = r {
86                         kwarn!(
87                             "Failed to parse cfg table: '{}', err: {e:?}",
88                             parser.table.name()
89                         );
90                     }
91                     flag = true;
92                     break 'parser_loop;
93                 }
94             }
95 
96             if !flag {
97                 kwarn!("Cannot find parser for guid: {:?}", table.vendor_guid);
98             }
99         }
100 
101         // 如果存在mem reserve table
102         if let Some(mem_reserve) = efi_manager().inner.read().memreserve_table_paddr {
103             let mut prev_paddr = mem_reserve;
104             while !prev_paddr.is_null() {
105                 let vaddr = EarlyIoRemap::map_not_aligned(prev_paddr, MMArch::PAGE_SIZE, true)
106                     .map_err(|e| {
107                         kerror!(
108                             "Failed to map UEFI memreserve table, paddr: {prev_paddr:?}, err: {e:?}"
109                         );
110 
111                         SystemError::ENOMEM
112                     })?;
113 
114                 let p = unsafe {
115                     (vaddr.data() as *const LinuxEFIMemReserveTable)
116                         .as_ref()
117                         .unwrap()
118                 };
119 
120                 // reserve the entry itself
121                 let psize: usize = p.size.try_into().unwrap();
122                 mem_block_manager()
123                     .reserve_block(
124                         prev_paddr,
125                         size_of::<LinuxEFIMemReserveTable>()
126                             + size_of::<LinuxEFIMemReserveEntry>() * psize,
127                     )
128                     .map_err(|e| {
129                         kerror!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}");
130                         EarlyIoRemap::unmap(vaddr).unwrap();
131                         e
132                     })?;
133 
134                 let entries = unsafe {
135                     core::slice::from_raw_parts(
136                         (vaddr.data() as *const LinuxEFIMemReserveTable).add(1)
137                             as *const LinuxEFIMemReserveEntry,
138                         p.count as usize,
139                     )
140                 };
141                 // reserve the entries
142                 for entry in entries {
143                     mem_block_manager()
144                         .reserve_block(PhysAddr::new(entry.base), entry.size)
145                         .map_err(|e| {
146                             kerror!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}");
147                             EarlyIoRemap::unmap(vaddr).unwrap();
148                             e
149                         })?;
150                 }
151 
152                 prev_paddr = p.next_paddr;
153                 EarlyIoRemap::unmap(vaddr).unwrap();
154             }
155         }
156         return Ok(());
157     }
158 }
159 
160 /// A structure describing a region of memory.
161 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
162 #[repr(C)]
163 pub struct MemoryDescriptor {
164     /// Type of memory occupying this range.
165     pub ty: MemoryType,
166     /// Starting physical address.
167     pub phys_start: uefi_raw::PhysicalAddress,
168     /// Starting virtual address.
169     pub virt_start: uefi_raw::VirtualAddress,
170     /// Number of 4 KiB pages contained in this range.
171     pub page_count: u64,
172     /// The capability attributes of this memory range.
173     pub att: MemoryAttribute,
174 }
175 
176 #[allow(dead_code)]
177 impl MemoryDescriptor {
178     /// Memory descriptor version number.
179     pub const VERSION: u32 = 1;
180 
181     /// 当前内存描述符是否表示真实的内存
182     #[inline]
183     pub fn is_memory(&self) -> bool {
184         if self.att.contains(MemoryAttribute::WRITE_BACK)
185             || self.att.contains(MemoryAttribute::WRITE_THROUGH)
186             || self.att.contains(MemoryAttribute::WRITE_COMBINE)
187         {
188             return true;
189         }
190 
191         return false;
192     }
193 
194     /// 判断当前内存描述符所表示的区域是否能被作为系统内存使用
195     ///
196     /// ## 返回
197     ///
198     /// - `true` - 可以
199     /// - `false` - 不可以
200     pub fn is_usable_memory(&self) -> bool {
201         match self.ty {
202             MemoryType::LOADER_CODE
203             | MemoryType::LOADER_DATA
204             | MemoryType::ACPI_RECLAIM
205             | MemoryType::BOOT_SERVICES_CODE
206             | MemoryType::BOOT_SERVICES_DATA
207             | MemoryType::CONVENTIONAL
208             | MemoryType::PERSISTENT_MEMORY => {
209                 // SPECIAL_PURPOSE的内存是“软保留”的,这意味着它最初被留出,
210                 // 但在启动后可以通过热插拔再次使用,或者分配给dax驱动程序。
211                 if self.att.contains(MemoryAttribute::SPECIAL_PURPOSE) {
212                     return false;
213                 }
214 
215                 // 根据规范,在调用ExitBootServices()之后,这些区域就不再被保留了。
216                 // 然而,只有当它们可以被映射为WRITE_BACK缓存时,我们才能将它们用作系统内存
217                 return self.att.contains(MemoryAttribute::WRITE_BACK);
218             }
219             _ => {
220                 return false;
221             }
222         }
223     }
224 }
225 
226 impl Default for MemoryDescriptor {
227     fn default() -> MemoryDescriptor {
228         MemoryDescriptor {
229             ty: MemoryType::RESERVED,
230             phys_start: 0,
231             virt_start: 0,
232             page_count: 0,
233             att: MemoryAttribute::empty(),
234         }
235     }
236 }
237 
238 trait MatchTable: Send + Sync {
239     /// 配置表名(仅用于日志显示)
240     fn name(&self) -> &'static str;
241 
242     /// 当前table的guid
243     fn guid(&self) -> &'static uefi_raw::Guid;
244 
245     /// 匹配阶段时,匹配器要映射vendor_table的大小。
246     ///
247     /// 如果为0,则不映射
248     fn map_size(&self) -> usize;
249 
250     /// 当表格被映射后,调用这个函数
251     ///
252     /// ## 锁
253     ///
254     /// 进入该函数前,不得持有efi_manager().inner的任何锁
255     fn post_process(
256         &self,
257         vendor_table_vaddr: Option<VirtAddr>,
258         table_raw: &ConfigurationTable,
259     ) -> Result<(), SystemError>;
260 }
261 
262 /// `DRAGONSTUB_EFI_PAYLOAD_EFI_GUID` 的匹配器
263 struct MatchTableDragonStubPayloadEFI;
264 
265 impl MatchTable for MatchTableDragonStubPayloadEFI {
266     fn name(&self) -> &'static str {
267         "DragonStub Payload"
268     }
269 
270     fn guid(&self) -> &'static uefi_raw::Guid {
271         &DRAGONSTUB_EFI_PAYLOAD_EFI_GUID
272     }
273 
274     fn map_size(&self) -> usize {
275         core::mem::size_of::<DragonStubPayloadEFI>()
276     }
277 
278     fn post_process(
279         &self,
280         vendor_table_vaddr: Option<VirtAddr>,
281         _table_raw: &ConfigurationTable,
282     ) -> Result<(), SystemError> {
283         let vendor_table_vaddr = vendor_table_vaddr.unwrap();
284         let data = unsafe { *(vendor_table_vaddr.data() as *const DragonStubPayloadEFI) };
285 
286         efi_manager().inner.write().dragonstub_load_info = Some(data);
287 
288         return Ok(());
289     }
290 }
291 
292 struct MatchTableMemoryAttributes;
293 
294 impl MatchTable for MatchTableMemoryAttributes {
295     fn name(&self) -> &'static str {
296         "MemAttr"
297     }
298 
299     fn guid(&self) -> &'static uefi_raw::Guid {
300         &EFI_MEMORY_ATTRIBUTES_TABLE_GUID
301     }
302 
303     fn map_size(&self) -> usize {
304         // 不映射
305         0
306     }
307 
308     fn post_process(
309         &self,
310         _vendor_table_vaddr: Option<VirtAddr>,
311         table_raw: &ConfigurationTable,
312     ) -> Result<(), SystemError> {
313         efi_manager()
314             .inner
315             .write_irqsave()
316             .memory_attribute_table_paddr = Some(PhysAddr::new(table_raw.vendor_table as usize));
317         return Ok(());
318     }
319 }
320 
321 struct MatchTableMemReserve;
322 
323 impl MatchTable for MatchTableMemReserve {
324     fn name(&self) -> &'static str {
325         "MemReserve"
326     }
327 
328     fn guid(&self) -> &'static uefi_raw::Guid {
329         &EFI_MEMRESERVE_TABLE_GUID
330     }
331 
332     fn map_size(&self) -> usize {
333         // 不映射
334         0
335     }
336 
337     fn post_process(
338         &self,
339         _vendor_table_vaddr: Option<VirtAddr>,
340         table_raw: &ConfigurationTable,
341     ) -> Result<(), SystemError> {
342         efi_manager().inner.write_irqsave().memreserve_table_paddr =
343             Some(PhysAddr::new(table_raw.vendor_table as usize));
344         kdebug!(
345             "memreserve_table_paddr: {:#x}",
346             table_raw.vendor_table as usize
347         );
348         return Ok(());
349     }
350 }
351 
352 /// 用于匹配配置表的匹配器
353 struct TableMatcher {
354     table: &'static dyn MatchTable,
355 }
356 
357 impl TableMatcher {
358     const fn new(table: &'static dyn MatchTable) -> Self {
359         Self { table }
360     }
361 
362     /// 判断配置表与当前匹配器是否匹配
363     #[inline(never)]
364     fn match_table(&self, table: &ConfigurationTable) -> Option<Result<(), SystemError>> {
365         if !table.vendor_guid.equivalent(self.table.guid()) {
366             return None;
367         }
368 
369         let table_map_size = self.table.map_size();
370 
371         let vendor_table_vaddr: Option<VirtAddr> = if table_map_size > 0 {
372             let table_paddr: PhysAddr = PhysAddr::new(table.vendor_table as usize);
373             let vaddr = EarlyIoRemap::map_not_aligned(table_paddr, table_map_size, true);
374 
375             if let Err(e) = vaddr {
376                 return Some(Err(e));
377             }
378 
379             Some(vaddr.unwrap())
380         } else {
381             None
382         };
383 
384         let r = self.table.post_process(vendor_table_vaddr, table);
385 
386         if let Some(vaddr) = vendor_table_vaddr {
387             EarlyIoRemap::unmap(vaddr).unwrap();
388         }
389         return Some(r);
390     }
391 }
392 
393 #[repr(C)]
394 #[derive(Debug)]
395 struct LinuxEFIMemReserveTable {
396     /// allocated size of the array
397     size: i32,
398     /// number of entries used
399     count: i32,
400     /// pa of next struct instance
401     next_paddr: PhysAddr,
402     entry: [LinuxEFIMemReserveEntry; 0],
403 }
404 
405 #[repr(C)]
406 #[derive(Debug)]
407 struct LinuxEFIMemReserveEntry {
408     base: usize,
409     size: usize,
410 }
411