Skip to content

Commit e920933

Browse files
committed
refactor(mmio): avoid vector creation for devices
1 parent c0a96f7 commit e920933

1 file changed

Lines changed: 36 additions & 46 deletions

File tree

src/arch/x86_64/kernel/mmio.rs

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use alloc::boxed::Box;
12
use alloc::string::String;
23
use alloc::vec::Vec;
34
use core::ptr::NonNull;
@@ -145,71 +146,60 @@ unsafe fn check_ptr(
145146
fn check_linux_args(
146147
linux_mmio: &'static [String],
147148
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@") {
155155
let v: Vec<&str> = arg.trim().split(':').collect();
156156
let without_prefix = v[0].trim_start_matches("0x");
157157
let current_address = usize::from_str_radix(without_prefix, 16).unwrap();
158158
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 {
167161
warn!("Invalid prefix in {arg}");
162+
None
168163
}
169-
}
170-
}
171-
172-
devices
164+
})
173165
}
174166

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)> {
179170
// 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()
200190
}
201191

202-
fn detect_devices() -> Vec<(VolatileRef<'static, DeviceRegisters>, u8)> {
192+
fn detect_devices() -> Box<dyn Iterator<Item = (VolatileRef<'static, DeviceRegisters>, u8)>> {
203193
let layout = PageLayout::from_size(BasePageSize::SIZE as usize).unwrap();
204194
let page_range = PageBox::new(layout).unwrap();
205195
let virtual_address = VirtAddr::from(page_range.start());
206196

207197
let linux_mmio = env::mmio();
208198

209199
if linux_mmio.is_empty() {
210-
guess_device(virtual_address)
200+
Box::new(guess_device(virtual_address))
211201
} else {
212-
check_linux_args(linux_mmio, virtual_address)
202+
Box::new(check_linux_args(linux_mmio, virtual_address))
213203
}
214204
}
215205

0 commit comments

Comments
 (0)