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