Skip to main content

strat9_kernel/boot/
modules.rs

1//! Pure conversion of physical boot modules into initfs registration arguments.
2use strat9_abi::boot::{ModuleEntry, MAX_BOOT_MODULES};
3
4pub struct InitfsModule<'a> {
5    pub name: &'a str,
6    pub virtual_base: u64,
7    pub len: usize,
8}
9
10impl<'a> InitfsModule<'a> {
11    /// Numeric validation only. The boot path must keep the payload reserved and
12    /// mapped for the lifetime of the VFS file before anyone dereferences it.
13    pub fn from_physical(entry: &'a ModuleEntry, hhdm: u64) -> Result<Self, &'static str> {
14        let name = entry.checked_name()?;
15        if entry.base == 0 || entry.size > isize::MAX as u64 {
16            return Err("invalid module payload extent");
17        }
18        entry
19            .base
20            .checked_add(entry.size)
21            .ok_or("module physical range overflow")?;
22        let virtual_base = hhdm
23            .checked_add(entry.base)
24            .ok_or("module HHDM address overflow")?;
25        let last = virtual_base
26            .checked_add(entry.size.saturating_sub(1))
27            .ok_or("module virtual range overflow")?;
28        // This boot path uses four-level x86-64 paging. Reject ranges through
29        // the noncanonical hole as well as already-converted physical inputs.
30        if !canonical(virtual_base) || !canonical(last) || (virtual_base >> 47) != (last >> 47) {
31            return Err("module virtual range is not canonical");
32        }
33        Ok(Self {
34            name,
35            virtual_base,
36            len: entry.size as usize,
37        })
38    }
39}
40
41pub fn validate_modules(entries: &[ModuleEntry], hhdm: u64) -> Result<(), &'static str> {
42    if entries.len() > MAX_BOOT_MODULES {
43        return Err("too many initfs modules");
44    }
45    for (index, entry) in entries.iter().enumerate() {
46        let view = InitfsModule::from_physical(entry, hhdm)?;
47        for previous in &entries[..index] {
48            if previous.checked_name()?.eq_ignore_ascii_case(view.name) {
49                return Err("duplicate initfs module name");
50            }
51        }
52    }
53    Ok(())
54}
55
56fn canonical(address: u64) -> bool {
57    address < (1 << 47) || address >= 0xFFFF_8000_0000_0000
58}