xref: /DragonOS/kernel/src/driver/firmware/efi/fdt.rs (revision 55e6f0b65f91b32638fd56581f711a816eccdcd1)
1 //! 与UEFI相关的fdt操作
2 
3 use core::fmt::Debug;
4 
5 use fdt::Fdt;
6 use log::error;
7 use system_error::SystemError;
8 
9 use crate::init::boot_params;
10 
11 use super::EFIManager;
12 
13 // 由于代码涉及转换,因此这里每个的大小都是8字节
14 #[derive(Default)]
15 pub struct EFIFdtParams {
16     // systable
17     pub systable: Option<u64>,
18     // mmap_base
19     pub mmap_base: Option<u64>,
20     // mmap_size
21     pub mmap_size: Option<u64>,
22     // mmap_desc_size
23     pub mmap_desc_size: Option<u64>,
24     // mmap_desc_version
25     pub mmap_desc_version: Option<u64>,
26 }
27 
28 impl Debug for EFIFdtParams {
29     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
30         // 十六进制输出
31         f.debug_struct("EFIFdtParams")
32             .field("systable", &format_args!("{:#x?}", self.systable))
33             .field("mmap_base", &format_args!("{:#x?}", self.mmap_base))
34             .field("mmap_size", &format_args!("{:#x?}", self.mmap_size))
35             .field(
36                 "mmap_desc_size",
37                 &format_args!("{:#x?}", self.mmap_desc_size),
38             )
39             .field(
40                 "mmap_desc_version",
41                 &format_args!("{:#x?}", self.mmap_desc_version),
42             )
43             .finish()
44     }
45 }
46 
47 /// 要从FDT中获取的属性
48 #[derive(Debug, Clone, Copy)]
49 enum FdtPropType {
50     SystemTable,
51     MMBase,
52     MMSize,
53     DescSize,
54     DescVersion,
55 }
56 
57 impl FdtPropType {
58     /// 获取属性对应的fdt属性名
59     fn prop_name(&self) -> &'static str {
60         (*self).into()
61     }
62 }
63 
64 impl From<FdtPropType> for &'static str {
65     fn from(value: FdtPropType) -> Self {
66         match value {
67             FdtPropType::SystemTable => "linux,uefi-system-table",
68             FdtPropType::MMBase => "linux,uefi-mmap-start",
69             FdtPropType::MMSize => "linux,uefi-mmap-size",
70             FdtPropType::DescSize => "linux,uefi-mmap-desc-size",
71             FdtPropType::DescVersion => "linux,uefi-mmap-desc-ver",
72         }
73     }
74 }
75 
76 impl TryFrom<&str> for FdtPropType {
77     type Error = SystemError;
78 
79     fn try_from(value: &str) -> Result<Self, Self::Error> {
80         match value {
81             "linux,uefi-system-table" => Ok(FdtPropType::SystemTable),
82             "linux,uefi-mmap-start" => Ok(FdtPropType::MMBase),
83             "linux,uefi-mmap-size" => Ok(FdtPropType::MMSize),
84             "linux,uefi-mmap-desc-size" => Ok(FdtPropType::DescSize),
85             "linux,uefi-mmap-desc-ver" => Ok(FdtPropType::DescVersion),
86             _ => Err(SystemError::EINVAL),
87         }
88     }
89 }
90 
91 struct ParamToRead {
92     /// FDT节点路径
93     path: &'static str,
94     /// 当前节点下要读取的属性
95     properties: &'static [FdtPropType],
96 }
97 
98 static PARAM_TO_READ: &[ParamToRead] = &[ParamToRead {
99     path: "/chosen",
100     properties: &[
101         FdtPropType::SystemTable,
102         FdtPropType::MMBase,
103         FdtPropType::MMSize,
104         FdtPropType::DescSize,
105         FdtPropType::DescVersion,
106     ],
107 }];
108 
109 impl EFIManager {
110     pub(super) fn get_fdt_params(&self) -> Result<EFIFdtParams, SystemError> {
111         let fdt = unsafe {
112             Fdt::from_ptr(
113                 boot_params()
114                     .read()
115                     .fdt()
116                     .ok_or(SystemError::ENODEV)?
117                     .data() as *const u8,
118             )
119         }
120         .map_err(|e| {
121             error!("failed to parse fdt, err={:?}", e);
122             SystemError::EINVAL
123         })?;
124 
125         let mut ret = EFIFdtParams::default();
126 
127         for param in PARAM_TO_READ {
128             let node = fdt.find_node(param.path);
129             if node.is_none() {
130                 continue;
131             }
132             let node = node.unwrap();
133 
134             for prop in param.properties {
135                 let prop = node.property(prop.prop_name());
136                 if prop.is_none() {
137                     continue;
138                 }
139                 let prop = prop.unwrap();
140                 let prop_type = FdtPropType::try_from(prop.name);
141                 if prop_type.is_err() {
142                     continue;
143                 }
144 
145                 let prop_type = prop_type.unwrap();
146 
147                 self.do_get_fdt_prop(prop_type, &prop, &mut ret)
148                     .unwrap_or_else(|e| {
149                         error!("Failed to get fdt prop: {prop_type:?}, error: {e:?}");
150                     })
151             }
152         }
153 
154         return Ok(ret);
155     }
156 
157     fn do_get_fdt_prop(
158         &self,
159         prop_type: FdtPropType,
160         prop: &fdt::node::NodeProperty<'_>,
161         target: &mut EFIFdtParams,
162     ) -> Result<(), SystemError> {
163         let val = if prop.value.len() == 4 {
164             u32::from_be_bytes(prop.value[0..4].try_into().unwrap()) as u64
165         } else {
166             u64::from_be_bytes(prop.value[0..8].try_into().unwrap())
167         };
168 
169         match prop_type {
170             FdtPropType::SystemTable => {
171                 target.systable = Some(val);
172             }
173             FdtPropType::MMBase => {
174                 target.mmap_base = Some(val);
175             }
176             FdtPropType::MMSize => {
177                 target.mmap_size = Some(val);
178             }
179             FdtPropType::DescSize => {
180                 target.mmap_desc_size = Some(val);
181             }
182             FdtPropType::DescVersion => {
183                 target.mmap_desc_version = Some(val);
184             }
185         }
186 
187         return Ok(());
188     }
189 }
190