Nothing to see here, move along meow
at main 262 lines 8.8 kB view raw
1use crate::static_vec::StaticVec; 2 3const DMAR_HEADER_SIZE: usize = 48; 4 5const DRHD_TYPE: u16 = 0; 6const RMRR_TYPE: u16 = 1; 7 8#[repr(C, packed)] 9struct DmarHeader { 10 _sdt_header: [u8; 36], 11 host_address_width: u8, 12 flags: u8, 13 _reserved: [u8; 10], 14} 15 16#[repr(C, packed)] 17struct RemappingStructHeader { 18 structure_type: u16, 19 length: u16, 20} 21 22#[repr(C, packed)] 23struct DrhdEntry { 24 _header: RemappingStructHeader, 25 flags: u8, 26 _reserved: u8, 27 segment: u16, 28 register_base: u64, 29} 30 31#[repr(C, packed)] 32struct RmrrEntry { 33 _header: RemappingStructHeader, 34 _reserved: u16, 35 segment: u16, 36 base_address: u64, 37 limit_address: u64, 38} 39 40#[repr(C, packed)] 41struct DeviceScopeEntry { 42 scope_type: u8, 43 length: u8, 44 _reserved: u16, 45 enumeration_id: u8, 46 start_bus: u8, 47} 48 49#[repr(C, packed)] 50struct DeviceScopePath { 51 device: u8, 52 function: u8, 53} 54 55#[derive(Debug, Clone)] 56#[allow(dead_code)] 57pub struct DeviceScopeInfo { 58 pub scope_type: u8, 59 pub enumeration_id: u8, 60 pub start_bus: u8, 61 pub path: StaticVec<(u8, u8), 4>, 62} 63 64#[derive(Debug, Clone)] 65pub struct DrhdInfo { 66 pub register_base: u64, 67 pub segment: u16, 68 pub flags: u8, 69 #[allow(dead_code)] 70 pub device_scopes: StaticVec<DeviceScopeInfo, 8>, 71} 72 73#[derive(Debug, Clone)] 74pub struct RmrrInfo { 75 #[allow(dead_code)] 76 pub segment: u16, 77 pub base_address: u64, 78 pub limit_address: u64, 79 pub device_scopes: StaticVec<DeviceScopeInfo, 8>, 80} 81 82#[derive(Debug, Clone)] 83pub struct DmarInfo { 84 #[allow(dead_code)] 85 pub host_address_width: u8, 86 #[allow(dead_code)] 87 pub flags: u8, 88 pub drhd_units: StaticVec<DrhdInfo, 4>, 89 pub rmrr_regions: StaticVec<RmrrInfo, 8>, 90} 91 92fn parse_device_scopes( 93 base: *const u8, 94 entry_len: usize, 95 fixed_header_size: usize, 96) -> StaticVec<DeviceScopeInfo, 8> { 97 let scope_start = fixed_header_size; 98 let min_scope = core::mem::size_of::<DeviceScopeEntry>(); 99 core::iter::successors(Some(scope_start), move |&offset| { 100 if offset + min_scope > entry_len { 101 return None; 102 } 103 let scope_ptr = unsafe { base.add(offset) } as *const DeviceScopeEntry; 104 let scope_len = 105 unsafe { core::ptr::addr_of!((*scope_ptr).length).read_unaligned() } as usize; 106 if scope_len < min_scope { 107 None 108 } else { 109 Some(offset + scope_len) 110 } 111 }) 112 .take_while(|&offset| offset + min_scope <= entry_len) 113 .fold(StaticVec::new(), |mut scopes, offset| { 114 let scope_ptr = unsafe { base.add(offset) } as *const DeviceScopeEntry; 115 let raw_scope_len = 116 unsafe { core::ptr::addr_of!((*scope_ptr).length).read_unaligned() } as usize; 117 let scope_len = raw_scope_len.min(entry_len.saturating_sub(offset)); 118 let scope_type = unsafe { core::ptr::addr_of!((*scope_ptr).scope_type).read_unaligned() }; 119 let enumeration_id = 120 unsafe { core::ptr::addr_of!((*scope_ptr).enumeration_id).read_unaligned() }; 121 let start_bus = unsafe { core::ptr::addr_of!((*scope_ptr).start_bus).read_unaligned() }; 122 123 let path_offset = core::mem::size_of::<DeviceScopeEntry>(); 124 let path_bytes = scope_len.saturating_sub(path_offset); 125 let path_count = path_bytes / core::mem::size_of::<DeviceScopePath>(); 126 127 let path = (0..path_count).fold(StaticVec::new(), |mut p, i| { 128 let path_ptr = 129 unsafe { base.add(offset + path_offset + i * 2) } as *const DeviceScopePath; 130 let device = unsafe { core::ptr::addr_of!((*path_ptr).device).read_unaligned() }; 131 let function = unsafe { core::ptr::addr_of!((*path_ptr).function).read_unaligned() }; 132 let _ = p.push((device, function)); 133 p 134 }); 135 136 let _ = scopes.push(DeviceScopeInfo { 137 scope_type, 138 enumeration_id, 139 start_bus, 140 path, 141 }); 142 scopes 143 }) 144} 145 146pub fn parse_dmar(virt_addr: u64, length: u32) -> DmarInfo { 147 let base = virt_addr as *const u8; 148 let hdr_ptr = base as *const DmarHeader; 149 let host_address_width = 150 unsafe { core::ptr::addr_of!((*hdr_ptr).host_address_width).read_unaligned() }; 151 let flags = unsafe { core::ptr::addr_of!((*hdr_ptr).flags).read_unaligned() }; 152 153 crate::kprintln!( 154 " DMAR: host address width {}, flags {:#x}", 155 host_address_width, 156 flags 157 ); 158 159 let min_entry = core::mem::size_of::<RemappingStructHeader>(); 160 let entries = core::iter::successors(Some(DMAR_HEADER_SIZE), move |&offset| { 161 if offset + min_entry > length as usize { 162 return None; 163 } 164 let header_ptr = unsafe { base.add(offset) } as *const RemappingStructHeader; 165 let entry_len = 166 unsafe { core::ptr::addr_of!((*header_ptr).length).read_unaligned() } as usize; 167 if entry_len < min_entry { 168 None 169 } else { 170 Some(offset + entry_len) 171 } 172 }); 173 174 let (drhd_units, rmrr_regions) = entries 175 .take_while(|&offset| offset + min_entry <= length as usize) 176 .fold( 177 (StaticVec::new(), StaticVec::new()), 178 |(mut units, mut rmrrs), offset| { 179 let header_ptr = unsafe { base.add(offset) } as *const RemappingStructHeader; 180 let structure_type = 181 unsafe { core::ptr::addr_of!((*header_ptr).structure_type).read_unaligned() }; 182 let entry_len = 183 unsafe { core::ptr::addr_of!((*header_ptr).length).read_unaligned() } as usize; 184 185 match structure_type { 186 DRHD_TYPE if entry_len >= core::mem::size_of::<DrhdEntry>() => { 187 let drhd_ptr = unsafe { base.add(offset) } as *const DrhdEntry; 188 let drhd_flags = 189 unsafe { core::ptr::addr_of!((*drhd_ptr).flags).read_unaligned() }; 190 let segment = 191 unsafe { core::ptr::addr_of!((*drhd_ptr).segment).read_unaligned() }; 192 let register_base = unsafe { 193 core::ptr::addr_of!((*drhd_ptr).register_base).read_unaligned() 194 }; 195 196 let device_scopes = parse_device_scopes( 197 unsafe { base.add(offset) }, 198 entry_len, 199 core::mem::size_of::<DrhdEntry>(), 200 ); 201 202 crate::kprintln!( 203 " DMAR: DRHD at {:#x}, segment {}, flags {:#x}, {} device scope(s)", 204 register_base, 205 segment, 206 drhd_flags, 207 device_scopes.len() 208 ); 209 210 let _ = units.push(DrhdInfo { 211 register_base, 212 segment, 213 flags: drhd_flags, 214 device_scopes, 215 }); 216 } 217 RMRR_TYPE if entry_len >= core::mem::size_of::<RmrrEntry>() => { 218 let rmrr_ptr = unsafe { base.add(offset) } as *const RmrrEntry; 219 let segment = 220 unsafe { core::ptr::addr_of!((*rmrr_ptr).segment).read_unaligned() }; 221 let base_address = unsafe { 222 core::ptr::addr_of!((*rmrr_ptr).base_address).read_unaligned() 223 }; 224 let limit_address = unsafe { 225 core::ptr::addr_of!((*rmrr_ptr).limit_address).read_unaligned() 226 }; 227 228 let device_scopes = parse_device_scopes( 229 unsafe { base.add(offset) }, 230 entry_len, 231 core::mem::size_of::<RmrrEntry>(), 232 ); 233 234 crate::kprintln!( 235 " DMAR: RMRR {:#x}-{:#x}, segment {}, {} device scope(s)", 236 base_address, 237 limit_address, 238 segment, 239 device_scopes.len() 240 ); 241 242 let _ = rmrrs.push(RmrrInfo { 243 segment, 244 base_address, 245 limit_address, 246 device_scopes, 247 }); 248 } 249 _ => {} 250 } 251 252 (units, rmrrs) 253 }, 254 ); 255 256 DmarInfo { 257 host_address_width, 258 flags, 259 drhd_units, 260 rmrr_regions, 261 } 262}