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