|
| 1 | +use alloc::boxed::Box; |
1 | 2 | use alloc::string::String; |
2 | 3 | use alloc::vec::Vec; |
3 | 4 | use core::ptr::NonNull; |
@@ -145,71 +146,60 @@ unsafe fn check_ptr( |
145 | 146 | fn check_linux_args( |
146 | 147 | linux_mmio: &'static [String], |
147 | 148 | virtual_address: VirtAddr, |
148 | | -) -> Vec<(VolatileRef<'static, DeviceRegisters>, u8)> { |
149 | | - let mut devices = vec![]; |
150 | | - for arg in linux_mmio { |
151 | | - trace!("check linux parameter: {arg}"); |
152 | | - |
153 | | - match arg.trim().trim_matches(char::from(0)).strip_prefix("4K@") { |
154 | | - Some(arg) => { |
| 149 | +) -> impl Iterator<Item = (VolatileRef<'static, DeviceRegisters>, u8)> { |
| 150 | + linux_mmio |
| 151 | + .iter() |
| 152 | + .inspect(|arg| trace!("check linux parameter: {arg}")) |
| 153 | + .flat_map(move |arg| { |
| 154 | + if let Some(arg) = arg.trim().trim_matches(char::from(0)).strip_prefix("4K@") { |
155 | 155 | let v: Vec<&str> = arg.trim().split(':').collect(); |
156 | 156 | let without_prefix = v[0].trim_start_matches("0x"); |
157 | 157 | let current_address = usize::from_str_radix(without_prefix, 16).unwrap(); |
158 | 158 | let irq: u8 = v[1].parse::<u8>().unwrap(); |
159 | | - |
160 | | - let Some(mmio) = (unsafe { check_ptr(virtual_address, current_address) }) else { |
161 | | - continue; |
162 | | - }; |
163 | | - |
164 | | - devices.push((mmio, irq)); |
165 | | - } |
166 | | - _ => { |
| 159 | + (unsafe { check_ptr(virtual_address, current_address) }).map(|mmio| (mmio, irq)) |
| 160 | + } else { |
167 | 161 | warn!("Invalid prefix in {arg}"); |
| 162 | + None |
168 | 163 | } |
169 | | - } |
170 | | - } |
171 | | - |
172 | | - devices |
| 164 | + }) |
173 | 165 | } |
174 | 166 |
|
175 | | -fn guess_device(virtual_address: VirtAddr) -> Vec<(VolatileRef<'static, DeviceRegisters>, u8)> { |
176 | | - // Trigger page mapping in the first iteration! |
177 | | - let mut current_page = 0; |
178 | | - |
| 167 | +fn guess_device( |
| 168 | + virtual_address: VirtAddr, |
| 169 | +) -> impl Iterator<Item = (VolatileRef<'static, DeviceRegisters>, u8)> { |
179 | 170 | // Look for the device-ID in all possible 64-byte aligned addresses within this range. |
180 | | - let mut devices = vec![]; |
181 | | - for current_address in (MMIO_START..MMIO_END).step_by(512) { |
182 | | - // Have we crossed a page boundary in the last iteration? |
183 | | - // info!("before the {}. paging", current_page); |
184 | | - if current_address / BasePageSize::SIZE as usize > current_page { |
185 | | - if !devices.is_empty() { |
186 | | - return devices; |
187 | | - } |
188 | | - |
189 | | - current_page = current_address / BasePageSize::SIZE as usize; |
190 | | - } |
191 | | - |
192 | | - let Some(mmio) = (unsafe { check_ptr(virtual_address, current_address) }) else { |
193 | | - continue; |
194 | | - }; |
195 | | - |
196 | | - devices.push((mmio, IRQ_NUMBER)); |
197 | | - } |
198 | | - |
199 | | - devices |
| 171 | + (MMIO_START..MMIO_END) |
| 172 | + .step_by(512) |
| 173 | + .scan( |
| 174 | + MMIO_END, |
| 175 | + // None signals the end of the scan, while Some(None) means a device was not found at the address but the scan should continue. |
| 176 | + move |end, current_address| { |
| 177 | + // Have we crossed the page boundary? |
| 178 | + (current_address < *end).then(|| { |
| 179 | + let mmio = unsafe { check_ptr(virtual_address, current_address) }; |
| 180 | + // We expect all the devices to be on the same page, so once we find a device, we adjust the end of the search range. |
| 181 | + if mmio.is_some() && *end == MMIO_END { |
| 182 | + *end = current_address |
| 183 | + .next_multiple_of(usize::try_from(BasePageSize::SIZE).unwrap()); |
| 184 | + } |
| 185 | + mmio.map(|mmio| (mmio, IRQ_NUMBER)) |
| 186 | + }) |
| 187 | + }, |
| 188 | + ) |
| 189 | + .flatten() |
200 | 190 | } |
201 | 191 |
|
202 | | -fn detect_devices() -> Vec<(VolatileRef<'static, DeviceRegisters>, u8)> { |
| 192 | +fn detect_devices() -> Box<dyn Iterator<Item = (VolatileRef<'static, DeviceRegisters>, u8)>> { |
203 | 193 | let layout = PageLayout::from_size(BasePageSize::SIZE as usize).unwrap(); |
204 | 194 | let page_range = PageBox::new(layout).unwrap(); |
205 | 195 | let virtual_address = VirtAddr::from(page_range.start()); |
206 | 196 |
|
207 | 197 | let linux_mmio = env::mmio(); |
208 | 198 |
|
209 | 199 | if linux_mmio.is_empty() { |
210 | | - guess_device(virtual_address) |
| 200 | + Box::new(guess_device(virtual_address)) |
211 | 201 | } else { |
212 | | - check_linux_args(linux_mmio, virtual_address) |
| 202 | + Box::new(check_linux_args(linux_mmio, virtual_address)) |
213 | 203 | } |
214 | 204 | } |
215 | 205 |
|
|
0 commit comments