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 { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result29 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属性名 prop_name(&self) -> &'static str59 fn prop_name(&self) -> &'static str { 60 (*self).into() 61 } 62 } 63 64 impl From<FdtPropType> for &'static str { from(value: FdtPropType) -> Self65 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 try_from(value: &str) -> Result<Self, Self::Error>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 { get_fdt_params(&self) -> Result<EFIFdtParams, SystemError>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 do_get_fdt_prop( &self, prop_type: FdtPropType, prop: &fdt::node::NodeProperty<'_>, target: &mut EFIFdtParams, ) -> Result<(), SystemError>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