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