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